html-proofer 4.3.0 → 4.4.0

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: e8afbf9c7f55055c38b77971166e852d6f7180481d1e9fb27f84e071c582d1a7
4
- data.tar.gz: 88db5f8e0bb8059ff3f6c50c8fcb4320bf0f6a4e1ef6fc053671591ff44a529f
3
+ metadata.gz: 98bde6dd5e32f42e5983fd1aaa7bf02d3359b40f2b4a8b5360a5826abf2cc674
4
+ data.tar.gz: 9b7d57fd18e625ab7cc91c46faceac510b05ba5290f665fb5dd333b92446b00b
5
5
  SHA512:
6
- metadata.gz: 3f765689616f7884c1a33685dceb08a0786c851839d4ec612023d3ed746ed7c7b7e9087bd91d8360d795fd54a2077fdbf9af9df2c0b25d246a9cc0a064579501
7
- data.tar.gz: 441a4f2b13e237505f9402a53fee5713a68d680824e6a976da42f26bfe1f57a0bdf661f6c3cafc45cb0fa28623c56d679c75044b10dd69db64ac824b7d911885
6
+ metadata.gz: a666be806bbb70028488b3ef89f1325d7b5faaec9f48e105220db2d2f7dd022c12dabac828949ffd2100bdc2b4e3bd4c1f9ce9df48bab17b9106d9453eb49f01
7
+ data.tar.gz: 8a58bb5b120ab3cf3eb0e692f3f52f4385bd5923d3a7c91e95dddd17d8b0e25d20dd207872099665ac37737afb6b4ed86d04d39bc7793c6af2abcd35390d2051
@@ -20,12 +20,13 @@ module HTMLProofer
20
20
 
21
21
  swap_urls!
22
22
  clean_url!
23
-
24
- # convert "//" links to "https://"
25
- @url.start_with?("//") ? @url = "https:#{@url}" : @url
26
23
  end
27
24
  end
28
25
 
26
+ def protocol_relative?
27
+ url.start_with?("//")
28
+ end
29
+
29
30
  def to_s
30
31
  @url
31
32
  end
@@ -16,7 +16,10 @@ module HTMLProofer
16
16
  return if immediate_redirect?
17
17
 
18
18
  if found
19
- if @favicon.url.remote?
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)
22
+ elsif @favicon.url.remote?
20
23
  add_to_external_urls(@favicon.url, @favicon.line)
21
24
  elsif !@favicon.url.exists?
22
25
  add_failure("internal favicon #{@favicon.url.raw_attribute} does not exist", line: @favicon.line,
@@ -6,7 +6,7 @@ module HTMLProofer
6
6
  SCREEN_SHOT_REGEX = /Screen(?: |%20)Shot(?: |%20)\d+-\d+-\d+(?: |%20)at(?: |%20)\d+.\d+.\d+/.freeze
7
7
 
8
8
  def run
9
- @html.css("img").each do |node|
9
+ @html.css("img, source").each do |node|
10
10
  @img = create_element(node)
11
11
 
12
12
  next if @img.ignore?
@@ -18,26 +18,22 @@ module HTMLProofer
18
18
  # does the image exist?
19
19
  if missing_src?
20
20
  add_failure("image has no src or srcset attribute", line: @img.line, content: @img.content)
21
+ 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)
21
24
  elsif @img.url.remote?
22
25
  add_to_external_urls(@img.url, @img.line)
23
26
  elsif !@img.url.exists? && !@img.multiple_srcsets? && !@img.multiple_sizes?
24
27
  add_failure("internal image #{@img.url.raw_attribute} does not exist", line: @img.line,
25
28
  content: @img.content)
26
- elsif @img.multiple_srcsets?
27
- @img.srcsets.each do |srcset|
28
- srcset_url = HTMLProofer::Attribute::Url.new(@runner, srcset, base_url: @img.base_url, extract_size: true)
29
-
30
- if srcset_url.remote?
31
- add_to_external_urls(srcset_url.url, @img.line)
32
- elsif !srcset_url.exists?
33
- add_failure("internal image #{srcset} does not exist", line: @img.line, content: @img.content)
34
- end
35
- end
36
- elsif @img.multiple_sizes?
29
+ elsif @img.multiple_srcsets? || @img.multiple_sizes?
37
30
  @img.srcsets_wo_sizes.each do |srcset|
38
31
  srcset_url = HTMLProofer::Attribute::Url.new(@runner, srcset, base_url: @img.base_url, extract_size: true)
39
32
 
40
- if srcset_url.remote?
33
+ 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)
36
+ elsif srcset_url.remote?
41
37
  add_to_external_urls(srcset_url.url, @img.line)
42
38
  elsif !srcset_url.exists?
43
39
  add_failure("internal image #{srcset} does not exist", line: @img.line, content: @img.content)
@@ -45,7 +41,8 @@ module HTMLProofer
45
41
  end
46
42
  end
47
43
 
