html-proofer 2.3.0 → 3.0.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.
Files changed (171) hide show
  1. checksums.yaml +4 -4
  2. data/bin/htmlproofer +85 -0
  3. data/lib/html-proofer/cache.rb +153 -0
  4. data/lib/html-proofer/check/favicon.rb +15 -0
  5. data/lib/html-proofer/check/html.rb +21 -0
  6. data/lib/html-proofer/check/images.rb +47 -0
  7. data/lib/html-proofer/check/links.rb +120 -0
  8. data/lib/html-proofer/check/scripts.rb +28 -0
  9. data/lib/html-proofer/check.rb +63 -0
  10. data/lib/html-proofer/configuration.rb +56 -0
  11. data/lib/html-proofer/element.rb +165 -0
  12. data/lib/{html/proofer/check_runner → html-proofer}/issue.rb +8 -10
  13. data/lib/html-proofer/log.rb +49 -0
  14. data/lib/html-proofer/runner.rb +160 -0
  15. data/lib/html-proofer/url_validator.rb +218 -0
  16. data/lib/html-proofer/utils.rb +40 -0
  17. data/lib/html-proofer/version.rb +3 -0
  18. data/lib/html-proofer.rb +47 -0
  19. metadata +64 -289
  20. data/.gitignore +0 -26
  21. data/.travis.yml +0 -12
  22. data/Gemfile +0 -3
  23. data/LICENSE.txt +0 -22
  24. data/README.md +0 -265
  25. data/Rakefile +0 -21
  26. data/bin/htmlproof +0 -71
  27. data/html-proofer.gemspec +0 -31
  28. data/lib/html/proofer/check_runner.rb +0 -62
  29. data/lib/html/proofer/checkable.rb +0 -164
  30. data/lib/html/proofer/checks/favicon.rb +0 -21
  31. data/lib/html/proofer/checks/html.rb +0 -40
  32. data/lib/html/proofer/checks/images.rb +0 -57
  33. data/lib/html/proofer/checks/links.rb +0 -107
  34. data/lib/html/proofer/checks/scripts.rb +0 -39
  35. data/lib/html/proofer/log.rb +0 -38
  36. data/lib/html/proofer/url_validator.rb +0 -135
  37. data/lib/html/proofer/utils.rb +0 -24
  38. data/lib/html/proofer/version.rb +0 -6
  39. data/lib/html/proofer.rb +0 -189
  40. data/script/bootstrap +0 -5
  41. data/spec/html/proofer/checkable_spec.rb +0 -47
  42. data/spec/html/proofer/command_spec.rb +0 -88
  43. data/spec/html/proofer/favicon_spec.rb +0 -47
  44. data/spec/html/proofer/fixtures/favicon/favicon_absent.html +0 -4
  45. data/spec/html/proofer/fixtures/favicon/favicon_absent_apple.html +0 -7
  46. data/spec/html/proofer/fixtures/favicon/favicon_broken.html +0 -7
  47. data/spec/html/proofer/fixtures/favicon/favicon_broken_but_ignored.html +0 -7
  48. data/spec/html/proofer/fixtures/favicon/favicon_present.html +0 -7
  49. data/spec/html/proofer/fixtures/favicon/favicon_present_shortcut.html +0 -7
  50. data/spec/html/proofer/fixtures/html/div_inside_head.html +0 -6
  51. data/spec/html/proofer/fixtures/html/html5_tags.html +0 -9
  52. data/spec/html/proofer/fixtures/html/invalid_tag.html +0 -3
  53. data/spec/html/proofer/fixtures/html/missing_closing_quotes.html +0 -5
  54. data/spec/html/proofer/fixtures/html/opening_and_ending_tag_mismatch.html +0 -7
  55. data/spec/html/proofer/fixtures/html/svg_elements.html +0 -729
  56. data/spec/html/proofer/fixtures/html/unescaped_ampersand_in_attribute.html +0 -4
  57. data/spec/html/proofer/fixtures/html/unmatched_end_tag.html +0 -5
  58. data/spec/html/proofer/fixtures/images/emptyImageAltText.html +0 -10
  59. data/spec/html/proofer/fixtures/images/existingImageExternal.html +0 -9
  60. data/spec/html/proofer/fixtures/images/gpl.png +0 -0
  61. data/spec/html/proofer/fixtures/images/ignorableAltViaOptions.html +0 -13
  62. data/spec/html/proofer/fixtures/images/ignorableImages.html +0 -10
  63. data/spec/html/proofer/fixtures/images/ignoreAltButNotLink.html +0 -13
  64. data/spec/html/proofer/fixtures/images/image_missing_protocol_invalid.html +0 -9
  65. data/spec/html/proofer/fixtures/images/image_missing_protocol_valid.html +0 -9
  66. data/spec/html/proofer/fixtures/images/missingImageAlt.html +0 -9
  67. data/spec/html/proofer/fixtures/images/missingImageAltText.html +0 -9
  68. data/spec/html/proofer/fixtures/images/missingImageExternal.html +0 -9
  69. data/spec/html/proofer/fixtures/images/missingImageInternal.html +0 -9
  70. data/spec/html/proofer/fixtures/images/missingImageSrc.html +0 -9
  71. data/spec/html/proofer/fixtures/images/relativeToSelf.html +0 -2
  72. data/spec/html/proofer/fixtures/images/rootRelativeImages.html +0 -2
  73. data/spec/html/proofer/fixtures/images/srcSetCheck.html +0 -7
  74. data/spec/html/proofer/fixtures/images/srcSetIgnorable.html +0 -13
  75. data/spec/html/proofer/fixtures/images/srcSetMissingAlt.html +0 -7
  76. data/spec/html/proofer/fixtures/images/srcSetMissingImage.html +0 -7
  77. data/spec/html/proofer/fixtures/images/terribleImageName.html +0 -9
  78. data/spec/html/proofer/fixtures/images/workingDataURIImage.html +0 -3
  79. data/spec/html/proofer/fixtures/links/_site/folder.html/index.html +0 -1
  80. data/spec/html/proofer/fixtures/links/anchors_in_pre.html +0 -12
  81. data/spec/html/proofer/fixtures/links/attributeWithDash.html +0 -8
  82. data/spec/html/proofer/fixtures/links/blank_mailto_link.html +0 -9
  83. data/spec/html/proofer/fixtures/links/blank_tel_link.html +0 -9
  84. data/spec/html/proofer/fixtures/links/brokenHashExternal.html +0 -11
  85. data/spec/html/proofer/fixtures/links/brokenHashInternal.html +0 -14
  86. data/spec/html/proofer/fixtures/links/brokenHashOnTheWeb.html +0 -2
  87. data/spec/html/proofer/fixtures/links/brokenInternalLink.html +0 -0
  88. data/spec/html/proofer/fixtures/links/brokenLinkExternal.html +0 -11
  89. data/spec/html/proofer/fixtures/links/brokenLinkInternal.html +0 -10
  90. data/spec/html/proofer/fixtures/links/brokenLinkWithNumber.html +0 -8
  91. data/spec/html/proofer/fixtures/links/brokenUnixLinks.html +0 -5
  92. data/spec/html/proofer/fixtures/links/broken_hash_with_query.html +0 -9
  93. data/spec/html/proofer/fixtures/links/checkSSLLinks.html +0 -1
  94. data/spec/html/proofer/fixtures/links/ensure_typhoeus_options.html +0 -1
  95. data/spec/html/proofer/fixtures/links/erstiebegr%C3%BC%C3%9Fung.html +0 -0
  96. data/spec/html/proofer/fixtures/links/erstiebegr/303/274/303/237ung.html +0 -0
  97. data/spec/html/proofer/fixtures/links/escape_pipes.html +0 -9
  98. data/spec/html/proofer/fixtures/links/file.foo +0 -11
  99. data/spec/html/proofer/fixtures/links/folder/anchorLink.html +0 -0
  100. data/spec/html/proofer/fixtures/links/folder/assets/barrel.png +0 -0
  101. data/spec/html/proofer/fixtures/links/folder/index.html +0 -0
  102. data/spec/html/proofer/fixtures/links/folder/multiples/catalog/file.html +0 -8
  103. data/spec/html/proofer/fixtures/links/folder/multiples/javadoc/file.html +0 -8
  104. data/spec/html/proofer/fixtures/links/folder/relativeImage.html +0 -2
  105. data/spec/html/proofer/fixtures/links/folder-php/index.php +0 -2
  106. data/spec/html/proofer/fixtures/links/githubHash.html +0 -1
  107. data/spec/html/proofer/fixtures/links/gpl.png +0 -0
  108. data/spec/html/proofer/fixtures/links/hashReferringToSelf.html +0 -44
  109. data/spec/html/proofer/fixtures/links/head_link_href.html +0 -7
  110. data/spec/html/proofer/fixtures/links/head_link_href_absent.html +0 -7
  111. data/spec/html/proofer/fixtures/links/head_link_href_empty.html +0 -7
  112. data/spec/html/proofer/fixtures/links/ignorableLinks.html +0 -13
  113. data/spec/html/proofer/fixtures/links/ignorableLinksViaOptions.html +0 -13
  114. data/spec/html/proofer/fixtures/links/invalid_mailto_link.html +0 -9
  115. data/spec/html/proofer/fixtures/links/javascript_link.html +0 -9
  116. data/spec/html/proofer/fixtures/links/linkToFolder.html +0 -9
  117. data/spec/html/proofer/fixtures/links/linkTranslatedViaHrefSwap.html +0 -9
  118. data/spec/html/proofer/fixtures/links/linkWithHttps.html +0 -9
  119. data/spec/html/proofer/fixtures/links/linkWithRedirect.html +0 -12
  120. data/spec/html/proofer/fixtures/links/link_directory_without_slash.html +0 -1
  121. data/spec/html/proofer/fixtures/links/link_missing_protocol_invalid.html +0 -9
  122. data/spec/html/proofer/fixtures/links/link_missing_protocol_valid.html +0 -9
  123. data/spec/html/proofer/fixtures/links/link_pointing_to_directory.html +0 -1
  124. data/spec/html/proofer/fixtures/links/links_in_pre.html +0 -13
  125. data/spec/html/proofer/fixtures/links/mailto_link.html +0 -9
  126. data/spec/html/proofer/fixtures/links/missingLinkHref.html +0 -9
  127. data/spec/html/proofer/fixtures/links/multipleProblems.html +0 -11
  128. data/spec/html/proofer/fixtures/links/nodupe.html +0 -1
  129. data/spec/html/proofer/fixtures/links/non_standard_characters.html +0 -10
  130. data/spec/html/proofer/fixtures/links/notarealhash.html +0 -0
  131. data/spec/html/proofer/fixtures/links/other_protocols.html +0 -4
  132. data/spec/html/proofer/fixtures/links/placeholder_with_empty_id.html +0 -1
  133. data/spec/html/proofer/fixtures/links/placeholder_with_id.html +0 -1
  134. data/spec/html/proofer/fixtures/links/placeholder_with_name.html +0 -1
  135. data/spec/html/proofer/fixtures/links/redirected_error.html +0 -1
  136. data/spec/html/proofer/fixtures/links/relativeLinks.html +0 -4
  137. data/spec/html/proofer/fixtures/links/rootLink/folder/index.html +0 -1
  138. data/spec/html/proofer/fixtures/links/rootLink/index.html +0 -1
  139. data/spec/html/proofer/fixtures/links/rootLink/rootLink.html +0 -9
  140. data/spec/html/proofer/fixtures/links/tel_link.html +0 -9
  141. data/spec/html/proofer/fixtures/links/urlencoded-href.html +0 -2
  142. data/spec/html/proofer/fixtures/links/utf8Link.html +0 -2
  143. data/spec/html/proofer/fixtures/resources/Screen Shot 2012-08-09 at 7.51.18 AM.png +0 -0
  144. data/spec/html/proofer/fixtures/resources/books/assets/getting-good-with-git.jpg +0 -0
  145. data/spec/html/proofer/fixtures/resources/books/assets/pro-git.jpg +0 -0
  146. data/spec/html/proofer/fixtures/resources/books/assets/version-control-with-git.jpg +0 -0
  147. data/spec/html/proofer/fixtures/resources/books/nestedRelativeImages.html +0 -5
  148. data/spec/html/proofer/fixtures/resources/gpl.png +0 -0
  149. data/spec/html/proofer/fixtures/scripts/ignorableLinksViaOptions.html +0 -4
  150. data/spec/html/proofer/fixtures/scripts/script.js +0 -1
  151. data/spec/html/proofer/fixtures/scripts/script_broken_external.html +0 -9
  152. data/spec/html/proofer/fixtures/scripts/script_content.html +0 -9
  153. data/spec/html/proofer/fixtures/scripts/script_content_absent.html +0 -9
  154. data/spec/html/proofer/fixtures/scripts/script_in_pre.html +0 -5
  155. data/spec/html/proofer/fixtures/scripts/script_missing_internal.html +0 -9
  156. data/spec/html/proofer/fixtures/scripts/script_valid_internal.html +0 -9
  157. data/spec/html/proofer/fixtures/sorting/issue/broken_image_one.html +0 -1
  158. data/spec/html/proofer/fixtures/sorting/issue/broken_image_two.html +0 -4
  159. data/spec/html/proofer/fixtures/sorting/path/multiple_issues.html +0 -11
  160. data/spec/html/proofer/fixtures/sorting/path/single_issue.html +0 -1
  161. data/spec/html/proofer/fixtures/sorting/status/a_404.html +0 -1
  162. data/spec/html/proofer/fixtures/sorting/status/broken_link.html +0 -3
  163. data/spec/html/proofer/fixtures/sorting/status/missing_redirect.html +0 -1
  164. data/spec/html/proofer/fixtures/utils/lang-jp.html +0 -1
  165. data/spec/html/proofer/html_spec.rb +0 -57
  166. data/spec/html/proofer/images_spec.rb +0 -147
  167. data/spec/html/proofer/links_spec.rb +0 -364
  168. data/spec/html/proofer/scripts_spec.rb +0 -47
  169. data/spec/html/proofer/utils_spec.rb +0 -14
  170. data/spec/html/proofer_spec.rb +0 -122
  171. data/spec/spec_helper.rb +0 -52
