# typed: strict # frozen_string_literal: true require "rubocops/extend/formula_cop" module RuboCop module Cop module FormulaAudit # This cop checks if redundant components are present and for other component errors. # # - `url|checksum|mirror|version` should be inside `stable` block # - `head` and `head do` should not be simultaneously present # - `bottle :unneeded`/`:disable` and `bottle do` should not be simultaneously present # - `stable do` should not be present without a `head` spec # - `stable do` should not be present with only `url|checksum|mirror|version` # - `head do` should not be present with only `url` class ComponentsRedundancy < FormulaCop HEAD_MSG = "`head` and `head do` should not be simultaneously present" BOTTLE_MSG = "`bottle :modifier` and `bottle do` should not be simultaneously present" STABLE_MSG = "`stable do` should not be present without a `head` spec" STABLE_BLOCK_METHODS = [:url, :sha256, :mirror, :version].freeze sig { override.params(formula_nodes: FormulaNodes).void } def audit_formula(formula_nodes) return if (body_node = formula_nodes.body_node).nil? urls = find_method_calls_by_name(body_node, :url) urls.each do |url| url.arguments.each do |arg| next if arg.class != RuboCop::AST::HashNode url_args = arg.keys.each.map(&:value) if method_called?(body_node, :sha256) && url_args.include?(:tag) && url_args.include?(:revision) problem "Do not use both `sha256` and `tag:`/`revision:`." end end end stable_block = find_block(body_node, :stable) if stable_block STABLE_BLOCK_METHODS.each do |method_name| problem "`#{method_name}` should be put inside `stable` block" if method_called?(body_node, method_name) end unless stable_block.body.nil? child_nodes = stable_block.body.begin_type? ? stable_block.body.child_nodes : [stable_block.body] if child_nodes.all? { |n| n.send_type? && STABLE_BLOCK_METHODS.include?(n.method_name) } problem "`stable do` should not be present with only #{STABLE_BLOCK_METHODS.join("/")}" end end end head_block = find_block(body_node, :head) if head_block && !head_block.body.nil? child_nodes = head_block.body.begin_type? ? head_block.body.child_nodes : [head_block.body] if child_nodes.all? { |n| n.send_type? && n.method_name == :url } problem "`head do` should not be present with only `url`" end end problem HEAD_MSG if method_called?(body_node, :head) && find_block(body_node, :head) problem BOTTLE_MSG if method_called?(body_node, :bottle) && find_block(body_node, :bottle) return if method_called?(body_node, :head) || find_block(body_node, :head) problem STABLE_MSG if stable_block end end end end end