| 
									
										
										
										
											2020-10-10 14:16:11 +02:00
										 |  |  | # typed: true | 
					
						
							| 
									
										
										
										
											2020-08-13 18:05:02 +05:30
										 |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | require "rubocops/extend/formula" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module RuboCop | 
					
						
							|  |  |  |   module Cop | 
					
						
							|  |  |  |     module FormulaAudit | 
					
						
							|  |  |  |       # This cop ensures that no other livecheck information is provided for | 
					
						
							|  |  |  |       # skipped formulae. | 
					
						
							|  |  |  |       # | 
					
						
							|  |  |  |       # @api private | 
					
						
							|  |  |  |       class LivecheckSkip < FormulaCop | 
					
						
							| 
									
										
										
										
											2021-01-12 13:58:53 +11:00
										 |  |  |         extend AutoCorrector | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-13 18:05:02 +05:30
										 |  |  |         def audit_formula(_node, _class_node, _parent_class_node, body_node) | 
					
						
							|  |  |  |           livecheck_node = find_block(body_node, :livecheck) | 
					
						
							|  |  |  |           return if livecheck_node.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           skip = find_every_method_call_by_name(livecheck_node, :skip).first | 
					
						
							| 
									
										
										
										
											2020-09-17 15:56:40 +05:30
										 |  |  |           return if skip.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           return if find_every_method_call_by_name(livecheck_node).length < 3
 | 
					
						
							| 
									
										
										
										
											2020-08-13 18:05:02 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  |           offending_node(livecheck_node) | 
					
						
							| 
									
										
										
										
											2021-01-12 13:58:53 +11:00
										 |  |  |           problem "Skipped formulae must not contain other livecheck information." do |corrector| | 
					
						
							|  |  |  |             skip = find_every_method_call_by_name(livecheck_node, :skip).first | 
					
						
							| 
									
										
										
										
											2020-08-13 18:05:02 +05:30
										 |  |  |             skip = find_strings(skip).first | 
					
						
							|  |  |  |             skip = string_content(skip) if skip.present? | 
					
						
							|  |  |  |             corrector.replace( | 
					
						
							| 
									
										
										
										
											2021-01-12 13:58:53 +11:00
										 |  |  |               livecheck_node.source_range, | 
					
						
							| 
									
										
										
										
											2020-09-17 15:56:40 +05:30
										 |  |  |               <<~EOS.strip, | 
					
						
							|  |  |  |                 livecheck do | 
					
						
							|  |  |  |                     skip#{" \"#{skip}\"" if skip.present?} | 
					
						
							|  |  |  |                   end | 
					
						
							|  |  |  |               EOS | 
					
						
							| 
									
										
										
										
											2020-08-13 18:05:02 +05:30
										 |  |  |             ) | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |       # This cop ensures that a `url` is specified in the `livecheck` block. | 
					
						
							| 
									
										
										
										
											2020-08-13 18:05:02 +05:30
										 |  |  |       # | 
					
						
							|  |  |  |       # @api private | 
					
						
							|  |  |  |       class LivecheckUrlProvided < FormulaCop | 
					
						
							|  |  |  |         def audit_formula(_node, _class_node, _parent_class_node, body_node) | 
					
						
							|  |  |  |           livecheck_node = find_block(body_node, :livecheck) | 
					
						
							|  |  |  |           return if livecheck_node.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           skip = find_every_method_call_by_name(livecheck_node, :skip).first | 
					
						
							|  |  |  |           return if skip.present? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           livecheck_url = find_every_method_call_by_name(livecheck_node, :url).first | 
					
						
							|  |  |  |           return if livecheck_url.present? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           offending_node(livecheck_node) | 
					
						
							|  |  |  |           problem "A `url` must be provided to livecheck." | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       # This cop ensures that a supported symbol (`head`, `stable, `homepage`) | 
					
						
							|  |  |  |       # is used when the livecheck `url` is identical to one of these formula URLs. | 
					
						
							|  |  |  |       # | 
					
						
							|  |  |  |       # @api private | 
					
						
							|  |  |  |       class LivecheckUrlSymbol < FormulaCop | 
					
						
							| 
									
										
										
										
											2021-01-12 13:58:53 +11:00
										 |  |  |         extend AutoCorrector | 
					
						
							| 
									
										
										
										
											2020-08-13 18:05:02 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  |         def audit_formula(_node, _class_node, _parent_class_node, body_node) | 
					
						
							|  |  |  |           livecheck_node = find_block(body_node, :livecheck) | 
					
						
							|  |  |  |           return if livecheck_node.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           skip = find_every_method_call_by_name(livecheck_node, :skip).first.present? | 
					
						
							|  |  |  |           return if skip.present? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           livecheck_url_node = find_every_method_call_by_name(livecheck_node, :url).first | 
					
						
							|  |  |  |           livecheck_url = find_strings(livecheck_url_node).first | 
					
						
							|  |  |  |           return if livecheck_url.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           livecheck_url = string_content(livecheck_url) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           head = find_every_method_call_by_name(body_node, :head).first | 
					
						
							|  |  |  |           head_url = find_strings(head).first | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           if head.present? && head_url.blank? | 
					
						
							|  |  |  |             head = find_every_method_call_by_name(head, :url).first | 
					
						
							|  |  |  |             head_url = find_strings(head).first | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           head_url = string_content(head_url) if head_url.present? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           stable = find_every_method_call_by_name(body_node, :url).first | 
					
						
							|  |  |  |           stable_url = find_strings(stable).first | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           if stable_url.blank? | 
					
						
							|  |  |  |             stable = find_every_method_call_by_name(body_node, :stable).first | 
					
						
							|  |  |  |             stable = find_every_method_call_by_name(stable, :url).first | 
					
						
							|  |  |  |             stable_url = find_strings(stable).first | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           stable_url = string_content(stable_url) if stable_url.present? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           homepage = find_every_method_call_by_name(body_node, :homepage).first | 
					
						
							|  |  |  |           homepage_url = string_content(find_strings(homepage).first) if homepage.present? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           formula_urls = { head: head_url, stable: stable_url, homepage: homepage_url }.compact | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           formula_urls.each do |symbol, url| | 
					
						
							| 
									
										
										
										
											2020-09-17 15:56:40 +05:30
										 |  |  |             next if url != livecheck_url && url != "#{livecheck_url}/" && "#{url}/" != livecheck_url | 
					
						
							| 
									
										
										
										
											2020-08-13 18:05:02 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  |             offending_node(livecheck_url_node) | 
					
						
							| 
									
										
										
										
											2021-01-12 13:58:53 +11:00
										 |  |  |             problem "Use `url :#{symbol}`" do |corrector| | 
					
						
							|  |  |  |               corrector.replace(livecheck_url_node.source_range, "url :#{symbol}") | 
					
						
							|  |  |  |             end | 
					
						
							| 
									
										
										
										
											2020-08-13 18:05:02 +05:30
										 |  |  |             break | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |       # This cop ensures that the `regex` call in the `livecheck` block uses parentheses. | 
					
						
							| 
									
										
										
										
											2020-08-13 18:05:02 +05:30
										 |  |  |       # | 
					
						
							|  |  |  |       # @api private | 
					
						
							|  |  |  |       class LivecheckRegexParentheses < FormulaCop | 
					
						
							| 
									
										
										
										
											2021-01-12 13:58:53 +11:00
										 |  |  |         extend AutoCorrector | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-13 18:05:02 +05:30
										 |  |  |         def audit_formula(_node, _class_node, _parent_class_node, body_node) | 
					
						
							|  |  |  |           livecheck_node = find_block(body_node, :livecheck) | 
					
						
							|  |  |  |           return if livecheck_node.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           skip = find_every_method_call_by_name(livecheck_node, :skip).first.present? | 
					
						
							|  |  |  |           return if skip.present? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           livecheck_regex_node = find_every_method_call_by_name(livecheck_node, :regex).first | 
					
						
							|  |  |  |           return if livecheck_regex_node.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           return if parentheses?(livecheck_regex_node) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           offending_node(livecheck_regex_node) | 
					
						
							| 
									
										
										
										
											2021-01-12 13:58:53 +11:00
										 |  |  |           problem "The `regex` call should always use parentheses." do |corrector| | 
					
						
							|  |  |  |             pattern = livecheck_regex_node.source.split[1..].join | 
					
						
							|  |  |  |             corrector.replace(livecheck_regex_node.source_range, "regex(#{pattern})") | 
					
						
							| 
									
										
										
										
											2020-08-13 18:05:02 +05:30
										 |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       # This cop ensures that the pattern provided to livecheck's `regex` uses `\.t` instead of | 
					
						
							|  |  |  |       # `\.tgz`, `\.tar.gz` and variants. | 
					
						
							|  |  |  |       # | 
					
						
							|  |  |  |       # @api private | 
					
						
							|  |  |  |       class LivecheckRegexExtension < FormulaCop | 
					
						
							| 
									
										
										
										
											2021-01-12 13:58:53 +11:00
										 |  |  |         extend AutoCorrector | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-13 18:05:02 +05:30
										 |  |  |         TAR_PATTERN = /\\?\.t(ar|(g|l|x)z$|[bz2]{2,4}$)(\\?\.((g|l|x)z)|[bz2]{2,4}|Z)?$/i.freeze | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def audit_formula(_node, _class_node, _parent_class_node, body_node) | 
					
						
							|  |  |  |           livecheck_node = find_block(body_node, :livecheck) | 
					
						
							|  |  |  |           return if livecheck_node.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           skip = find_every_method_call_by_name(livecheck_node, :skip).first.present? | 
					
						
							|  |  |  |           return if skip.present? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           livecheck_regex_node = find_every_method_call_by_name(livecheck_node, :regex).first | 
					
						
							|  |  |  |           return if livecheck_regex_node.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           regex_node = livecheck_regex_node.descendants.first | 
					
						
							|  |  |  |           pattern = string_content(find_strings(regex_node).first) | 
					
						
							|  |  |  |           match = pattern.match(TAR_PATTERN) | 
					
						
							|  |  |  |           return if match.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           offending_node(regex_node) | 
					
						
							| 
									
										
										
										
											2021-01-12 13:58:53 +11:00
										 |  |  |           problem "Use `\\.t` instead of `#{match}`" do |corrector| | 
					
						
							|  |  |  |             node = find_strings(regex_node).first | 
					
						
							| 
									
										
										
										
											2020-08-13 18:05:02 +05:30
										 |  |  |             correct = node.source.gsub(TAR_PATTERN, "\\.t") | 
					
						
							|  |  |  |             corrector.replace(node.source_range, correct) | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       # This cop ensures that a `regex` is provided when `strategy :page_match` is specified | 
					
						
							| 
									
										
										
										
											2020-11-05 17:17:03 -05:00
										 |  |  |       # in the `livecheck` block. | 
					
						
							| 
									
										
										
										
											2020-08-13 18:05:02 +05:30
										 |  |  |       # | 
					
						
							|  |  |  |       # @api private | 
					
						
							|  |  |  |       class LivecheckRegexIfPageMatch < FormulaCop | 
					
						
							|  |  |  |         def audit_formula(_node, _class_node, _parent_class_node, body_node) | 
					
						
							|  |  |  |           livecheck_node = find_block(body_node, :livecheck) | 
					
						
							|  |  |  |           return if livecheck_node.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           skip = find_every_method_call_by_name(livecheck_node, :skip).first.present? | 
					
						
							|  |  |  |           return if skip.present? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           livecheck_strategy_node = find_every_method_call_by_name(livecheck_node, :strategy).first | 
					
						
							|  |  |  |           return if livecheck_strategy_node.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           strategy = livecheck_strategy_node.descendants.first.source | 
					
						
							|  |  |  |           return if strategy != ":page_match" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           livecheck_regex_node = find_every_method_call_by_name(livecheck_node, :regex).first | 
					
						
							|  |  |  |           return if livecheck_regex_node.present? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           offending_node(livecheck_node) | 
					
						
							|  |  |  |           problem "A `regex` is required if `strategy :page_match` is present." | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       # This cop ensures that the `regex` provided to livecheck is case-insensitive, | 
					
						
							|  |  |  |       # unless sensitivity is explicitly required for proper matching. | 
					
						
							|  |  |  |       # | 
					
						
							|  |  |  |       # @api private | 
					
						
							|  |  |  |       class LivecheckRegexCaseInsensitive < FormulaCop | 
					
						
							| 
									
										
										
										
											2021-01-12 13:58:53 +11:00
										 |  |  |         extend AutoCorrector | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         MSG = "Regexes should be case-insensitive unless sensitivity is explicitly required for proper matching." | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-13 18:05:02 +05:30
										 |  |  |         def audit_formula(_node, _class_node, _parent_class_node, body_node) | 
					
						
							| 
									
										
										
										
											2020-11-27 12:49:49 -05:00
										 |  |  |           return if tap_style_exception? :regex_case_sensitive_allowlist | 
					
						
							| 
									
										
										
										
											2020-08-13 18:05:02 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  |           livecheck_node = find_block(body_node, :livecheck) | 
					
						
							|  |  |  |           return if livecheck_node.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           skip = find_every_method_call_by_name(livecheck_node, :skip).first.present? | 
					
						
							|  |  |  |           return if skip.present? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           livecheck_regex_node = find_every_method_call_by_name(livecheck_node, :regex).first | 
					
						
							|  |  |  |           return if livecheck_regex_node.blank? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           regex_node = livecheck_regex_node.descendants.first | 
					
						
							|  |  |  |           options_node = regex_node.regopt | 
					
						
							|  |  |  |           return if options_node.source.include?("i") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           offending_node(regex_node) | 
					
						
							| 
									
										
										
										
											2021-01-12 13:58:53 +11:00
										 |  |  |           problem MSG do |corrector| | 
					
						
							|  |  |  |             node = regex_node.regopt | 
					
						
							| 
									
										
										
										
											2020-08-13 18:05:02 +05:30
										 |  |  |             corrector.replace(node.source_range, "i#{node.source}".chars.sort.join) | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | end |