@@ -1,57 +0,0 @@
1
- # encoding: utf-8
2
-
3
- class ImageCheckable < ::HTML::Proofer::Checkable
4
-
5
- SCREEN_SHOT_REGEX = /Screen(?: |%20)Shot(?: |%20)\d+-\d+-\d+(?: |%20)at(?: |%20)\d+.\d+.\d+/
6
-
7
- def alt
8
- @alt
9
- end
10
-
11
- def empty_alt_tag?
12
- alt.strip.empty?
13
- end
14
-
15
- def terrible_filename?
16
- src =~ SCREEN_SHOT_REGEX
17
- end
18
-
19
- def src
20
- real_attr(@src) || real_attr(@srcset)
21
- end
22
-
23
- def missing_src?
24
- !src
25
- end
26
-
27
- end
28
-
29
- class ImageCheck < ::HTML::Proofer::CheckRunner
30
- def run
31
- @html.css('img').each do |i|
32
- img = ImageCheckable.new i, self
33
-
34
- next if img.ignore?
35
-
36
- # screenshot filenames should return because of terrible names
37
- next add_issue("image has a terrible filename (#{img.src})", i.line) if img.terrible_filename?
38
-
39
- # does the image exist?
40
- if img.missing_src?
41
- add_issue('image has no src or srcset attribute', i.line)
42
- else
43
- if img.remote?
44
- add_to_external_urls img.src
45
- else
46
- add_issue("internal image #{img.src} does not exist", i.line) unless img.exists?
47
- end
48
- end
49
-
50
- if img.alt.nil? || (img.empty_alt_tag? && !img.ignore_empty_alt?)
51
- add_issue("image #{img.src} does not have an alt attribute", i.line)
52
- end
53
- end
54
-
55
- external_urls
56
- end
57
- end
@@ -1,107 +0,0 @@
1
- # encoding: utf-8
2
- class LinkCheckable < ::HTML::Proofer::Checkable
3
-
4
- def href
5
- real_attr @href
6
- end
7
-
8
- def id
9
- real_attr @id
10
- end
11
-
12
- def name
13
- real_attr @name
14
- end
15
-
16
- def missing_href?
17
- href.nil? && name.nil? && id.nil?
18
- end
19
-
20
- def placeholder?
21
- (id || name) && href.nil?
22
- end
23
-
24
- end
25
-
26
- class LinkCheck < ::HTML::Proofer::CheckRunner
27
- include HTML::Utils
28
-
29
- def run
30
- @html.css('a, link').each do |l|
31
- link = LinkCheckable.new l, self
32
-
33
- next if link.ignore?
34
- next if link.href =~ /^javascript:/ # can't put this in ignore? because the URI does not parse
35
- next if link.placeholder?
36
-
37
- # is it even a valid URL?
38
- unless link.valid?
39
- add_issue("#{link.href} is an invalid URL", l.line)
40
- next
41
- end
42
-
43
- case link.scheme
44
- when 'mailto'
45
- if link.path.empty?
46
- add_issue("#{link.href} contains no email address", l.line)
47
- elsif !link.path.include?('@')
48
- add_issue("#{link.href} contains an invalid email address", l.line)
49
- end
50
- when 'tel'
51
- add_issue("#{link.href} contains no phone number", l.line) if link.path.empty?
52
- end
53
-
54
- # is there even a href?
55
- if link.missing_href?
56
- add_issue('anchor has no href attribute', l.line)
57
- next
58
- end
59
-
60
- # intentionally here because we still want valid? & missing_href? to execute
61
- next if link.non_http_remote?
62
-
63
- # does the file even exist?
64
- if link.remote?
65
- add_to_external_urls link.href
66
- next
67
- elsif !link.internal?
68
- add_issue("internally linking to #{link.href}, which does not exist", l.line) unless link.exists?
69
- end
70
-
71
- # does the local directory have a trailing slash?
72
- if link.unslashed_directory? link.absolute_path
73
- add_issue("internally linking to a directory #{link.absolute_path} without trailing slash", l.line)
74
- next
75
- end
76
-
77
- # verify the target hash
78
- if link.hash
79
- if link.internal?
80
- unless hash_check @html, link.hash
81
- add_issue("linking to internal hash ##{link.hash} that does not exist", l.line)
82
- end
83
- elsif link.external?
84
- external_link_check(link)
85
- end
86
- end
87
- end
88
-
89
- external_urls
90
- end
91
-
92
- def external_link_check(link)
93
- if !link.exists?
94
- add_issue("trying to find hash of #{link.href}, but #{link.absolute_path} does not exist", link.line)
95
- else
96
- target_html = create_nokogiri link.absolute_path
97
- unless hash_check target_html, link.hash
98
- add_issue("linking to #{link.href}, but #{link.hash} does not exist", link.line)
99
- end
100
- end
101
- end
102
-
103
- def hash_check(html, href_hash)
104
- html.xpath("//*[@id='#{href_hash}']", "//*[@name='#{href_hash}']").length > 0
105
- end
106
-
107
- end
@@ -1,39 +0,0 @@
1
- # encoding: utf-8
2
-
3
- class ScriptCheckable < ::HTML::Proofer::Checkable
4
-
5
- def src
6
- real_attr @src
7
- end
8
-
9
- def missing_src?
10
- !src
11
- end
12
-
13
- def blank?
14
- @text.strip.empty?
15
- end
16
-
17
- end
18
-
19
- class ScriptCheck < ::HTML::Proofer::CheckRunner
20
- def run
21
- @html.css('script').each do |s|
22
- script = ScriptCheckable.new s, self
23
-
24
- next if script.ignore?
25
- next unless script.blank?
26
-
27
- # does the script exist?
28
- if script.missing_src?
29
- add_issue('script is empty and has no src attribute', s.line)
30
- elsif script.remote?
31
- add_to_external_urls script.src
32
- else
33
- add_issue("internal script #{script.src} does not exist", s.line) unless script.exists?
34
- end
35
- end
36
-
37
- external_urls
38
- end
39
- end
@@ -1,38 +0,0 @@
1
- require 'yell'
2
- require 'colored'
3
-
4
- module HTML
5
- class Proofer
6
- class Log
7
- include Yell::Loggable
8
-
9
- def initialize(verbose)
10
- log_level = verbose ? :debug : :info
11
-
12
- @logger = Yell.new(:format => false, \
13
- :name => 'HTML::Proofer', \
14
- :level => "gte.#{log_level}") do |l|
15
- l.adapter :stdout, :level => [:debug, :info, :warn]
16
- l.adapter :stderr, :level => [:error, :fatal]
17
- end
18
- end
19
-
20
- def log(level, color, message)
21
- @logger.send level, colorize(color, message)
22
- end
23
-
24
- def colorize(color, message)
25
- if $stdout.isatty && $stderr.isatty
26
- Colored.colorize(message, foreground: color)
27
- else
28
- message
29
- end
30
- end
31
-
32
- # dumb override to play nice with Typhoeus/Ethon
33
- def debug(message = nil)
34
- log(:debug, :yellow, message) unless message.nil?
35
- end
36
- end
37
- end
38
- end
@@ -1,135 +0,0 @@
1
- require 'typhoeus'
2
- require 'uri'
3
- require_relative './utils'
4
-
5
- module HTML
6
- class Proofer
7
- class UrlValidator
8
- include Utils
9
-
10
- attr_accessor :logger, :external_urls, :hydra
11
-
12
- def initialize(logger, external_urls, options, typhoeus_opts, hydra_opts)
13
- @logger = logger
14
- @external_urls = external_urls
15
- @failed_tests = []
16
- @options = options
17
- @hydra = Typhoeus::Hydra.new(hydra_opts)
18
- @typhoeus_opts = typhoeus_opts
19
- end
20
-
21
- def run
22
- external_link_checker(external_urls)
23
- @failed_tests
24
- end
25
-
26
- # Proofer runs faster if we pull out all the external URLs and run the checks
27
- # at the end. Otherwise, we're halting the consuming process for every file during
28
- # the check_directory_of_files process.
29
- #
30
- # In addition, sorting the list lets libcurl keep connections to the same hosts alive.
31
- #
32
- # Finally, we'll first make a HEAD request, rather than GETing all the contents.
33
- # If the HEAD fails, we'll fall back to GET, as some servers are not configured
34
- # for HEAD. If we've decided to check for hashes, we must do a GET--HEAD is
35
- # not an option.
36
- def external_link_checker(external_urls)
37
- external_urls = Hash[external_urls.sort]
38
-
39
- count = external_urls.length
40
- check_text = "#{count} " << (count == 1 ? 'external link' : 'external links')
41
- logger.log :info, :blue, "Checking #{check_text}..."
42
-
43
- Ethon.logger = logger # log from Typhoeus/Ethon
44
-
45
- url_processor(external_urls)
46
-
47
- logger.log :debug, :yellow, "Running requests for all #{hydra.queued_requests.size} external URLs..."
48
- hydra.run
49
- end
50
-
51
- def url_processor(external_urls)
52
- external_urls.each_pair do |href, filenames|
53
- href = clean_url(href)
54
- if hash?(href) && @options[:check_external_hash]
55
- queue_request(:get, href, filenames)
56
- else
57
- queue_request(:head, href, filenames)
58
- end
59
- end
60
- end
61
-
62
- def clean_url(href)
63
- Addressable::URI.parse(href).normalize
64
- end
65
-
66
- def queue_request(method, href, filenames)
67
- request = Typhoeus::Request.new(href, @typhoeus_opts.merge({ :method => method }))
68
- request.on_complete { |response| response_handler(response, filenames) }
69
- hydra.queue request
70
- end
71
-
72
- def response_handler(response, filenames)
73
- effective_url = response.options[:effective_url]
74
- href = response.request.base_url.to_s
75
- method = response.request.options[:method]
76
- response_code = response.code
77
- debug_msg = "Received a #{response_code} for #{href}"
78
- debug_msg << " in #{filenames.join(' ')}" unless filenames.nil?
79
- logger.log :debug, :yellow, debug_msg
80
-
81
- if response_code.between?(200, 299)
82
- check_hash_in_2xx_response(href, effective_url, response, filenames)
83
- elsif response.timed_out?
84
- handle_timeout(href, filenames, response_code)
85
- elsif method == :head
86
- queue_request(:get, href, filenames)
87
- else
88
- return if @options[:only_4xx] && !response_code.between?(400, 499)
89
- # Received a non-successful http response.
90
- add_failed_tests filenames, "External link #{href} failed: #{response_code} #{response.return_message}", response_code
91
- end
92
- end
93
-
94
- # Even though the response was a success, we may have been asked to check
95
- # if the hash on the URL exists on the page
96
- def check_hash_in_2xx_response(href, effective_url, response, filenames)
97
- return if @options[:only_4xx]
98
- return unless @options[:check_external_hash]
99
- return unless (hash = hash?(href))
100
-
101
- body_doc = create_nokogiri(response.body)
102
-
103
- # user-content is a special addition by GitHub.
104
- xpath = %(//*[@name="#{hash}"]|//*[@id="#{hash}"])
105
- if URI.parse(href).host.match(/github\.com/i)
106
- xpath << %(|//*[@name="user-content-#{hash}"]|//*[@id="user-content-#{hash}"])
107
- end
108
-
109
- return unless body_doc.xpath(xpath).empty?
110
-
111
- add_failed_tests filenames, "External link #{href} failed: #{effective_url} exists, but the hash '#{hash}' does not", response.code
112
- end
113
-
114
- def handle_timeout(href, filenames, response_code)
115
- return if @options[:only_4xx]
116
- add_failed_tests filenames, "External link #{href} failed: got a time out", response_code
117
- end
118
-
119
- def add_failed_tests(filenames, desc, status = nil)
120
- if filenames.nil?
121
- @failed_tests << CheckRunner::Issue.new('', desc, nil, status)
122
- else
123
- filenames.each { |f| @failed_tests << CheckRunner::Issue.new(f, desc, nil, status) }
124
- end
125
- end
126
-
127
- def hash?(url)
128
- URI.parse(url).fragment
129
- rescue URI::InvalidURIError
130
- nil
131
- end
132
-
133
- end
134
- end
135
- end
@@ -1,24 +0,0 @@
1
- require 'nokogiri'
2
-
3
- module HTML
4
- module Utils
5
- def create_nokogiri(path)
6
- if File.exist? path
7
- content = File.open(path).read
8
- else
9
- content = path
10
- end
11
-
12
- Nokogiri::HTML(content)
13
- end
14
- module_function :create_nokogiri
15
-
16
- def swap(href, replacement)
17
- replacement.each do |link, replace|
18
- href = href.gsub(link, replace)
19
- end
20
- href
21
- end
22
- module_function :swap
23
- end
24
- end
@@ -1,6 +0,0 @@
1
- module HTML
2
- class Proofer
3
- VERSION = '2.3.0'
4
- end
5
- end
6
-
data/lib/html/proofer.rb DELETED
@@ -1,189 +0,0 @@
1
- def require_all(path)
2
- glob = File.join(File.dirname(__FILE__), path, '*.rb')
3
- Dir[glob].each do |f|
4
- require f
5
- end
6
- end
7
-
8
- require_all 'proofer'
9
- require_all 'proofer/check_runner'
10
- require_all 'proofer/checks'
11
- require_relative './proofer/utils'
12
-
13
- require 'parallel'
14
-
15
- begin
16
- require 'awesome_print'
17
- rescue LoadError; end
18
-
19
- module HTML
20
-
21
- class Proofer
22
- include Utils
23
-
24
- attr_reader :options, :typhoeus_opts, :hydra_opts, :parallel_opts
25
-
26
- TYPHOEUS_DEFAULTS = {
27
- :followlocation => true,
28
- :headers => {
29
- "User-Agent" => "Mozilla/5.0 (compatible; HTML Proofer/#{VERSION}; +https://github.com/gjtorikian/html-proofer)"
30
- }
31
- }
32
-
33
- def initialize(src, opts = {})
34
- @src = src
35
-
36
- @proofer_opts = {
37
- :ext => '.html',
38
- :check_favicon => false,
39
- :href_swap => [],
40
- :href_ignore => [],
41
- :file_ignore => [],
42
- :url_ignore => [],
43
- :check_external_hash => false,
44
- :alt_ignore => [],
45
- :empty_alt_ignore => false,
46
- :disable_external => false,
47
- :verbose => false,
48
- :only_4xx => false,
49
- :directory_index_file => 'index.html',
50
- :check_html => false,
51
- :error_sort => :path,
52
- :checks_to_ignore => []
53
- }
54
-
55
- @typhoeus_opts = TYPHOEUS_DEFAULTS.merge(opts[:typhoeus] || {})
56
- opts.delete(:typhoeus)
57
-
58
- @hydra_opts = opts[:hydra] || {}
59
- opts.delete(:hydra)
60
-
61
- # fall back to parallel defaults
62
- @parallel_opts = opts[:parallel] || {}
63
- opts.delete(:parallel)
64
-
65
- @options = @proofer_opts.merge(opts)
66
-
67
- @failed_tests = []
68
- end
69
-
70
- def logger
71
- @logger ||= HTML::Proofer::Log.new(@options[:verbose])
72
- end
73
-
74
- def run
75
- count = checks.length
76
- check_text = "#{checks} " << (count == 1 ? 'check' : 'checks')
77
- logger.log :info, :blue, "Running #{check_text} on #{@src} on *#{@options[:ext]}... \n\n"
78
-
79
- if @src.is_a?(Array) && !@options[:disable_external]
80
- check_list_of_links
81
- else
82
- check_directory_of_files
83
- end
84
-
85
- if @failed_tests.empty?
86
- logger.log :info, :green, 'HTML-Proofer finished successfully.'
87
- else
88
- print_failed_tests
89
- end
90
- end
91
-
92
- def check_list_of_links
93
- if @options[:href_swap]
94
- @src = @src.map do |external_url|
95
- swap(external_url, @options[:href_swap])
96
- end
97
- end
98
- external_urls = Hash[*@src.map { |s| [s, nil] }.flatten]
99
- validate_urls(external_urls)
100
- end
101
-
102
- # Collects any external URLs found in a directory of files. Also collectes
103
- # every failed test from check_files_for_internal_woes.
104
- # Sends the external URLs to Typhoeus for batch processing.
105
- def check_directory_of_files
106
- external_urls = {}
107
- results = check_files_for_internal_woes
108
-
109
- results.each do |item|
110
- external_urls.merge!(item[:external_urls])
111
- @failed_tests.concat(item[:failed_tests])
112
- end
113
-
114
- validate_urls(external_urls) unless @options[:disable_external]
115
-
116
- logger.log :info, :blue, "Ran on #{files.length} files!\n\n"
117
- end
118
-
119
- # Walks over each implemented check and runs them on the files, in parallel.
120
- def check_files_for_internal_woes
121
- Parallel.map(files, @parallel_opts) do |path|
122
- html = create_nokogiri(path)
123
- result = { :external_urls => {}, :failed_tests => [] }
124
-
125
- checks.each do |klass|
126
- logger.log :debug, :yellow, "Checking #{klass.to_s.downcase} on #{path} ..."
127
- check = Object.const_get(klass).new(@src, path, html, @options, @typhoeus_opts, @hydra_opts, @parallel_opts)
128
- check.run
129
- result[:external_urls].merge!(check.external_urls)
130
- result[:failed_tests].concat(check.issues) if check.issues.length > 0
131
- end
132
- result
133
- end
134
- end
135
-
136
- def validate_urls(external_urls)
137
- url_validator = HTML::Proofer::UrlValidator.new(logger, external_urls, @options, @typhoeus_opts, @hydra_opts)
138
- @failed_tests.concat(url_validator.run)
139
- end
140
-
141
- def files
142
- if File.directory? @src
143
- pattern = File.join(@src, '**', "*#{@options[:ext]}")
144
- files = Dir.glob(pattern).select { |fn| File.file? fn }
145
- files.reject { |f| ignore_file?(f) }
146
- elsif File.extname(@src) == @options[:ext]
147
- [@src].reject { |f| ignore_file?(f) }
148
- else
149
- []
150
- end
151
- end
152
-
153
- def ignore_file?(file)
154
- options[:file_ignore].each do |pattern|
155
- return true if pattern.is_a?(String) && pattern == file
156
- return true if pattern.is_a?(Regexp) && pattern =~ file
157
- end
158
-
159
- false
160
- end
161
-
162
- def checks
163
- return @checks unless @checks.nil?
164
- @checks = HTML::Proofer::CheckRunner.checks.map(&:name)
165
- @checks.delete('FaviconCheck') unless @options[:check_favicon]
166
- @checks.delete('HtmlCheck') unless @options[:check_html]
167
- @options[:checks_to_ignore].each do |ignored|
168
- @checks.delete(ignored)
169
- end
170
- @checks
171
- end
172
-
173
- def failed_tests
174
- return [] if @failed_tests.empty?
175
- result = []
176
- @failed_tests.each { |f| result << f.to_s }
177
- result
178
- end
179
-
180
- def print_failed_tests
181
- sorted_failures = HTML::Proofer::CheckRunner::SortedIssues.new(@failed_tests, @options[:error_sort], logger)
182
-
183
- sorted_failures.sort_and_report
184
- count = @failed_tests.length
185
- failure_text = "#{count} " << (count == 1 ? 'failure' : 'failures')
186
- fail logger.colorize :red, "HTML-Proofer found #{failure_text}!"
187
- end
188
- end
189
- end
data/script/bootstrap DELETED
@@ -1,5 +0,0 @@
1
- #!/bin/sh
2
-
3
- set -e
4
-
5
- bundle install "$@"
@@ -1,47 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe HTML::Proofer::Checkable do
4
- describe '#initialize' do
5
- it 'accepts the xmlns attribute' do
6
- nokogiri = Nokogiri::HTML '<a xmlns:cc="http://creativecommons.org/ns#">Creative Commons</a>'
7
- checkable = HTML::Proofer::Checkable.new nokogiri.css('a').first, nil
8
- expect(checkable.instance_variable_get(:@xmlns_cc)).to eq 'http://creativecommons.org/ns#'
9
- end
10
- it 'assignes the text node' do
11
- nokogiri = Nokogiri::HTML '<p>One'
12
- checkable = HTML::Proofer::Checkable.new nokogiri.css('p').first, nil
13
- expect(checkable.instance_variable_get(:@text)).to eq 'One'
14
- end
15
- it 'accepts the content attribute' do
16
- nokogiri = Nokogiri::HTML '<meta name="twitter:card" content="summary">'
17
- checkable = HTML::Proofer::Checkable.new nokogiri.css('meta').first, nil
18
- expect(checkable.instance_variable_get(:@content)).to eq 'summary'
19
- end
20
- end
21
- describe '#ignores_pattern_check' do
22
- it 'works for regex patterns' do
23
- nokogiri = Nokogiri::HTML '<script src=/assets/main.js></script>'
24
- checkable = HTML::Proofer::Checkable.new nokogiri.css('script').first, nil
25
- expect(checkable.ignores_pattern_check([/\/assets\/.*(js|css|png|svg)/])).to eq true
26
- end
27
- it 'works for string patterns' do
28
- nokogiri = Nokogiri::HTML '<script src=/assets/main.js></script>'
29
- checkable = HTML::Proofer::Checkable.new nokogiri.css('script').first, nil
30
- expect(checkable.ignores_pattern_check(['/assets/main.js'])).to eq true
31
- end
32
- end
33
- describe '#url' do
34
- it 'works for src attributes' do
35
- nokogiri = Nokogiri::HTML '<img src=image.png />'
36
- checkable = HTML::Proofer::Checkable.new nokogiri.css('img').first, nil
37
- expect(checkable.url).to eq 'image.png'
38
- end
39
- end
40
- describe '#ignore' do
41
- it 'works for twitter cards' do
42
- nokogiri = Nokogiri::HTML '<meta name="twitter:url" data-proofer-ignore content="http://example.com/soon-to-be-published-url">'
43
- checkable = HTML::Proofer::Checkable.new nokogiri.css('meta').first, nil
44
- expect(checkable.ignore?).to eq true
45
- end
46
- end
47
- end