rubocop-graphql 0.12.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/rubocop/cop/graphql/argument_uniqueness.rb +4 -10
- data/lib/rubocop/cop/graphql/field_uniqueness.rb +4 -10
- data/lib/rubocop/cop/graphql/ordered_arguments.rb +25 -3
- data/lib/rubocop/cop/graphql/unused_argument.rb +44 -8
- data/lib/rubocop/graphql/argument/kwargs.rb +16 -0
- data/lib/rubocop/graphql/argument.rb +8 -0
- data/lib/rubocop/graphql/class.rb +17 -0
- data/lib/rubocop/graphql/node_uniqueness.rb +12 -0
- data/lib/rubocop/graphql/version.rb +1 -1
- data/lib/rubocop-graphql.rb +2 -0
- metadata +4 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: d809ed60d2d98c5f7f84a3555d8ad24ad2c2e1ece6a5fed616b6698260981d29
         | 
| 4 | 
            +
              data.tar.gz: e62936fc399419ee72070e658be32660763a96144776727e183007aa53ad0bd8
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 8c508f31ceb2e6f1290ef0220896019c5f3ff007dbd2ec651ba44ad5cc422680ec761ccb6739a7e90f243cc434b787f849d872143c6e709967deeeb81e6500ec
         | 
| 7 | 
            +
              data.tar.gz: ccd1741a8b20403f5a904aa321526fb089f4af357b1a8cce37547221f11ef1fa4f407169aedb35923b85c4b5dc5eb0bba76f74ce7b585b260a0d90549c2d7dfb
         | 
| @@ -20,11 +20,13 @@ module RuboCop | |
| 20 20 | 
             
                  #   end
         | 
| 21 21 | 
             
                  #
         | 
| 22 22 | 
             
                  class ArgumentUniqueness < Base
         | 
| 23 | 
            +
                    include RuboCop::GraphQL::NodeUniqueness
         | 
| 24 | 
            +
             | 
| 23 25 | 
             
                    MSG = "Argument names should only be defined once per block. "\
         | 
| 24 26 | 
             
                          "Argument `%<current>s` is duplicated%<field_name>s."
         | 
| 25 27 |  | 
| 26 28 | 
             
                    def on_class(node)
         | 
| 27 | 
            -
                      return if  | 
| 29 | 
            +
                      return if ::RuboCop::GraphQL::Class.new(node).nested?
         | 
| 28 30 |  | 
| 29 31 | 
             
                      # { "MyClassName" => { "test_field" => <Set: {"field_arg_name"}> } }
         | 
| 30 32 | 
             
                      argument_names_by_field_by_class = Hash.new do |h, k|
         | 
| @@ -36,7 +38,7 @@ module RuboCop | |
| 36 38 | 
             
                      argument_declarations(node).each do |current|
         | 
| 37 39 | 
             
                        current_field_name = field_name(current)
         | 
| 38 40 | 
             
                        current_argument_name = argument_name(current)
         | 
| 39 | 
            -
                        class_name =  | 
| 41 | 
            +
                        class_name = current_class_full_name(current)
         | 
| 40 42 |  | 
| 41 43 | 
             
                        argument_names = if current_field_name
         | 
| 42 44 | 
             
                                           argument_names_by_field_by_class[class_name][current_field_name]
         | 
| @@ -55,14 +57,6 @@ module RuboCop | |
| 55 57 |  | 
| 56 58 | 
             
                    private
         | 
| 57 59 |  | 
| 58 | 
            -
                    def current_class_name(node)
         | 
| 59 | 
            -
                      node.each_ancestor(:class).first.defined_module_name
         | 
| 60 | 
            -
                    end
         | 
| 61 | 
            -
             | 
| 62 | 
            -
                    def nested_class?(node)
         | 
| 63 | 
            -
                      node.each_ancestor(:class).any?
         | 
| 64 | 
            -
                    end
         | 
| 65 | 
            -
             | 
| 66 60 | 
             
                    def register_offense(current)
         | 
| 67 61 | 
             
                      current_field_name = field_name(current)
         | 
| 68 62 | 
             
                      field_name_message = " in field `#{current_field_name}`" if current_field_name
         | 
| @@ -27,16 +27,18 @@ module RuboCop | |
| 27 27 | 
             
                  #   end
         | 
| 28 28 | 
             
                  #
         | 
| 29 29 | 
             
                  class FieldUniqueness < Base
         | 
| 30 | 
            +
                    include RuboCop::GraphQL::NodeUniqueness
         | 
