html-proofer 5.0.3 → 5.0.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 337d1725f7139e6efda6d350b83b15ecfd51eb67ee44e068f1b29859104320dd
4
- data.tar.gz: 3ad1dcdb66a4789853e92303a1cd6e9872d95db137ab589df75f5f6af00d7ed0
3
+ metadata.gz: 5480fbee53b67ca43a6a5896919e8d6ab82bca8e31b20e0734b60c78a71747c6
4
+ data.tar.gz: 12d2e42cefdab3b45b8048e7293e2bb0ccb2235fb6ac2b1722b662f1129a7202
5
5
  SHA512:
6
- metadata.gz: 656b20f4feeffc2dca48e38e42d510c8b7f5d4e7f563167429e0c687c0b1a938008dfe8bb7e21591ed8a5c76fd7ea8c20d63b78f2c71fcf54a3a9bcf55970a7e
7
- data.tar.gz: 490f87dcd3a849a55c2051e56e93e8b65e47e18ffea0fd82061b8418736709cff5ec5230fd84d937e7b748ccec19c644650ef970dda49a0ce100f57914be6418
6
+ metadata.gz: 6789de48b6d391cb36fd1c7b05bba18960e1782e4ef20b9cf15c076efdb147231a7b56c7c79eaad0c4c267a58fbc3355cb8a063334a7224a8901ac8a594908d8
7
+ data.tar.gz: 17fb7a62b96b1eb3b47dd297f8aedab8e02ffb2eacf3880d1b4ea7b0061ab4ba13dcc20993e76ba36d766d29f6ef8726823e5f73524b01eea5de96cba2455e96
@@ -141,12 +141,16 @@ module HTMLProofer
141
141
  # either overwrite with root_dir; or, if source is directory, use that; or, just get the current file's dirname
142
142
  @runner.options[:root_dir] || (File.directory?(@runner.current_source) ? @runner.current_source : File.dirname(@runner.current_source))
143
143
  # relative links, path is a file
144
- elsif File.exist?(File.expand_path(path,
145
- @runner.current_source)) || File.exist?(File.expand_path(path_dot_ext, @runner.current_source))
144
+ elsif File.exist?(File.expand_path(
145
+ path,
146
+ @runner.current_source,
147
+ )) || File.exist?(File.expand_path(path_dot_ext, @runner.current_source))
146
148
  File.dirname(@runner.current_filename)
147
149
  # relative links in nested dir, path is a file
148
- elsif File.exist?(File.join(File.dirname(@runner.current_filename),
149
- path)) || File.exist?(File.join(File.dirname(@runner.current_filename), path_dot_ext))
150
+ elsif File.exist?(File.join(
151
+ File.dirname(@runner.current_filename),
152
+ path,
153
+ )) || File.exist?(File.join(File.dirname(@runner.current_filename), path_dot_ext))
150
154
  File.dirname(@runner.current_filename)
151
155
  # relative link, path is a directory
152
156
  else
@@ -213,7 +217,7 @@ module HTMLProofer
213
217
  url.start_with?("?")
214
218
  end
215
219
 
