html-proofer 5.0.3 → 5.0.5

Sign up to get free protection for your applications and to get access to all the features.
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