class LinkCheck
def check_schemes(link, line)
def check_schemes(link, line) case link.scheme when 'mailto' handle_mailto(link, line) when 'tel' handle_tel(link, line) when 'http' return unless @options[:enforce_https] add_issue("#{link.href} is not an HTTPS link", line: line) end end
def external_link_check(link, line)
def external_link_check(link, line) if !link.exists? add_issue("trying to find hash of #{link.href}, but #{link.absolute_path} does not exist", line: line) else target_html = create_nokogiri link.absolute_path unless hash_check target_html, link.hash add_issue("linking to #{link.href}, but #{link.hash} does not exist", line: line) end end end
def handle_hash(link, line)
def handle_hash(link, line) if link.internal? unless hash_check @html, link.hash add_issue("linking to internal hash ##{link.hash} that does not exist", line: line) end elsif link.external? external_link_check(link, line) end end
def handle_mailto(link, line)
def handle_mailto(link, line) if link.path.empty? add_issue("#{link.href} contains no email address", line: line) elsif !link.path.include?('@') add_issue("#{link.href} contains an invalid email address", line: line) end end
def handle_tel(link, line)
def handle_tel(link, line) add_issue("#{link.href} contains no phone number", line: line) if link.path.empty? end
def hash_check(html, href_hash)
def hash_check(html, href_hash) decoded_href_hash = URI.decode(href_hash) html.xpath("//*[case_insensitive_equals(@id, '#{href_hash}')]", \ "//*[case_insensitive_equals(@name, '#{href_hash}')]", \ "//*[case_insensitive_equals(@id, '#{decoded_href_hash}')]", \ "//*[case_insensitive_equals(@name, '#{decoded_href_hash}')]", \ XpathFunctions.new).length > 0 end
def missing_href?
def missing_href? blank?(@link.href) && blank?(@link.name) && blank?(@link.id) end
def placeholder?
def placeholder? (!blank?(@link.id) || !blank?(@link.name)) && @link.href.nil? end
def run
def run @html.css('a, link').each do |node| @link = create_element(node) line = @node.line next if @link.ignore? next if placeholder? next if @link.allow_hash_href? && @link.href == '#' # is it even a valid URL? unless @link.valid? add_issue("#{@link.href} is an invalid URL", line: line) next end check_schemes(@link, line) # is there even an href? if missing_href? # HTML5 allows dropping the href: http://git.io/vBX0z next if @html.internal_subset.name == 'html' && @html.internal_subset.external_id.nil? add_issue('anchor has no href attribute', line: line) next end # intentionally here because we still want valid? & missing_href? to execute next if @link.non_http_remote? # does the file even exist? if @link.remote? add_to_external_urls(@link.href, line) next elsif !@link.internal? && !@link.exists? add_issue("internally linking to #{@link.href}, which does not exist", line: line) end # does the local directory have a trailing slash? if @link.unslashed_directory? @link.absolute_path add_issue("internally linking to a directory #{@link.absolute_path} without trailing slash", line: line) next end # verify the target hash handle_hash(@link, line) if @link.hash end external_urls end