| 31 | 
            +
             | 
| 30 32 | 
             
                    MSG = "Field names should only be defined once per type. "\
         | 
| 31 33 | 
             
                          "Field `%<current>s` is duplicated."
         | 
| 32 34 |  | 
| 33 35 | 
             
                    def on_class(node)
         | 
| 34 | 
            -
                      return if  | 
| 36 | 
            +
                      return if ::RuboCop::GraphQL::Class.new(node).nested?
         | 
| 35 37 |  | 
| 36 38 | 
             
                      field_names_by_class = Hash.new { |h, k| h[k] = Set.new }
         | 
| 37 39 |  | 
| 38 40 | 
             
                      field_declarations(node).each do |current|
         | 
| 39 | 
            -
                        current_class =  | 
| 41 | 
            +
                        current_class = current_class_full_name(current)
         | 
| 40 42 | 
             
                        field_names = field_names_by_class[current_class]
         | 
| 41 43 | 
             
                        current_field_name = field_name(current)
         | 
| 42 44 |  | 
| @@ -51,10 +53,6 @@ module RuboCop | |
| 51 53 |  | 
| 52 54 | 
             
                    private
         | 
| 53 55 |  | 
| 54 | 
            -
                    def nested_class?(node)
         | 
| 55 | 
            -
                      node.each_ancestor(:class).any?
         | 
| 56 | 
            -
                    end
         | 
| 57 | 
            -
             | 
| 58 56 | 
             
                    def register_offense(current)
         | 