48
- unless ignore_element?
44
+ # if this is an img element, check that the alt attribute is present
45
+ if @img.img_tag? && !ignore_element?
49
46
  if missing_alt_tag? && !ignore_missing_alt?
50
47
  add_failure("image #{@img.url.raw_attribute} does not have an alt attribute", line: @img.line,
51
48
  content: @img.content)
@@ -4,7 +4,7 @@ module HTMLProofer
4
4
  class Check
5
5
  class Links < HTMLProofer::Check
6
6
  def run
7
- @html.css("a, link, source").each do |node|
7
+ @html.css("a, link").each do |node|
8
8
  @link = create_element(node)
9
9
 
10
10
  next if @link.ignore?
@@ -28,6 +28,12 @@ module HTMLProofer
28
28
  next
29
29
  end
30
30
 
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)
34
+ next
35
+ end
36
+
31
37
  check_schemes
32
38
 
33
39
  # intentionally down here because we still want valid? & missing_href? to execute
@@ -16,6 +16,9 @@ module HTMLProofer
16
16
  add_failure("open graph content attribute is empty", line: @open_graph.line, content: @open_graph.content)
17
17
  elsif !@open_graph.url.valid?
18
18
  add_failure("#{@open_graph.src} is an invalid URL", line: @open_graph.line)
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)
19
22
  elsif @open_graph.url.remote?
20
23
  add_to_external_urls(@open_graph.url, @open_graph.line)
21
24
  else
@@ -13,8 +13,11 @@ module HTMLProofer
13
13
  # does the script exist?
14
14
  if missing_src?
15
15
  add_failure("script is empty and has no src attribute", line: @script.line, content: @script.content)
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)
16
19
  elsif @script.url.remote?
17
- add_to_external_urls(@script.src, @script.line)
20
+ add_to_external_urls(@script.url, @script.line)
18
21
  check_sri if @runner.check_sri?
19
22
  elsif !@script.url.exists?
20
23
  add_failure("internal script reference #{@script.src} does not exist", line: @script.line,
@@ -29,28 +29,10 @@ module HTMLProofer
29
29
  content: content)
30
30
  end
31
31
 
32
- def self.subchecks(runner_options)
33
- # grab all known checks
34
- checks = ObjectSpace.each_object(Class).select do |klass|
35
- klass < self
36
- end
37
-
38
- # remove any checks not explicitly included
39
- checks.each_with_object([]) do |check, arr|
40
- next unless runner_options[:checks].include?(check.short_name)
41
-
42
- arr << check
43
- end
44
- end
45
-
46
32
  def short_name
47
33
  self.class.name.split("::").last
48
34
  end
49
35
 
50
- def self.short_name
51
- name.split("::").last
52
- end
53
-
54
36
  def add_to_internal_urls(url, line)
55
37
  url_string = url.raw_attribute
56
38
 
@@ -74,6 +56,26 @@ module HTMLProofer
74
56
  @external_urls[url_string] << { filename: @runner.current_filename, line: line }
75
57
  end
76
58
 
59
+ class << self
60
+ def subchecks(runner_options)
61
+ # grab all known checks
62
+ checks = ObjectSpace.each_object(Class).select do |klass|
63
+ klass < self
64
+ end
65
+
66
+ # remove any checks not explicitly included
67
+ checks.each_with_object([]) do |check, arr|
68
+ next unless runner_options[:checks].include?(check.short_name)
69
+
70
+ arr << check
71
+ end
72
+ end
73
+
74
+ def short_name
75
+ name.split("::").last
76
+ end
77
+ end
78
+
77
79
  private def base_url
78
80
  return @base_url if defined?(@base_url)
79
81
 
@@ -47,42 +47,44 @@ module HTMLProofer
47
47
 
48
48
  CACHE_DEFAULTS = {}.freeze
49
49
 
50
- def self.generate_defaults(opts)
51
- options = PROOFER_DEFAULTS.merge(opts)
50
+ class << self
51
+ def generate_defaults(opts)
52
+ options = PROOFER_DEFAULTS.merge(opts)
52
53
 
53
- options[:typhoeus] = HTMLProofer::Configuration::TYPHOEUS_DEFAULTS.merge(opts[:typhoeus] || {})
54
- options[:hydra] = HTMLProofer::Configuration::HYDRA_DEFAULTS.merge(opts[:hydra] || {})
54
+ options[:typhoeus] = HTMLProofer::Configuration::TYPHOEUS_DEFAULTS.merge(opts[:typhoeus] || {})
55
+ options[:hydra] = HTMLProofer::Configuration::HYDRA_DEFAULTS.merge(opts[:hydra] || {})
55
56
 
56
- options[:parallel] = HTMLProofer::Configuration::PARALLEL_DEFAULTS.merge(opts[:parallel] || {})
57
- options[:cache] = HTMLProofer::Configuration::CACHE_DEFAULTS.merge(opts[:cache] || {})
57
+ options[:parallel] = HTMLProofer::Configuration::PARALLEL_DEFAULTS.merge(opts[:parallel] || {})
58
+ options[:cache] = HTMLProofer::Configuration::CACHE_DEFAULTS.merge(opts[:cache] || {})
58
59
 