216
- def sans_hash
220
+ def without_hash
217
221
  @url.to_s.sub(/##{hash}/, "")
218
222
  end
219
223
 
@@ -93,8 +93,10 @@ module HTMLProofer
93
93
  # if there are no urls, bail
94
94
  return {} if urls_detected.empty?
95
95
 
96
- urls_detected = urls_detected.transform_keys do |url|
97
- cleaned_url(url)
96
+ if type == :external
97
+ urls_detected = urls_detected.transform_keys do |url|
98
+ cleaned_url(url)
99
+ end
98
100
  end
99
101
 
100
102
  urls_to_check = detect_url_changes(urls_detected, type)
@@ -17,13 +17,19 @@ module HTMLProofer
17
17
 
18
18
  if found
19
19
  if @favicon.url.protocol_relative?
20
- add_failure("favicon link #{@favicon.url} is a protocol-relative URL, use explicit https:// instead",
21
- line: @favicon.line, content: @favicon.content)
20
+ add_failure(
21
+ "favicon link #{@favicon.url} is a protocol-relative URL, use explicit https:// instead",
22
+ line: @favicon.line,
23
+ content: @favicon.content,
24
+ )
22
25
  elsif @favicon.url.remote?
23
26
  add_to_external_urls(@favicon.url, @favicon.line)
24
27
  elsif !@favicon.url.exists?
25
- add_failure("internal favicon #{@favicon.url.raw_attribute} does not exist", line: @favicon.line,
26
- content: @favicon.content)
28
+ add_failure(
29
+ "internal favicon #{@favicon.url.raw_attribute} does not exist",
30
+ line: @favicon.line,
31
+ content: @favicon.content,
32
+ )
27
33
  end
28
34
  else
29
35
  add_failure("no favicon provided")
@@ -12,27 +12,39 @@ module HTMLProofer
12
12
  next if @img.ignore?
13
13
 
14
14
  # screenshot filenames should return because of terrible names
15
- add_failure("image has a terrible filename (#{@img.url.raw_attribute})", line: @img.line,
16
- content: @img.content) if terrible_filename?
15
+ add_failure(
16
+ "image has a terrible filename (#{@img.url.raw_attribute})",
17
+ line: @img.line,
18
+ content: @img.content,
19
+ ) if terrible_filename?
17
20
 
18
21
  # does the image exist?
19
22
  if missing_src?
20
23
  add_failure("image has no src or srcset attribute", line: @img.line, content: @img.content)
21
24
  elsif @img.url.protocol_relative?
22
- add_failure("image link #{@img.url} is a protocol-relative URL, use explicit https:// instead",
23
- line: @img.line, content: @img.content)
25
+ add_failure(
26
+ "image link #{@img.url} is a protocol-relative URL, use explicit https:// instead",
27
+ line: @img.line,
28
+ content: @img.content,
29
+ )
24
30
  elsif @img.url.remote?
25
31
  add_to_external_urls(@img.url, @img.line)
26
32
  elsif !@img.url.exists? && !@img.multiple_srcsets? && !@img.multiple_sizes?
27
- add_failure("internal image #{@img.url.raw_attribute} does not exist", line: @img.line,
28
- content: @img.content)
33
+ add_failure(
34
+ "internal image #{@img.url.raw_attribute} does not exist",
35
+ line: @img.line,
36
+ content: @img.content,
37
+ )
29
38
  elsif @img.multiple_srcsets? || @img.multiple_sizes?
30
39
  @img.srcsets_wo_sizes.each do |srcset|
31
40
  srcset_url = HTMLProofer::Attribute::Url.new(@runner, srcset, base_url: @img.base_url, extract_size: true)
32
41
 
33
42
  if srcset_url.protocol_relative?
34
- add_failure("image link #{srcset_url.url} is a protocol-relative URL, use explicit https:// instead",
35
- line: @img.line, content: @img.content)
43
+ add_failure(
44
+ "image link #{srcset_url.url} is a protocol-relative URL, use explicit https:// instead",
45
+ line: @img.line,
46
+ content: @img.content,
47
+ )
36
48
  elsif srcset_url.remote?
37
49
  add_to_external_urls(srcset_url.url, @img.line)
38
50
  elsif !srcset_url.exists?
@@ -44,16 +56,25 @@ module HTMLProofer
44
56
  # if this is an img element, check that the alt attribute is present
45
57
  if @img.img_tag? && !ignore_element?
46
58
  if missing_alt_tag? && !ignore_missing_alt?
47
- add_failure("image #{@img.url.raw_attribute} does not have an alt attribute", line: @img.line,
48
- content: @img.content)
59
+ add_failure(
60
+ "image #{@img.url.raw_attribute} does not have an alt attribute",
61
+ line: @img.line,
62
+ content: @img.content,
63
+ )
49
64
  elsif (empty_alt_tag? || alt_all_spaces?) && !ignore_empty_alt?
50
- add_failure("image #{@img.url.raw_attribute} has an alt attribute, but no content", line: @img.line,
51
- content: @img.content)
65
+ add_failure(
66
+ "image #{@img.url.raw_attribute} has an alt attribute, but no content",
67
+ line: @img.line,
68
+ content: @img.content,
69
+ )
52
70
  end
53
71
  end
54
72
 
55
- add_failure("image #{@img.url.raw_attribute} uses the http scheme", line: @img.line,
56
- content: @img.content) if @runner.enforce_https? && @img.url.http?
73
+ add_failure(
74
+ "image #{@img.url.raw_attribute} uses the http scheme",
75
+ line: @img.line,
76
+ content: @img.content,
77
+ ) if @runner.enforce_https? && @img.url.http?
57
78
  end
58
79
 
59
80
  external_urls
@@ -29,8 +29,11 @@ module HTMLProofer
29
29
  end
30
30
 
31
31
  if @link.url.protocol_relative?
32
- add_failure("#{@link.url} is a protocol-relative URL, use explicit https:// instead",
33
- line: @link.line, content: @link.content)
32
+ add_failure(
33
+ "#{@link.url} is a protocol-relative URL, use explicit https:// instead",
34
+ line: @link.line,
35
+ content: @link.content,
36
+ )
34
37
  next
35
38
  end
36
39
 
@@ -55,8 +58,11 @@ module HTMLProofer
55
58
  elsif @link.url.internal?
56
59
  # does the local directory have a trailing slash?
57
60
  if @link.url.unslashed_directory?(@link.url.absolute_path)
58
- add_failure("internally linking to a directory #{@link.url.raw_attribute} without trailing slash",
59
- line: @link.line, content: @link.content)
61
+ add_failure(
62
+ "internally linking to a directory #{@link.url.raw_attribute} without trailing slash",
63
+ line: @link.line,
64
+ content: @link.content,
65
+ )
60
66
  next
61
67
  end
62
68
 
@@ -88,17 +94,26 @@ module HTMLProofer
88
94
 
89
95
  def handle_mailto
90
96
  if @link.url.path.empty?
91
- add_failure("#{@link.url.raw_attribute} contains no email address", line: @link.line,
92
- content: @link.content) unless ignore_empty_mailto?
97
+ add_failure(
98
+ "#{@link.url.raw_attribute} contains no email address",
99
+ line: @link.line,
100
+ content: @link.content,
101
+ ) unless ignore_empty_mailto?
93
102
  elsif !/#{URI::MailTo::EMAIL_REGEXP}/o.match?(@link.url.path)
94
- add_failure("#{@link.url.raw_attribute} contains an invalid email address", line: @link.line,
95
- content: @link.content)
103
+ add_failure(
104
+ "#{@link.url.raw_attribute} contains an invalid email address",
105
+ line: @link.line,
106
+ content: @link.content,
107
+ )
96
108
  end
97
109
  end
98
110
 
99
111
  def handle_tel
100
- add_failure("#{@link.url.raw_attribute} contains no phone number", line: @link.line,
101
- content: @link.content) if @link.url.path.empty?
112
+ add_failure(
113
+ "#{@link.url.raw_attribute} contains no phone number",
114
+ line: @link.line,
115
+ content: @link.content,
116
+ ) if @link.url.path.empty?
102
117
  end
103
118
 
104
119
  def ignore_empty_mailto?
@@ -113,13 +128,19 @@ module HTMLProofer
113
128
  return unless SRI_REL_TYPES.include?(@link.node["rel"])
114
129
 
115
130
  if blank?(@link.node["integrity"]) && blank?(@link.node["crossorigin"])
116
- add_failure("SRI and CORS not provided in: #{@link.url.raw_attribute}", line: @link.line,
117
- content: @link.content)
131
+ add_failure(
132
+ "SRI and CORS not provided in: #{@link.url.raw_attribute}",
133
+ line: @link.line,
134
+ content: @link.content,
135
+ )
118
136
  elsif blank?(@link.node["integrity"])
119
137
  add_failure("Integrity is missing in: #{@link.url.raw_attribute}", line: @link.line, content: @link.content)
120
138
  elsif blank?(@link.node["crossorigin"])
121
- add_failure("CORS not provided for external resource in: #{@link.link.url.raw_attribute}", line: @link.line,
122
- content: @link.content)
139
+ add_failure(
140
+ "CORS not provided for external resource in: #{@link.link.url.raw_attribute}",
141
+ line: @link.line,
142
+ content: @link.content,
143
+ )
123
144
  end
124
145
  end
125
146
 
@@ -17,13 +17,19 @@ module HTMLProofer
17
17
  elsif !@open_graph.url.valid?
18
18
  add_failure("#{@open_graph.src} is an invalid URL", line: @open_graph.line)
19
19
  elsif @open_graph.url.protocol_relative?
20
- add_failure("open graph link #{@open_graph.url} is a protocol-relative URL, use explicit https:// instead",
21
- line: @open_graph.line, content: @open_graph.content)
20
+ add_failure(
21
+ "open graph link #{@open_graph.url} is a protocol-relative URL, use explicit https:// instead",
22
+ line: @open_graph.line,
23
+ content: @open_graph.content,
24
+ )
22
25
  elsif @open_graph.url.remote?
23
26
  add_to_external_urls(@open_graph.url, @open_graph.line)
24
27
  else
25
- add_failure("internal open graph #{@open_graph.url.raw_attribute} does not exist", line: @open_graph.line,
26
- content: @open_graph.content) unless @open_graph.url.exists?
28
+ add_failure(
29
+ "internal open graph #{@open_graph.url.raw_attribute} does not exist",
30
+ line: @open_graph.line,
31
+ content: @open_graph.content,
32
+ ) unless @open_graph.url.exists?
27
33
  end
28
34
  end
29
35
 
@@ -14,14 +14,20 @@ module HTMLProofer
14
14
  if missing_src?
15
15
  add_failure("script is empty and has no src attribute", line: @script.line, content: @script.content)
16
16
  elsif @script.url.protocol_relative?
17
- add_failure("script link #{@script.url} is a protocol-relative URL, use explicit https:// instead",
18
- line: @script.line, content: @script.content)
17
+ add_failure(
18
+ "script link #{@script.url} is a protocol-relative URL, use explicit https:// instead",
19
+ line: @script.line,
20
+ content: @script.content,
21
+ )
19
22
  elsif @script.url.remote?
20
23
  add_to_external_urls(@script.url, @script.line)
21
24
  check_sri if @runner.check_sri?
22
25
  elsif !@script.url.exists?
23
- add_failure("internal script reference #{@script.src} does not exist", line: @script.line,
24
- content: @script.content)
26
+ add_failure(
27
+ "internal script reference #{@script.src} does not exist",
28
+ line: @script.line,
29
+ content: @script.content,
30
+ )
25
31
  end
26
32
  end
27
33
 
@@ -34,14 +40,23 @@ module HTMLProofer
34
40
 
35
41
  def check_sri
36
42
  if blank?(@script.node["integrity"]) && blank?(@script.node["crossorigin"])
37
- add_failure("SRI and CORS not provided in: #{@script.url.raw_attribute}", line: @script.line,
38
- content: @script.content)
43
+ add_failure(
44
+ "SRI and CORS not provided in: #{@script.url.raw_attribute}",
45
+ line: @script.line,
46
+ content: @script.content,
47
+ )
39
48
  elsif blank?(@script.node["integrity"])
40
- add_failure("Integrity is missing in: #{@script.url.raw_attribute}", line: @script.line,
41
- content: @script.content)
49
+ add_failure(
50
+ "Integrity is missing in: #{@script.url.raw_attribute}",
51
+ line: @script.line,
52
+ content: @script.content,
53
+ )
42
54
  elsif blank?(@script.node["crossorigin"])
43
- add_failure("CORS not provided for external resource in: #{@script.url.raw_attribute}", line: @script.line,
44
- content: @script.content)
55
+ add_failure(
56
+ "CORS not provided for external resource in: #{@script.url.raw_attribute}",
57
+ line: @script.line,
58
+ content: @script.content,
59
+ )
45
60
  end
46
61
  end
47
62
  end
@@ -25,8 +25,14 @@ module HTMLProofer
25
25
  end
26
26
 
27
27
  def add_failure(description, line: nil, status: nil, content: nil)
28
- @failures << Failure.new(@runner.current_filename, short_name, description, line: line, status: status,
29
- content: content)
28
+ @failures << Failure.new(
29
+ @runner.current_filename,
30
+ short_name,
31
+ description,
32
+ line: line,
33
+ status: status,
34
+ content: content,
35
+ )
30
36
  end
31
37
 
32
38
  def short_name
@@ -280,17 +280,25 @@ module HTMLProofer
280
280
  module ConfigurationHelp
281
281
  TEXT = {
282
282
  as_links: ["Assumes that `PATH` is a comma-separated array of links to check."],
283
- assume_extension: ["Automatically add specified extension to files for internal links, ",
284
- "to allow extensionless URLs (as supported by most servers) (default: `.html`).",],
283
+ assume_extension: [
284
+ "Automatically add specified extension to files for internal links, ",
285
+ "to allow extensionless URLs (as supported by most servers) (default: `.html`).",
286
+ ],
285
287
  directory_index_file: ["Sets the file to look for when a link refers to a directory. (default: `index.html`)."],
286
- extensions: ["A comma-separated list of Strings indicating the file extensions you",
287
- "would like to check (default: `.html`)",],
288
+ extensions: [
289
+ "A comma-separated list of Strings indicating the file extensions you",
290
+ "would like to check (default: `.html`)",
291
+ ],
288
292
 
289
293
  allow_hash_href: ['"If `true`, assumes `href="#"` anchors are valid (default: `true`)"'],
290
- allow_missing_href: ["If `true`, does not flag `a` tags missing `href`. In HTML5, this is technically ",
291
- "allowed, but could also be human error. (default: `false`)",],
292
- checks: ["A comma-separated list of Strings indicating which checks you",
293
- "want to run (default: `[\"Links\", \"Images\", \"Scripts\"]",],
294
+ allow_missing_href: [
295
+ "If `true`, does not flag `a` tags missing `href`. In HTML5, this is technically ",
296
+ "allowed, but could also be human error. (default: `false`)",
297
+ ],
298
+ checks: [
299
+ "A comma-separated list of Strings indicating which checks you",
300
+ "want to run (default: `[\"Links\", \"Images\", \"Scripts\"]",
301
+ ],
294
302
  check_external_hash: ["Checks whether external hashes exist (even if the webpage exists) (default: `true`)."],
295
303
  check_internal_hash: ["Checks whether internal hashes exist (even if the webpage exists) (default: `true`)."],
296
304
  check_sri: ["Check that `<link>` and `<script>` external resources use SRI (default: `false`)."],
@@ -298,31 +306,43 @@ module HTMLProofer
298
306
  enforce_https: ["Fails a link if it's not marked as `https` (default: `true`)."],
299
307
  root_dir: ["The absolute path to the directory serving your html-files."],
300
308
 
301
- ignore_empty_alt: ["If `true`, ignores images with empty/missing ",
302
- "alt tags (in other words, `<img alt>` and `<img alt=\"\">`",
303
- "are valid; set this to `false` to flag those) (default: `true`).",],
304
- ignore_empty_mailto: ["If `true`, allows `mailto:` `href`s which don't",
305
- "contain an email address (default: `false`)'.",],
309
+ ignore_empty_alt: [
310
+ "If `true`, ignores images with empty/missing ",
311
+ "alt tags (in other words, `<img alt>` and `<img alt=\"\">`",
312
+ "are valid; set this to `false` to flag those) (default: `true`).",
313
+ ],
314
+ ignore_empty_mailto: [
315
+ "If `true`, allows `mailto:` `href`s which don't",
316
+ "contain an email address (default: `false`)'.",
317
+ ],
306
318
  ignore_missing_alt: ["If `true`, ignores images with missing alt tags (default: `false`)."],
307
319
  ignore_status_codes: ["A comma-separated list of numbers representing status codes to ignore."],
308
320
  ignore_files: ["A comma-separated list of Strings or RegExps containing file paths that are safe to ignore"],
309
- ignore_urls: ["A comma-separated list of Strings or RegExps containing URLs that are",
310
- "safe to ignore. This affects all HTML attributes, such as `alt` tags on images.",],
321
+ ignore_urls: [
322
+ "A comma-separated list of Strings or RegExps containing URLs that are",
323
+ "safe to ignore. This affects all HTML attributes, such as `alt` tags on images.",
324
+ ],
311
325
  only_status_codes: ["A comma-separated list of numbers representing the only status codes to report on."],
312
326
  only_4xx: ["Only reports errors for links that fall within the 4xx status code range."],
313
327
 
314
- swap_attributes: ["JSON-formatted config that maps element names to the",
315
- "preferred attribute to check (default: `{}`).",],
316
- swap_urls: ["A comma-separated list containing key-value pairs of `RegExp => String`.",
317
- "It transforms URLs that match `RegExp` into `String` via `gsub`.",
318
- "The escape sequences `\\:` should be used to produce literal `:`s.",],
328
+ swap_attributes: [
329
+ "JSON-formatted config that maps element names to the",
330
+ "preferred attribute to check (default: `{}`).",
331
+ ],
332
+ swap_urls: [
333
+ "A comma-separated list containing key-value pairs of `RegExp => String`.",
334
+ "It transforms URLs that match `RegExp` into `String` via `gsub`.",
335
+ "The escape sequences `\\:` should be used to produce literal `:`s.",
336
+ ],
319
337
 
320
338
  typhoeus: ["JSON-formatted string of Typhoeus config; if set, overrides the html-proofer defaults."],
321
339
  hydra: ["JSON-formatted string of Hydra config; if set, overrides the html-proofer defaults."],
322
340
  cache: ["JSON-formatted string of cache config; if set, overrides the html-proofer defaults."],
323
341
 
324
- log_level: ["Sets the logging level. One of `:debug`, `:info`, ",
325
- "`:warn`, `:error`, or `:fatal`. (default: `:info`)",],
342
+ log_level: [
343
+ "Sets the logging level. One of `:debug`, `:info`, ",
344
+ "`:warn`, `:error`, or `:fatal`. (default: `:info`)",
345
+ ],
326
346
 
327
347
  version: ["Prints the version of html-proofer."],
328
348
  }.freeze
@@ -11,9 +11,11 @@ module HTMLProofer
11
11
  STDERR_LEVELS = [:error, :fatal].freeze
12
12
 
13
13
  def initialize(log_level)
14
- @logger = Yell.new(format: false, \
14
+ @logger = Yell.new(
15
+ format: false, \
15
16
  name: "HTMLProofer", \
16
- level: "gte.#{log_level}") do |l|
17
+ level: "gte.#{log_level}",
18
+ ) do |l|
17
19
  l.adapter(:stdout, level: "lte.warn")
18
20
  l.adapter(:stderr, level: "gte.error")
19
21
  end
@@ -42,8 +42,10 @@ module HTMLProofer
42
42
  @logger.log(:info, "Running #{check_text} (#{format_checks_list(checks)}) on #{@source} ...\n\n")
43
43
  check_list_of_links unless @options[:disable_external]
44
44
  else
45
- @logger.log(:info,
46
- "Running #{check_text} (#{format_checks_list(checks)}) in #{@source} on *#{@options[:extensions].join(", ")} files ...\n\n")
45
+ @logger.log(
46
+ :info,
47
+ "Running #{check_text} (#{format_checks_list(checks)}) in #{@source} on *#{@options[:extensions].join(", ")} files ...\n\n",
48
+ )
47
49
 
48
50
  check_files
49
51
  @logger.log(:info, "Ran on #{pluralize(files.length, "file", "files")}!\n\n")
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "typhoeus"
4
- require "uri"
4
+ require "open-uri"
5
+ # require "uri"
6
+ require "pdf-reader"
5
7
 
6
8
  module HTMLProofer
7
9
  class UrlValidator
@@ -88,8 +90,12 @@ module HTMLProofer
88
90
  return if @runner.options[:ignore_status_codes].include?(response_code)
89
91
 
90
92
  if response_code.between?(200, 299)
91
- @cache.add_external(href, filenames, response_code, "OK", true) unless check_hash_in_2xx_response(href, url,
92
- response, filenames)
93
+ @cache.add_external(href, filenames, response_code, "OK", true) unless check_hash_in_2xx_response(
94
+ href,
95
+ url,
96
+ response,
97
+ filenames,
98
+ )
93
99
  elsif response.timed_out?
94
100
  handle_timeout(href, filenames, response_code)
95
101
  elsif response_code.zero?
@@ -115,6 +121,28 @@ module HTMLProofer
115
121
  return false unless url.hash?
116
122
 
117
123
  hash = url.hash
124
+ headers = response.options.fetch(:headers, {})
125
+ content_type = headers.find { |k, _| k.casecmp("content-type").zero? }
126
+
127
+ # attempt to verify PDF hash ref; see #787 for more details
128
+ # FIXME: this is re-reading the PDF response
129
+ if content_type && content_type[1].include?("pdf")
130
+ io = URI.parse(url.to_s).open
131
+ reader = PDF::Reader.new(io)
132
+
133
+ pages = reader.pages
134
+ if hash =~ /\Apage=(\d+)\z/
135
+ page = Regexp.last_match[1].to_i
136
+
137
+ unless pages[page - 1]
138
+ msg = "External link #{href} failed: #{url.without_hash} exists, but the hash '#{hash}' does not"
139
+ add_failure(filenames, msg, response.code)
140
+ @cache.add_external(href, filenames, response.code, msg, false)
141
+ end
142
+
143
+ return true
144
+ end
145
+ end
118
146
 
119
147
  body_doc = create_nokogiri(response.body)
120
148
 
@@ -130,7 +158,7 @@ module HTMLProofer
130
158
 
131
159
  return unless body_doc.xpath(xpath.join("|")).empty?
132
160
 
133
- msg = "External link #{href} failed: #{url.sans_hash} exists, but the hash '#{hash}' does not"
161
+ msg = "External link #{href} failed: #{url.without_hash} exists, but the hash '#{hash}' does not"
134
162
  add_failure(filenames, msg, response.code)
135
163
  @cache.add_external(href, filenames, response.code, msg, false)
136
164
  true
@@ -36,8 +36,14 @@ module HTMLProofer
36
36
 
37
37
  target_file_path = url.absolute_path
38
38
  unless file_exists?(target_file_path)
39
- @failed_checks << Failure.new(@runner.current_filename, "Links > Internal",
40
- "internally linking to #{url}, which does not exist", line: metadata[:line], status: nil, content: nil)
39
+ @failed_checks << Failure.new(
40
+ @runner.current_filename,
41
+ "Links > Internal",
42
+ "internally linking to #{url}, which does not exist",
43
+ line: metadata[:line],
44
+ status: nil,
45
+ content: nil,
46
+ )
41
47
  to_add << [url, metadata, false]
42
48
  next
43
49
  end
@@ -55,8 +61,14 @@ module HTMLProofer
55
61
  next
56
62
  end
57
63
  unless hash_exists
58
- @failed_checks << Failure.new(@runner.current_filename, "Links > Internal",
59
- "internally linking to #{url}; the file exists, but the hash '#{url.hash}' does not", line: metadata[:line], status: nil, content: nil)
64
+ @failed_checks << Failure.new(
65
+ @runner.current_filename,
66
+ "Links > Internal",
67
+ "internally linking to #{url}; the file exists, but the hash '#{url.hash}' does not",
68
+ line: metadata[:line],
69
+ status: nil,
70
+ content: nil,
71
+ )
60
72
  to_add << [url, metadata, false]
61
73
  next
62
74
  end
@@ -75,8 +87,14 @@ module HTMLProofer
75
87
  exists = hash_exists_in_html?(href_hash, html)
76
88
  url_metadata.each do |(url, metadata)|
77
89
  unless exists
78
- @failed_checks << Failure.new(metadata[:filename], "Links > Internal",
79
- "internally linking to #{url}; the file exists, but the hash '#{href_hash}' does not", line: metadata[:line], status: nil, content: nil)
90
+ @failed_checks << Failure.new(
91
+ metadata[:filename],
92
+ "Links > Internal",
93
+ "internally linking to #{url}; the file exists, but the hash '#{href_hash}' does not",
94
+ line: metadata[:line],
95
+ status: nil,
96
+ content: nil,
97
+ )
80
98
  end
81
99
  to_add << [url, metadata, exists]
82
100
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HTMLProofer
4
- VERSION = "5.0.3"
4
+ VERSION = "5.0.5"
5
5
  end
@@ -4,7 +4,7 @@ module HTMLProofer
4
4
  # https://stackoverflow.com/a/8812293
5
5
  class XpathFunctions
6
6
  def case_sensitive_equals(node_set, str_to_match)
7
- node_set.find_all { |node| node.to_s.== str_to_match.to_s }
7
+ node_set.find_all { |node| node.to_s == str_to_match.to_s }
8
8
  end
9
9
  end
10
10
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: html-proofer
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.3
4
+ version: 5.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Garen Torikian
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-12-05 00:00:00.000000000 Z
11
+ date: 2023-03-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '1.13'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pdf-reader
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.11'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.11'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: rainbow
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -108,62 +122,6 @@ dependencies:
108
122
  - - "~>"
109
123
  - !ruby/object:Gem::Version
110
124
  version: '2.5'
111
- - !ruby/object:Gem::Dependency
112
- name: awesome_print
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - ">="
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
- - !ruby/object:Gem::Dependency
126
- name: debug
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - ">="
130
- - !ruby/object:Gem::Version
131
- version: '0'
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - ">="
137
- - !ruby/object:Gem::Version
138
- version: '0'
139
- - !ruby/object:Gem::Dependency
140
- name: rake
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - ">="
144
- - !ruby/object:Gem::Version
145
- version: '0'
146
- type: :development
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - ">="
151
- - !ruby/object:Gem::Version
152
- version: '0'
153
- - !ruby/object:Gem::Dependency
154
- name: redcarpet
155
- requirement: !ruby/object:Gem::Requirement
156
- requirements:
157
- - - ">="
158
- - !ruby/object:Gem::Version
159
- version: '0'
160
- type: :development
161
- prerelease: false
162
- version_requirements: !ruby/object:Gem::Requirement
163
- requirements:
164
- - - ">="
165
- - !ruby/object:Gem::Version
166
- version: '0'
167
125
  - !ruby/object:Gem::Dependency
168
126
  name: rspec
169
127
  requirement: !ruby/object:Gem::Requirement
@@ -178,48 +136,6 @@ dependencies:
178
136
  - - "~>"
179
137
  - !ruby/object:Gem::Version
180
138
  version: '3.1'
181
- - !ruby/object:Gem::Dependency
182
- name: rubocop
183
- requirement: !ruby/object:Gem::Requirement
184
- requirements:
185
- - - ">="
186
- - !ruby/object:Gem::Version
187
- version: '0'
188
- type: :development
189
- prerelease: false
190
- version_requirements: !ruby/object:Gem::Requirement
191
- requirements:
192
- - - ">="
193
- - !ruby/object:Gem::Version
194
- version: '0'
195
- - !ruby/object:Gem::Dependency
196
- name: rubocop-rspec
197
- requirement: !ruby/object:Gem::Requirement
198
- requirements:
199
- - - ">="
200
- - !ruby/object:Gem::Version
201
- version: '0'
202
- type: :development
203
- prerelease: false
204
- version_requirements: !ruby/object:Gem::Requirement
205
- requirements:
206
- - - ">="
207
- - !ruby/object:Gem::Version
208
- version: '0'
209
- - !ruby/object:Gem::Dependency
210
- name: rubocop-standard
211
- requirement: !ruby/object:Gem::Requirement
212
- requirements:
213
- - - ">="
214
- - !ruby/object:Gem::Version
215
- version: '0'
216
- type: :development
217
- prerelease: false
218
- version_requirements: !ruby/object:Gem::Requirement
219
- requirements:
220
- - - ">="
221
- - !ruby/object:Gem::Version
222
- version: '0'
223
139
  - !ruby/object:Gem::Dependency
224
140
  name: timecop
225
141
  requirement: !ruby/object:Gem::Requirement