| 59 57 | 
             
                      message = format(
         | 
| 60 58 | 
             
                        self.class::MSG,
         | 
| @@ -68,10 +66,6 @@ module RuboCop | |
| 68 66 | 
             
                      node.first_argument.value.to_s
         | 
| 69 67 | 
             
                    end
         | 
| 70 68 |  | 
| 71 | 
            -
                    def current_class_name(node)
         | 
| 72 | 
            -
                      node.each_ancestor(:class).first.defined_module_name
         | 
| 73 | 
            -
                    end
         | 
| 74 | 
            -
             | 
| 75 69 | 
             
                    def_node_search :field_declarations, <<~PATTERN
         | 
| 76 70 | 
             
                      {
         | 
| 77 71 | 
             
                        (send nil? :field (:sym _) ...)
         | 
| @@ -57,7 +57,19 @@ module RuboCop | |
| 57 57 | 
             
                          "Field `%<current>s` should appear before `%<previous>s`."
         | 
| 58 58 |  | 
| 59 59 | 
             
                    def on_class(node)
         | 
| 60 | 
            -
                       | 
| 60 | 
            +
                      declarations_with_blocks = argument_declarations_with_blocks(node)
         | 
| 61 | 
            +
                      declarations_without_blocks = argument_declarations_without_blocks(node)
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                      argument_declarations = declarations_without_blocks.map do |node|
         | 
| 64 | 
            +
                        arg_name = argument_name(node)
         | 
| 65 | 
            +
                        same_arg_with_block_declaration = declarations_with_blocks.find do |dec|
         | 
| 66 | 
            +
                          argument_name(dec) == arg_name
         | 
| 67 | 
            +
                        end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                        same_arg_with_block_declaration || node
         | 
| 70 | 
            +
                      end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                      argument_declarations.each_cons(2) do |previous, current|
         | 
| 61 73 | 
             
                        next unless consecutive_lines(previous, current)
         | 
| 62 74 | 
             
                        next if argument_name(current) >= argument_name(previous)
         | 
| 63 75 |  | 
| @@ -80,16 +92,26 @@ module RuboCop | |
| 80 92 | 
             
                    end
         | 
| 81 93 |  | 
| 82 94 | 
             
                    def argument_name(node)
         | 
| 83 | 
            -
                      node.first_argument. | 
| 95 | 
            +
                      argument = node.block_type? ? node.children.first.first_argument : node.first_argument
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                      argument.value.to_s
         | 
| 84 98 | 
             
                    end
         | 
| 85 99 |  | 
| 86 100 | 
             
                    def consecutive_lines(previous, current)
         | 
| 87 101 | 
             
                      previous.source_range.last_line == current.source_range.first_line - 1
         | 
| 88 102 | 
             
                    end
         | 
| 89 103 |  | 
| 90 | 
            -
                    def_node_search : | 
| 104 | 
            +
                    def_node_search :argument_declarations_without_blocks, <<~PATTERN
         | 
| 91 105 | 
             
                      (send nil? :argument (:sym _) ...)
         | 
| 92 106 | 
             
                    PATTERN
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                    def_node_search :argument_declarations_with_blocks, <<~PATTERN
         | 
| 109 | 
            +
                      (block
         | 
| 110 | 
            +
                        (send nil? :argument
         | 
| 111 | 
            +
                          (:sym _)
         | 
| 112 | 
            +
                          ...)
         | 
| 113 | 
            +
                        ...)
         | 
| 114 | 
            +
                    PATTERN
         | 
| 93 115 | 
             
                  end
         | 
| 94 116 | 
             
                end
         | 
| 95 117 | 
             
              end
         | 
| @@ -10,16 +10,19 @@ module RuboCop | |
| 10 10 | 
             
                  #
         | 
| 11 11 | 
             
                  #   class SomeResolver < Resolvers::Base
         | 
| 12 12 | 
             
                  #     argument :arg1, String, required: true
         | 
| 13 | 
            -
                  #     argument : | 
| 13 | 
            +
                  #     argument :user_id, String, required: true, loads: Types::UserType
         | 
| 14 | 
            +
                  #     argument :post_id, String, loads: Types::PostType, as: :article
         | 
| 15 | 
            +
                  #     argument :comment_ids, String, loads: Types::CommentType
         | 
| 14 16 | 
             
                  #
         | 
| 15 | 
            -
                  #     def resolve(arg1:,  | 
| 17 | 
            +
                  #     def resolve(arg1:, user:, article:, comments:); end
         | 
| 16 18 | 
             
                  #   end
         | 
| 17 19 | 
             
                  #
         | 
| 18 20 | 
             
                  #   # good
         | 
| 19 21 | 
             
                  #
         | 
| 20 22 | 
             
                  #   class SomeResolver < Resolvers::Base
         | 
| 21 23 | 
             
                  #     argument :arg1, String, required: true
         | 
| 22 | 
            -
                  #     argument : | 
| 24 | 
            +
                  #     argument :user_id, String, required: true, loads: Types::UserType
         | 
| 25 | 
            +
                  #     argument :comment_ids, String, loads: Types::CommentType
         | 
| 23 26 | 
             
                  #
         | 
| 24 27 | 
             
                  #     def resolve(arg1:, **rest); end
         | 
| 25 28 | 
             
                  #   end
         | 
| @@ -69,7 +72,7 @@ module RuboCop | |
| 69 72 | 
             
                                  arg.arg_type? || arg.kwrestarg_type?
         | 
| 70 73 | 
             
                                end
         | 
| 71 74 |  | 
| 72 | 
            -
                      declared_arg_nodes =  | 
| 75 | 
            +
                      declared_arg_nodes = find_declared_arg_nodes(node)
         | 
| 73 76 | 
             
                      return unless declared_arg_nodes.any?
         | 
| 74 77 |  | 
| 75 78 | 
             
                      unresolved_args = find_unresolved_args(resolve_method_node, declared_arg_nodes)
         | 
| @@ -78,18 +81,31 @@ module RuboCop | |
| 78 81 |  | 
| 79 82 | 
             
                    private
         | 
| 80 83 |  | 
| 84 | 
            +
                    def find_declared_arg_nodes(node)
         | 
| 85 | 
            +
                      argument_declarations(node).select do |arg_declaration|
         | 
| 86 | 
            +
                        # argument is declared on the same class that is being analyzed
         | 
| 87 | 
            +
                        arg_declaration.each_ancestor(:class).first == node
         | 
| 88 | 
            +
                      end
         | 
| 89 | 
            +
                    end
         | 
| 90 | 
            +
             | 
| 81 91 | 
             
                    def find_resolve_method_node(node)
         | 
| 82 92 | 
             
                      resolve_method_nodes = resolve_method_definition(node)
         | 
| 83 | 
            -
                      resolve_method_nodes. | 
| 93 | 
            +
                      resolve_method_nodes.find do |resolve_node|
         | 
| 94 | 
            +
                        # reject resolve methods from other classes
         | 
| 95 | 
            +
                        resolve_node.each_ancestor(:class).first == node
         | 
| 96 | 
            +
                      end
         | 
| 84 97 | 
             
                    end
         | 
| 85 98 |  | 
| 86 99 | 
             
                    def find_unresolved_args(method_node, declared_arg_nodes)
         | 
| 87 | 
            -
                      resolve_method_kwargs = method_node.arguments.select | 
| 100 | 
            +
                      resolve_method_kwargs = method_node.arguments.select do |arg|
         | 
| 101 | 
            +
                        arg.kwarg_type? || arg.kwoptarg_type?
         | 
| 102 | 
            +
                      end
         | 
| 103 | 
            +
                      resolve_method_kwargs_names = resolve_method_kwargs.map do |node|
         | 
| 88 104 | 
             
                        node.node_parts[0]
         | 
| 89 105 | 
             
                      end.to_set
         | 
| 90 106 | 
             
                      declared_args = declared_arg_nodes.map { |node| RuboCop::GraphQL::Argument.new(node) }
         | 
| 91 | 
            -
                      declared_args.map( | 
| 92 | 
            -
                         | 
| 107 | 
            +
                      declared_args.map(&method(:arg_name)).uniq.reject do |declared_arg_name|
         | 
| 108 | 
            +
                        resolve_method_kwargs_names.include?(declared_arg_name)
         | 
| 93 109 | 
             
                      end
         | 
| 94 110 | 
             
                    end
         | 
| 95 111 |  | 
| @@ -119,6 +135,26 @@ module RuboCop | |
| 119 135 | 
             
                      node.loc.expression.end
         | 
| 120 136 | 
             
                    end
         | 
| 121 137 |  | 
| 138 | 
            +
                    def inferred_arg_name(name_as_string)
         | 
| 139 | 
            +
                      case name_as_string
         | 
| 140 | 
            +
                      when /_id$/
         | 
| 141 | 
            +
                        name_as_string.sub(/_id$/, "").to_sym
         | 
| 142 | 
            +
                      when /_ids$/
         | 
| 143 | 
            +
                        name_as_string.sub(/_ids$/, "")
         | 
| 144 | 
            +
                                      .sub(/([^s])$/, "\\1s")
         | 
| 145 | 
            +
                                      .to_sym
         | 
| 146 | 
            +
                      else
         | 
| 147 | 
            +
                        name
         | 
| 148 | 
            +
                      end
         | 
| 149 | 
            +
                    end
         | 
| 150 | 
            +
             | 
| 151 | 
            +
                    def arg_name(declared_arg)
         | 
| 152 | 
            +
                      return declared_arg.as if declared_arg.kwargs.as
         | 
| 153 | 
            +
                      return inferred_arg_name(declared_arg.name.to_s) if declared_arg.kwargs.loads
         | 
| 154 | 
            +
             | 
| 155 | 
            +
                      declared_arg.name
         | 
| 156 | 
            +
                    end
         | 
| 157 | 
            +
             | 
| 122 158 | 
             
                    def_node_search :argument_declarations, <<~PATTERN
         | 
| 123 159 | 
             
                      (send nil? :argument (:sym _) ...)
         | 
| 124 160 | 
             
                    PATTERN
         | 
| @@ -19,6 +19,14 @@ module RuboCop | |
| 19 19 | 
             
                      (pair (sym :description) ...)
         | 
| 20 20 | 
             
                    PATTERN
         | 
| 21 21 |  | 
| 22 | 
            +
                    def_node_matcher :loads_kwarg?, <<~PATTERN
         | 
| 23 | 
            +
                      (pair (sym :loads) ...)
         | 
| 24 | 
            +
                    PATTERN
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                    def_node_matcher :as_kwarg?, <<~PATTERN
         | 
| 27 | 
            +
                      (pair (sym :as) ...)
         | 
| 28 | 
            +
                    PATTERN
         | 
| 29 | 
            +
             | 
| 22 30 | 
             
                    def initialize(argument_node)
         | 
| 23 31 | 
             
                      @nodes = argument_kwargs(argument_node) || []
         | 
| 24 32 | 
             
                    end
         | 
| @@ -26,6 +34,14 @@ module RuboCop | |
| 26 34 | 
             
                    def description
         | 
| 27 35 | 
             
                      @nodes.find { |kwarg| description_kwarg?(kwarg) }
         | 
| 28 36 | 
             
                    end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                    def loads
         | 
| 39 | 
            +
                      @nodes.find { |kwarg| loads_kwarg?(kwarg) }
         | 
| 40 | 
            +
                    end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                    def as
         | 
| 43 | 
            +
                      @nodes.find { |kwarg| as_kwarg?(kwarg) }
         | 
| 44 | 
            +
                    end
         | 
| 29 45 | 
             
                  end
         | 
| 30 46 | 
             
                end
         | 
| 31 47 | 
             
              end
         | 
| @@ -13,6 +13,10 @@ module RuboCop | |
| 13 13 | 
             
                    (send nil? :argument (:sym $_) ...)
         | 
| 14 14 | 
             
                  PATTERN
         | 
| 15 15 |  | 
| 16 | 
            +
                  def_node_matcher :argument_as, <<~PATTERN
         | 
| 17 | 
            +
                    (pair (sym :as) (sym $_))
         | 
| 18 | 
            +
                  PATTERN
         | 
| 19 | 
            +
             | 
| 16 20 | 
             
                  attr_reader :node
         | 
| 17 21 |  | 
| 18 22 | 
             
                  def initialize(node)
         | 
| @@ -23,6 +27,10 @@ module RuboCop | |
| 23 27 | 
             
                    @name ||= argument_name(@node)
         | 
| 24 28 | 
             
                  end
         | 
| 25 29 |  | 
| 30 | 
            +
                  def as
         | 
| 31 | 
            +
                    @as ||= argument_as(kwargs.as)
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
             | 
| 26 34 | 
             
                  def description
         | 
| 27 35 | 
             
                    @description ||= argument_description(@node) || kwargs.description || block.description
         | 
| 28 36 | 
             
                  end
         | 
| @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module RuboCop
         | 
| 4 | 
            +
              module GraphQL
         | 
| 5 | 
            +
                # Shared methods to check duplicated definitions
         | 
| 6 | 
            +
                module NodeUniqueness
         | 
| 7 | 
            +
                  def current_class_full_name(node)
         | 
| 8 | 
            +
                    node.each_ancestor(:class).map(&:defined_module_name).join("::")
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
            end
         | 
    
        data/lib/rubocop-graphql.rb
    CHANGED
    
    | @@ -9,11 +9,13 @@ require_relative "rubocop/graphql/version" | |
| 9 9 | 
             
            require_relative "rubocop/graphql/inject"
         | 
| 10 10 | 
             
            require_relative "rubocop/graphql/description_method"
         | 
| 11 11 | 
             
            require_relative "rubocop/graphql/node_pattern"
         | 
| 12 | 
            +
            require_relative "rubocop/graphql/node_uniqueness"
         | 
| 12 13 | 
             
            require_relative "rubocop/graphql/swap_range"
         | 
| 13 14 |  | 
| 14 15 | 
             
            require_relative "rubocop/graphql/argument"
         | 
| 15 16 | 
             
            require_relative "rubocop/graphql/argument/block"
         | 
| 16 17 | 
             
            require_relative "rubocop/graphql/argument/kwargs"
         | 
| 18 | 
            +
            require_relative "rubocop/graphql/class"
         | 
| 17 19 | 
             
            require_relative "rubocop/graphql/field"
         | 
| 18 20 | 
             
            require_relative "rubocop/graphql/field/block"
         | 
| 19 21 | 
             
            require_relative "rubocop/graphql/field/kwargs"
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: rubocop-graphql
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.13.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Dmitry Tsepelev
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date:  | 
| 11 | 
            +
            date: 2022-02-11 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: bundler
         | 
| @@ -106,6 +106,7 @@ files: | |
| 106 106 | 
             
            - lib/rubocop/graphql/argument.rb
         | 
| 107 107 | 
             
            - lib/rubocop/graphql/argument/block.rb
         | 
| 108 108 | 
             
            - lib/rubocop/graphql/argument/kwargs.rb
         | 
| 109 | 
            +
            - lib/rubocop/graphql/class.rb
         | 
| 109 110 | 
             
            - lib/rubocop/graphql/description_method.rb
         | 
| 110 111 | 
             
            - lib/rubocop/graphql/ext/snake_case.rb
         | 
| 111 112 | 
             
            - lib/rubocop/graphql/field.rb
         | 
| @@ -113,6 +114,7 @@ files: | |
| 113 114 | 
             
            - lib/rubocop/graphql/field/kwargs.rb
         | 
| 114 115 | 
             
            - lib/rubocop/graphql/inject.rb
         | 
| 115 116 | 
             
            - lib/rubocop/graphql/node_pattern.rb
         | 
| 117 | 
            +
            - lib/rubocop/graphql/node_uniqueness.rb
         | 
| 116 118 | 
             
            - lib/rubocop/graphql/schema_member.rb
         | 
| 117 119 | 
             
            - lib/rubocop/graphql/swap_range.rb
         | 
| 118 120 | 
             
            - lib/rubocop/graphql/version.rb
         |