59
- options.delete(:src)
60
+ options.delete(:src)
60
61
 
61
- options
62
- end
62
+ options
63
+ end
63
64
 
64
- def self.to_regex?(item)
65
- if item.start_with?("/") && item.end_with?("/")
66
- Regexp.new(item[1...-1])
67
- else
68
- item
65
+ def to_regex?(item)
66
+ if item.start_with?("/") && item.end_with?("/")
67
+ Regexp.new(item[1...-1])
68
+ else
69
+ item
70
+ end
69
71
  end
70
- end
71
72
 
72
- def self.parse_json_option(option_name, config, symbolize_names: true)
73
- raise ArgumentError, "Must provide an option name in string format." unless option_name.is_a?(String)
74
- raise ArgumentError, "Must provide an option name in string format." if option_name.strip.empty?
73
+ def parse_json_option(option_name, config, symbolize_names: true)
74
+ raise ArgumentError, "Must provide an option name in string format." unless option_name.is_a?(String)
75
+ raise ArgumentError, "Must provide an option name in string format." if option_name.strip.empty?
75
76
 
76
- return {} if config.nil?
77
+ return {} if config.nil?
77
78
 
78
- raise ArgumentError, "Must provide a JSON configuration in string format." unless config.is_a?(String)
79
+ raise ArgumentError, "Must provide a JSON configuration in string format." unless config.is_a?(String)
79
80
 
80
- return {} if config.strip.empty?
81
+ return {} if config.strip.empty?
81
82
 
82
- begin
83
- JSON.parse(config, { symbolize_names: symbolize_names })
84
- rescue StandardError
85
- raise ArgumentError, "Option '#{option_name} did not contain valid JSON."
83
+ begin
84
+ JSON.parse(config, { symbolize_names: symbolize_names })
85
+ rescue StandardError
86
+ raise ArgumentError, "Option '#{option_name} did not contain valid JSON."
87
+ end
86
88
  end
87
89
  end
88
90
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HTMLProofer
4
- VERSION = "4.3.0"
4
+ VERSION = "4.4.0"
5
5
  end
data/lib/html_proofer.rb CHANGED
@@ -20,37 +20,39 @@ if ENV.fetch("DEBUG", false)
20
20
  end
21
21
 
22
22
  module HTMLProofer
23
- def self.check_file(file, options = {})
24
- raise ArgumentError unless file.is_a?(String)
25
- raise ArgumentError, "#{file} does not exist" unless File.exist?(file)
23
+ class << self
24
+ def check_file(file, options = {})
25
+ raise ArgumentError unless file.is_a?(String)
26
+ raise ArgumentError, "#{file} does not exist" unless File.exist?(file)
26
27
 
27
- options[:type] = :file
28
- HTMLProofer::Runner.new(file, options)
29
- end
28
+ options[:type] = :file
29
+ HTMLProofer::Runner.new(file, options)
30
+ end
30
31
 
31
- def self.check_directory(directory, options = {})
32
- raise ArgumentError unless directory.is_a?(String)
33
- raise ArgumentError, "#{directory} does not exist" unless Dir.exist?(directory)
32
+ def check_directory(directory, options = {})
33
+ raise ArgumentError unless directory.is_a?(String)
34
+ raise ArgumentError, "#{directory} does not exist" unless Dir.exist?(directory)
34
35
 
35
- options[:type] = :directory
36
- HTMLProofer::Runner.new([directory], options)
37
- end
36
+ options[:type] = :directory
37
+ HTMLProofer::Runner.new([directory], options)
38
+ end
38
39
 
39
- def self.check_directories(directories, options = {})
40
- raise ArgumentError unless directories.is_a?(Array)
40
+ def check_directories(directories, options = {})
41
+ raise ArgumentError unless directories.is_a?(Array)
41
42
 
42
- options[:type] = :directory
43
- directories.each do |directory|
44
- raise ArgumentError, "#{directory} does not exist" unless Dir.exist?(directory)
43
+ options[:type] = :directory
44
+ directories.each do |directory|
45
+ raise ArgumentError, "#{directory} does not exist" unless Dir.exist?(directory)
46
+ end
47
+ HTMLProofer::Runner.new(directories, options)
45
48
  end
46
- HTMLProofer::Runner.new(directories, options)
47
- end
48
49
 
49
- def self.check_links(links, options = {})
50
- raise ArgumentError unless links.is_a?(Array)
50
+ def check_links(links, options = {})
51
+ raise ArgumentError unless links.is_a?(Array)
51
52
 
52
- options[:type] = :links
53
- HTMLProofer::Runner.new(links, options)
53
+ options[:type] = :links
54
+ HTMLProofer::Runner.new(links, options)
55
+ end
54
56
  end
55
57
  end
56
58
 
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: 4.3.0
4
+ version: 4.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Garen Torikian
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-07-26 00:00:00.000000000 Z
11
+ date: 2022-08-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable