From daf4cceab48b772ed8a3ff66958f71b35580f120 Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Tue, 24 Feb 2026 13:14:44 +0100 Subject: [PATCH 1/4] Add fragment-arguments --- libraries/apollo-ast/api/apollo-ast.api | 16 +- libraries/apollo-ast/api/apollo-ast.klib.api | 16 +- .../com/apollographql/apollo/ast/Issue.kt | 2 +- .../com/apollographql/apollo/ast/api.kt | 14 +- .../com/apollographql/apollo/ast/gql.kt | 115 ++++++++-- .../ast/internal/ExecutableValidationScope.kt | 135 ++++++++--- .../apollo/ast/internal/Parser.kt | 18 +- .../apollo/ast/internal/ValidationCommon.kt | 24 +- .../apollo/ast/internal/fields_merging.kt | 90 +++++++- .../ast/test/ExecutableValidationTest.kt | 3 +- .../apollo/graphql/ast/test/fixtures.kt | 10 +- .../parser/fragment-arguments-error.expected | 2 + .../parser/fragment-arguments-error.graphql | 7 + .../parser/fragment-arguments.expected | 8 + .../parser/fragment-arguments.graphql | 9 + .../executable/UnusedVariable.expected | 2 +- .../default_value.expected} | 0 .../fragment_arguments/default_value.graphql | 12 + .../fragment_arguments/merge_error.expected | 11 + .../fragment_arguments/merge_error.graphql | 31 +++ .../missing_required_argument.expected | 2 + .../missing_required_argument.graphql | 12 + .../operation_variable_passthrough.expected} | 0 .../operation_variable_passthrough.graphql | 12 + .../fragment_arguments/schema.graphqls | 29 +++ .../fragment_arguments/type_mismatch.expected | 2 + .../fragment_arguments/type_mismatch.graphql | 12 + .../unknown_argument.expected | 2 + .../unknown_argument.graphql | 12 + .../unused_fragment_variable.expected | 2 + .../unused_fragment_variable.graphql | 12 + .../valid_usage.expected} | 0 .../fragment_arguments/valid_usage.graphql | 12 + .../variable_scoping.expected} | 0 .../variable_scoping.graphql | 18 ++ .../graphql-js/LICENSE | 0 .../graphql-js/README.md | 0 .../allows_different_order_of_args.expected | 0 .../allows_different_order_of_args.graphql | 0 .../field_merging_order}/schema.graphqls | 0 ...input_object_fields_in_arg_values.expected | 0 ..._input_object_fields_in_arg_values.graphql | 0 .../input_field_order}/schema.graphqls | 0 .../keywords}/schema.graphqls | 0 ..._field_names_that_are_js_keywords.expected | 0 ...r_field_names_that_are_js_keywords.graphql | 0 .../known_directive/schema.graphqls | 13 ++ .../with_misplaced_directives.expected | 29 +++ .../with_misplaced_directives.graphql | 10 + .../with_no_directive.expected} | 0 .../known_directive/with_no_directive.graphql | 8 + .../with_standard_directives.expected | 2 + .../with_standard_directives.graphql | 4 + .../with_unknown_directive.expected | 5 + .../with_unknown_directive.graphql | 3 + ...ot_unused_or_undefined_variables.expected} | 0 ..._not_unused_or_undefined_variables.graphql | 12 + ...guments_are_not_unused_variables.expected} | 0 ...ot_unused_or_undefined_variables.expected} | 0 ..._not_unused_or_undefined_variables.graphql | 12 + ...variables_produce_multiple_errors.expected | 35 +++ ..._variables_produce_multiple_errors.graphql | 24 ++ ...ariables_in_fragments_not_defined.expected | 5 + ...variables_in_fragments_not_defined.graphql | 20 ++ .../multiple_variables_not_defined.expected | 5 + .../multiple_variables_not_defined.graphql | 5 + .../multiple_variables_not_used.expected | 5 + .../multiple_variables_not_used.graphql | 5 + ...e_variables_not_used_in_fragments.expected | 5 + ...le_variables_not_used_in_fragments.graphql | 20 ++ .../no_unused_variable.expected | 2 + .../no_unused_variable.graphql | 5 + .../schema.graphqls | 8 + ...ot_defined_by_multiple_operations.expected | 5 + ...not_defined_by_multiple_operations.graphql | 15 ++ ...d_fragment_variables_are_reported.expected | 2 + ...ed_fragment_variables_are_reported.graphql | 12 + .../uses_all_variables_deeply.expected} | 0 .../uses_all_variables_deeply.graphql | 9 + ...ables_deeply_in_inline_fragments.expected} | 0 ...riables_deeply_in_inline_fragments.graphql | 13 ++ .../uses_all_variables_in_fragments.expected} | 0 .../uses_all_variables_in_fragments.graphql | 20 ++ ...fragment_not_defined_by_operation.expected | 2 + ..._fragment_not_defined_by_operation.graphql | 20 ++ ...ment_not_defined_by_unnamed_query.expected | 5 + ...gment_not_defined_by_unnamed_query.graphql | 10 + ..._fragment_used_by_other_operation.expected | 11 + ...n_fragment_used_by_other_operation.graphql | 20 ++ .../variable_not_defined.expected | 2 + .../variable_not_defined.graphql | 5 + ...le_not_defined_by_anonymous_query.expected | 5 + ...ble_not_defined_by_anonymous_query.graphql | 5 + .../variable_not_used.expected | 5 + .../variable_not_used.graphql | 5 + ..._fragment_used_by_other_operation.expected | 11 + ...y_fragment_used_by_other_operation.graphql | 20 ++ ...not_used_by_unreferenced_fragment.expected | 8 + ..._not_used_by_unreferenced_fragment.graphql | 15 ++ .../variable_not_used_in_fragments.expected | 2 + .../variable_not_used_in_fragments.graphql | 20 ++ ..._fragment_in_multiple_operations.expected} | 0 ...by_fragment_in_multiple_operations.graphql | 20 ++ ...riable_used_by_recursive_fragment.expected | 2 + ...ariable_used_by_recursive_fragment.graphql | 10 + ...ot_defined_by_multiple_operations.expected | 5 + ...not_defined_by_multiple_operations.graphql | 15 ++ ...nts_are_still_undefined_variables.expected | 5 + ...ents_are_still_undefined_variables.graphql | 15 ++ ...uments_may_be_undefined_variables.expected | 5 + ...guments_may_be_undefined_variables.graphql | 12 + ...fragments_without_type_condition.expected} | 0 ...e_fragments_without_type_condition.graphql | 0 ...non_conflicting_overlapping_types.expected | 0 ..._non_conflicting_overlapping_types.graphql | 0 ...ompares_deep_types_including_list.expected | 0 ...compares_deep_types_including_list.graphql | 0 ..._shapes_on_different_return_types.expected | 0 ...n_shapes_on_different_return_types.graphql | 0 ...n_types_which_potentially_overlap.expected | 0 ...rn_types_which_potentially_overlap.graphql | 0 ...p_return_types_despite_no_overlap.expected | 0 ...ep_return_types_despite_no_overlap.graphql | 0 ...rn_type_list_despite_no_overlap_1.expected | 0 ...urn_type_list_despite_no_overlap_1.graphql | 0 ...rn_type_list_despite_no_overlap_2.expected | 0 ...urn_type_list_despite_no_overlap_2.graphql | 0 ...pe_nullability_despite_no_overlap.expected | 0 ...ype_nullability_despite_no_overlap.graphql | 0 ...g_return_types_despite_no_overlap.expected | 0 ...ng_return_types_despite_no_overlap.graphql | 0 .../disallows_differing_subfields.expected | 0 .../disallows_differing_subfields.graphql | 0 .../ignores_unknown_types.expected | 0 .../ignores_unknown_types.graphql | 0 ...on_exclusive_follows_an_exclusive.expected | 0 ...non_exclusive_follows_an_exclusive.graphql | 0 .../same_wrapped_scalar_return_types.expected | 0 .../same_wrapped_scalar_return_types.graphql | 0 .../same_response_shape}/schema.graphqls | 0 ...alias_masking_direct_field_access.expected | 0 .../alias_masking_direct_field_access.graphql | 0 ...rgs_where_no_conflict_is_possible.expected | 0 ...args_where_no_conflict_is_possible.graphql | 0 ..._fragment_without_arg_is_reported.expected | 5 + ...o_fragment_without_arg_is_reported.graphql | 10 + .../schema1/conflicting_arg_names.expected | 0 .../schema1/conflicting_arg_names.graphql | 0 .../schema1/conflicting_arg_values.expected | 0 .../schema1/conflicting_arg_values.graphql | 0 .../graphql-js/schema1/deep_conflict.expected | 0 .../graphql-js/schema1/deep_conflict.graphql | 0 ...eep_conflict_with_multiple_issues.expected | 0 ...deep_conflict_with_multiple_issues.graphql | 0 ...rent_args_second_adds_an_argument.expected | 0 ...erent_args_second_adds_an_argument.graphql | 0 ...t_args_second_missing_an_argument.expected | 0 ...nt_args_second_missing_an_argument.graphql | 0 ...erent_args_with_different_aliases.expected | 0 ...ferent_args_with_different_aliases.graphql | 0 ...directives_with_different_aliases.expected | 0 ..._directives_with_different_aliases.graphql | 0 ..._skip_include_directives_accepted.expected | 0 ...t_skip_include_directives_accepted.graphql | 0 ...on_immediately_recursive_fragment.expected | 0 ..._on_immediately_recursive_fragment.graphql | 0 ...finite_loop_on_recursive_fragment.expected | 0 ...nfinite_loop_on_recursive_fragment.graphql | 0 ...with_a_field_named_after_fragment.expected | 0 ..._with_a_field_named_after_fragment.graphql | 0 ...ive_fragments_separated_by_fields.expected | 0 ...sive_fragments_separated_by_fields.graphql | 0 ...n_transitively_recursive_fragment.expected | 0 ...on_transitively_recursive_fragment.graphql | 0 .../encounters_conflict_in_fragments.expected | 0 .../encounters_conflict_in_fragments.graphql | 0 ...s_conflict_in_fragments_with_args.expected | 8 + ...rs_conflict_in_fragments_with_args.graphql | 9 + ...th_immediately_recursive_fragment.expected | 0 ...ith_immediately_recursive_fragment.graphql | 0 ...n_with_field_named_after_fragment.expected | 0 ...en_with_field_named_after_fragment.graphql | 0 .../schema1/fragment_args_are_known.expected | 2 + .../schema1/fragment_args_are_known.graphql | 10 + .../schema1/identical_fields.expected | 0 .../schema1/identical_fields.graphql | 0 ...ntical_fields_with_identical_args.expected | 0 ...entical_fields_with_identical_args.graphql | 0 ..._fields_with_identical_directives.expected | 0 ...l_fields_with_identical_directives.graphql | 0 .../ignores_unknown_fragments.expected | 0 .../schema1/ignores_unknown_fragments.graphql | 0 ...p_conflict_after_nested_fragments.expected | 0 ...ep_conflict_after_nested_fragments.graphql | 0 ...deep_conflict_in_nested_fragments.expected | 0 ..._deep_conflict_in_nested_fragments.graphql | 0 ...nflict_to_nearest_common_ancestor.expected | 0 ...onflict_to_nearest_common_ancestor.graphql | 0 ...rest_common_ancestor_in_fragments.expected | 0 ...arest_common_ancestor_in_fragments.graphql | 0 .../reports_each_conflict_once.expected | 0 .../reports_each_conflict_once.graphql | 0 ...allowed_on_non_overlapping_fields.expected | 0 ..._allowed_on_non_overlapping_fields.graphql | 0 ...ases_with_different_field_targets.expected | 0 ...iases_with_different_field_targets.graphql | 0 .../graphql-js/schema1/schema.graphqls | 1 + .../graphql-js/schema1/unique_fields.expected | 0 .../graphql-js/schema1/unique_fields.graphql | 0 .../unknown_args_amongst_known_args.expected | 8 + .../unknown_args_amongst_known_args.graphql | 7 + .../schema1/very_deep_conflict.expected | 0 .../schema1/very_deep_conflict.graphql | 0 .../mandatory_argument.expected | 2 +- .../apollo-compiler/api/apollo-compiler.api | 7 +- .../apollo/compiler/ApolloCompiler.kt | 6 +- .../apollographql/apollo/compiler/Options.kt | 6 +- .../apollo/compiler/ir/IrOperationsBuilder.kt | 2 +- .../apollo-execution/api/apollo-execution.api | 1 + .../api/apollo-execution.klib.api | 1 + .../apollo/execution/ExecutableSchema.kt | 16 +- .../execution/internal/OperationContext.kt | 210 ++++++++++-------- .../internal/coerceArgumentValues.kt | 71 +++++- .../apollo/execution/internal/prepare.kt | 15 +- .../kotlin/test/ExecutionTest.kt | 132 ++++++++++- .../api/apollo-gradle-plugin-tasks.api | 4 +- .../gradle/task/apolloGenerateOptions.kt | 2 + .../api/apollo-gradle-plugin.api | 3 +- .../apollo/gradle/api/Service.kt | 7 + .../gradle/internal/DefaultApolloExtension.kt | 1 + tests/fragment-arguments/build.gradle.kts | 24 ++ .../src/main/graphql/operations.graphql | 7 + .../src/main/graphql/schema.graphqls | 3 + .../test/kotlin/test/FragmentArgumentsTest.kt | 39 ++++ tests/settings.gradle.kts | 1 + 235 files changed, 1647 insertions(+), 203 deletions(-) create mode 100644 libraries/apollo-ast/test-fixtures/parser/fragment-arguments-error.expected create mode 100644 libraries/apollo-ast/test-fixtures/parser/fragment-arguments-error.graphql create mode 100644 libraries/apollo-ast/test-fixtures/parser/fragment-arguments.expected create mode 100644 libraries/apollo-ast/test-fixtures/parser/fragment-arguments.graphql rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema1/allows_different_args_where_no_conflict_is_possible.expected => fragment_arguments/default_value.expected} (100%) create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/default_value.graphql create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/merge_error.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/merge_error.graphql create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/missing_required_argument.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/missing_required_argument.graphql rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema1/different_args_with_different_aliases.expected => fragment_arguments/operation_variable_passthrough.expected} (100%) create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/operation_variable_passthrough.graphql create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/schema.graphqls create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/type_mismatch.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/type_mismatch.graphql create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/unknown_argument.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/unknown_argument.graphql create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/unused_fragment_variable.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/unused_fragment_variable.graphql rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema1/different_directives_with_different_aliases.expected => fragment_arguments/valid_usage.expected} (100%) create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/valid_usage.graphql rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema1/different_skip_include_directives_accepted.expected => fragment_arguments/variable_scoping.expected} (100%) create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/variable_scoping.graphql rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/LICENSE (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/README.md (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema2 => graphql-js/field_merging_order}/allows_different_order_of_args.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema2 => graphql-js/field_merging_order}/allows_different_order_of_args.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema2 => graphql-js/field_merging_order}/schema.graphqls (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema3 => graphql-js/input_field_order}/allows_different_order_of_input_object_fields_in_arg_values.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema3 => graphql-js/input_field_order}/allows_different_order_of_input_object_fields_in_arg_values.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema3 => graphql-js/input_field_order}/schema.graphqls (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema5 => graphql-js/keywords}/schema.graphqls (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema5 => graphql-js/keywords}/works_for_field_names_that_are_js_keywords.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema5 => graphql-js/keywords}/works_for_field_names_that_are_js_keywords.graphql (100%) create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/schema.graphqls create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/with_misplaced_directives.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/with_misplaced_directives.graphql rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema1/identical_fields.expected => graphql-js/known_directive/with_no_directive.expected} (100%) create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/with_no_directive.graphql create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/with_standard_directives.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/with_standard_directives.graphql create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/with_unknown_directive.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/with_unknown_directive.graphql rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema1/identical_fields_with_identical_args.expected => graphql-js/no_unused_or_undefined_variable/defined_variables_used as_fragment_arguments_are_not_unused_or_undefined_variables.expected} (100%) create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/defined_variables_used as_fragment_arguments_are_not_unused_or_undefined_variables.graphql rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema1/identical_fields_with_identical_directives.expected => graphql-js/no_unused_or_undefined_variable/defined_variables_used as_fragment_arguments_are_not_unused_variables.expected} (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema1/same_aliases_allowed_on_non_overlapping_fields.expected => graphql-js/no_unused_or_undefined_variable/fragment_defined_arguments_are_not_unused_or_undefined_variables.expected} (100%) create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/fragment_defined_arguments_are_not_unused_or_undefined_variables.graphql create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_undefined_variables_produce_multiple_errors.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_undefined_variables_produce_multiple_errors.graphql create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_in_fragments_not_defined.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_in_fragments_not_defined.graphql create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_not_defined.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_not_defined.graphql create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_not_used.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_not_used.graphql create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_not_used_in_fragments.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_not_used_in_fragments.graphql create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/no_unused_variable.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/no_unused_variable.graphql create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/schema.graphqls create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/single_variable_in_fragment_not_defined_by_multiple_operations.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/single_variable_in_fragment_not_defined_by_multiple_operations.graphql create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/unused_fragment_variables_are_reported.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/unused_fragment_variables_are_reported.graphql rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema1/unique_fields.expected => graphql-js/no_unused_or_undefined_variable/uses_all_variables_deeply.expected} (100%) create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/uses_all_variables_deeply.graphql rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema4/allows_inline_fragments_without_type_condition.expected => graphql-js/no_unused_or_undefined_variable/uses_all_variables_deeply_in_inline_fragments.expected} (100%) create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/uses_all_variables_deeply_in_inline_fragments.graphql rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema4/allows_non_conflicting_overlapping_types.expected => graphql-js/no_unused_or_undefined_variable/uses_all_variables_in_fragments.expected} (100%) create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/uses_all_variables_in_fragments.graphql create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_in_fragment_not_defined_by_operation.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_in_fragment_not_defined_by_operation.graphql create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_in_fragment_not_defined_by_unnamed_query.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_in_fragment_not_defined_by_unnamed_query.graphql create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_in_fragment_used_by_other_operation.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_in_fragment_used_by_other_operation.graphql create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_defined.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_defined.graphql create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_defined_by_anonymous_query.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_defined_by_anonymous_query.graphql create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used.graphql create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used_by_fragment_used_by_other_operation.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used_by_fragment_used_by_other_operation.graphql create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used_by_unreferenced_fragment.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used_by_unreferenced_fragment.graphql create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used_in_fragments.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used_in_fragments.graphql rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema4/compatible_return_shapes_on_different_return_types.expected => graphql-js/no_unused_or_undefined_variable/variable_used_by_fragment_in_multiple_operations.expected} (100%) create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_used_by_fragment_in_multiple_operations.graphql create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_used_by_recursive_fragment.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_used_by_recursive_fragment.graphql create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variables_in_fragment_not_defined_by_multiple_operations.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variables_in_fragment_not_defined_by_multiple_operations.graphql create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variables_shadowed_by_parent_fragment_arguments_are_still_undefined_variables.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variables_shadowed_by_parent_fragment_arguments_are_still_undefined_variables.graphql create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variables_used_as_fragment_arguments_may_be_undefined_variables.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variables_used_as_fragment_arguments_may_be_undefined_variables.graphql rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema4/same_wrapped_scalar_return_types.expected => graphql-js/same_response_shape/allows_inline_fragments_without_type_condition.expected} (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema4 => graphql-js/same_response_shape}/allows_inline_fragments_without_type_condition.graphql (100%) create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/allows_non_conflicting_overlapping_types.expected rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema4 => graphql-js/same_response_shape}/allows_non_conflicting_overlapping_types.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema4 => graphql-js/same_response_shape}/compares_deep_types_including_list.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema4 => graphql-js/same_response_shape}/compares_deep_types_including_list.graphql (100%) create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/compatible_return_shapes_on_different_return_types.expected rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema4 => graphql-js/same_response_shape}/compatible_return_shapes_on_different_return_types.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema4 => graphql-js/same_response_shape}/conflicting_return_types_which_potentially_overlap.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema4 => graphql-js/same_response_shape}/conflicting_return_types_which_potentially_overlap.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema4 => graphql-js/same_response_shape}/disallows_differing_deep_return_types_despite_no_overlap.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema4 => graphql-js/same_response_shape}/disallows_differing_deep_return_types_despite_no_overlap.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema4 => graphql-js/same_response_shape}/disallows_differing_return_type_list_despite_no_overlap_1.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema4 => graphql-js/same_response_shape}/disallows_differing_return_type_list_despite_no_overlap_1.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema4 => graphql-js/same_response_shape}/disallows_differing_return_type_list_despite_no_overlap_2.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema4 => graphql-js/same_response_shape}/disallows_differing_return_type_list_despite_no_overlap_2.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema4 => graphql-js/same_response_shape}/disallows_differing_return_type_nullability_despite_no_overlap.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema4 => graphql-js/same_response_shape}/disallows_differing_return_type_nullability_despite_no_overlap.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema4 => graphql-js/same_response_shape}/disallows_differing_return_types_despite_no_overlap.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema4 => graphql-js/same_response_shape}/disallows_differing_return_types_despite_no_overlap.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema4 => graphql-js/same_response_shape}/disallows_differing_subfields.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema4 => graphql-js/same_response_shape}/disallows_differing_subfields.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema4 => graphql-js/same_response_shape}/ignores_unknown_types.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema4 => graphql-js/same_response_shape}/ignores_unknown_types.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema4 => graphql-js/same_response_shape}/reports_correctly_when_a_non_exclusive_follows_an_exclusive.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema4 => graphql-js/same_response_shape}/reports_correctly_when_a_non_exclusive_follows_an_exclusive.graphql (100%) create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/same_wrapped_scalar_return_types.expected rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema4 => graphql-js/same_response_shape}/same_wrapped_scalar_return_types.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge/graphql-js/schema4 => graphql-js/same_response_shape}/schema.graphqls (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/alias_masking_direct_field_access.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/alias_masking_direct_field_access.graphql (100%) create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/allows_different_args_where_no_conflict_is_possible.expected rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/allows_different_args_where_no_conflict_is_possible.graphql (100%) create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/arg_passed_to_fragment_without_arg_is_reported.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/arg_passed_to_fragment_without_arg_is_reported.graphql rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/conflicting_arg_names.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/conflicting_arg_names.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/conflicting_arg_values.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/conflicting_arg_values.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/deep_conflict.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/deep_conflict.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/deep_conflict_with_multiple_issues.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/deep_conflict_with_multiple_issues.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/different_args_second_adds_an_argument.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/different_args_second_adds_an_argument.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/different_args_second_missing_an_argument.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/different_args_second_missing_an_argument.graphql (100%) create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/different_args_with_different_aliases.expected rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/different_args_with_different_aliases.graphql (100%) create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/different_directives_with_different_aliases.expected rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/different_directives_with_different_aliases.graphql (100%) create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/different_skip_include_directives_accepted.expected rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/different_skip_include_directives_accepted.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/does_not_infinite_loop_on_immediately_recursive_fragment.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/does_not_infinite_loop_on_immediately_recursive_fragment.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/does_not_infinite_loop_on_recursive_fragment.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/does_not_infinite_loop_on_recursive_fragment.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/does_not_infinite_loop_on_recursive_fragment_with_a_field_named_after_fragment.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/does_not_infinite_loop_on_recursive_fragment_with_a_field_named_after_fragment.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/does_not_infinite_loop_on_recursive_fragments_separated_by_fields.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/does_not_infinite_loop_on_recursive_fragments_separated_by_fields.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/does_not_infinite_loop_on_transitively_recursive_fragment.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/does_not_infinite_loop_on_transitively_recursive_fragment.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/encounters_conflict_in_fragments.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/encounters_conflict_in_fragments.graphql (100%) create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/encounters_conflict_in_fragments_with_args.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/encounters_conflict_in_fragments_with_args.graphql rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/finds_invalid_case_even_with_immediately_recursive_fragment.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/finds_invalid_case_even_with_immediately_recursive_fragment.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/finds_invalid_cases_even_with_field_named_after_fragment.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/finds_invalid_cases_even_with_field_named_after_fragment.graphql (100%) create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/fragment_args_are_known.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/fragment_args_are_known.graphql create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/identical_fields.expected rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/identical_fields.graphql (100%) create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/identical_fields_with_identical_args.expected rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/identical_fields_with_identical_args.graphql (100%) create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/identical_fields_with_identical_directives.expected rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/identical_fields_with_identical_directives.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/ignores_unknown_fragments.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/ignores_unknown_fragments.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/reports_deep_conflict_after_nested_fragments.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/reports_deep_conflict_after_nested_fragments.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/reports_deep_conflict_in_nested_fragments.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/reports_deep_conflict_in_nested_fragments.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/reports_deep_conflict_to_nearest_common_ancestor.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/reports_deep_conflict_to_nearest_common_ancestor.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/reports_deep_conflict_to_nearest_common_ancestor_in_fragments.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/reports_deep_conflict_to_nearest_common_ancestor_in_fragments.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/reports_each_conflict_once.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/reports_each_conflict_once.graphql (100%) create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/same_aliases_allowed_on_non_overlapping_fields.expected rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/same_aliases_allowed_on_non_overlapping_fields.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/same_aliases_with_different_field_targets.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/same_aliases_with_different_field_targets.graphql (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/schema.graphqls (99%) create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/unique_fields.expected rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/unique_fields.graphql (100%) create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/unknown_args_amongst_known_args.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/unknown_args_amongst_known_args.graphql rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/very_deep_conflict.expected (100%) rename libraries/apollo-ast/test-fixtures/validation/executable/{fields_in_set_can_merge => }/graphql-js/schema1/very_deep_conflict.graphql (100%) create mode 100644 tests/fragment-arguments/build.gradle.kts create mode 100644 tests/fragment-arguments/src/main/graphql/operations.graphql create mode 100644 tests/fragment-arguments/src/main/graphql/schema.graphqls create mode 100644 tests/fragment-arguments/src/test/kotlin/test/FragmentArgumentsTest.kt diff --git a/libraries/apollo-ast/api/apollo-ast.api b/libraries/apollo-ast/api/apollo-ast.api index fd83f840ad9..64e939c7af9 100644 --- a/libraries/apollo-ast/api/apollo-ast.api +++ b/libraries/apollo-ast/api/apollo-ast.api @@ -432,8 +432,12 @@ public final class com/apollographql/apollo/ast/GQLFloatValue : com/apollographq public final class com/apollographql/apollo/ast/GQLFragmentDefinition : com/apollographql/apollo/ast/GQLDescribed, com/apollographql/apollo/ast/GQLExecutableDefinition, com/apollographql/apollo/ast/GQLHasDirectives, com/apollographql/apollo/ast/GQLNamed { public fun (Lcom/apollographql/apollo/ast/SourceLocation;Ljava/lang/String;Ljava/util/List;Lcom/apollographql/apollo/ast/GQLNamedType;Ljava/util/List;Ljava/lang/String;)V public synthetic fun (Lcom/apollographql/apollo/ast/SourceLocation;Ljava/lang/String;Ljava/util/List;Lcom/apollographql/apollo/ast/GQLNamedType;Ljava/util/List;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Lcom/apollographql/apollo/ast/SourceLocation;Ljava/lang/String;Ljava/util/List;Ljava/util/List;Lcom/apollographql/apollo/ast/GQLNamedType;Ljava/util/List;Ljava/lang/String;)V + public synthetic fun (Lcom/apollographql/apollo/ast/SourceLocation;Ljava/lang/String;Ljava/util/List;Ljava/util/List;Lcom/apollographql/apollo/ast/GQLNamedType;Ljava/util/List;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun copy (Lcom/apollographql/apollo/ast/SourceLocation;Ljava/lang/String;Ljava/util/List;Lcom/apollographql/apollo/ast/GQLNamedType;Ljava/util/List;Ljava/lang/String;)Lcom/apollographql/apollo/ast/GQLFragmentDefinition; + public final fun copy (Lcom/apollographql/apollo/ast/SourceLocation;Ljava/lang/String;Ljava/util/List;Ljava/util/List;Lcom/apollographql/apollo/ast/GQLNamedType;Ljava/util/List;Ljava/lang/String;)Lcom/apollographql/apollo/ast/GQLFragmentDefinition; public static synthetic fun copy$default (Lcom/apollographql/apollo/ast/GQLFragmentDefinition;Lcom/apollographql/apollo/ast/SourceLocation;Ljava/lang/String;Ljava/util/List;Lcom/apollographql/apollo/ast/GQLNamedType;Ljava/util/List;Ljava/lang/String;ILjava/lang/Object;)Lcom/apollographql/apollo/ast/GQLFragmentDefinition; + public static synthetic fun copy$default (Lcom/apollographql/apollo/ast/GQLFragmentDefinition;Lcom/apollographql/apollo/ast/SourceLocation;Ljava/lang/String;Ljava/util/List;Ljava/util/List;Lcom/apollographql/apollo/ast/GQLNamedType;Ljava/util/List;Ljava/lang/String;ILjava/lang/Object;)Lcom/apollographql/apollo/ast/GQLFragmentDefinition; public fun copyWithNewChildrenInternal (Lcom/apollographql/apollo/ast/NodeContainer;)Lcom/apollographql/apollo/ast/GQLNode; public fun getChildren ()Ljava/util/List; public fun getDescription ()Ljava/lang/String; @@ -443,15 +447,21 @@ public final class com/apollographql/apollo/ast/GQLFragmentDefinition : com/apol public final fun getSelections ()Ljava/util/List; public fun getSourceLocation ()Lcom/apollographql/apollo/ast/SourceLocation; public final fun getTypeCondition ()Lcom/apollographql/apollo/ast/GQLNamedType; + public final fun getVariableDefinitions ()Ljava/util/List; public fun writeInternal (Lcom/apollographql/apollo/ast/SDLWriter;)V } public final class com/apollographql/apollo/ast/GQLFragmentSpread : com/apollographql/apollo/ast/GQLSelection, com/apollographql/apollo/ast/GQLHasDirectives, com/apollographql/apollo/ast/GQLNamed { public fun (Lcom/apollographql/apollo/ast/SourceLocation;Ljava/lang/String;Ljava/util/List;)V public synthetic fun (Lcom/apollographql/apollo/ast/SourceLocation;Ljava/lang/String;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Lcom/apollographql/apollo/ast/SourceLocation;Ljava/lang/String;Ljava/util/List;Ljava/util/List;)V + public synthetic fun (Lcom/apollographql/apollo/ast/SourceLocation;Ljava/lang/String;Ljava/util/List;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun copy (Lcom/apollographql/apollo/ast/SourceLocation;Ljava/lang/String;Ljava/util/List;)Lcom/apollographql/apollo/ast/GQLFragmentSpread; + public final fun copy (Lcom/apollographql/apollo/ast/SourceLocation;Ljava/lang/String;Ljava/util/List;Ljava/util/List;)Lcom/apollographql/apollo/ast/GQLFragmentSpread; public static synthetic fun copy$default (Lcom/apollographql/apollo/ast/GQLFragmentSpread;Lcom/apollographql/apollo/ast/SourceLocation;Ljava/lang/String;Ljava/util/List;ILjava/lang/Object;)Lcom/apollographql/apollo/ast/GQLFragmentSpread; + public static synthetic fun copy$default (Lcom/apollographql/apollo/ast/GQLFragmentSpread;Lcom/apollographql/apollo/ast/SourceLocation;Ljava/lang/String;Ljava/util/List;Ljava/util/List;ILjava/lang/Object;)Lcom/apollographql/apollo/ast/GQLFragmentSpread; public fun copyWithNewChildrenInternal (Lcom/apollographql/apollo/ast/NodeContainer;)Lcom/apollographql/apollo/ast/GQLNode; + public final fun getArguments ()Ljava/util/List; public fun getChildren ()Ljava/util/List; public fun getDirectives ()Ljava/util/List; public fun getName ()Ljava/lang/String; @@ -1134,9 +1144,10 @@ public final class com/apollographql/apollo/ast/OtherValidationIssue : com/apoll public final class com/apollographql/apollo/ast/ParserOptions { public static final field Companion Lcom/apollographql/apollo/ast/ParserOptions$Companion; - public synthetic fun (ZZZZLkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun (ZZZZZLkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun getAllowDirectivesOnDirectives ()Z public final fun getAllowEmptyDocuments ()Z + public final fun getAllowFragmentArguments ()Z public final fun getAllowServiceCapabilities ()Z public final fun getWithSourceLocation ()Z } @@ -1145,14 +1156,17 @@ public final class com/apollographql/apollo/ast/ParserOptions$Builder { public fun ()V public final fun allowDirectivesOnDirectives (Z)Lcom/apollographql/apollo/ast/ParserOptions$Builder; public final fun allowEmptyDocuments (Z)Lcom/apollographql/apollo/ast/ParserOptions$Builder; + public final fun allowFragmentArguments (Z)Lcom/apollographql/apollo/ast/ParserOptions$Builder; public final fun allowServiceCapabilities (Z)Lcom/apollographql/apollo/ast/ParserOptions$Builder; public final fun build ()Lcom/apollographql/apollo/ast/ParserOptions; public final fun getAllowDirectivesOnDirectives ()Z public final fun getAllowEmptyDocuments ()Z + public final fun getAllowFragmentArguments ()Z public final fun getAllowServiceCapabilities ()Z public final fun getWithSourceLocation ()Z public final fun setAllowDirectivesOnDirectives (Z)V public final fun setAllowEmptyDocuments (Z)V + public final fun setAllowFragmentArguments (Z)V public final fun setAllowServiceCapabilities (Z)V public final fun setWithSourceLocation (Z)V public final fun withSourceLocation (Z)Lcom/apollographql/apollo/ast/ParserOptions$Builder; diff --git a/libraries/apollo-ast/api/apollo-ast.klib.api b/libraries/apollo-ast/api/apollo-ast.klib.api index 6ad360e3171..52d0a8a074d 100644 --- a/libraries/apollo-ast/api/apollo-ast.klib.api +++ b/libraries/apollo-ast/api/apollo-ast.klib.api @@ -588,6 +588,7 @@ final class com.apollographql.apollo.ast/GQLFloatValue : com.apollographql.apoll final class com.apollographql.apollo.ast/GQLFragmentDefinition : com.apollographql.apollo.ast/GQLDescribed, com.apollographql.apollo.ast/GQLExecutableDefinition, com.apollographql.apollo.ast/GQLHasDirectives, com.apollographql.apollo.ast/GQLNamed { // com.apollographql.apollo.ast/GQLFragmentDefinition|null[0] constructor (com.apollographql.apollo.ast/SourceLocation? = ..., kotlin/String, kotlin.collections/List, com.apollographql.apollo.ast/GQLNamedType, kotlin.collections/List, kotlin/String?) // com.apollographql.apollo.ast/GQLFragmentDefinition.|(com.apollographql.apollo.ast.SourceLocation?;kotlin.String;kotlin.collections.List;com.apollographql.apollo.ast.GQLNamedType;kotlin.collections.List;kotlin.String?){}[0] + constructor (com.apollographql.apollo.ast/SourceLocation? = ..., kotlin/String, kotlin.collections/List, kotlin.collections/List, com.apollographql.apollo.ast/GQLNamedType, kotlin.collections/List, kotlin/String?) // com.apollographql.apollo.ast/GQLFragmentDefinition.|(com.apollographql.apollo.ast.SourceLocation?;kotlin.String;kotlin.collections.List;kotlin.collections.List;com.apollographql.apollo.ast.GQLNamedType;kotlin.collections.List;kotlin.String?){}[0] final val children // com.apollographql.apollo.ast/GQLFragmentDefinition.children|{}children[0] final fun (): kotlin.collections/List // com.apollographql.apollo.ast/GQLFragmentDefinition.children.|(){}[0] @@ -605,17 +606,23 @@ final class com.apollographql.apollo.ast/GQLFragmentDefinition : com.apollograph final fun (): com.apollographql.apollo.ast/SourceLocation? // com.apollographql.apollo.ast/GQLFragmentDefinition.sourceLocation.|(){}[0] final val typeCondition // com.apollographql.apollo.ast/GQLFragmentDefinition.typeCondition|{}typeCondition[0] final fun (): com.apollographql.apollo.ast/GQLNamedType // com.apollographql.apollo.ast/GQLFragmentDefinition.typeCondition.|(){}[0] + final val variableDefinitions // com.apollographql.apollo.ast/GQLFragmentDefinition.variableDefinitions|{}variableDefinitions[0] + final fun (): kotlin.collections/List // com.apollographql.apollo.ast/GQLFragmentDefinition.variableDefinitions.|(){}[0] final fun copy(com.apollographql.apollo.ast/SourceLocation? = ..., kotlin/String = ..., kotlin.collections/List = ..., com.apollographql.apollo.ast/GQLNamedType = ..., kotlin.collections/List = ..., kotlin/String? = ...): com.apollographql.apollo.ast/GQLFragmentDefinition // com.apollographql.apollo.ast/GQLFragmentDefinition.copy|copy(com.apollographql.apollo.ast.SourceLocation?;kotlin.String;kotlin.collections.List;com.apollographql.apollo.ast.GQLNamedType;kotlin.collections.List;kotlin.String?){}[0] + final fun copy(com.apollographql.apollo.ast/SourceLocation? = ..., kotlin/String = ..., kotlin.collections/List = ..., kotlin.collections/List = ..., com.apollographql.apollo.ast/GQLNamedType = ..., kotlin.collections/List = ..., kotlin/String? = ...): com.apollographql.apollo.ast/GQLFragmentDefinition // com.apollographql.apollo.ast/GQLFragmentDefinition.copy|copy(com.apollographql.apollo.ast.SourceLocation?;kotlin.String;kotlin.collections.List;kotlin.collections.List;com.apollographql.apollo.ast.GQLNamedType;kotlin.collections.List;kotlin.String?){}[0] final fun copyWithNewChildrenInternal(com.apollographql.apollo.ast/NodeContainer): com.apollographql.apollo.ast/GQLNode // com.apollographql.apollo.ast/GQLFragmentDefinition.copyWithNewChildrenInternal|copyWithNewChildrenInternal(com.apollographql.apollo.ast.NodeContainer){}[0] final fun writeInternal(com.apollographql.apollo.ast/SDLWriter) // com.apollographql.apollo.ast/GQLFragmentDefinition.writeInternal|writeInternal(com.apollographql.apollo.ast.SDLWriter){}[0] } final class com.apollographql.apollo.ast/GQLFragmentSpread : com.apollographql.apollo.ast/GQLHasDirectives, com.apollographql.apollo.ast/GQLNamed, com.apollographql.apollo.ast/GQLSelection { // com.apollographql.apollo.ast/GQLFragmentSpread|null[0] + constructor (com.apollographql.apollo.ast/SourceLocation? = ..., kotlin/String, kotlin.collections/List, kotlin.collections/List) // com.apollographql.apollo.ast/GQLFragmentSpread.|(com.apollographql.apollo.ast.SourceLocation?;kotlin.String;kotlin.collections.List;kotlin.collections.List){}[0] constructor (com.apollographql.apollo.ast/SourceLocation? = ..., kotlin/String, kotlin.collections/List) // com.apollographql.apollo.ast/GQLFragmentSpread.|(com.apollographql.apollo.ast.SourceLocation?;kotlin.String;kotlin.collections.List){}[0] + final val arguments // com.apollographql.apollo.ast/GQLFragmentSpread.arguments|{}arguments[0] + final fun (): kotlin.collections/List // com.apollographql.apollo.ast/GQLFragmentSpread.arguments.|(){}[0] final val children // com.apollographql.apollo.ast/GQLFragmentSpread.children|{}children[0] - final fun (): kotlin.collections/List // com.apollographql.apollo.ast/GQLFragmentSpread.children.|(){}[0] + final fun (): kotlin.collections/List // com.apollographql.apollo.ast/GQLFragmentSpread.children.|(){}[0] final val directives // com.apollographql.apollo.ast/GQLFragmentSpread.directives|{}directives[0] final fun (): kotlin.collections/List // com.apollographql.apollo.ast/GQLFragmentSpread.directives.|(){}[0] final val name // com.apollographql.apollo.ast/GQLFragmentSpread.name|{}name[0] @@ -623,6 +630,7 @@ final class com.apollographql.apollo.ast/GQLFragmentSpread : com.apollographql.a final val sourceLocation // com.apollographql.apollo.ast/GQLFragmentSpread.sourceLocation|{}sourceLocation[0] final fun (): com.apollographql.apollo.ast/SourceLocation? // com.apollographql.apollo.ast/GQLFragmentSpread.sourceLocation.|(){}[0] + final fun copy(com.apollographql.apollo.ast/SourceLocation? = ..., kotlin/String = ..., kotlin.collections/List = ..., kotlin.collections/List = ...): com.apollographql.apollo.ast/GQLFragmentSpread // com.apollographql.apollo.ast/GQLFragmentSpread.copy|copy(com.apollographql.apollo.ast.SourceLocation?;kotlin.String;kotlin.collections.List;kotlin.collections.List){}[0] final fun copy(com.apollographql.apollo.ast/SourceLocation? = ..., kotlin/String = ..., kotlin.collections/List = ...): com.apollographql.apollo.ast/GQLFragmentSpread // com.apollographql.apollo.ast/GQLFragmentSpread.copy|copy(com.apollographql.apollo.ast.SourceLocation?;kotlin.String;kotlin.collections.List){}[0] final fun copyWithNewChildrenInternal(com.apollographql.apollo.ast/NodeContainer): com.apollographql.apollo.ast/GQLNode // com.apollographql.apollo.ast/GQLFragmentSpread.copyWithNewChildrenInternal|copyWithNewChildrenInternal(com.apollographql.apollo.ast.NodeContainer){}[0] final fun writeInternal(com.apollographql.apollo.ast/SDLWriter) // com.apollographql.apollo.ast/GQLFragmentSpread.writeInternal|writeInternal(com.apollographql.apollo.ast.SDLWriter){}[0] @@ -1316,6 +1324,8 @@ final class com.apollographql.apollo.ast/ParserOptions { // com.apollographql.ap final fun (): kotlin/Boolean // com.apollographql.apollo.ast/ParserOptions.allowDirectivesOnDirectives.|(){}[0] final val allowEmptyDocuments // com.apollographql.apollo.ast/ParserOptions.allowEmptyDocuments|{}allowEmptyDocuments[0] final fun (): kotlin/Boolean // com.apollographql.apollo.ast/ParserOptions.allowEmptyDocuments.|(){}[0] + final val allowFragmentArguments // com.apollographql.apollo.ast/ParserOptions.allowFragmentArguments|{}allowFragmentArguments[0] + final fun (): kotlin/Boolean // com.apollographql.apollo.ast/ParserOptions.allowFragmentArguments.|(){}[0] final val allowServiceCapabilities // com.apollographql.apollo.ast/ParserOptions.allowServiceCapabilities|{}allowServiceCapabilities[0] final fun (): kotlin/Boolean // com.apollographql.apollo.ast/ParserOptions.allowServiceCapabilities.|(){}[0] final val withSourceLocation // com.apollographql.apollo.ast/ParserOptions.withSourceLocation|{}withSourceLocation[0] @@ -1330,6 +1340,9 @@ final class com.apollographql.apollo.ast/ParserOptions { // com.apollographql.ap final var allowEmptyDocuments // com.apollographql.apollo.ast/ParserOptions.Builder.allowEmptyDocuments|{}allowEmptyDocuments[0] final fun (): kotlin/Boolean // com.apollographql.apollo.ast/ParserOptions.Builder.allowEmptyDocuments.|(){}[0] final fun (kotlin/Boolean) // com.apollographql.apollo.ast/ParserOptions.Builder.allowEmptyDocuments.|(kotlin.Boolean){}[0] + final var allowFragmentArguments // com.apollographql.apollo.ast/ParserOptions.Builder.allowFragmentArguments|{}allowFragmentArguments[0] + final fun (): kotlin/Boolean // com.apollographql.apollo.ast/ParserOptions.Builder.allowFragmentArguments.|(){}[0] + final fun (kotlin/Boolean) // com.apollographql.apollo.ast/ParserOptions.Builder.allowFragmentArguments.|(kotlin.Boolean){}[0] final var allowServiceCapabilities // com.apollographql.apollo.ast/ParserOptions.Builder.allowServiceCapabilities|{}allowServiceCapabilities[0] final fun (): kotlin/Boolean // com.apollographql.apollo.ast/ParserOptions.Builder.allowServiceCapabilities.|(){}[0] final fun (kotlin/Boolean) // com.apollographql.apollo.ast/ParserOptions.Builder.allowServiceCapabilities.|(kotlin.Boolean){}[0] @@ -1339,6 +1352,7 @@ final class com.apollographql.apollo.ast/ParserOptions { // com.apollographql.ap final fun allowDirectivesOnDirectives(kotlin/Boolean): com.apollographql.apollo.ast/ParserOptions.Builder // com.apollographql.apollo.ast/ParserOptions.Builder.allowDirectivesOnDirectives|allowDirectivesOnDirectives(kotlin.Boolean){}[0] final fun allowEmptyDocuments(kotlin/Boolean): com.apollographql.apollo.ast/ParserOptions.Builder // com.apollographql.apollo.ast/ParserOptions.Builder.allowEmptyDocuments|allowEmptyDocuments(kotlin.Boolean){}[0] + final fun allowFragmentArguments(kotlin/Boolean): com.apollographql.apollo.ast/ParserOptions.Builder // com.apollographql.apollo.ast/ParserOptions.Builder.allowFragmentArguments|allowFragmentArguments(kotlin.Boolean){}[0] final fun allowServiceCapabilities(kotlin/Boolean): com.apollographql.apollo.ast/ParserOptions.Builder // com.apollographql.apollo.ast/ParserOptions.Builder.allowServiceCapabilities|allowServiceCapabilities(kotlin.Boolean){}[0] final fun build(): com.apollographql.apollo.ast/ParserOptions // com.apollographql.apollo.ast/ParserOptions.Builder.build|build(){}[0] final fun withSourceLocation(kotlin/Boolean): com.apollographql.apollo.ast/ParserOptions.Builder // com.apollographql.apollo.ast/ParserOptions.Builder.withSourceLocation|withSourceLocation(kotlin.Boolean){}[0] diff --git a/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/Issue.kt b/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/Issue.kt index 22ce805b580..5c933499524 100644 --- a/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/Issue.kt +++ b/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/Issue.kt @@ -10,7 +10,7 @@ sealed interface Issue { } /** - * An issue from the GraphQL spec + * An issue from the GraphQL spec, either a parsing error or a validation issue. */ sealed interface GraphQLIssue : Issue diff --git a/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/api.kt b/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/api.kt index 314497b25ad..5c75aa146e0 100644 --- a/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/api.kt +++ b/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/api.kt @@ -76,7 +76,8 @@ class ParserOptions private constructor( val allowEmptyDocuments: Boolean, val withSourceLocation: Boolean, val allowDirectivesOnDirectives: Boolean, - val allowServiceCapabilities: Boolean + val allowServiceCapabilities: Boolean, + val allowFragmentArguments: Boolean ) { class Builder { var allowEmptyDocuments = true @@ -88,6 +89,9 @@ class ParserOptions private constructor( @ApolloExperimental var allowServiceCapabilities = false + @ApolloExperimental + var allowFragmentArguments = false + fun allowEmptyDocuments(allowEmptyDocuments: Boolean) = apply { this.allowEmptyDocuments = allowEmptyDocuments } @@ -106,12 +110,18 @@ class ParserOptions private constructor( this.allowDirectivesOnDirectives = allowDirectivesOnDirectives } + @ApolloExperimental + fun allowFragmentArguments(allowFragmentArguments: Boolean) = apply { + this.allowFragmentArguments = allowFragmentArguments + } + fun build(): ParserOptions { return ParserOptions( allowEmptyDocuments = allowEmptyDocuments, withSourceLocation = withSourceLocation, allowDirectivesOnDirectives = allowDirectivesOnDirectives, - allowServiceCapabilities = allowServiceCapabilities + allowServiceCapabilities = allowServiceCapabilities, + allowFragmentArguments = allowFragmentArguments ) } } diff --git a/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/gql.kt b/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/gql.kt index 737f9cf9ed1..c3b0ddaae41 100644 --- a/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/gql.kt +++ b/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/gql.kt @@ -230,14 +230,33 @@ class GQLOperationDefinition( } } -class GQLFragmentDefinition( +class GQLFragmentDefinition @ApolloExperimental constructor( override val sourceLocation: SourceLocation? = null, override val name: String, + val variableDefinitions: List, override val directives: List, val typeCondition: GQLNamedType, val selections: List, - override val description: String?, // spec extension + override val description: String?, ) : GQLExecutableDefinition, GQLNamed, GQLDescribed, GQLHasDirectives { + + constructor( + sourceLocation: SourceLocation? = null, + name: String, + directives: List, + typeCondition: GQLNamedType, + selections: List, + description: String?, + ) : this( + sourceLocation = sourceLocation, + name = name, + variableDefinitions = emptyList(), + directives = directives, + typeCondition = typeCondition, + selections = selections, + description = description + ) + @Suppress("DEPRECATION_ERROR") @Deprecated("Use selections directly", level = DeprecationLevel.ERROR) @ApolloDeprecatedSince(ApolloDeprecatedSince.Version.v4_0_0) @@ -249,11 +268,15 @@ class GQLFragmentDefinition( ) } - override val children = directives + selections + typeCondition + override val children = variableDefinitions + directives + selections + typeCondition override fun writeInternal(writer: SDLWriter) { with(writer) { - write("fragment $name on ${typeCondition.name}") + write("fragment $name") + if (variableDefinitions.isNotEmpty()) { + variableDefinitions.join(writer = writer, separator = ", ", prefix = "(", postfix = ")") + } + write(" on ${typeCondition.name}") if (directives.isNotEmpty()) { write(" ") directives.join(writer) @@ -265,9 +288,11 @@ class GQLFragmentDefinition( } } + @ApolloExperimental fun copy( sourceLocation: SourceLocation? = this.sourceLocation, name: String = this.name, + variableDefinitions: List = this.variableDefinitions, directives: List = this.directives, typeCondition: GQLNamedType = this.typeCondition, selections: List = this.selections, @@ -276,6 +301,26 @@ class GQLFragmentDefinition( return GQLFragmentDefinition( sourceLocation = sourceLocation, name = name, + variableDefinitions = variableDefinitions, + directives = directives, + typeCondition = typeCondition, + selections = selections, + description = description, + ) + } + + fun copy( + sourceLocation: SourceLocation? = this.sourceLocation, + name: String = this.name, + directives: List = this.directives, + typeCondition: GQLNamedType = this.typeCondition, + selections: List = this.selections, + description: String? = this.description, + ): GQLFragmentDefinition { + return copy( + sourceLocation = sourceLocation, + name = name, + variableDefinitions = variableDefinitions, directives = directives, typeCondition = typeCondition, selections = selections, @@ -286,6 +331,7 @@ class GQLFragmentDefinition( override fun copyWithNewChildrenInternal(container: NodeContainer): GQLNode { return copy( directives = container.take(), + variableDefinitions = container.take(), typeCondition = container.take().single(), selections = container.take(), ) @@ -1440,8 +1486,14 @@ class GQLInputValueDefinition( } /** - * A variable definition is very similar to an InputValue definition except it doesn't - * have a description + * A variable definition is very similar to a [GQLInputValueDefinition]. + * They are different grammar rules because [GQLVariableDefinition] didn't support descriptions early on. + * Also input values have a `name` and variables have a `$name`. + * + * We could probably merge them. + * + * See https://github.com/graphql/graphql-spec/pull/1170 for the PR that adds description to the variable + * definitions */ class GQLVariableDefinition( override val sourceLocation: SourceLocation? = null, @@ -1873,17 +1925,33 @@ class GQLInlineFragment( } } -class GQLFragmentSpread( +class GQLFragmentSpread @ApolloExperimental constructor( override val sourceLocation: SourceLocation? = null, override val name: String, + @ApolloExperimental + val arguments: List, override val directives: List, ) : GQLSelection(), GQLNamed, GQLHasDirectives { - override val children = directives + constructor( + sourceLocation: SourceLocation? = null, + name: String, + directives: List, + ) : this( + sourceLocation = sourceLocation, + name = name, + arguments = emptyList(), + directives = directives + ) + + override val children: List = arguments + directives override fun writeInternal(writer: SDLWriter) { with(writer) { write("...${name}") + if (arguments.isNotEmpty()) { + arguments.writeArguments(writer) + } if (directives.isNotEmpty()) { write(" ") directives.join(writer) @@ -1892,19 +1960,38 @@ class GQLFragmentSpread( } } + @ApolloExperimental fun copy( sourceLocation: SourceLocation? = this.sourceLocation, name: String = this.name, + arguments: List = this.arguments, directives: List = this.directives, - ) = GQLFragmentSpread( - sourceLocation = sourceLocation, - name = name, - directives = directives, - ) + ): GQLFragmentSpread { + return GQLFragmentSpread( + sourceLocation = sourceLocation, + name = name, + arguments = arguments, + directives = directives, + ) + } + + fun copy( + sourceLocation: SourceLocation? = this.sourceLocation, + name: String = this.name, + directives: List = this.directives, + ): GQLFragmentSpread { + return copy( + sourceLocation = sourceLocation, + name = name, + arguments = arguments, + directives = directives, + ) + } override fun copyWithNewChildrenInternal(container: NodeContainer): GQLNode { return copy( - directives = container.take() + arguments = container.take(), + directives = container.take(), ) } } diff --git a/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/ExecutableValidationScope.kt b/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/ExecutableValidationScope.kt index fa8d131b9a5..14d52d05c69 100644 --- a/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/ExecutableValidationScope.kt +++ b/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/ExecutableValidationScope.kt @@ -1,5 +1,6 @@ package com.apollographql.apollo.ast.internal +import com.apollographql.apollo.annotations.ApolloExperimental import com.apollographql.apollo.annotations.ApolloInternal import com.apollographql.apollo.ast.AnonymousOperation import com.apollographql.apollo.ast.DeprecatedUsage @@ -16,6 +17,7 @@ import com.apollographql.apollo.ast.GQLFloatValue import com.apollographql.apollo.ast.GQLFragmentDefinition import com.apollographql.apollo.ast.GQLFragmentSpread import com.apollographql.apollo.ast.GQLInlineFragment +import com.apollographql.apollo.ast.GQLInputValueDefinition import com.apollographql.apollo.ast.GQLIntValue import com.apollographql.apollo.ast.GQLListType import com.apollographql.apollo.ast.GQLListValue @@ -30,6 +32,7 @@ import com.apollographql.apollo.ast.GQLStringValue import com.apollographql.apollo.ast.GQLType import com.apollographql.apollo.ast.GQLTypeDefinition import com.apollographql.apollo.ast.GQLValue +import com.apollographql.apollo.ast.GQLVariableDefinition import com.apollographql.apollo.ast.GQLVariableValue import com.apollographql.apollo.ast.Issue import com.apollographql.apollo.ast.OtherValidationIssue @@ -41,7 +44,9 @@ import com.apollographql.apollo.ast.definitionFromScope import com.apollographql.apollo.ast.findCatch import com.apollographql.apollo.ast.findDeprecationReason import com.apollographql.apollo.ast.getArgumentValueOrDefault +import com.apollographql.apollo.ast.internal.pretty import com.apollographql.apollo.ast.internal.validation.validateDeferLabels +import com.apollographql.apollo.ast.isInputType import com.apollographql.apollo.ast.pretty import com.apollographql.apollo.ast.rawType import com.apollographql.apollo.ast.responseName @@ -49,7 +54,7 @@ import com.apollographql.apollo.ast.rootTypeDefinition import com.apollographql.apollo.ast.sharesPossibleTypesWith -@OptIn(ApolloInternal::class) +@OptIn(ApolloInternal::class, ApolloExperimental::class) internal class ExecutableValidationScope( private val schema: Schema, ) : ValidationScope { @@ -64,7 +69,11 @@ internal class ExecutableValidationScope( */ override val issues = mutableListOf() private val fragmentDefinitions = mutableMapOf() - private val fragmentVariableUsages = mutableMapOf>() + + /** + * Contains the direct variable usages in the given fragment definition that are not defined by the fragment itself. + */ + private val fragmentOperationVariableUsages = mutableMapOf>() private val cyclicFragments = mutableSetOf() private val usedFragments = mutableSetOf() private val hasCatchByDefault = schema.directiveDefinitions.any { schema.originalDirectiveName(it.key) == Schema.CATCH_BY_DEFAULT } @@ -113,7 +122,11 @@ internal class ExecutableValidationScope( val index = path.indexOf("__${name}") val nextPath = path + "__${fragment.name}" if (index != -1) { - issues.add(FragmentCycle("Fragment '$name' spreads itself, creating a cycle at '${nextPath.subList(index, nextPath.size).joinToString(".")}'", it.sourceLocation)) + issues.add(FragmentCycle("Fragment '$name' spreads itself, creating a cycle at '${ + nextPath.subList(index, nextPath.size).joinToString(".") + }'", it.sourceLocation + ) + ) cyclicFragments.add(name) return@forEach } @@ -143,6 +156,7 @@ internal class ExecutableValidationScope( val fragments = document.definitions.filterIsInstance() fragments.checkDuplicateFragments() fragments.forEach { + // Needs to happen before validating the operations to set `fragmentVariableUsages` it.validate() } @@ -163,7 +177,7 @@ internal class ExecutableValidationScope( val fragmentVariables = fragments.associate { it.name to (setOf(it.name) + it.selections.collectFragmentSpreads()).fold(emptyList()) { acc, item -> - acc + fragmentVariableUsages.get(item).orEmpty() + acc + fragmentOperationVariableUsages.get(item).orEmpty() } } return ExecutableValidationResult(fragmentVariables, issues) @@ -204,7 +218,8 @@ internal class ExecutableValidationScope( } if (typeDefinition !is GQLScalarTypeDefinition - && typeDefinition !is GQLEnumTypeDefinition) { + && typeDefinition !is GQLEnumTypeDefinition + ) { if (selections.isEmpty()) { registerIssue( message = "Field `$name` of type `${fieldDefinition.type.pretty()}` must have a selection of sub-fields", @@ -342,6 +357,24 @@ internal class ExecutableValidationScope( return } + validateArguments( + arguments, + sourceLocation, + fragmentDefinition.variableDefinitions.map { + GQLInputValueDefinition( + sourceLocation = it.sourceLocation, + description = it.description, + name = it.name, + directives = it.directives, + type = it.type, + defaultValue = it.defaultValue + ) + }, + debug = "fragment `$name`" + ) { + variableUsages.add(it) + } + validateDirectives(directives, this) { variableUsages.add(it) } @@ -371,12 +404,20 @@ internal class ExecutableValidationScope( return } - validateCommon(this, selections, directives, rootTypeDefinition) + validateCommon(this, selections, directives, variableDefinitions, rootTypeDefinition) + if (schema.errorAware) { validateCatch(selections.collectFieldsNoFragments()) } - fragmentVariableUsages[name] = variableUsages.toList() + val ownVariables = variableDefinitions.map { it.name }.toSet() + val (ownVariableUsages, operationVariableUsages) = variableUsages.partition { it.variable.name in ownVariables } + validateVariableUsages(variableDefinitions, ownVariableUsages, context = "fragment `$name`") + + /** + * We only track the variables that are not by this fragment. + */ + fragmentOperationVariableUsages[name] = operationVariableUsages } /** @@ -387,6 +428,7 @@ internal class ExecutableValidationScope( directiveContext: GQLNode, selections: List, directives: List, + variableDefinitions: List, rootTypeDefinition: GQLTypeDefinition, ) { variableUsages.clear() @@ -394,8 +436,36 @@ internal class ExecutableValidationScope( selections.validate(rootTypeDefinition) validateDirectives(directives, directiveContext) { + /** + * ```graphql + * query GetFoo($arg: Int!) @myDirective(arg: $arg) { + * foo + * } + * ``` + */ variableUsages.add(it) } + + variableDefinitions.forEach { varDef -> + if (!varDef.type.isInputType(typeDefinitions)) { + registerIssue( + message = "Variable `${varDef.name}` of type `${varDef.type.pretty()}` is not an input type", + sourceLocation = varDef.sourceLocation + ) + } + if (varDef.defaultValue != null) { + validateAndCoerceValue( + value = varDef.defaultValue, + expectedType = varDef.type, + hasLocationDefaultValue = false, + isOneOfInputField = false + ) { + issues.add(it.constContextError()) + } + } + + validateDirectivesInConstContext(varDef.directives, varDef) + } } private fun GQLOperationDefinition.validate() { @@ -408,7 +478,7 @@ internal class ExecutableValidationScope( ) return } - validateCommon(this, selections, directives, rootTypeDefinition) + validateCommon(this, selections, directives, variableDefinitions, rootTypeDefinition) if (schema.errorAware) { validateCatch(selections.collectFieldsNoFragments()) @@ -423,36 +493,34 @@ internal class ExecutableValidationScope( it.key !in cyclicFragments }) + validateDirectives(directives, this) { + variableUsages.add(it) + } issues.addAll(validateDeferLabels(this, rootTypeDefinition.name, schema, fragmentDefinitions)) - val allVariableUsages = selections.collectFragmentSpreads().flatMap { fragmentVariableUsages.get(it) ?: emptyList() } + variableUsages - (allVariableUsages).forEach { - validateVariable(this, it) + val allVariableUsages = selections.collectFragmentSpreads().flatMap { fragmentOperationVariableUsages.get(it) ?: emptyList() } + variableUsages + validateVariableUsages(variableDefinitions, allVariableUsages, context = this.pretty()) + } + + private fun validateVariableUsages(variableDefinitions: List, variableUsages: List, context: String) { + variableUsages.forEach { + validateVariableUsage( + variableUsage = it, + variableDefinitions = variableDefinitions, + context = context, + ) } - val foundVariables = allVariableUsages.map { it.variable.name }.toSet() + val foundVariables = variableUsages.map { it.variable.name }.toSet() variableDefinitions.forEach { if (!foundVariables.contains(it.name)) { issues.add(UnusedVariable( - message = "Variable `${it.name}` is unused", + message = "Variable `${it.name}` is unused in $context", sourceLocation = it.sourceLocation - )) - } - } - validateDirectives(directives, this) { - variableUsages.add(it) - } - variableDefinitions.forEach { - if (it.defaultValue != null) { - validateAndCoerceValue( - value = it.defaultValue, - expectedType = it.type, - hasLocationDefaultValue = false, - isOneOfInputField = false - ) { - issues.add(it.constContextError()) - } + ) + ) } } + } private fun List.collectFragmentSpreads(): Set { @@ -601,7 +669,8 @@ internal class ExecutableValidationScope( issues.add(OtherValidationIssue( message = "Fragment ${it.name} is already defined", sourceLocation = it.sourceLocation, - )) + ) + ) } } return issues @@ -615,7 +684,8 @@ internal class ExecutableValidationScope( issues.add(AnonymousOperation( message = "Apollo does not support anonymous operations", sourceLocation = it.sourceLocation, - )) + ) + ) return@forEach } val existing = filtered.putIfAbsentMpp(it.name, it) @@ -623,7 +693,8 @@ internal class ExecutableValidationScope( issues.add(OtherValidationIssue( message = "Operation ${it.name} is already defined", sourceLocation = it.sourceLocation, - )) + ) + ) } } return issues diff --git a/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/Parser.kt b/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/Parser.kt index 4fd8c0d57fc..50903abe1db 100644 --- a/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/Parser.kt +++ b/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/Parser.kt @@ -15,6 +15,7 @@ internal class Parser( private val allowEmptyDocuments = options.allowEmptyDocuments private val allowDirectivesOnDirectives = options.allowDirectivesOnDirectives private val allowServiceCapabilities = options.allowServiceCapabilities + private val allowFragmentArguments = options.allowFragmentArguments fun parseDocument(): GQLDocument { val start = token @@ -198,11 +199,18 @@ internal class Parser( val on = expectOptionalKeyword("on") return if (on == null && peek()) { val name = parseFragmentName() + val arguments: List + if (allowFragmentArguments) { + arguments = parseArguments(false) + } else { + arguments = emptyList() + } val directives = parseDirectives(const = false) GQLFragmentSpread( sourceLocation = sourceLocation(start), name = name, - directives = directives + arguments = arguments, + directives = directives, ) } else { val typeCondition = if (on != null) parseNamedType() else null @@ -865,6 +873,11 @@ internal class Parser( val description = parseDescription() expectKeyword("fragment") val name = parseFragmentName() + val variableDefinitions = if (allowFragmentArguments) { + parseVariableDefinitions() + } else { + emptyList() + } expectKeyword("on") val typeCondition = parseNamedType() val directives = parseDirectives(const = false) @@ -875,7 +888,8 @@ internal class Parser( name = name, typeCondition = typeCondition, directives = directives, - selections = selections + selections = selections, + variableDefinitions = variableDefinitions ) } diff --git a/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/ValidationCommon.kt b/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/ValidationCommon.kt index 16ae06b6ff5..ccc0a3bb3d4 100644 --- a/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/ValidationCommon.kt +++ b/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/ValidationCommon.kt @@ -345,7 +345,7 @@ internal fun ValidationScope.validateArguments( // This will be caught later when validating individual arguments // registerIssue((message = "Cannot pass `null` for a required argument", sourceLocation = argumentValue.sourceLocation)) } else if (argumentValue == null) { - registerIssue(message = "No value passed for required argument '${inputValueDefinition.name}'", sourceLocation = sourceLocation) + registerIssue(message = "No value passed for required argument `${inputValueDefinition.name}` on $debug", sourceLocation = sourceLocation) } } } @@ -355,20 +355,24 @@ internal fun ValidationScope.validateArguments( } } -internal fun ValidationScope.validateVariable( - operation: GQLOperationDefinition?, - variableUsage: VariableUsage, -) { - if (operation == null) { - // if operation is null, it means we're currently validating a fragment outside the context of an operation - return +internal fun GQLOperationDefinition.pretty(): String { + return if (name == null) { + "anonymous operation" + } else { + "operation `${name}`" } +} +internal fun ValidationScope.validateVariableUsage( + variableUsage: VariableUsage, + variableDefinitions: List, + context: String, +) { val variable = variableUsage.variable - val variableDefinition = operation.variableDefinitions.firstOrNull { it.name == variable.name } + val variableDefinition = variableDefinitions.firstOrNull { it.name == variable.name } if (variableDefinition == null) { registerIssue( - message = "Variable `${variable.name}` is not defined by operation `${operation.name}`", + message = "Variable `${variable.name}` is not defined by $context", sourceLocation = variable.sourceLocation ) return diff --git a/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/fields_merging.kt b/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/fields_merging.kt index dc62b80e160..30dd5a85a8f 100644 --- a/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/fields_merging.kt +++ b/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/fields_merging.kt @@ -1,5 +1,6 @@ package com.apollographql.apollo.ast.internal +import com.apollographql.apollo.annotations.ApolloExperimental import com.apollographql.apollo.ast.* /** @@ -8,7 +9,7 @@ import com.apollographql.apollo.ast.* * There is no caching per-fieldset because it hides some otherwise useful diagnostics. * * See `reports_each_conflict_once` for an example. The caching only works when reusing fragment - * spreads but because the fragments may be spread at different paths, having the full path for + * spreads, but because the fragments may be spread at different paths, having the full path for * each issue can be useful. */ internal fun IssuesScope.fieldsInSetCanMerge( @@ -30,8 +31,7 @@ internal fun IssuesScope.fieldsInSetCanMerge( } val fieldMap = mutableMapOf>() - val visitedFragmentSpreads = mutableSetOf() - collectFields(fieldMap, operation.selections, rootType, visitedFragmentSpreads, context) + collectFields(fieldMap, operation.selections, rootType, context) sameResponseShapeByName(fieldMap, emptyList(), context) sameForCommonParentsByName(fieldMap, emptyList(), context) @@ -61,11 +61,11 @@ private data class ValidationContext( val fragments: Map, ) +@OptIn(ApolloExperimental::class) private fun collectFields( fieldMap: MutableMap>, selections: List, parentType: GQLTypeDefinition, - visitedFragmentSpreads: MutableSet, context: ValidationContext, ) { for (selection in selections) { @@ -90,17 +90,22 @@ private fun collectFields( } // See ignores_unknown_types test if (fragmentType != null) { - collectFields(fieldMap, selection.selections, fragmentType, visitedFragmentSpreads, context) + collectFields(fieldMap, selection.selections, fragmentType, context) } } is GQLFragmentSpread -> { val fragment = context.fragments[selection.name] - if (fragment != null && fragment.name !in visitedFragmentSpreads) { - visitedFragmentSpreads.add(fragment.name) + if (fragment != null) { + // Use name + arguments as key so same fragment with different arguments is collected twice val fragmentType = context.schema.typeDefinitions[fragment.typeCondition.name] if (fragmentType != null) { - collectFields(fieldMap, fragment.selections, fragmentType, visitedFragmentSpreads, context) + val selections = if (selection.arguments.isNotEmpty() && fragment.variableDefinitions.isNotEmpty()) { + substituteFragmentVariables(fragment.selections, fragment.variableDefinitions, selection.arguments) + } else { + fragment.selections + } + collectFields(fieldMap, selections, fragmentType, context) } } } @@ -129,12 +134,10 @@ private fun mergeSubSelections(sameNameFields: Set, context: Valid val fieldMap = mutableMapOf>() for (fieldAndType in sameNameFields) { if (fieldAndType.field.selections.isNotEmpty() && fieldAndType.type != null) { - val visitedFragmentSpreads = mutableSetOf() - val unwrappedType = fieldAndType.type.rawType() val typeDefinition = context.schema.typeDefinitions[unwrappedType.name] if (typeDefinition != null) { - collectFields(fieldMap, fieldAndType.field.selections, typeDefinition, visitedFragmentSpreads, context) + collectFields(fieldMap, fieldAndType.field.selections, typeDefinition, context) } } } @@ -329,4 +332,69 @@ private data class FieldAndType( private fun buildMessage(path: List, message: String): String { return "Field at path `${path.joinToString(".")}` conflicts with another field: " + "$message. Use different aliases on the fields to fetch both if this was intentional." +} + +/** + * Substitutes fragment variable references in selections with actual argument values. + * This ensures field merging compares resolved values when a fragment is spread with arguments. + */ +@OptIn(ApolloExperimental::class) +private fun substituteFragmentVariables( + selections: List, + variableDefinitions: List, + arguments: List, +): List { + val argMap = mutableMapOf() + for (varDef in variableDefinitions) { + val arg = arguments.firstOrNull { it.name == varDef.name } + if (arg != null) { + argMap[varDef.name] = arg.value + } else if (varDef.defaultValue != null) { + argMap[varDef.name] = varDef.defaultValue + } + } + if (argMap.isEmpty()) return selections + return selections.map { it.substituteVariables(argMap) } +} + +@OptIn(ApolloExperimental::class) +private fun GQLSelection.substituteVariables(argMap: Map): GQLSelection { + return when (this) { + is GQLField -> GQLField( + sourceLocation = sourceLocation, + alias = alias, + name = name, + arguments = arguments.map { arg -> + GQLArgument( + sourceLocation = arg.sourceLocation, + name = arg.name, + value = arg.value.substituteVariables(argMap) + ) + }, + directives = directives, + selections = selections.map { it.substituteVariables(argMap) } + ) + + is GQLInlineFragment -> GQLInlineFragment( + sourceLocation = sourceLocation, + typeCondition = typeCondition, + directives = directives, + selections = selections.map { it.substituteVariables(argMap) } + ) + + is GQLFragmentSpread -> this + } +} + +private fun GQLValue.substituteVariables(argMap: Map): GQLValue { + return when (this) { + is GQLVariableValue -> argMap[name] ?: this + is GQLListValue -> GQLListValue(sourceLocation = sourceLocation, values = values.map { it.substituteVariables(argMap) }) + is GQLObjectValue -> GQLObjectValue( + sourceLocation = sourceLocation, + fields = fields.map { GQLObjectField(sourceLocation = it.sourceLocation, name = it.name, value = it.value.substituteVariables(argMap)) } + ) + + else -> this + } } \ No newline at end of file diff --git a/libraries/apollo-ast/src/jvmTest/kotlin/com/apollographql/apollo/graphql/ast/test/ExecutableValidationTest.kt b/libraries/apollo-ast/src/jvmTest/kotlin/com/apollographql/apollo/graphql/ast/test/ExecutableValidationTest.kt index 93d738130fc..e5086708f11 100644 --- a/libraries/apollo-ast/src/jvmTest/kotlin/com/apollographql/apollo/graphql/ast/test/ExecutableValidationTest.kt +++ b/libraries/apollo-ast/src/jvmTest/kotlin/com/apollographql/apollo/graphql/ast/test/ExecutableValidationTest.kt @@ -21,7 +21,8 @@ class ExecutableValidationTest { @Test fun testValidation(@TestParameter(valuesProvider = ParametersProvider::class) graphQLFile: File) { findSchemaAndCheck(graphQLFile) { schema -> - val parseResult = graphQLFile.source().buffer().parseAsGQLDocument(graphQLFile.name) + val parserOptions = graphQLFile.pragmas().toParserOptions() + val parseResult = graphQLFile.source().buffer().parseAsGQLDocument(graphQLFile.name, parserOptions) val issues = if (parseResult.issues.isNotEmpty()) { parseResult.issues } else { diff --git a/libraries/apollo-ast/src/jvmTest/kotlin/com/apollographql/apollo/graphql/ast/test/fixtures.kt b/libraries/apollo-ast/src/jvmTest/kotlin/com/apollographql/apollo/graphql/ast/test/fixtures.kt index 764959cff30..96ce4090a6c 100644 --- a/libraries/apollo-ast/src/jvmTest/kotlin/com/apollographql/apollo/graphql/ast/test/fixtures.kt +++ b/libraries/apollo-ast/src/jvmTest/kotlin/com/apollographql/apollo/graphql/ast/test/fixtures.kt @@ -73,18 +73,17 @@ enum class Pragma { // Parser allowDirectivesOnDirectives, allowServiceCapabilities, - // Merger allowMergingFieldDefinitions, - // Schema validation addBuiltinForeignSchemas, addKotlinLabsDefinitions, addBuiltinDefinitions, noAddBuiltinDefinitions, - - // + // Executable validation allowDirectiveRedefinition, + // Parser and validation + allowFragmentArguments, } fun File.pragmas(): List = @@ -99,6 +98,9 @@ fun List.toParserOptions(): ParserOptions { if (Pragma.allowDirectivesOnDirectives in this@toParserOptions) { allowDirectivesOnDirectives(true) } + if (Pragma.allowFragmentArguments in this@toParserOptions) { + allowFragmentArguments(true) + } } .build() } diff --git a/libraries/apollo-ast/test-fixtures/parser/fragment-arguments-error.expected b/libraries/apollo-ast/test-fixtures/parser/fragment-arguments-error.expected new file mode 100644 index 00000000000..ced9532d2f9 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/parser/fragment-arguments-error.expected @@ -0,0 +1,2 @@ +ParsingError (2:9) +Expected Name, found '('. \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/parser/fragment-arguments-error.graphql b/libraries/apollo-ast/test-fixtures/parser/fragment-arguments-error.graphql new file mode 100644 index 00000000000..57cceb0bfd3 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/parser/fragment-arguments-error.graphql @@ -0,0 +1,7 @@ +{ + ...foo(a: 42, b: $b) +} + +fragment foo on Query($a: Int, $b: [String]) { + __typename +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/parser/fragment-arguments.expected b/libraries/apollo-ast/test-fixtures/parser/fragment-arguments.expected new file mode 100644 index 00000000000..a378465c553 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/parser/fragment-arguments.expected @@ -0,0 +1,8 @@ + +query { + ...foo(a: 42, b: $b) +} + +fragment foo($a: Int, $b: [String]) on Query { + __typename +} diff --git a/libraries/apollo-ast/test-fixtures/parser/fragment-arguments.graphql b/libraries/apollo-ast/test-fixtures/parser/fragment-arguments.graphql new file mode 100644 index 00000000000..765d20ebbec --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/parser/fragment-arguments.graphql @@ -0,0 +1,9 @@ +# PRAGMA allowFragmentArguments + +{ + ...foo(a: 42, b: $b) +} + +fragment foo($a: Int, $b: [String]) on Query { + __typename +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/UnusedVariable.expected b/libraries/apollo-ast/test-fixtures/validation/executable/UnusedVariable.expected index a4b55dbce15..7611db3511d 100644 --- a/libraries/apollo-ast/test-fixtures/validation/executable/UnusedVariable.expected +++ b/libraries/apollo-ast/test-fixtures/validation/executable/UnusedVariable.expected @@ -1,2 +1,2 @@ UnusedVariable (2:16) -Variable `condition` is unused \ No newline at end of file +Variable `condition` is unused in operation `HeroName` \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/allows_different_args_where_no_conflict_is_possible.expected b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/default_value.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/allows_different_args_where_no_conflict_is_possible.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/default_value.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/default_value.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/default_value.graphql new file mode 100644 index 00000000000..100cbdb3114 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/default_value.graphql @@ -0,0 +1,12 @@ +# PRAGMA allowFragmentArguments + +fragment UserFields($includeEmail: Boolean! = true) on User { + name + email @include(if: $includeEmail) +} + +query GetUser { + user(id: "1") { + ...UserFields + } +} diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/merge_error.expected b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/merge_error.expected new file mode 100644 index 00000000000..6d6e3e87042 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/merge_error.expected @@ -0,0 +1,11 @@ +OtherValidationIssue (4:3) +Field at path `users` conflicts with another field: they have different arguments. Use different aliases on the fields to fetch both if this was intentional. +------------ +OtherValidationIssue (12:3) +Field at path `users` conflicts with another field: they have different arguments. Use different aliases on the fields to fetch both if this was intentional. +------------ +OtherValidationIssue (18:3) +Field at path `users` conflicts with another field: they have different arguments. Use different aliases on the fields to fetch both if this was intentional. +------------ +OtherValidationIssue (12:3) +Field at path `users` conflicts with another field: they have different arguments. Use different aliases on the fields to fetch both if this was intentional. \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/merge_error.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/merge_error.graphql new file mode 100644 index 00000000000..04e8a1f35e4 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/merge_error.graphql @@ -0,0 +1,31 @@ +# PRAGMA allowFragmentArguments + +query GetFoo { + users(first: 20) { + totalCount + } + # invalid: different literals + ...queryDetails(first: 10) +} + +fragment queryDetails($first: Int!) on Query { + users(first: $first) { + totalCount + } +} + +query GetFoo2($first: Int!) { + users(first: $first) { + totalCount + } + # invalid: different variables + ...queryDetails(first: 10) +} + +query GetFoo3($first: Int!) { + users(first: $first) { + totalCount + } + # valid + ...queryDetails(first: $first) +} diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/missing_required_argument.expected b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/missing_required_argument.expected new file mode 100644 index 00000000000..0eee718c8b2 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/missing_required_argument.expected @@ -0,0 +1,2 @@ +OtherValidationIssue (10:9) +No value passed for required argument `includeEmail` on fragment `UserFields` \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/missing_required_argument.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/missing_required_argument.graphql new file mode 100644 index 00000000000..61a55704150 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/missing_required_argument.graphql @@ -0,0 +1,12 @@ +# PRAGMA allowFragmentArguments + +fragment UserFields($includeEmail: Boolean!) on User { + name + email @include(if: $includeEmail) +} + +query GetUser { + user(id: "1") { + ...UserFields + } +} diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/different_args_with_different_aliases.expected b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/operation_variable_passthrough.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/different_args_with_different_aliases.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/operation_variable_passthrough.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/operation_variable_passthrough.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/operation_variable_passthrough.graphql new file mode 100644 index 00000000000..cea4daff9cb --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/operation_variable_passthrough.graphql @@ -0,0 +1,12 @@ +# PRAGMA allowFragmentArguments + +fragment UserFields($includeEmail: Boolean!) on User { + name + email @include(if: $includeEmail) +} + +query GetUser($showEmail: Boolean!) { + user(id: "1") { + ...UserFields(includeEmail: $showEmail) + } +} diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/schema.graphqls b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/schema.graphqls new file mode 100644 index 00000000000..affa654dc67 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/schema.graphqls @@ -0,0 +1,29 @@ +# PRAGMA allowFragmentArguments + +type Query { + user(id: ID!): User + users(first: Int, after: String): UserConnection + node(id: ID!): Node +} + +type User implements Node { + id: ID! + name: String + age: Int + email: String + friends(first: Int, after: String): UserConnection +} + +type UserConnection { + edges: [UserEdge] + totalCount: Int +} + +type UserEdge { + node: User + cursor: String +} + +interface Node { + id: ID! +} diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/type_mismatch.expected b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/type_mismatch.expected new file mode 100644 index 00000000000..ce88e6ffcd1 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/type_mismatch.expected @@ -0,0 +1,2 @@ +OtherValidationIssue (10:37) +Value `"not_a_boolean"` cannot be used in position expecting `Boolean` \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/type_mismatch.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/type_mismatch.graphql new file mode 100644 index 00000000000..a38c2ab1ba1 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/type_mismatch.graphql @@ -0,0 +1,12 @@ +# PRAGMA allowFragmentArguments + +fragment UserFields($includeEmail: Boolean!) on User { + name + email @include(if: $includeEmail) +} + +query GetUser { + user(id: "1") { + ...UserFields(includeEmail: "not_a_boolean") + } +} diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/unknown_argument.expected b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/unknown_argument.expected new file mode 100644 index 00000000000..9f4217bedcd --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/unknown_argument.expected @@ -0,0 +1,2 @@ +OtherValidationIssue (10:43) +Unknown argument `unknownArg` on fragment `UserFields` \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/unknown_argument.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/unknown_argument.graphql new file mode 100644 index 00000000000..ebf6bf136ea --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/unknown_argument.graphql @@ -0,0 +1,12 @@ +# PRAGMA allowFragmentArguments + +fragment UserFields($includeEmail: Boolean!) on User { + name + email @include(if: $includeEmail) +} + +query GetUser { + user(id: "1") { + ...UserFields(includeEmail: true, unknownArg: "foo") + } +} diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/unused_fragment_variable.expected b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/unused_fragment_variable.expected new file mode 100644 index 00000000000..8b358a0c0e4 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/unused_fragment_variable.expected @@ -0,0 +1,2 @@ +UnusedVariable (3:46) +Variable `unused` is unused in fragment `UserFields` \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/unused_fragment_variable.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/unused_fragment_variable.graphql new file mode 100644 index 00000000000..f21b10928f2 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/unused_fragment_variable.graphql @@ -0,0 +1,12 @@ +# PRAGMA allowFragmentArguments + +fragment UserFields($includeEmail: Boolean!, $unused: String) on User { + name + email @include(if: $includeEmail) +} + +query GetUser { + user(id: "1") { + ...UserFields(includeEmail: true) + } +} diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/different_directives_with_different_aliases.expected b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/valid_usage.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/different_directives_with_different_aliases.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/valid_usage.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/valid_usage.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/valid_usage.graphql new file mode 100644 index 00000000000..685cc1fc84a --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/valid_usage.graphql @@ -0,0 +1,12 @@ +# PRAGMA allowFragmentArguments + +fragment UserFields($includeEmail: Boolean!) on User { + name + email @include(if: $includeEmail) +} + +query GetUser { + user(id: "1") { + ...UserFields(includeEmail: true) + } +} diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/different_skip_include_directives_accepted.expected b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/variable_scoping.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/different_skip_include_directives_accepted.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/variable_scoping.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/variable_scoping.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/variable_scoping.graphql new file mode 100644 index 00000000000..e6ddd30de82 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/variable_scoping.graphql @@ -0,0 +1,18 @@ +# PRAGMA allowFragmentArguments + +fragment UserFields($first: Int!) on User { + friends(first: $first) { + edges { + node { + name + } + } + } +} + +query GetUser($first: Int!) { + user(id: "1") { + ...UserFields(first: $first) + name + } +} diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/LICENSE b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/LICENSE similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/LICENSE rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/LICENSE diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/README.md b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/README.md similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/README.md rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/README.md diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema2/allows_different_order_of_args.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/field_merging_order/allows_different_order_of_args.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema2/allows_different_order_of_args.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/field_merging_order/allows_different_order_of_args.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema2/allows_different_order_of_args.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/field_merging_order/allows_different_order_of_args.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema2/allows_different_order_of_args.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/field_merging_order/allows_different_order_of_args.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema2/schema.graphqls b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/field_merging_order/schema.graphqls similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema2/schema.graphqls rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/field_merging_order/schema.graphqls diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema3/allows_different_order_of_input_object_fields_in_arg_values.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/input_field_order/allows_different_order_of_input_object_fields_in_arg_values.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema3/allows_different_order_of_input_object_fields_in_arg_values.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/input_field_order/allows_different_order_of_input_object_fields_in_arg_values.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema3/allows_different_order_of_input_object_fields_in_arg_values.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/input_field_order/allows_different_order_of_input_object_fields_in_arg_values.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema3/allows_different_order_of_input_object_fields_in_arg_values.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/input_field_order/allows_different_order_of_input_object_fields_in_arg_values.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema3/schema.graphqls b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/input_field_order/schema.graphqls similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema3/schema.graphqls rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/input_field_order/schema.graphqls diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema5/schema.graphqls b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/keywords/schema.graphqls similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema5/schema.graphqls rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/keywords/schema.graphqls diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema5/works_for_field_names_that_are_js_keywords.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/keywords/works_for_field_names_that_are_js_keywords.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema5/works_for_field_names_that_are_js_keywords.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/keywords/works_for_field_names_that_are_js_keywords.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema5/works_for_field_names_that_are_js_keywords.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/keywords/works_for_field_names_that_are_js_keywords.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema5/works_for_field_names_that_are_js_keywords.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/keywords/works_for_field_names_that_are_js_keywords.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/schema.graphqls b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/schema.graphqls new file mode 100644 index 00000000000..5527f01fdb0 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/schema.graphqls @@ -0,0 +1,13 @@ + type Query { + foo: String + } + + directive @onQuery on QUERY + directive @onMutation on MUTATION + directive @onSubscription on SUBSCRIPTION + directive @onField on FIELD + directive @onFragmentDefinition on FRAGMENT_DEFINITION + directive @onFragmentSpread on FRAGMENT_SPREAD + directive @onInlineFragment on INLINE_FRAGMENT + directive @onVariableDefinition on VARIABLE_DEFINITION + directive @onFragmentVariableDefinition on VARIABLE_DEFINITION \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/with_misplaced_directives.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/with_misplaced_directives.expected new file mode 100644 index 00000000000..e73e67aec21 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/with_misplaced_directives.expected @@ -0,0 +1,29 @@ +OtherValidationIssue (9:7) +Directive 'onQuery' cannot be applied on 'FIELD' +------------ +OtherValidationIssue (8:44) +Directive 'onQuery' cannot be applied on 'FRAGMENT_DEFINITION' +------------ +OtherValidationIssue (8:25) +Directive 'onField' cannot be applied on 'VARIABLE_DEFINITION' +------------ +UnusedVariable (8:15) +Variable `arg` is unused in fragment `Frag` +------------ +AnonymousOperation (3:1) +Apollo does not support anonymous operations +------------ +OtherValidationIssue (4:22) +Directive 'onQuery' cannot be applied on 'FRAGMENT_SPREAD' +------------ +OtherValidationIssue (5:7) +Directive 'onQuery' cannot be applied on 'FIELD' +------------ +OtherValidationIssue (3:28) +Directive 'onMutation' cannot be applied on 'QUERY' +------------ +OtherValidationIssue (3:18) +Directive 'onQuery' cannot be applied on 'VARIABLE_DEFINITION' +------------ +OtherValidationIssue (3:28) +Directive 'onMutation' cannot be applied on 'QUERY' \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/with_misplaced_directives.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/with_misplaced_directives.graphql new file mode 100644 index 00000000000..31a85965684 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/with_misplaced_directives.graphql @@ -0,0 +1,10 @@ +# PRAGMA allowFragmentArguments + +query ($var: Int @onQuery) @onMutation { + ...Frag(arg: $var) @onQuery + foo @onQuery +} + +fragment Frag($arg: Int @onField) on Query @onQuery { + foo @onQuery +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/identical_fields.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/with_no_directive.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/identical_fields.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/with_no_directive.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/with_no_directive.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/with_no_directive.graphql new file mode 100644 index 00000000000..b2170e856b9 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/with_no_directive.graphql @@ -0,0 +1,8 @@ +query Foo { + foo + ...Frag +} + +fragment Frag on Query { + foo +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/with_standard_directives.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/with_standard_directives.expected new file mode 100644 index 00000000000..b1706a1018c --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/with_standard_directives.expected @@ -0,0 +1,2 @@ +AnonymousOperation (1:1) +Apollo does not support anonymous operations \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/with_standard_directives.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/with_standard_directives.graphql new file mode 100644 index 00000000000..062535e50e3 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/with_standard_directives.graphql @@ -0,0 +1,4 @@ +{ + foo @skip(if: false) + foo @include(if: true) +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/with_unknown_directive.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/with_unknown_directive.expected new file mode 100644 index 00000000000..a622bc69e31 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/with_unknown_directive.expected @@ -0,0 +1,5 @@ +AnonymousOperation (1:1) +Apollo does not support anonymous operations +------------ +UnknownDirective (2:7) +Unknown directive '@unknown' \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/with_unknown_directive.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/with_unknown_directive.graphql new file mode 100644 index 00000000000..b84b33f5fd9 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/known_directive/with_unknown_directive.graphql @@ -0,0 +1,3 @@ +{ + foo @unknown(directive: "value") +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/identical_fields_with_identical_args.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/defined_variables_used as_fragment_arguments_are_not_unused_or_undefined_variables.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/identical_fields_with_identical_args.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/defined_variables_used as_fragment_arguments_are_not_unused_or_undefined_variables.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/defined_variables_used as_fragment_arguments_are_not_unused_or_undefined_variables.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/defined_variables_used as_fragment_arguments_are_not_unused_or_undefined_variables.graphql new file mode 100644 index 00000000000..f0233f07832 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/defined_variables_used as_fragment_arguments_are_not_unused_or_undefined_variables.graphql @@ -0,0 +1,12 @@ +# PRAGMA allowFragmentArguments + +query Foo($b: String) { + field { + ...FragA(a: $b) + } +} +fragment FragA($a: String) on Type { + field(a: $a) { + foo + } +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/identical_fields_with_identical_directives.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/defined_variables_used as_fragment_arguments_are_not_unused_variables.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/identical_fields_with_identical_directives.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/defined_variables_used as_fragment_arguments_are_not_unused_variables.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/same_aliases_allowed_on_non_overlapping_fields.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/fragment_defined_arguments_are_not_unused_or_undefined_variables.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/same_aliases_allowed_on_non_overlapping_fields.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/fragment_defined_arguments_are_not_unused_or_undefined_variables.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/fragment_defined_arguments_are_not_unused_or_undefined_variables.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/fragment_defined_arguments_are_not_unused_or_undefined_variables.graphql new file mode 100644 index 00000000000..444f4834400 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/fragment_defined_arguments_are_not_unused_or_undefined_variables.graphql @@ -0,0 +1,12 @@ +# PRAGMA allowFragmentArguments + +query Foo { + field { + ...FragA + } +} +fragment FragA($a: String) on Type { + field(a: $a) { + foo + } +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_undefined_variables_produce_multiple_errors.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_undefined_variables_produce_multiple_errors.expected new file mode 100644 index 00000000000..5ffe948dfb5 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_undefined_variables_produce_multiple_errors.expected @@ -0,0 +1,35 @@ +OtherValidationIssue (12:3) +Field at path `field.field` conflicts with another field: they have different arguments. Use different aliases on the fields to fetch both if this was intentional. +------------ +OtherValidationIssue (21:3) +Field at path `field.field` conflicts with another field: they have different arguments. Use different aliases on the fields to fetch both if this was intentional. +------------ +OtherValidationIssue (16:3) +Field at path `field.field` conflicts with another field: they have different arguments. Use different aliases on the fields to fetch both if this was intentional. +------------ +OtherValidationIssue (12:12) +Variable `a` is not defined by operation `Foo` +------------ +OtherValidationIssue (16:12) +Variable `a` is not defined by operation `Foo` +------------ +OtherValidationIssue (21:12) +Variable `c` is not defined by operation `Foo` +------------ +OtherValidationIssue (12:3) +Field at path `field.field` conflicts with another field: they have different arguments. Use different aliases on the fields to fetch both if this was intentional. +------------ +OtherValidationIssue (21:3) +Field at path `field.field` conflicts with another field: they have different arguments. Use different aliases on the fields to fetch both if this was intentional. +------------ +OtherValidationIssue (16:3) +Field at path `field.field` conflicts with another field: they have different arguments. Use different aliases on the fields to fetch both if this was intentional. +------------ +OtherValidationIssue (12:19) +Variable `b` is not defined by operation `Bar` +------------ +OtherValidationIssue (16:19) +Variable `b` is not defined by operation `Bar` +------------ +OtherValidationIssue (21:12) +Variable `c` is not defined by operation `Bar` \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_undefined_variables_produce_multiple_errors.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_undefined_variables_produce_multiple_errors.graphql new file mode 100644 index 00000000000..7268a421a7e --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_undefined_variables_produce_multiple_errors.graphql @@ -0,0 +1,24 @@ +query Foo($b: String) { + field { + ...FragAB + } +} +query Bar($a: String) { + field { + ...FragAB + } +} +fragment FragAB on Type { + field(a: $a, b: $b) { + foo + } + ...FragC + field(a: $a, b: $b) { + foo + } +} +fragment FragC on Type { + field(c: $c) { + foo + } +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_in_fragments_not_defined.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_in_fragments_not_defined.expected new file mode 100644 index 00000000000..c2700cefdcd --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_in_fragments_not_defined.expected @@ -0,0 +1,5 @@ +OtherValidationIssue (7:12) +Variable `a` is not defined by operation `Foo` +------------ +OtherValidationIssue (17:12) +Variable `c` is not defined by operation `Foo` \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_in_fragments_not_defined.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_in_fragments_not_defined.graphql new file mode 100644 index 00000000000..d943360de17 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_in_fragments_not_defined.graphql @@ -0,0 +1,20 @@ +query Foo($b: String) { + field { + ...FragA + } +} +fragment FragA on Type { + field(a: $a) { + ...FragB + } +} +fragment FragB on Type { + field(b: $b) { + ...FragC + } +} +fragment FragC on Type { + field(c: $c) { + foo + } +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_not_defined.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_not_defined.expected new file mode 100644 index 00000000000..6dce7a07100 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_not_defined.expected @@ -0,0 +1,5 @@ +OtherValidationIssue (2:12) +Variable `a` is not defined by operation `Foo` +------------ +OtherValidationIssue (2:26) +Variable `c` is not defined by operation `Foo` \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_not_defined.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_not_defined.graphql new file mode 100644 index 00000000000..336738713d0 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_not_defined.graphql @@ -0,0 +1,5 @@ +query Foo($b: String) { + field(a: $a, b: $b, c: $c) { + foo + } +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_not_used.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_not_used.expected new file mode 100644 index 00000000000..ea399ca9066 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_not_used.expected @@ -0,0 +1,5 @@ +UnusedVariable (1:11) +Variable `a` is unused in operation `Foo` +------------ +UnusedVariable (1:35) +Variable `c` is unused in operation `Foo` \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_not_used.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_not_used.graphql new file mode 100644 index 00000000000..4d52296a65f --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_not_used.graphql @@ -0,0 +1,5 @@ +query Foo($a: String, $b: String, $c: String) { + field(b: $b) { + foo + } +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_not_used_in_fragments.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_not_used_in_fragments.expected new file mode 100644 index 00000000000..ea399ca9066 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_not_used_in_fragments.expected @@ -0,0 +1,5 @@ +UnusedVariable (1:11) +Variable `a` is unused in operation `Foo` +------------ +UnusedVariable (1:35) +Variable `c` is unused in operation `Foo` \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_not_used_in_fragments.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_not_used_in_fragments.graphql new file mode 100644 index 00000000000..09e0df678b3 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/multiple_variables_not_used_in_fragments.graphql @@ -0,0 +1,20 @@ +query Foo($a: String, $b: String, $c: String) { + field { + ...FragA + } +} +fragment FragA on Type { + field { + ...FragB + } +} +fragment FragB on Type { + field(b: $b) { + ...FragC + } +} +fragment FragC on Type { + field { + foo + } +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/no_unused_variable.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/no_unused_variable.expected new file mode 100644 index 00000000000..b1706a1018c --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/no_unused_variable.expected @@ -0,0 +1,2 @@ +AnonymousOperation (1:1) +Apollo does not support anonymous operations \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/no_unused_variable.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/no_unused_variable.graphql new file mode 100644 index 00000000000..ec35ba4dff6 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/no_unused_variable.graphql @@ -0,0 +1,5 @@ +query ($a: String, $b: String, $c: String) { + field(a: $a, b: $b, c: $c) { + foo + } +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/schema.graphqls b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/schema.graphqls new file mode 100644 index 00000000000..9ca5222e607 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/schema.graphqls @@ -0,0 +1,8 @@ +type Query { + field(a: String, b: String, c: String): Type +} + +type Type { + field(a: String, b: String, c: String): Type + foo: String +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/single_variable_in_fragment_not_defined_by_multiple_operations.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/single_variable_in_fragment_not_defined_by_multiple_operations.expected new file mode 100644 index 00000000000..f7a2bde8091 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/single_variable_in_fragment_not_defined_by_multiple_operations.expected @@ -0,0 +1,5 @@ +OtherValidationIssue (12:19) +Variable `b` is not defined by operation `Foo` +------------ +OtherValidationIssue (12:19) +Variable `b` is not defined by operation `Bar` \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/single_variable_in_fragment_not_defined_by_multiple_operations.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/single_variable_in_fragment_not_defined_by_multiple_operations.graphql new file mode 100644 index 00000000000..f1a7dd6a088 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/single_variable_in_fragment_not_defined_by_multiple_operations.graphql @@ -0,0 +1,15 @@ +query Foo($a: String) { + field { + ...FragAB + } +} +query Bar($a: String) { + field { + ...FragAB + } +} +fragment FragAB on Type { + field(a: $a, b: $b) { + foo + } +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/unused_fragment_variables_are_reported.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/unused_fragment_variables_are_reported.expected new file mode 100644 index 00000000000..99b508932b9 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/unused_fragment_variables_are_reported.expected @@ -0,0 +1,2 @@ +UnusedVariable (8:16) +Variable `a` is unused in fragment `FragA` \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/unused_fragment_variables_are_reported.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/unused_fragment_variables_are_reported.graphql new file mode 100644 index 00000000000..11c6a6b03f0 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/unused_fragment_variables_are_reported.graphql @@ -0,0 +1,12 @@ +# PRAGMA allowFragmentArguments + +query Foo { + field { + ...FragA(a: "value") + } +} +fragment FragA($a: String) on Type { + field { + foo + } +} diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/unique_fields.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/uses_all_variables_deeply.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/unique_fields.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/uses_all_variables_deeply.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/uses_all_variables_deeply.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/uses_all_variables_deeply.graphql new file mode 100644 index 00000000000..11c9c705cec --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/uses_all_variables_deeply.graphql @@ -0,0 +1,9 @@ +query Foo($a: String, $b: String, $c: String) { + field(a: $a) { + field(b: $b) { + field(c: $c) { + foo + } + } + } +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/allows_inline_fragments_without_type_condition.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/uses_all_variables_deeply_in_inline_fragments.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/allows_inline_fragments_without_type_condition.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/uses_all_variables_deeply_in_inline_fragments.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/uses_all_variables_deeply_in_inline_fragments.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/uses_all_variables_deeply_in_inline_fragments.graphql new file mode 100644 index 00000000000..2673eca1248 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/uses_all_variables_deeply_in_inline_fragments.graphql @@ -0,0 +1,13 @@ +query Foo($a: String, $b: String, $c: String) { + field(a: $a) { + ... on Type { + field(b: $b) { + ... on Type { + field(c: $c) { + foo + } + } + } + } + } +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/allows_non_conflicting_overlapping_types.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/uses_all_variables_in_fragments.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/allows_non_conflicting_overlapping_types.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/uses_all_variables_in_fragments.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/uses_all_variables_in_fragments.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/uses_all_variables_in_fragments.graphql new file mode 100644 index 00000000000..ea56411befd --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/uses_all_variables_in_fragments.graphql @@ -0,0 +1,20 @@ +query Foo($a: String, $b: String, $c: String) { + field { + ...FragA + } +} +fragment FragA on Type { + field(a: $a) { + ...FragB + } +} +fragment FragB on Type { + field(b: $b) { + ...FragC + } +} +fragment FragC on Type { + field(c: $c) { + foo + } +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_in_fragment_not_defined_by_operation.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_in_fragment_not_defined_by_operation.expected new file mode 100644 index 00000000000..ef249ab4242 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_in_fragment_not_defined_by_operation.expected @@ -0,0 +1,2 @@ +OtherValidationIssue (17:12) +Variable `c` is not defined by operation `Foo` \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_in_fragment_not_defined_by_operation.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_in_fragment_not_defined_by_operation.graphql new file mode 100644 index 00000000000..9e623bb17fa --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_in_fragment_not_defined_by_operation.graphql @@ -0,0 +1,20 @@ +query Foo($a: String, $b: String) { + field { + ...FragA + } +} +fragment FragA on Type { + field(a: $a) { + ...FragB + } +} +fragment FragB on Type { + field(b: $b) { + ...FragC + } +} +fragment FragC on Type { + field(c: $c) { + foo + } +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_in_fragment_not_defined_by_unnamed_query.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_in_fragment_not_defined_by_unnamed_query.expected new file mode 100644 index 00000000000..070deb1ece2 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_in_fragment_not_defined_by_unnamed_query.expected @@ -0,0 +1,5 @@ +AnonymousOperation (1:1) +Apollo does not support anonymous operations +------------ +OtherValidationIssue (7:12) +Variable `a` is not defined by anonymous operation \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_in_fragment_not_defined_by_unnamed_query.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_in_fragment_not_defined_by_unnamed_query.graphql new file mode 100644 index 00000000000..34e192ad136 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_in_fragment_not_defined_by_unnamed_query.graphql @@ -0,0 +1,10 @@ +{ + field { + ...FragA + } +} +fragment FragA on Type { + field(a: $a) { + foo + } +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_in_fragment_used_by_other_operation.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_in_fragment_used_by_other_operation.expected new file mode 100644 index 00000000000..4792c4d5933 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_in_fragment_used_by_other_operation.expected @@ -0,0 +1,11 @@ +OtherValidationIssue (12:12) +Variable `a` is not defined by operation `Foo` +------------ +UnusedVariable (1:11) +Variable `b` is unused in operation `Foo` +------------ +OtherValidationIssue (17:12) +Variable `b` is not defined by operation `Bar` +------------ +UnusedVariable (6:11) +Variable `a` is unused in operation `Bar` \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_in_fragment_used_by_other_operation.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_in_fragment_used_by_other_operation.graphql new file mode 100644 index 00000000000..d471844b2bd --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_in_fragment_used_by_other_operation.graphql @@ -0,0 +1,20 @@ +query Foo($b: String) { + field { + ...FragA + } +} +query Bar($a: String) { + field { + ...FragB + } +} +fragment FragA on Type { + field(a: $a) { + foo + } +} +fragment FragB on Type { + field(b: $b) { + foo + } +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_defined.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_defined.expected new file mode 100644 index 00000000000..363f744e4c8 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_defined.expected @@ -0,0 +1,2 @@ +OtherValidationIssue (2:30) +Unknown argument `d` on field `field` \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_defined.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_defined.graphql new file mode 100644 index 00000000000..251c5a106f3 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_defined.graphql @@ -0,0 +1,5 @@ +query Foo($a: String, $b: String, $c: String) { + field(a: $a, b: $b, c: $c, d: $d) { + foo + } +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_defined_by_anonymous_query.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_defined_by_anonymous_query.expected new file mode 100644 index 00000000000..44ca4a7f203 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_defined_by_anonymous_query.expected @@ -0,0 +1,5 @@ +AnonymousOperation (1:1) +Apollo does not support anonymous operations +------------ +OtherValidationIssue (2:12) +Variable `a` is not defined by anonymous operation \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_defined_by_anonymous_query.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_defined_by_anonymous_query.graphql new file mode 100644 index 00000000000..7c2e92af70c --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_defined_by_anonymous_query.graphql @@ -0,0 +1,5 @@ +{ + field(a: $a) { + foo + } +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used.expected new file mode 100644 index 00000000000..4d6e373c1a6 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used.expected @@ -0,0 +1,5 @@ +AnonymousOperation (1:1) +Apollo does not support anonymous operations +------------ +UnusedVariable (1:32) +Variable `c` is unused in anonymous operation \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used.graphql new file mode 100644 index 00000000000..9da60d80721 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used.graphql @@ -0,0 +1,5 @@ +query ($a: String, $b: String, $c: String) { + field(a: $a, b: $b) { + foo + } +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used_by_fragment_used_by_other_operation.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used_by_fragment_used_by_other_operation.expected new file mode 100644 index 00000000000..4792c4d5933 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used_by_fragment_used_by_other_operation.expected @@ -0,0 +1,11 @@ +OtherValidationIssue (12:12) +Variable `a` is not defined by operation `Foo` +------------ +UnusedVariable (1:11) +Variable `b` is unused in operation `Foo` +------------ +OtherValidationIssue (17:12) +Variable `b` is not defined by operation `Bar` +------------ +UnusedVariable (6:11) +Variable `a` is unused in operation `Bar` \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used_by_fragment_used_by_other_operation.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used_by_fragment_used_by_other_operation.graphql new file mode 100644 index 00000000000..d471844b2bd --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used_by_fragment_used_by_other_operation.graphql @@ -0,0 +1,20 @@ +query Foo($b: String) { + field { + ...FragA + } +} +query Bar($a: String) { + field { + ...FragB + } +} +fragment FragA on Type { + field(a: $a) { + foo + } +} +fragment FragB on Type { + field(b: $b) { + foo + } +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used_by_unreferenced_fragment.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used_by_unreferenced_fragment.expected new file mode 100644 index 00000000000..361d2800e85 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used_by_unreferenced_fragment.expected @@ -0,0 +1,8 @@ +OtherValidationIssue (7:12) +Variable `a` is not defined by operation `Foo` +------------ +UnusedVariable (1:11) +Variable `b` is unused in operation `Foo` +------------ +UnusedFragment (11:1) +Fragment 'FragB' is not used \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used_by_unreferenced_fragment.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used_by_unreferenced_fragment.graphql new file mode 100644 index 00000000000..a39746fa17a --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used_by_unreferenced_fragment.graphql @@ -0,0 +1,15 @@ +query Foo($b: String) { + field { + ...FragA + } +} +fragment FragA on Type { + field(a: $a) { + foo + } +} +fragment FragB on Type { + field(b: $b) { + foo + } +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used_in_fragments.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used_in_fragments.expected new file mode 100644 index 00000000000..f3526598127 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used_in_fragments.expected @@ -0,0 +1,2 @@ +UnusedVariable (1:35) +Variable `c` is unused in operation `Foo` \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used_in_fragments.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used_in_fragments.graphql new file mode 100644 index 00000000000..7f3390bf86a --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_not_used_in_fragments.graphql @@ -0,0 +1,20 @@ +query Foo($a: String, $b: String, $c: String) { + field { + ...FragA + } +} +fragment FragA on Type { + field(a: $a) { + ...FragB + } +} +fragment FragB on Type { + field(b: $b) { + ...FragC + } +} +fragment FragC on Type { + field { + foo + } +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/compatible_return_shapes_on_different_return_types.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_used_by_fragment_in_multiple_operations.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/compatible_return_shapes_on_different_return_types.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_used_by_fragment_in_multiple_operations.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_used_by_fragment_in_multiple_operations.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_used_by_fragment_in_multiple_operations.graphql new file mode 100644 index 00000000000..8a059b6709c --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_used_by_fragment_in_multiple_operations.graphql @@ -0,0 +1,20 @@ +query Foo($a: String) { + field { + ...FragA + } +} +query Bar($b: String) { + field { + ...FragB + } +} +fragment FragA on Type { + field(a: $a) { + foo + } +} +fragment FragB on Type { + field(b: $b) { + foo + } +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_used_by_recursive_fragment.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_used_by_recursive_fragment.expected new file mode 100644 index 00000000000..78f221843a9 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_used_by_recursive_fragment.expected @@ -0,0 +1,2 @@ +FragmentCycle (8:5) +Fragment 'FragA' spreads itself, creating a cycle at '__FragA.field.__FragA' \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_used_by_recursive_fragment.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_used_by_recursive_fragment.graphql new file mode 100644 index 00000000000..c9a36d8b5e3 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variable_used_by_recursive_fragment.graphql @@ -0,0 +1,10 @@ +query Foo($a: String) { + field { + ...FragA + } +} +fragment FragA on Type { + field(a: $a) { + ...FragA + } +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variables_in_fragment_not_defined_by_multiple_operations.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variables_in_fragment_not_defined_by_multiple_operations.expected new file mode 100644 index 00000000000..894268a694a --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variables_in_fragment_not_defined_by_multiple_operations.expected @@ -0,0 +1,5 @@ +OtherValidationIssue (12:12) +Variable `a` is not defined by operation `Foo` +------------ +OtherValidationIssue (12:19) +Variable `b` is not defined by operation `Bar` \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variables_in_fragment_not_defined_by_multiple_operations.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variables_in_fragment_not_defined_by_multiple_operations.graphql new file mode 100644 index 00000000000..8ebd3eaf9c4 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variables_in_fragment_not_defined_by_multiple_operations.graphql @@ -0,0 +1,15 @@ +query Foo($b: String) { + field { + ...FragAB + } +} +query Bar($a: String) { + field { + ...FragAB + } +} +fragment FragAB on Type { + field(a: $a, b: $b) { + foo + } +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variables_shadowed_by_parent_fragment_arguments_are_still_undefined_variables.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variables_shadowed_by_parent_fragment_arguments_are_still_undefined_variables.expected new file mode 100644 index 00000000000..b61ba629392 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variables_shadowed_by_parent_fragment_arguments_are_still_undefined_variables.expected @@ -0,0 +1,5 @@ +UnusedVariable (8:16) +Variable `a` is unused in fragment `FragA` +------------ +OtherValidationIssue (12:12) +Variable `a` is not defined by operation `Foo` \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variables_shadowed_by_parent_fragment_arguments_are_still_undefined_variables.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variables_shadowed_by_parent_fragment_arguments_are_still_undefined_variables.graphql new file mode 100644 index 00000000000..65d50e6e5c4 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variables_shadowed_by_parent_fragment_arguments_are_still_undefined_variables.graphql @@ -0,0 +1,15 @@ +# PRAGMA allowFragmentArguments + +query Foo { + field { + ...FragA + } +} +fragment FragA($a: String) on Type { + ...FragB +} +fragment FragB on Type { + field(a: $a) { + foo + } +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variables_used_as_fragment_arguments_may_be_undefined_variables.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variables_used_as_fragment_arguments_may_be_undefined_variables.expected new file mode 100644 index 00000000000..e6bfd61c763 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variables_used_as_fragment_arguments_may_be_undefined_variables.expected @@ -0,0 +1,5 @@ +UnusedVariable (8:16) +Variable `a` is unused in fragment `FragA` +------------ +OtherValidationIssue (5:17) +Variable `a` is not defined by operation `Foo` \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variables_used_as_fragment_arguments_may_be_undefined_variables.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variables_used_as_fragment_arguments_may_be_undefined_variables.graphql new file mode 100644 index 00000000000..f1beb670f73 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/no_unused_or_undefined_variable/variables_used_as_fragment_arguments_may_be_undefined_variables.graphql @@ -0,0 +1,12 @@ +# PRAGMA allowFragmentArguments + +query Foo { + field { + ...FragA(a: $a) + } +} +fragment FragA($a: String) on Type { + field { + foo + } +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/same_wrapped_scalar_return_types.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/allows_inline_fragments_without_type_condition.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/same_wrapped_scalar_return_types.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/allows_inline_fragments_without_type_condition.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/allows_inline_fragments_without_type_condition.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/allows_inline_fragments_without_type_condition.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/allows_inline_fragments_without_type_condition.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/allows_inline_fragments_without_type_condition.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/allows_non_conflicting_overlapping_types.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/allows_non_conflicting_overlapping_types.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/allows_non_conflicting_overlapping_types.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/allows_non_conflicting_overlapping_types.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/allows_non_conflicting_overlapping_types.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/allows_non_conflicting_overlapping_types.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/compares_deep_types_including_list.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/compares_deep_types_including_list.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/compares_deep_types_including_list.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/compares_deep_types_including_list.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/compares_deep_types_including_list.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/compares_deep_types_including_list.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/compares_deep_types_including_list.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/compares_deep_types_including_list.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/compatible_return_shapes_on_different_return_types.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/compatible_return_shapes_on_different_return_types.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/compatible_return_shapes_on_different_return_types.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/compatible_return_shapes_on_different_return_types.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/compatible_return_shapes_on_different_return_types.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/compatible_return_shapes_on_different_return_types.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/conflicting_return_types_which_potentially_overlap.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/conflicting_return_types_which_potentially_overlap.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/conflicting_return_types_which_potentially_overlap.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/conflicting_return_types_which_potentially_overlap.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/conflicting_return_types_which_potentially_overlap.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/conflicting_return_types_which_potentially_overlap.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/conflicting_return_types_which_potentially_overlap.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/conflicting_return_types_which_potentially_overlap.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/disallows_differing_deep_return_types_despite_no_overlap.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/disallows_differing_deep_return_types_despite_no_overlap.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/disallows_differing_deep_return_types_despite_no_overlap.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/disallows_differing_deep_return_types_despite_no_overlap.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/disallows_differing_deep_return_types_despite_no_overlap.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/disallows_differing_deep_return_types_despite_no_overlap.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/disallows_differing_deep_return_types_despite_no_overlap.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/disallows_differing_deep_return_types_despite_no_overlap.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/disallows_differing_return_type_list_despite_no_overlap_1.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/disallows_differing_return_type_list_despite_no_overlap_1.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/disallows_differing_return_type_list_despite_no_overlap_1.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/disallows_differing_return_type_list_despite_no_overlap_1.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/disallows_differing_return_type_list_despite_no_overlap_1.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/disallows_differing_return_type_list_despite_no_overlap_1.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/disallows_differing_return_type_list_despite_no_overlap_1.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/disallows_differing_return_type_list_despite_no_overlap_1.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/disallows_differing_return_type_list_despite_no_overlap_2.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/disallows_differing_return_type_list_despite_no_overlap_2.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/disallows_differing_return_type_list_despite_no_overlap_2.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/disallows_differing_return_type_list_despite_no_overlap_2.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/disallows_differing_return_type_list_despite_no_overlap_2.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/disallows_differing_return_type_list_despite_no_overlap_2.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/disallows_differing_return_type_list_despite_no_overlap_2.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/disallows_differing_return_type_list_despite_no_overlap_2.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/disallows_differing_return_type_nullability_despite_no_overlap.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/disallows_differing_return_type_nullability_despite_no_overlap.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/disallows_differing_return_type_nullability_despite_no_overlap.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/disallows_differing_return_type_nullability_despite_no_overlap.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/disallows_differing_return_type_nullability_despite_no_overlap.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/disallows_differing_return_type_nullability_despite_no_overlap.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/disallows_differing_return_type_nullability_despite_no_overlap.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/disallows_differing_return_type_nullability_despite_no_overlap.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/disallows_differing_return_types_despite_no_overlap.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/disallows_differing_return_types_despite_no_overlap.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/disallows_differing_return_types_despite_no_overlap.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/disallows_differing_return_types_despite_no_overlap.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/disallows_differing_return_types_despite_no_overlap.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/disallows_differing_return_types_despite_no_overlap.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/disallows_differing_return_types_despite_no_overlap.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/disallows_differing_return_types_despite_no_overlap.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/disallows_differing_subfields.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/disallows_differing_subfields.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/disallows_differing_subfields.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/disallows_differing_subfields.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/disallows_differing_subfields.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/disallows_differing_subfields.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/disallows_differing_subfields.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/disallows_differing_subfields.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/ignores_unknown_types.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/ignores_unknown_types.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/ignores_unknown_types.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/ignores_unknown_types.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/ignores_unknown_types.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/ignores_unknown_types.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/ignores_unknown_types.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/ignores_unknown_types.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/reports_correctly_when_a_non_exclusive_follows_an_exclusive.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/reports_correctly_when_a_non_exclusive_follows_an_exclusive.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/reports_correctly_when_a_non_exclusive_follows_an_exclusive.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/reports_correctly_when_a_non_exclusive_follows_an_exclusive.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/reports_correctly_when_a_non_exclusive_follows_an_exclusive.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/reports_correctly_when_a_non_exclusive_follows_an_exclusive.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/reports_correctly_when_a_non_exclusive_follows_an_exclusive.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/reports_correctly_when_a_non_exclusive_follows_an_exclusive.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/same_wrapped_scalar_return_types.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/same_wrapped_scalar_return_types.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/same_wrapped_scalar_return_types.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/same_wrapped_scalar_return_types.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/same_wrapped_scalar_return_types.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/same_wrapped_scalar_return_types.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/schema.graphqls b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/schema.graphqls similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema4/schema.graphqls rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/same_response_shape/schema.graphqls diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/alias_masking_direct_field_access.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/alias_masking_direct_field_access.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/alias_masking_direct_field_access.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/alias_masking_direct_field_access.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/alias_masking_direct_field_access.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/alias_masking_direct_field_access.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/alias_masking_direct_field_access.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/alias_masking_direct_field_access.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/allows_different_args_where_no_conflict_is_possible.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/allows_different_args_where_no_conflict_is_possible.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/allows_different_args_where_no_conflict_is_possible.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/allows_different_args_where_no_conflict_is_possible.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/allows_different_args_where_no_conflict_is_possible.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/allows_different_args_where_no_conflict_is_possible.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/arg_passed_to_fragment_without_arg_is_reported.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/arg_passed_to_fragment_without_arg_is_reported.expected new file mode 100644 index 00000000000..d6151c8d959 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/arg_passed_to_fragment_without_arg_is_reported.expected @@ -0,0 +1,5 @@ +AnonymousOperation (3:1) +Apollo does not support anonymous operations +------------ +OtherValidationIssue (5:19) +Unknown argument `unknown` on fragment `withoutArg` \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/arg_passed_to_fragment_without_arg_is_reported.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/arg_passed_to_fragment_without_arg_is_reported.graphql new file mode 100644 index 00000000000..e84dd9c5acc --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/arg_passed_to_fragment_without_arg_is_reported.graphql @@ -0,0 +1,10 @@ +# PRAGMA allowFragmentArguments + +{ + dog { + ...withoutArg(unknown: true) + } +} +fragment withoutArg on Dog { + doesKnowCommand +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/conflicting_arg_names.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/conflicting_arg_names.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/conflicting_arg_names.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/conflicting_arg_names.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/conflicting_arg_names.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/conflicting_arg_names.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/conflicting_arg_names.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/conflicting_arg_names.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/conflicting_arg_values.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/conflicting_arg_values.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/conflicting_arg_values.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/conflicting_arg_values.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/conflicting_arg_values.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/conflicting_arg_values.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/conflicting_arg_values.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/conflicting_arg_values.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/deep_conflict.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/deep_conflict.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/deep_conflict.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/deep_conflict.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/deep_conflict.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/deep_conflict.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/deep_conflict.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/deep_conflict.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/deep_conflict_with_multiple_issues.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/deep_conflict_with_multiple_issues.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/deep_conflict_with_multiple_issues.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/deep_conflict_with_multiple_issues.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/deep_conflict_with_multiple_issues.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/deep_conflict_with_multiple_issues.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/deep_conflict_with_multiple_issues.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/deep_conflict_with_multiple_issues.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/different_args_second_adds_an_argument.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/different_args_second_adds_an_argument.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/different_args_second_adds_an_argument.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/different_args_second_adds_an_argument.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/different_args_second_adds_an_argument.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/different_args_second_adds_an_argument.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/different_args_second_adds_an_argument.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/different_args_second_adds_an_argument.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/different_args_second_missing_an_argument.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/different_args_second_missing_an_argument.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/different_args_second_missing_an_argument.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/different_args_second_missing_an_argument.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/different_args_second_missing_an_argument.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/different_args_second_missing_an_argument.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/different_args_second_missing_an_argument.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/different_args_second_missing_an_argument.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/different_args_with_different_aliases.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/different_args_with_different_aliases.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/different_args_with_different_aliases.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/different_args_with_different_aliases.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/different_args_with_different_aliases.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/different_args_with_different_aliases.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/different_directives_with_different_aliases.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/different_directives_with_different_aliases.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/different_directives_with_different_aliases.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/different_directives_with_different_aliases.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/different_directives_with_different_aliases.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/different_directives_with_different_aliases.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/different_skip_include_directives_accepted.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/different_skip_include_directives_accepted.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/different_skip_include_directives_accepted.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/different_skip_include_directives_accepted.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/different_skip_include_directives_accepted.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/different_skip_include_directives_accepted.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/does_not_infinite_loop_on_immediately_recursive_fragment.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/does_not_infinite_loop_on_immediately_recursive_fragment.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/does_not_infinite_loop_on_immediately_recursive_fragment.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/does_not_infinite_loop_on_immediately_recursive_fragment.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/does_not_infinite_loop_on_immediately_recursive_fragment.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/does_not_infinite_loop_on_immediately_recursive_fragment.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/does_not_infinite_loop_on_immediately_recursive_fragment.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/does_not_infinite_loop_on_immediately_recursive_fragment.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/does_not_infinite_loop_on_recursive_fragment.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/does_not_infinite_loop_on_recursive_fragment.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/does_not_infinite_loop_on_recursive_fragment.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/does_not_infinite_loop_on_recursive_fragment.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/does_not_infinite_loop_on_recursive_fragment.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/does_not_infinite_loop_on_recursive_fragment.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/does_not_infinite_loop_on_recursive_fragment.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/does_not_infinite_loop_on_recursive_fragment.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/does_not_infinite_loop_on_recursive_fragment_with_a_field_named_after_fragment.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/does_not_infinite_loop_on_recursive_fragment_with_a_field_named_after_fragment.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/does_not_infinite_loop_on_recursive_fragment_with_a_field_named_after_fragment.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/does_not_infinite_loop_on_recursive_fragment_with_a_field_named_after_fragment.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/does_not_infinite_loop_on_recursive_fragment_with_a_field_named_after_fragment.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/does_not_infinite_loop_on_recursive_fragment_with_a_field_named_after_fragment.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/does_not_infinite_loop_on_recursive_fragment_with_a_field_named_after_fragment.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/does_not_infinite_loop_on_recursive_fragment_with_a_field_named_after_fragment.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/does_not_infinite_loop_on_recursive_fragments_separated_by_fields.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/does_not_infinite_loop_on_recursive_fragments_separated_by_fields.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/does_not_infinite_loop_on_recursive_fragments_separated_by_fields.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/does_not_infinite_loop_on_recursive_fragments_separated_by_fields.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/does_not_infinite_loop_on_recursive_fragments_separated_by_fields.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/does_not_infinite_loop_on_recursive_fragments_separated_by_fields.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/does_not_infinite_loop_on_recursive_fragments_separated_by_fields.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/does_not_infinite_loop_on_recursive_fragments_separated_by_fields.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/does_not_infinite_loop_on_transitively_recursive_fragment.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/does_not_infinite_loop_on_transitively_recursive_fragment.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/does_not_infinite_loop_on_transitively_recursive_fragment.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/does_not_infinite_loop_on_transitively_recursive_fragment.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/does_not_infinite_loop_on_transitively_recursive_fragment.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/does_not_infinite_loop_on_transitively_recursive_fragment.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/does_not_infinite_loop_on_transitively_recursive_fragment.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/does_not_infinite_loop_on_transitively_recursive_fragment.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/encounters_conflict_in_fragments.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/encounters_conflict_in_fragments.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/encounters_conflict_in_fragments.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/encounters_conflict_in_fragments.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/encounters_conflict_in_fragments.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/encounters_conflict_in_fragments.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/encounters_conflict_in_fragments.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/encounters_conflict_in_fragments.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/encounters_conflict_in_fragments_with_args.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/encounters_conflict_in_fragments_with_args.expected new file mode 100644 index 00000000000..40be299b56f --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/encounters_conflict_in_fragments_with_args.expected @@ -0,0 +1,8 @@ +AnonymousOperation (3:1) +Apollo does not support anonymous operations +------------ +OtherValidationIssue (8:3) +Field at path `foo` conflicts with another field: they have different arguments. Use different aliases on the fields to fetch both if this was intentional. +------------ +OtherValidationIssue (8:3) +Field at path `foo` conflicts with another field: they have different arguments. Use different aliases on the fields to fetch both if this was intentional. \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/encounters_conflict_in_fragments_with_args.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/encounters_conflict_in_fragments_with_args.graphql new file mode 100644 index 00000000000..ed08641659c --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/encounters_conflict_in_fragments_with_args.graphql @@ -0,0 +1,9 @@ +# PRAGMA allowFragmentArguments + +{ + ...WithArgs(x: 3) + ...WithArgs(x: 4) +} +fragment WithArgs($x: Int) on QueryRoot { + foo(x: $x) +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/finds_invalid_case_even_with_immediately_recursive_fragment.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/finds_invalid_case_even_with_immediately_recursive_fragment.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/finds_invalid_case_even_with_immediately_recursive_fragment.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/finds_invalid_case_even_with_immediately_recursive_fragment.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/finds_invalid_case_even_with_immediately_recursive_fragment.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/finds_invalid_case_even_with_immediately_recursive_fragment.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/finds_invalid_case_even_with_immediately_recursive_fragment.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/finds_invalid_case_even_with_immediately_recursive_fragment.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/finds_invalid_cases_even_with_field_named_after_fragment.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/finds_invalid_cases_even_with_field_named_after_fragment.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/finds_invalid_cases_even_with_field_named_after_fragment.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/finds_invalid_cases_even_with_field_named_after_fragment.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/finds_invalid_cases_even_with_field_named_after_fragment.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/finds_invalid_cases_even_with_field_named_after_fragment.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/finds_invalid_cases_even_with_field_named_after_fragment.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/finds_invalid_cases_even_with_field_named_after_fragment.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/fragment_args_are_known.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/fragment_args_are_known.expected new file mode 100644 index 00000000000..ea58182f70c --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/fragment_args_are_known.expected @@ -0,0 +1,2 @@ +AnonymousOperation (3:1) +Apollo does not support anonymous operations \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/fragment_args_are_known.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/fragment_args_are_known.graphql new file mode 100644 index 00000000000..10fac85faa2 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/fragment_args_are_known.graphql @@ -0,0 +1,10 @@ +# PRAGMA allowFragmentArguments + +{ + dog { + ...withArg(dogCommand: SIT) + } +} +fragment withArg($dogCommand: DogCommand) on Dog { + doesKnowCommand(dogCommand: $dogCommand) +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/identical_fields.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/identical_fields.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/identical_fields.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/identical_fields.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/identical_fields.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/identical_fields.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/identical_fields_with_identical_args.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/identical_fields_with_identical_args.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/identical_fields_with_identical_args.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/identical_fields_with_identical_args.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/identical_fields_with_identical_args.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/identical_fields_with_identical_args.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/identical_fields_with_identical_directives.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/identical_fields_with_identical_directives.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/identical_fields_with_identical_directives.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/identical_fields_with_identical_directives.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/identical_fields_with_identical_directives.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/identical_fields_with_identical_directives.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/ignores_unknown_fragments.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/ignores_unknown_fragments.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/ignores_unknown_fragments.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/ignores_unknown_fragments.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/ignores_unknown_fragments.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/ignores_unknown_fragments.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/ignores_unknown_fragments.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/ignores_unknown_fragments.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/reports_deep_conflict_after_nested_fragments.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/reports_deep_conflict_after_nested_fragments.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/reports_deep_conflict_after_nested_fragments.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/reports_deep_conflict_after_nested_fragments.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/reports_deep_conflict_after_nested_fragments.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/reports_deep_conflict_after_nested_fragments.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/reports_deep_conflict_after_nested_fragments.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/reports_deep_conflict_after_nested_fragments.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/reports_deep_conflict_in_nested_fragments.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/reports_deep_conflict_in_nested_fragments.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/reports_deep_conflict_in_nested_fragments.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/reports_deep_conflict_in_nested_fragments.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/reports_deep_conflict_in_nested_fragments.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/reports_deep_conflict_in_nested_fragments.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/reports_deep_conflict_in_nested_fragments.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/reports_deep_conflict_in_nested_fragments.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/reports_deep_conflict_to_nearest_common_ancestor.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/reports_deep_conflict_to_nearest_common_ancestor.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/reports_deep_conflict_to_nearest_common_ancestor.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/reports_deep_conflict_to_nearest_common_ancestor.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/reports_deep_conflict_to_nearest_common_ancestor.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/reports_deep_conflict_to_nearest_common_ancestor.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/reports_deep_conflict_to_nearest_common_ancestor.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/reports_deep_conflict_to_nearest_common_ancestor.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/reports_deep_conflict_to_nearest_common_ancestor_in_fragments.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/reports_deep_conflict_to_nearest_common_ancestor_in_fragments.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/reports_deep_conflict_to_nearest_common_ancestor_in_fragments.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/reports_deep_conflict_to_nearest_common_ancestor_in_fragments.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/reports_deep_conflict_to_nearest_common_ancestor_in_fragments.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/reports_deep_conflict_to_nearest_common_ancestor_in_fragments.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/reports_deep_conflict_to_nearest_common_ancestor_in_fragments.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/reports_deep_conflict_to_nearest_common_ancestor_in_fragments.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/reports_each_conflict_once.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/reports_each_conflict_once.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/reports_each_conflict_once.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/reports_each_conflict_once.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/reports_each_conflict_once.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/reports_each_conflict_once.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/reports_each_conflict_once.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/reports_each_conflict_once.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/same_aliases_allowed_on_non_overlapping_fields.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/same_aliases_allowed_on_non_overlapping_fields.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/same_aliases_allowed_on_non_overlapping_fields.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/same_aliases_allowed_on_non_overlapping_fields.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/same_aliases_allowed_on_non_overlapping_fields.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/same_aliases_allowed_on_non_overlapping_fields.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/same_aliases_with_different_field_targets.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/same_aliases_with_different_field_targets.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/same_aliases_with_different_field_targets.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/same_aliases_with_different_field_targets.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/same_aliases_with_different_field_targets.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/same_aliases_with_different_field_targets.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/same_aliases_with_different_field_targets.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/same_aliases_with_different_field_targets.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/schema.graphqls b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/schema.graphqls similarity index 99% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/schema.graphqls rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/schema.graphqls index 442a14f4375..909311ab74e 100644 --- a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/schema.graphqls +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/schema.graphqls @@ -105,6 +105,7 @@ type QueryRoot { f1: Type f2: Type f3: Type + foo(x: Int): String } type Type { diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/unique_fields.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/unique_fields.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/unique_fields.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/unique_fields.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/unique_fields.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/unique_fields.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/unknown_args_amongst_known_args.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/unknown_args_amongst_known_args.expected new file mode 100644 index 00000000000..43e29d3ed5f --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/unknown_args_amongst_known_args.expected @@ -0,0 +1,8 @@ +OtherValidationIssue (6:19) +Unknown argument `whoKnows` on field `doesKnowCommand` +------------ +OtherValidationIssue (6:49) +Unknown argument `unknown` on field `doesKnowCommand` +------------ +AnonymousOperation (3:1) +Apollo does not support anonymous operations \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/unknown_args_amongst_known_args.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/unknown_args_amongst_known_args.graphql new file mode 100644 index 00000000000..17cbefcf9ab --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/unknown_args_amongst_known_args.graphql @@ -0,0 +1,7 @@ +# PRAGMA allowFragmentArguments + +{ dog {...oneGoodArgOneInvalidArg } } + +fragment oneGoodArgOneInvalidArg on Dog { + doesKnowCommand(whoKnows: 1, dogCommand: SIT, unknown: true) +} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/very_deep_conflict.expected b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/very_deep_conflict.expected similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/very_deep_conflict.expected rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/very_deep_conflict.expected diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/very_deep_conflict.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/very_deep_conflict.graphql similarity index 100% rename from libraries/apollo-ast/test-fixtures/validation/executable/fields_in_set_can_merge/graphql-js/schema1/very_deep_conflict.graphql rename to libraries/apollo-ast/test-fixtures/validation/executable/graphql-js/schema1/very_deep_conflict.graphql diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/mandatory_argument/mandatory_argument.expected b/libraries/apollo-ast/test-fixtures/validation/executable/mandatory_argument/mandatory_argument.expected index 0e4e1f63c51..2f64772383c 100644 --- a/libraries/apollo-ast/test-fixtures/validation/executable/mandatory_argument/mandatory_argument.expected +++ b/libraries/apollo-ast/test-fixtures/validation/executable/mandatory_argument/mandatory_argument.expected @@ -1,2 +1,2 @@ OtherValidationIssue (2:5) -No value passed for required argument 'input' \ No newline at end of file +No value passed for required argument `input` on field `edit` \ No newline at end of file diff --git a/libraries/apollo-compiler/api/apollo-compiler.api b/libraries/apollo-compiler/api/apollo-compiler.api index 4052b1b9188..998e9ed262d 100644 --- a/libraries/apollo-compiler/api/apollo-compiler.api +++ b/libraries/apollo-compiler/api/apollo-compiler.api @@ -286,8 +286,9 @@ public final class com/apollographql/apollo/compiler/InputFile { public final class com/apollographql/apollo/compiler/IrOptions { public static final field Companion Lcom/apollographql/apollo/compiler/IrOptions$Companion; - public fun (Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/Map;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Set;Ljava/lang/String;)V + public fun (Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/Map;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Set;Ljava/lang/String;Ljava/lang/Boolean;)V public final fun getAddTypename ()Ljava/lang/String; + public final fun getAllowFragmentArguments ()Ljava/lang/Boolean; public final fun getAlwaysGenerateTypesMatching ()Ljava/util/Set; public final fun getCodegenModels ()Ljava/lang/String; public final fun getDecapitalizeFields ()Ljava/lang/Boolean; @@ -399,8 +400,8 @@ public final class com/apollographql/apollo/compiler/OptionsKt { public static final field MODELS_RESPONSE_BASED Ljava/lang/String; public static final fun buildCodegenOptions (Lcom/apollographql/apollo/compiler/TargetLanguage;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/List;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/List;Ljava/lang/Boolean;Lcom/apollographql/apollo/compiler/JavaNullable;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/String;)Lcom/apollographql/apollo/compiler/CodegenOptions; public static synthetic fun buildCodegenOptions$default (Lcom/apollographql/apollo/compiler/TargetLanguage;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/List;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/List;Ljava/lang/Boolean;Lcom/apollographql/apollo/compiler/JavaNullable;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lcom/apollographql/apollo/compiler/CodegenOptions; - public static final fun buildIrOptions (Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Set;Ljava/lang/String;Ljava/util/Map;)Lcom/apollographql/apollo/compiler/IrOptions; - public static synthetic fun buildIrOptions$default (Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Set;Ljava/lang/String;Ljava/util/Map;ILjava/lang/Object;)Lcom/apollographql/apollo/compiler/IrOptions; + public static final fun buildIrOptions (Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Set;Ljava/lang/String;Ljava/util/Map;Ljava/lang/Boolean;)Lcom/apollographql/apollo/compiler/IrOptions; + public static synthetic fun buildIrOptions$default (Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Set;Ljava/lang/String;Ljava/util/Map;Ljava/lang/Boolean;ILjava/lang/Object;)Lcom/apollographql/apollo/compiler/IrOptions; public static final fun validate (Lcom/apollographql/apollo/compiler/CodegenOptions;)V } diff --git a/libraries/apollo-compiler/src/main/kotlin/com/apollographql/apollo/compiler/ApolloCompiler.kt b/libraries/apollo-compiler/src/main/kotlin/com/apollographql/apollo/compiler/ApolloCompiler.kt index 07f807a25d7..60b74992d8a 100644 --- a/libraries/apollo-compiler/src/main/kotlin/com/apollographql/apollo/compiler/ApolloCompiler.kt +++ b/libraries/apollo-compiler/src/main/kotlin/com/apollographql/apollo/compiler/ApolloCompiler.kt @@ -214,11 +214,11 @@ object ApolloCompiler { /** * Parses the given files. Throws if there are parsing errors */ - private fun File.definitions(): List { + private fun File.definitions(allowFragmentArguments: Boolean): List { val definitions = mutableListOf() val parseIssues = mutableListOf() - val parseResult = parseAsGQLDocument(options = ParserOptions.Builder().build()) + val parseResult = parseAsGQLDocument(options = ParserOptions.Builder().allowFragmentArguments(allowFragmentArguments).build()) if (parseResult.issues.isNotEmpty()) { parseIssues.addAll(parseResult.issues) } else { @@ -263,7 +263,7 @@ object ApolloCompiler { * See https://github.com/apollographql/apollo-kotlin/pull/5916 */ executableFiles.sortedBy { it.normalizedPath }.forEach { normalizedFile -> - val fileDefinitions = normalizedFile.file.definitions() + val fileDefinitions = normalizedFile.file.definitions(options.allowFragmentArguments ?: false) userDefinitions.addAll(fileDefinitions) fileDefinitions.forEach { diff --git a/libraries/apollo-compiler/src/main/kotlin/com/apollographql/apollo/compiler/Options.kt b/libraries/apollo-compiler/src/main/kotlin/com/apollographql/apollo/compiler/Options.kt index 497303e9fe6..dc833b63482 100644 --- a/libraries/apollo-compiler/src/main/kotlin/com/apollographql/apollo/compiler/Options.kt +++ b/libraries/apollo-compiler/src/main/kotlin/com/apollographql/apollo/compiler/Options.kt @@ -199,6 +199,8 @@ class IrOptions( val alwaysGenerateTypesMatching: Set?, val codegenModels: String?, + + val allowFragmentArguments: Boolean? ) fun buildIrOptions( @@ -210,6 +212,7 @@ fun buildIrOptions( alwaysGenerateTypesMatching: Set? = null, codegenModels: String? = null, issueSeverity: Map? = null, + allowFragmentArguments: Boolean? = null ): IrOptions = IrOptions( decapitalizeFields = decapitalizeFields, flattenModels = flattenModels, @@ -218,7 +221,8 @@ fun buildIrOptions( generateOptionalOperationVariables = generateOptionalOperationVariables, alwaysGenerateTypesMatching = alwaysGenerateTypesMatching, codegenModels = codegenModels, - issueSeverities = issueSeverity + issueSeverities = issueSeverity, + allowFragmentArguments = allowFragmentArguments ) interface CommonCodegenOpt { diff --git a/libraries/apollo-compiler/src/main/kotlin/com/apollographql/apollo/compiler/ir/IrOperationsBuilder.kt b/libraries/apollo-compiler/src/main/kotlin/com/apollographql/apollo/compiler/ir/IrOperationsBuilder.kt index 5a14a0653ce..859b8dc1bad 100644 --- a/libraries/apollo-compiler/src/main/kotlin/com/apollographql/apollo/compiler/ir/IrOperationsBuilder.kt +++ b/libraries/apollo-compiler/src/main/kotlin/com/apollographql/apollo/compiler/ir/IrOperationsBuilder.kt @@ -300,7 +300,7 @@ internal class IrOperationsBuilder( description = description, filePath = fragmentNameToNormalizedPath[name] ?: "", typeCondition = typeDefinition.name, - variables = inferredVariables.map { it.toIr() }, + variables = inferredVariables.map { it.toIr() } + variableDefinitions.map { it.toIr() }, selectionSets = SelectionSetsBuilder(schema, allFragmentDefinitions).build(selections, typeCondition.name), interfaceModelGroup = interfaceModelGroup, dataProperty = dataProperty, diff --git a/libraries/apollo-execution/api/apollo-execution.api b/libraries/apollo-execution/api/apollo-execution.api index 824cd8ccf5a..3dbc44d82ce 100644 --- a/libraries/apollo-execution/api/apollo-execution.api +++ b/libraries/apollo-execution/api/apollo-execution.api @@ -33,6 +33,7 @@ public final class com/apollographql/apollo/execution/ExecutableSchema$Builder { public final fun build ()Lcom/apollographql/apollo/execution/ExecutableSchema; public final fun mutationRoot (Lcom/apollographql/apollo/execution/RootResolver;)Lcom/apollographql/apollo/execution/ExecutableSchema$Builder; public final fun onError (Lcom/apollographql/apollo/execution/OnError;)Lcom/apollographql/apollo/execution/ExecutableSchema$Builder; + public final fun parserOptions (Lcom/apollographql/apollo/ast/ParserOptions;)Lcom/apollographql/apollo/execution/ExecutableSchema$Builder; public final fun persistedDocumentCache (Lcom/apollographql/apollo/execution/PersistedDocumentCache;)Lcom/apollographql/apollo/execution/ExecutableSchema$Builder; public final fun queryRoot (Lcom/apollographql/apollo/execution/RootResolver;)Lcom/apollographql/apollo/execution/ExecutableSchema$Builder; public final fun resolver (Lcom/apollographql/apollo/execution/Resolver;)Lcom/apollographql/apollo/execution/ExecutableSchema$Builder; diff --git a/libraries/apollo-execution/api/apollo-execution.klib.api b/libraries/apollo-execution/api/apollo-execution.klib.api index 9235b4a52db..cd84e921298 100644 --- a/libraries/apollo-execution/api/apollo-execution.klib.api +++ b/libraries/apollo-execution/api/apollo-execution.klib.api @@ -79,6 +79,7 @@ final class com.apollographql.apollo.execution/ExecutableSchema { // com.apollog final fun build(): com.apollographql.apollo.execution/ExecutableSchema // com.apollographql.apollo.execution/ExecutableSchema.Builder.build|build(){}[0] final fun mutationRoot(com.apollographql.apollo.execution/RootResolver): com.apollographql.apollo.execution/ExecutableSchema.Builder // com.apollographql.apollo.execution/ExecutableSchema.Builder.mutationRoot|mutationRoot(com.apollographql.apollo.execution.RootResolver){}[0] final fun onError(com.apollographql.apollo.execution/OnError): com.apollographql.apollo.execution/ExecutableSchema.Builder // com.apollographql.apollo.execution/ExecutableSchema.Builder.onError|onError(com.apollographql.apollo.execution.OnError){}[0] + final fun parserOptions(com.apollographql.apollo.ast/ParserOptions): com.apollographql.apollo.execution/ExecutableSchema.Builder // com.apollographql.apollo.execution/ExecutableSchema.Builder.parserOptions|parserOptions(com.apollographql.apollo.ast.ParserOptions){}[0] final fun persistedDocumentCache(com.apollographql.apollo.execution/PersistedDocumentCache?): com.apollographql.apollo.execution/ExecutableSchema.Builder // com.apollographql.apollo.execution/ExecutableSchema.Builder.persistedDocumentCache|persistedDocumentCache(com.apollographql.apollo.execution.PersistedDocumentCache?){}[0] final fun queryRoot(com.apollographql.apollo.execution/RootResolver): com.apollographql.apollo.execution/ExecutableSchema.Builder // com.apollographql.apollo.execution/ExecutableSchema.Builder.queryRoot|queryRoot(com.apollographql.apollo.execution.RootResolver){}[0] final fun resolver(com.apollographql.apollo.execution/Resolver): com.apollographql.apollo.execution/ExecutableSchema.Builder // com.apollographql.apollo.execution/ExecutableSchema.Builder.resolver|resolver(com.apollographql.apollo.execution.Resolver){}[0] diff --git a/libraries/apollo-execution/src/commonMain/kotlin/com/apollographql/apollo/execution/ExecutableSchema.kt b/libraries/apollo-execution/src/commonMain/kotlin/com/apollographql/apollo/execution/ExecutableSchema.kt index 574145c4e5f..55f17fa1ce6 100644 --- a/libraries/apollo-execution/src/commonMain/kotlin/com/apollographql/apollo/execution/ExecutableSchema.kt +++ b/libraries/apollo-execution/src/commonMain/kotlin/com/apollographql/apollo/execution/ExecutableSchema.kt @@ -29,6 +29,7 @@ class ExecutableSchema internal constructor( private val instrumentations: List, private val persistedDocumentCache: PersistedDocumentCache?, private val onError: OnError, + private val parserOptions: ParserOptions ) { private val introspectionResolver: Resolver = introspectionResolver(schema) @@ -36,7 +37,7 @@ class ExecutableSchema internal constructor( request: GraphQLRequest, executionContext: ExecutionContext = ExecutionContext.Empty, ): GraphQLResponse { - return prepareRequest(schema, coercings, persistedDocumentCache, request).fold( + return prepareRequest(schema, coercings, persistedDocumentCache, parserOptions, request).fold( ifLeft = { GraphQLResponse.Builder().errors(it).build() }, @@ -50,7 +51,7 @@ class ExecutableSchema internal constructor( request: GraphQLRequest, executionContext: ExecutionContext = ExecutionContext.Empty, ): Flow { - return prepareRequest(schema, coercings, persistedDocumentCache, request).fold( + return prepareRequest(schema, coercings, persistedDocumentCache, parserOptions, request).fold( ifLeft = { flowOf(SubscriptionResponse(GraphQLResponse.Builder().errors(it).build())) }, @@ -90,6 +91,7 @@ class ExecutableSchema internal constructor( private val instrumentations = mutableListOf() private var persistedDocumentCache: PersistedDocumentCache? = null private var onError: OnError = OnError.PROPAGATE + private var parserOptions: ParserOptions = ParserOptions.Default fun schema(schema: GQLDocument): Builder = apply { this.schema = schema @@ -138,6 +140,13 @@ class ExecutableSchema internal constructor( this.onError = onError } + /** + * Configures the parsing options for this executable schema. + */ + fun parserOptions(parserOptions: ParserOptions): Builder = apply { + this.parserOptions = parserOptions + } + fun build(): ExecutableSchema { check(schema != null) { "A schema is required to build an ExecutableSchema" @@ -164,7 +173,8 @@ class ExecutableSchema internal constructor( typeResolver ?: ThrowingTypeResolver, instrumentations, persistedDocumentCache, - onError + onError, + parserOptions ) } } diff --git a/libraries/apollo-execution/src/commonMain/kotlin/com/apollographql/apollo/execution/internal/OperationContext.kt b/libraries/apollo-execution/src/commonMain/kotlin/com/apollographql/apollo/execution/internal/OperationContext.kt index 7bac0ec0054..aebfdba1f10 100644 --- a/libraries/apollo-execution/src/commonMain/kotlin/com/apollographql/apollo/execution/internal/OperationContext.kt +++ b/libraries/apollo-execution/src/commonMain/kotlin/com/apollographql/apollo/execution/internal/OperationContext.kt @@ -163,31 +163,41 @@ internal class OperationContext( private fun resolveFieldEventStream( subscriptionType: GQLObjectTypeDefinition, rootValue: ResolverValue, - fields: List, - argumentValues: Map, + collectedResult: CollectedResult, responseName: String, ): Flow { return flow { - val resolveInfo = ResolveInfo( - parentObject = rootValue, - executionContext = executionContext, - fields = fields, - schema = schema, - arguments = argumentValues, - parentType = subscriptionType.name, - path = emptyList() - ) + val value = when (collectedResult) { + is CollectedError -> { + Error.Builder(collectedResult.message) + .build() + } + is CollectedField -> { + val resolveInfo = ResolveInfo( + parentObject = rootValue, + executionContext = executionContext, + fields = collectedResult.fields, + schema = schema, + arguments = collectedResult.coercedArguments, + parentType = subscriptionType.name, + path = emptyList() + ) + resolveFieldValue(resolveInfo) + } + } - emit(resolveFieldValue(resolveInfo)) + emit(value) }.flatMapConcat { - if (it !is Flow<*>) { + if (it is Error) { + flowOf(FieldEventError(it.message)) + } else if (it !is Flow<*>) { flowOf(FieldEventError("Subscription resolvers must return a Flow<> (got '$it')")) } else { it.map { objectValue -> FieldEventItem( parentType = subscriptionType.name, objectValue = objectValue, - fields = fields, + collectedResult = collectedResult, responseName = responseName ) } @@ -199,7 +209,7 @@ internal class OperationContext( private class FieldEventItem( val parentType: String, val objectValue: InternalValue, - val fields: List, + val collectedResult: CollectedResult, val responseName: String, ) : FieldEvent @@ -225,15 +235,12 @@ internal class OperationContext( check(groupedFieldsSet.size == 1) { return flowOf(FieldEventError("Subscriptions must have a single root field")) } - val fields = groupedFieldsSet.entries.single().value - val field = fields.first() - val argumentValues = coerceArgumentValues(schema, typeDefinition.name, field, coercings, variableValues) + val collectedResult = groupedFieldsSet.entries.single().value return resolveFieldEventStream( subscriptionType = typeDefinition, rootValue = rootValue, - fields = fields, - argumentValues = argumentValues, - responseName = fields.first().responseName() + collectedResult = collectedResult, + responseName = collectedResult.first.responseName() ) } @@ -256,8 +263,8 @@ internal class OperationContext( coroutineScope { val fieldData = completeValue( scope = this, - fieldType = event.fields.first().definitionFromScope(schema, event.parentType)!!.type, - fields = event.fields, + fieldType = event.collectedResult.first.definitionFromScope(schema, event.parentType)!!.type, + fields = (event.collectedResult as? CollectedField)?.fields.orEmpty(), result = event.objectValue, path = listOf(event.responseName) ) @@ -275,66 +282,69 @@ internal class OperationContext( * @param objectType the parent type of the field. Always a concrete object type. * @param objectValue the parent object as returned from a resolver. * @param fieldType the field type as in the schema field definition. - * @param fields the merged fields - * @param variableValues the coerced variable values. + * @param collectedResult the merged fields */ private fun executeField( scope: CoroutineScope, objectType: GQLObjectTypeDefinition, objectValue: ResolverValue, fieldType: GQLType, - fields: List, - variableValues: Map, + collectedResult: CollectedResult, path: List, ): Deferred { - val field = fields.first() - val argumentValues = coerceArgumentValues(schema, objectType.name, field, coercings, variableValues) - return scope.async(start = CoroutineStart.UNDISPATCHED) { - val resolveInfo = ResolveInfo( - parentObject = objectValue, - executionContext = executionContext, - fields = fields, - schema = schema, - arguments = argumentValues, - parentType = objectType.name, - path = path, - ) + when (collectedResult) { + is CollectedError -> Error.Builder(collectedResult.message) + .path(path) + .build() + + is CollectedField -> { + val resolveInfo = ResolveInfo( + parentObject = objectValue, + executionContext = executionContext, + fields = collectedResult.fields, + schema = schema, + arguments = collectedResult.coercedArguments, + parentType = objectType.name, + path = path, + ) + + val fieldCallbacks = mutableListOf() + var instrumentationError: Error? = null + instrumentations.map { + try { + val callback = it.onField(resolveInfo) + if (callback != null) { + fieldCallbacks.add(callback) + } + } catch (e: Exception) { + if (e is CancellationException) { + throw e + } + instrumentationError = Error.Builder("Cannot instrument '${path.lastOrNull()}': ${e.message}") + .path(path) + .build() + } + } - val fieldCallbacks = mutableListOf() - var instrumentationError: Error? = null - instrumentations.map { - try { - val callback = it.onField(resolveInfo) - if (callback != null) { - fieldCallbacks.add(callback) + val completedValue = if (instrumentationError == null) { + val resolvedValue = resolveFieldValue(resolveInfo) + completeValue( + scope = scope, + fieldType = fieldType, + fields = collectedResult.fields, + result = resolvedValue, + path = path + ) + } else { + instrumentationError } - } catch (e: Exception) { - if (e is CancellationException) { - throw e + fieldCallbacks.forEach { + it.onFieldCompleted(completedValue) } - instrumentationError = Error.Builder("Cannot instrument '${path.lastOrNull()}': ${e.message}") - .path(path) - .build() + completedValue } } - - val completedValue = if (instrumentationError == null) { - val resolvedValue = resolveFieldValue(resolveInfo) - completeValue( - scope = scope, - fieldType = fieldType, - fields = fields, - result = resolvedValue, - path = path - ) - } else { - instrumentationError - } - fieldCallbacks.forEach { - it.onFieldCompleted(completedValue) - } - completedValue } } @@ -502,7 +512,7 @@ internal class OperationContext( private suspend fun executeGroupedFieldSet( scope: CoroutineScope, - groupedFieldSet: Map>, + groupedFieldSet: Map, typeDefinition: GQLObjectTypeDefinition, objectValue: ResolverValue, variableValues: Map, @@ -511,12 +521,12 @@ internal class OperationContext( ): ExternalValue { val typename = typeDefinition.name val entries = groupedFieldSet.entries.map { entry -> - val field = entry.value.first() + val field = entry.value.first val fieldDefinition = field.definitionFromScope(schema, typename)!! val fieldPath = path + field.responseName() val deferred = - executeField(scope, typeDefinition, objectValue, fieldDefinition.type, entry.value, variableValues, fieldPath) + executeField(scope, typeDefinition, objectValue, fieldDefinition.type, entry.value, fieldPath) if (serial) { deferred.await() } @@ -573,22 +583,13 @@ internal class OperationContext( return false } - private fun MutableMap.update(key: K, update: (prev: V?) -> V) { - val newValue = if (this.containsKey(key)) { - update(this.get(key)) - } else { - update(null) - } - put(key, newValue) - } - private fun collectFields( objectType: String, selections: List, coercedVariables: Map, - ): Map> { - val groupedFields = mutableMapOf>() - collectFields(objectType, selections, coercedVariables, mutableSetOf(), groupedFields) + ): Map { + val groupedFields = mutableMapOf() + collectFields(objectType, selections, coercedVariables, emptyMap(), mutableSetOf(), groupedFields) return groupedFields } @@ -596,8 +597,9 @@ internal class OperationContext( objectType: String, selections: List, coercedVariables: Map, + fragmentCoercedVariables: Map, visitedFragments: MutableSet, - groupedFields: MutableMap>, + groupedFields: MutableMap, ) { selections.forEach { selection -> if (selection.directives.shouldSkip(coercedVariables)) { @@ -605,8 +607,21 @@ internal class OperationContext( } when (selection) { is GQLField -> { - groupedFields.update(selection.responseName()) { - (it.orEmpty()).plus(selection) + val responseName = selection.responseName() + val collectedField = groupedFields.get(responseName) + if (collectedField == null) { + val arguments = try { + // Fragment variables take precedence here + coerceArgumentValues(schema, objectType, selection, coercings, coercedVariables + fragmentCoercedVariables) + } catch (e: Exception) { + groupedFields.put(responseName, CollectedError(selection, e.message ?: "Error")) + return@forEach + } + groupedFields.put(responseName, + CollectedField(selection, arguments) + ) + } else if (collectedField is CollectedField) { + collectedField.fields.add(selection) } } @@ -619,14 +634,15 @@ internal class OperationContext( val fragmentDefinition = fragments.get(selection.name)!! if (schema.possibleTypes(fragmentDefinition.typeCondition.name).contains(objectType)) { - collectFields(objectType, fragmentDefinition.selections, coercedVariables, visitedFragments, groupedFields) + val fragmentCoercedVariables = coerceArgumentValues(schema, fragmentDefinition.variableDefinitions, selection.arguments, coercings, coercedVariables) + collectFields(objectType, fragmentDefinition.selections, coercedVariables, fragmentCoercedVariables, visitedFragments, groupedFields) } } is GQLInlineFragment -> { val typeCondition = selection.typeCondition?.name if (typeCondition == null || schema.possibleTypes(typeCondition).contains(objectType)) { - collectFields(objectType, selection.selections, coercedVariables, visitedFragments, groupedFields) + collectFields(objectType, selection.selections, coercedVariables, fragmentCoercedVariables, visitedFragments, groupedFields) } } } @@ -641,3 +657,19 @@ private val GQLSelection.directives: List is GQLInlineFragment -> directives } +internal class CollectedField( + override val first: GQLField, + val coercedArguments: Map, +) : CollectedResult { + val fields = mutableListOf() + + init { + fields.add(first) + } +} + +internal sealed interface CollectedResult { + val first: GQLField +} + +internal class CollectedError(override val first: GQLField, val message: String) : CollectedResult \ No newline at end of file diff --git a/libraries/apollo-execution/src/commonMain/kotlin/com/apollographql/apollo/execution/internal/coerceArgumentValues.kt b/libraries/apollo-execution/src/commonMain/kotlin/com/apollographql/apollo/execution/internal/coerceArgumentValues.kt index a09e2664614..837109417ba 100644 --- a/libraries/apollo-execution/src/commonMain/kotlin/com/apollographql/apollo/execution/internal/coerceArgumentValues.kt +++ b/libraries/apollo-execution/src/commonMain/kotlin/com/apollographql/apollo/execution/internal/coerceArgumentValues.kt @@ -1,9 +1,11 @@ package com.apollographql.apollo.execution.internal +import com.apollographql.apollo.ast.GQLArgument import com.apollographql.apollo.ast.GQLEnumTypeDefinition import com.apollographql.apollo.ast.GQLEnumValue import com.apollographql.apollo.ast.GQLField import com.apollographql.apollo.ast.GQLInputObjectTypeDefinition +import com.apollographql.apollo.ast.GQLInputValueDefinition import com.apollographql.apollo.ast.GQLInterfaceTypeDefinition import com.apollographql.apollo.ast.GQLListType import com.apollographql.apollo.ast.GQLListValue @@ -16,6 +18,7 @@ import com.apollographql.apollo.ast.GQLScalarTypeDefinition import com.apollographql.apollo.ast.GQLType import com.apollographql.apollo.ast.GQLUnionTypeDefinition import com.apollographql.apollo.ast.GQLValue +import com.apollographql.apollo.ast.GQLVariableDefinition import com.apollographql.apollo.ast.GQLVariableValue import com.apollographql.apollo.ast.Schema import com.apollographql.apollo.ast.definitionFromScope @@ -24,15 +27,45 @@ import com.apollographql.apollo.execution.InternalValue import com.apollographql.apollo.execution.scalarCoercingParseLiteral internal fun coerceArgumentValues( - schema: Schema, - typename: String, - field: GQLField, - coercings: Map>, - coercedVariables: Map, + schema: Schema, + typename: String, + field: GQLField, + coercings: Map>, + coercedVariables: Map, ): Map { - val coercedValues = mutableMapOf() - val argumentValues = field.arguments.associate { it.name to it.value } val argumentDefinitions = field.definitionFromScope(schema, typename)!!.arguments + return coerceArgumentValues(schema, coercings, argumentDefinitions, field.arguments, coercedVariables) +} + +internal fun coerceArgumentValues( + schema: Schema, + variableDefinitions: List, + arguments: List, + coercings: Map>, + coercedVariables: Map, +): Map { + + return coerceArgumentValues(schema, coercings, variableDefinitions.map { + GQLInputValueDefinition( + sourceLocation = it.sourceLocation, + description = it.description, + name = it.name, + directives = it.directives, + type = it.type, + defaultValue = it.defaultValue + ) + }, arguments, coercedVariables) +} + +internal fun coerceArgumentValues( + schema: Schema, + coercings: Map>, + argumentDefinitions: List, + arguments: List, + coercedVariables: Map, +): Map { + val coercedValues = mutableMapOf() + val argumentValues = arguments.associate { it.name to it.value } argumentDefinitions.forEach { argumentDefinition -> val argumentName = argumentDefinition.name @@ -86,7 +119,13 @@ internal fun coerceArgumentValues( * * @throws IllegalStateException if [value] cannot be coerced. */ -internal fun coerceInputLiteralToInternal(schema: Schema, value: GQLValue, type: GQLType, coercings: Map>, coercedVariables: Map?): InternalValue { +internal fun coerceInputLiteralToInternal( + schema: Schema, + value: GQLValue, + type: GQLType, + coercings: Map>, + coercedVariables: Map?, +): InternalValue { if (value is GQLNullValue) { check(type !is GQLNonNullType) { "'null' found in non-null position" @@ -166,7 +205,7 @@ internal fun coerceInputLiteralToInternal(schema: Schema, value: GQLValue, type: is GQLInterfaceTypeDefinition, is GQLObjectTypeDefinition, is GQLUnionTypeDefinition, - -> { + -> { error("Output type '${definition.name}' cannot be used in input position") } @@ -178,7 +217,11 @@ internal fun coerceInputLiteralToInternal(schema: Schema, value: GQLValue, type: } } -internal fun coerceEnumLiteralToInternal(value: GQLValue, coercings: Map>, definition: GQLEnumTypeDefinition): InternalValue { +internal fun coerceEnumLiteralToInternal( + value: GQLValue, + coercings: Map>, + definition: GQLEnumTypeDefinition, +): InternalValue { check(value is GQLEnumValue) { error("Don't know how to coerce '$value' to a '${definition.name}' enum value") } @@ -196,7 +239,13 @@ internal fun coerceEnumLiteralToInternal(value: GQLValue, coercings: Map>, coercedVariables: Map?): InternalValue { +private fun coerceInputObject( + schema: Schema, + definition: GQLInputObjectTypeDefinition, + literalValue: GQLValue, + coercings: Map>, + coercedVariables: Map?, +): InternalValue { if (literalValue !is GQLObjectValue) { error("Don't know how to coerce '$literalValue' to a '${definition.name}' input object") } diff --git a/libraries/apollo-execution/src/commonMain/kotlin/com/apollographql/apollo/execution/internal/prepare.kt b/libraries/apollo-execution/src/commonMain/kotlin/com/apollographql/apollo/execution/internal/prepare.kt index 99c988ce8fc..e2218a822fe 100644 --- a/libraries/apollo-execution/src/commonMain/kotlin/com/apollographql/apollo/execution/internal/prepare.kt +++ b/libraries/apollo-execution/src/commonMain/kotlin/com/apollographql/apollo/execution/internal/prepare.kt @@ -27,8 +27,8 @@ internal class PreparedRequest( * Parses and validates a document. When using persisted documents, the result of this function may be * cached for future reuse. */ -internal fun validateDocument(schema: Schema, document: String): Either, GQLDocument> { - val parseResult = document.parseAsGQLDocument() +internal fun validateDocument(schema: Schema, document: String, parserOptions: ParserOptions): Either, GQLDocument> { + val parseResult = document.parseAsGQLDocument(parserOptions) var issues = parseResult.issues.filterIsInstance() if (issues.isNotEmpty()) { return issues.left() @@ -98,6 +98,7 @@ internal fun Raise.prepareRequest( internal fun Raise.getPersistedDocument( schema: Schema, persistedDocumentCache: PersistedDocumentCache?, + parserOptions: ParserOptions, request: GraphQLRequest, ): PersistedDocument { val persistedQuery = request.extensions.get("persistedQuery") @@ -125,7 +126,7 @@ internal fun Raise.getPersistedDocument( raise("PersistedQueryNotFound") } - persistedDocument = validateDocument(schema, request.document).toPersistedDocument() + persistedDocument = validateDocument(schema, request.document, parserOptions).toPersistedDocument() /** * Note this code trusts the client for the id. Given that APQs are not a security @@ -137,7 +138,7 @@ internal fun Raise.getPersistedDocument( if (request.document == null) { raise("no GraphQL document found") } - persistedDocument = validateDocument(schema, request.document).toPersistedDocument() + persistedDocument = validateDocument(schema, request.document, parserOptions).toPersistedDocument() } return persistedDocument @@ -156,12 +157,13 @@ internal fun Raise>.prepareRequest( schema: Schema, coercings: Map>, persistedDocumentCache: PersistedDocumentCache?, + parserOptions: ParserOptions, request: GraphQLRequest, ): PreparedRequest { val persistedDocument = withError({ singleGraphQLError(it) }) { - getPersistedDocument(schema, persistedDocumentCache, request) + getPersistedDocument(schema, persistedDocumentCache, parserOptions, request) } if (persistedDocument is ErrorPersistedDocument) { @@ -181,7 +183,8 @@ internal fun prepareRequest( schema: Schema, coercings: Map>, persistedDocumentCache: PersistedDocumentCache?, + parserOptions: ParserOptions, request: GraphQLRequest, ): Either, PreparedRequest> = either { - prepareRequest(schema, coercings, persistedDocumentCache, request) + prepareRequest(schema, coercings, persistedDocumentCache, parserOptions, request) } \ No newline at end of file diff --git a/libraries/apollo-execution/src/concurrentTest/kotlin/test/ExecutionTest.kt b/libraries/apollo-execution/src/concurrentTest/kotlin/test/ExecutionTest.kt index 3829f901d91..cf2fb861ab3 100644 --- a/libraries/apollo-execution/src/concurrentTest/kotlin/test/ExecutionTest.kt +++ b/libraries/apollo-execution/src/concurrentTest/kotlin/test/ExecutionTest.kt @@ -2,7 +2,9 @@ package test +import com.apollographql.apollo.annotations.ApolloExperimental import com.apollographql.apollo.api.ExecutionContext +import com.apollographql.apollo.ast.ParserOptions import com.apollographql.apollo.execution.ExecutableSchema import com.apollographql.apollo.execution.GraphQLRequest import com.apollographql.apollo.execution.OnError @@ -22,6 +24,7 @@ fun String.toGraphQLRequest(): GraphQLRequest { .build() } +@OptIn(ApolloExperimental::class) class ExecutionTest { @Test @@ -67,12 +70,12 @@ class ExecutionTest { val response = ExecutableSchema.Builder() .schema(schema) .resolver { resolveInfo -> - resolveInfo.getArgument("first").getOrNull()?.toString(16) + resolveInfo.getArgument("first").getOrNull()?.toString() } .build() .execute(document.toGraphQLRequest(), ExecutionContext.Empty) - assertEquals(mapOf("foo" to "2a"), response.data) + assertEquals(mapOf("foo" to "42"), response.data) assertEquals(null, response.errors) } @@ -216,4 +219,129 @@ class ExecutionTest { assertEquals(listOf("foo"), errors.orEmpty().single().path) } } + + @Test + fun fragmentArgument() = runBlocking { + val schema = """ + type Query { + foo(first: Int): String! + } + """.trimIndent() + + val document = """ + { + ...queryDetails(first: 42) + } + + fragment queryDetails(${'$'}first: Int) on Query { + foo(first: ${'$'}first) + } + """.trimIndent() + + val response = ExecutableSchema.Builder() + .schema(schema) + .parserOptions(ParserOptions.Builder().allowFragmentArguments(true).build()) + .resolver { resolveInfo -> + resolveInfo.getArgument("first").getOrNull()?.toString() + } + .build() + .execute(document.toGraphQLRequest(), ExecutionContext.Empty) + + assertEquals(mapOf("foo" to "42"), response.data) + assertEquals(null, response.errors) + } + + @Test + fun fragmentArgumentfromOperationVariable() = runBlocking { + val schema = """ + type Query { + foo(first: Int): String! + } + """.trimIndent() + + val document = """ + query GetFoo(${'$'}first: Int!) { + ...queryDetails(first: ${'$'}first) + } + + fragment queryDetails(${'$'}first: Int) on Query { + foo(first: ${'$'}first) + } + """.trimIndent() + + val response = ExecutableSchema.Builder() + .schema(schema) + .parserOptions(ParserOptions.Builder().allowFragmentArguments(true).build()) + .resolver { resolveInfo -> + resolveInfo.getArgument("first").getOrNull()?.toString() + } + .build() + .execute(GraphQLRequest.Builder().document(document).variables(mapOf("first" to 42)).build(), ExecutionContext.Empty) + + assertEquals(mapOf("foo" to "42"), response.data) + assertEquals(null, response.errors) + } + + @Test + fun fragmentVariableTakePrecedenceOverOperationVariable() = runBlocking { + val schema = """ + type Query { + foo(first: Int): String! + } + """.trimIndent() + + val document = """ + query GetFoo(${'$'}first: Int!) { + a: foo(first: ${'$'}first) + ...queryDetails(first: 42) + } + + fragment queryDetails(${'$'}first: Int) on Query { + foo(first: ${'$'}first) + } + """.trimIndent() + + val response = ExecutableSchema.Builder() + .schema(schema) + .parserOptions(ParserOptions.Builder().allowFragmentArguments(true).build()) + .resolver { resolveInfo -> + resolveInfo.getArgument("first").getOrNull()?.toString() + } + .build() + .execute(GraphQLRequest.Builder().document(document).variables(mapOf("first" to 43)).build(), ExecutionContext.Empty) + + assertEquals(mapOf("a" to "43", "foo" to "42"), response.data) + assertEquals(null, response.errors) + } + + @Test + fun variableReferencingOperationVariable() = runBlocking { + val schema = """ + type Query { + foo(first: Int): String! + } + """.trimIndent() + + val document = """ + query GetFoo(${'$'}first: Int!) { + ...queryDetails + } + + fragment queryDetails on Query { + foo(first: ${'$'}first) + } + """.trimIndent() + + val response = ExecutableSchema.Builder() + .schema(schema) + .parserOptions(ParserOptions.Builder().allowFragmentArguments(true).build()) + .resolver { resolveInfo -> + resolveInfo.getArgument("first").getOrNull()?.toString() + } + .build() + .execute(GraphQLRequest.Builder().document(document).variables(mapOf("first" to 42)).build(), ExecutionContext.Empty) + + assertEquals(mapOf("foo" to "42"), response.data) + assertEquals(null, response.errors) + } } \ No newline at end of file diff --git a/libraries/apollo-gradle-plugin-tasks/api/apollo-gradle-plugin-tasks.api b/libraries/apollo-gradle-plugin-tasks/api/apollo-gradle-plugin-tasks.api index 26325ce379b..41254284612 100644 --- a/libraries/apollo-gradle-plugin-tasks/api/apollo-gradle-plugin-tasks.api +++ b/libraries/apollo-gradle-plugin-tasks/api/apollo-gradle-plugin-tasks.api @@ -61,11 +61,11 @@ public final class com/apollographql/apollo/gradle/task/ApolloGenerateIrOperatio public final class com/apollographql/apollo/gradle/task/ApolloGenerateOptionsEntryPoint { public static final field Companion Lcom/apollographql/apollo/gradle/task/ApolloGenerateOptionsEntryPoint$Companion; public fun ()V - public static final fun run (Ljava/lang/Boolean;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/Set;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/List;Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/util/List;ZLjava/lang/String;ZZLjava/io/File;Ljava/io/File;Ljava/io/File;Ljava/io/File;)V + public static final fun run (Ljava/lang/Boolean;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/Set;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/List;Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/util/List;ZLjava/lang/String;ZZLjava/io/File;Ljava/io/File;Ljava/io/File;Ljava/io/File;)V } public final class com/apollographql/apollo/gradle/task/ApolloGenerateOptionsEntryPoint$Companion { - public final fun run (Ljava/lang/Boolean;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/Set;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/List;Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/util/List;ZLjava/lang/String;ZZLjava/io/File;Ljava/io/File;Ljava/io/File;Ljava/io/File;)V + public final fun run (Ljava/lang/Boolean;Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/Set;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/List;Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/String;Ljava/util/List;ZLjava/lang/String;ZZLjava/io/File;Ljava/io/File;Ljava/io/File;Ljava/io/File;)V } public final class com/apollographql/apollo/gradle/task/ApolloGenerateOptionsKt { diff --git a/libraries/apollo-gradle-plugin-tasks/src/main/kotlin/com/apollographql/apollo/gradle/task/apolloGenerateOptions.kt b/libraries/apollo-gradle-plugin-tasks/src/main/kotlin/com/apollographql/apollo/gradle/task/apolloGenerateOptions.kt index 06c3100ec0f..d079c78b09b 100644 --- a/libraries/apollo-gradle-plugin-tasks/src/main/kotlin/com/apollographql/apollo/gradle/task/apolloGenerateOptions.kt +++ b/libraries/apollo-gradle-plugin-tasks/src/main/kotlin/com/apollographql/apollo/gradle/task/apolloGenerateOptions.kt @@ -45,6 +45,7 @@ internal fun apolloGenerateOptions( generatedSchemaName: String?, operationManifestFormat: String?, severities: Map?, + allowFragmentArguments: Boolean?, // JavaCodegenOptions generatePrimitiveTypes: Boolean?, nullableFieldStyle: String?, @@ -110,6 +111,7 @@ internal fun apolloGenerateOptions( generateOptionalOperationVariables = generateOptionalOperationVariables, alwaysGenerateTypesMatching = alwaysGenerateTypesMatching, issueSeverities = severities?.convert(), + allowFragmentArguments = allowFragmentArguments ).writeTo(irOptionsFile) CodegenOptions( diff --git a/libraries/apollo-gradle-plugin/api/apollo-gradle-plugin.api b/libraries/apollo-gradle-plugin/api/apollo-gradle-plugin.api index aab3a652bb0..73b8d3c9787 100644 --- a/libraries/apollo-gradle-plugin/api/apollo-gradle-plugin.api +++ b/libraries/apollo-gradle-plugin/api/apollo-gradle-plugin.api @@ -139,6 +139,7 @@ public abstract interface class com/apollographql/apollo/gradle/api/Service { public abstract fun dependsOn (Ljava/lang/Object;Z)V public abstract fun getAddJvmOverloads ()Lorg/gradle/api/provider/Property; public abstract fun getAddTypename ()Lorg/gradle/api/provider/Property; + public abstract fun getAllowFragmentArguments ()Lorg/gradle/api/provider/Property; public abstract fun getAlwaysGenerateTypesMatching ()Lorg/gradle/api/provider/SetProperty; public abstract fun getClassesForEnumsMatching ()Lorg/gradle/api/provider/ListProperty; public abstract fun getCodegenModels ()Lorg/gradle/api/provider/Property; @@ -244,6 +245,6 @@ public abstract interface class com/apollographql/apollo/gradle/api/Service$Outg } public final class com/apollographql/apollo/gradle/task/ApolloGenerateOptionsTaskKt { - public static synthetic fun registerApolloGenerateOptionsTask$default (Lorg/gradle/api/Project;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/gradle/api/file/FileCollection;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/file/FileCollection;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;IILjava/lang/Object;)Lorg/gradle/api/tasks/TaskProvider; + public static synthetic fun registerApolloGenerateOptionsTask$default (Lorg/gradle/api/Project;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/gradle/api/file/FileCollection;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/file/FileCollection;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;Lorg/gradle/api/provider/Provider;IILjava/lang/Object;)Lorg/gradle/api/tasks/TaskProvider; } diff --git a/libraries/apollo-gradle-plugin/src/main/kotlin/com/apollographql/apollo/gradle/api/Service.kt b/libraries/apollo-gradle-plugin/src/main/kotlin/com/apollographql/apollo/gradle/api/Service.kt index 0e29b0adc1f..0f354e5bc38 100644 --- a/libraries/apollo-gradle-plugin/src/main/kotlin/com/apollographql/apollo/gradle/api/Service.kt +++ b/libraries/apollo-gradle-plugin/src/main/kotlin/com/apollographql/apollo/gradle/api/Service.kt @@ -689,6 +689,13 @@ interface Service { */ val decapitalizeFields: Property + /** + * Whether to allow fragment spread with arguments. + * Default: false + */ + @ApolloExperimental + val allowFragmentArguments: Property + /** * Configures [Introspection] to download an introspection Json schema */ diff --git a/libraries/apollo-gradle-plugin/src/main/kotlin/com/apollographql/apollo/gradle/internal/DefaultApolloExtension.kt b/libraries/apollo-gradle-plugin/src/main/kotlin/com/apollographql/apollo/gradle/internal/DefaultApolloExtension.kt index f35789bc435..2f0efa220f5 100644 --- a/libraries/apollo-gradle-plugin/src/main/kotlin/com/apollographql/apollo/gradle/internal/DefaultApolloExtension.kt +++ b/libraries/apollo-gradle-plugin/src/main/kotlin/com/apollographql/apollo/gradle/internal/DefaultApolloExtension.kt @@ -475,6 +475,7 @@ abstract class DefaultApolloExtension( failOnWarnings = service.failOnWarnings, generateOptionalOperationVariables = service.generateOptionalOperationVariables, alwaysGenerateTypesMatching = service.alwaysGenerateTypesMatching, + allowFragmentArguments = service.allowFragmentArguments, /** * CommonCodegenOptions diff --git a/tests/fragment-arguments/build.gradle.kts b/tests/fragment-arguments/build.gradle.kts new file mode 100644 index 00000000000..6a0f6125052 --- /dev/null +++ b/tests/fragment-arguments/build.gradle.kts @@ -0,0 +1,24 @@ +@file:OptIn(ApolloExperimental::class) + +import com.apollographql.apollo.annotations.ApolloExperimental + +plugins { + id("org.jetbrains.kotlin.jvm") + id("com.apollographql.apollo") +} + +apolloTest() + +dependencies { + implementation(libs.apollo.api) + testImplementation(libs.junit) + testImplementation(libs.apollo.execution) + testImplementation(libs.okhttp) +} + +apollo { + service("service") { + packageName.set("fragment.arguments") + allowFragmentArguments.set(true) + } +} diff --git a/tests/fragment-arguments/src/main/graphql/operations.graphql b/tests/fragment-arguments/src/main/graphql/operations.graphql new file mode 100644 index 00000000000..817d5e578f3 --- /dev/null +++ b/tests/fragment-arguments/src/main/graphql/operations.graphql @@ -0,0 +1,7 @@ +query GetFoo { + ...queryDetails(arg: 10) +} + +fragment queryDetails($arg: Int!) on Query { + foo(arg: $arg) +} \ No newline at end of file diff --git a/tests/fragment-arguments/src/main/graphql/schema.graphqls b/tests/fragment-arguments/src/main/graphql/schema.graphqls new file mode 100644 index 00000000000..a0d06f2ff2e --- /dev/null +++ b/tests/fragment-arguments/src/main/graphql/schema.graphqls @@ -0,0 +1,3 @@ +type Query { + foo(arg: Int!): Int! +} \ No newline at end of file diff --git a/tests/fragment-arguments/src/test/kotlin/test/FragmentArgumentsTest.kt b/tests/fragment-arguments/src/test/kotlin/test/FragmentArgumentsTest.kt new file mode 100644 index 00000000000..3c136c01d33 --- /dev/null +++ b/tests/fragment-arguments/src/test/kotlin/test/FragmentArgumentsTest.kt @@ -0,0 +1,39 @@ +package test + +import com.apollographql.apollo.api.json.MapJsonReader +import com.apollographql.apollo.api.parseData +import com.apollographql.apollo.api.parseResponse +import com.apollographql.apollo.ast.ParserOptions +import com.apollographql.apollo.ast.toGQLDocument +import com.apollographql.apollo.execution.ExecutableSchema +import com.apollographql.apollo.execution.GraphQLRequest +import java.io.File +import kotlin.test.Test +import fragment.arguments.GetFooQuery +import kotlinx.coroutines.runBlocking +import kotlin.test.assertEquals + +class FragmentArguementsTest { + @Test + fun fragmentArgumentsEndToEnd() { + val parserOptions = ParserOptions.Builder().allowFragmentArguments(true).build() + val executableSchema = ExecutableSchema.Builder() + .schema(File("src/main/graphql/schema.graphqls").toGQLDocument()) + .parserOptions(parserOptions) + .resolver { + 42 + } + .build() + + val query = GetFooQuery() + + val result = runBlocking { + executableSchema.execute(GraphQLRequest.Builder().document(query.document()).build()) + } + + val reader = MapJsonReader(result.data) + val data = query.parseData(reader) + + assertEquals(42, data?.queryDetails?.foo) + } +} diff --git a/tests/settings.gradle.kts b/tests/settings.gradle.kts index ff99af3862b..4642da4d911 100644 --- a/tests/settings.gradle.kts +++ b/tests/settings.gradle.kts @@ -29,6 +29,7 @@ listOf( "enums", "escaping", "filesystem-sensitivity", + "fragment-arguments", "generated-methods", "gzip", "http-cache", From 32e079e15bc0ba5b6b141b3fff0a64a683a5f917 Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Tue, 24 Feb 2026 14:12:22 +0100 Subject: [PATCH 2/4] Add missing experimental flag, format --- .../commonMain/kotlin/com/apollographql/apollo/ast/api.kt | 1 + .../commonMain/kotlin/com/apollographql/apollo/ast/gql.kt | 1 + .../apollo/ast/internal/ExecutableValidationScope.kt | 6 +----- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/api.kt b/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/api.kt index 5c75aa146e0..9a1c2be9753 100644 --- a/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/api.kt +++ b/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/api.kt @@ -77,6 +77,7 @@ class ParserOptions private constructor( val withSourceLocation: Boolean, val allowDirectivesOnDirectives: Boolean, val allowServiceCapabilities: Boolean, + @ApolloExperimental val allowFragmentArguments: Boolean ) { class Builder { diff --git a/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/gql.kt b/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/gql.kt index c3b0ddaae41..9142eb433a8 100644 --- a/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/gql.kt +++ b/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/gql.kt @@ -233,6 +233,7 @@ class GQLOperationDefinition( class GQLFragmentDefinition @ApolloExperimental constructor( override val sourceLocation: SourceLocation? = null, override val name: String, + @ApolloExperimental val variableDefinitions: List, override val directives: List, val typeCondition: GQLNamedType, diff --git a/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/ExecutableValidationScope.kt b/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/ExecutableValidationScope.kt index 14d52d05c69..7b91d7925f9 100644 --- a/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/ExecutableValidationScope.kt +++ b/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/ExecutableValidationScope.kt @@ -122,11 +122,7 @@ internal class ExecutableValidationScope( val index = path.indexOf("__${name}") val nextPath = path + "__${fragment.name}" if (index != -1) { - issues.add(FragmentCycle("Fragment '$name' spreads itself, creating a cycle at '${ - nextPath.subList(index, nextPath.size).joinToString(".") - }'", it.sourceLocation - ) - ) + issues.add(FragmentCycle("Fragment '$name' spreads itself, creating a cycle at '${nextPath.subList(index, nextPath.size).joinToString(".")}'", it.sourceLocation)) cyclicFragments.add(name) return@forEach } From 8328e27763fe3acac22ee1f37ad58481318d5835 Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Tue, 24 Feb 2026 15:12:07 +0100 Subject: [PATCH 3/4] Update libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/ExecutableValidationScope.kt Co-authored-by: Benoit 'BoD' Lubek --- .../apollo/ast/internal/ExecutableValidationScope.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/ExecutableValidationScope.kt b/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/ExecutableValidationScope.kt index 7b91d7925f9..a6114882b32 100644 --- a/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/ExecutableValidationScope.kt +++ b/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/ExecutableValidationScope.kt @@ -411,7 +411,7 @@ internal class ExecutableValidationScope( validateVariableUsages(variableDefinitions, ownVariableUsages, context = "fragment `$name`") /** - * We only track the variables that are not by this fragment. + * We only track the variables that are not defined by this fragment. */ fragmentOperationVariableUsages[name] = operationVariableUsages } From 8c74b4d2ec22491065c62bcdfb91106e9c25e8c4 Mon Sep 17 00:00:00 2001 From: Martin Bonnin Date: Tue, 24 Feb 2026 17:19:15 +0100 Subject: [PATCH 4/4] fix validation of nested fragments --- .../apollo/ast/internal/ExtensionsMerger.kt | 2 +- .../apollo/ast/internal/fields_merging.kt | 112 ++++++++---------- .../nested_merge_error.expected | 5 + .../nested_merge_error.graphql | 27 +++++ 4 files changed, 82 insertions(+), 64 deletions(-) create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/nested_merge_error.expected create mode 100644 libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/nested_merge_error.graphql diff --git a/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/ExtensionsMerger.kt b/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/ExtensionsMerger.kt index 021079e63f4..3ab2e3b8283 100644 --- a/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/ExtensionsMerger.kt +++ b/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/ExtensionsMerger.kt @@ -530,7 +530,7 @@ internal fun areEqual(a: GQLValue?, b: GQLValue?): Boolean { if (b !is GQLObjectValue) { false } else { - // TODO: Can object literal have duplicate fields? + // TODO: Can object literals have duplicate fields? if (a.fields.size != b.fields.size) { false } else { diff --git a/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/fields_merging.kt b/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/fields_merging.kt index 30dd5a85a8f..6664e223b34 100644 --- a/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/fields_merging.kt +++ b/libraries/apollo-ast/src/commonMain/kotlin/com/apollographql/apollo/ast/internal/fields_merging.kt @@ -59,7 +59,47 @@ private fun IssuesScope.addDifferentShapeIssue(path: List, message: Stri private data class ValidationContext( val schema: Schema, val fragments: Map, -) +) { + val variableValuesInScope = mutableListOf>() + + fun pushFragment(arguments: List, variableDefinitions: List) { + val newValues = mutableMapOf() + variableDefinitions.forEach { variableDefinition -> + val argument = arguments.firstOrNull { it.name == variableDefinition.name } + if (argument == null) { + if (variableDefinition.defaultValue != null) { + newValues.put(variableDefinition.name, variableDefinition.defaultValue) + } + } else { + newValues.put(variableDefinition.name, substituteVariables(argument.value)) + } + } + variableValuesInScope.add(variableValuesInScope.lastOrNull().orEmpty() + newValues) + } + + fun substituteVariables(value: GQLValue): GQLValue { + return when (value) { + is GQLBooleanValue -> value + is GQLEnumValue -> value + is GQLFloatValue -> value + is GQLIntValue -> value + is GQLListValue -> value.copy(values = value.values.map { substituteVariables(it) }) + is GQLNullValue -> value + is GQLObjectValue -> value.copy(fields = value.fields.map { it.copy(value = substituteVariables(it.value)) }) + is GQLStringValue -> value + is GQLVariableValue -> variableValue(value.name) + } + } + + fun popFragment() { + variableValuesInScope.removeLast() + } + + fun variableValue(variableName: String): GQLValue { + // the variableName may not exist in the operation, which validation should catch + return variableValuesInScope.lastOrNull()?.get(variableName) ?: GQLVariableValue(null, variableName) + } +} @OptIn(ApolloExperimental::class) private fun collectFields( @@ -97,15 +137,12 @@ private fun collectFields( is GQLFragmentSpread -> { val fragment = context.fragments[selection.name] if (fragment != null) { - // Use name + arguments as key so same fragment with different arguments is collected twice val fragmentType = context.schema.typeDefinitions[fragment.typeCondition.name] if (fragmentType != null) { - val selections = if (selection.arguments.isNotEmpty() && fragment.variableDefinitions.isNotEmpty()) { - substituteFragmentVariables(fragment.selections, fragment.variableDefinitions, selection.arguments) - } else { - fragment.selections - } + context.pushFragment(selection.arguments, fragment.variableDefinitions) + val selections = fragment.selections.map { it.substituteVariables(context) } collectFields(fieldMap, selections, fragmentType, context) + context.popFragment() } } } @@ -334,67 +371,16 @@ private fun buildMessage(path: List, message: String): String { "$message. Use different aliases on the fields to fetch both if this was intentional." } -/** - * Substitutes fragment variable references in selections with actual argument values. - * This ensures field merging compares resolved values when a fragment is spread with arguments. - */ @OptIn(ApolloExperimental::class) -private fun substituteFragmentVariables( - selections: List, - variableDefinitions: List, - arguments: List, -): List { - val argMap = mutableMapOf() - for (varDef in variableDefinitions) { - val arg = arguments.firstOrNull { it.name == varDef.name } - if (arg != null) { - argMap[varDef.name] = arg.value - } else if (varDef.defaultValue != null) { - argMap[varDef.name] = varDef.defaultValue - } - } - if (argMap.isEmpty()) return selections - return selections.map { it.substituteVariables(argMap) } -} - -@OptIn(ApolloExperimental::class) -private fun GQLSelection.substituteVariables(argMap: Map): GQLSelection { +private fun GQLSelection.substituteVariables(context: ValidationContext): GQLSelection { return when (this) { - is GQLField -> GQLField( - sourceLocation = sourceLocation, - alias = alias, - name = name, + is GQLField -> copy( arguments = arguments.map { arg -> - GQLArgument( - sourceLocation = arg.sourceLocation, - name = arg.name, - value = arg.value.substituteVariables(argMap) - ) - }, - directives = directives, - selections = selections.map { it.substituteVariables(argMap) } - ) - - is GQLInlineFragment -> GQLInlineFragment( - sourceLocation = sourceLocation, - typeCondition = typeCondition, - directives = directives, - selections = selections.map { it.substituteVariables(argMap) } + arg.copy(value = context.substituteVariables(arg.value)) + } ) + is GQLInlineFragment -> this is GQLFragmentSpread -> this } } - -private fun GQLValue.substituteVariables(argMap: Map): GQLValue { - return when (this) { - is GQLVariableValue -> argMap[name] ?: this - is GQLListValue -> GQLListValue(sourceLocation = sourceLocation, values = values.map { it.substituteVariables(argMap) }) - is GQLObjectValue -> GQLObjectValue( - sourceLocation = sourceLocation, - fields = fields.map { GQLObjectField(sourceLocation = it.sourceLocation, name = it.name, value = it.value.substituteVariables(argMap)) } - ) - - else -> this - } -} \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/nested_merge_error.expected b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/nested_merge_error.expected new file mode 100644 index 00000000000..b09ca218710 --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/nested_merge_error.expected @@ -0,0 +1,5 @@ +OtherValidationIssue (14:3) +Field at path `users` conflicts with another field: they have different arguments. Use different aliases on the fields to fetch both if this was intentional. +------------ +OtherValidationIssue (8:3) +Field at path `users` conflicts with another field: they have different arguments. Use different aliases on the fields to fetch both if this was intentional. \ No newline at end of file diff --git a/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/nested_merge_error.graphql b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/nested_merge_error.graphql new file mode 100644 index 00000000000..6ec7f4c96df --- /dev/null +++ b/libraries/apollo-ast/test-fixtures/validation/executable/fragment_arguments/nested_merge_error.graphql @@ -0,0 +1,27 @@ +# PRAGMA allowFragmentArguments + +fragment queryDetails0($first: Int!) on Query { + ...queryDetails1(first: $first) +} + +fragment queryDetails1($first: Int!) on Query { + users(first: $first) { + totalCount + } +} + +query GetFoo($first: Int!, $second: Int!) { + users(first: $first) { + totalCount + } + # invalid: different variables + ...queryDetails0(first: $second) +} + +query GetFoo1($first: Int!) { + users(first: $first) { + totalCount + } + # valid + ...queryDetails0(first: $first) +}