html-proofer 5.0.5 → 5.0.6

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: 5480fbee53b67ca43a6a5896919e8d6ab82bca8e31b20e0734b60c78a71747c6
4
- data.tar.gz: 12d2e42cefdab3b45b8048e7293e2bb0ccb2235fb6ac2b1722b662f1129a7202
3
+ metadata.gz: 96326ab8326657b7f11d5cc1baddfb82e8dcb115e4a2aa576161642ebbe9afe4
4
+ data.tar.gz: ce761e92fcfe407fa4711558b60a6453545cdba6b7b97f8be8da22109e451256
5
5
  SHA512:
6
- metadata.gz: 6789de48b6d391cb36fd1c7b05bba18960e1782e4ef20b9cf15c076efdb147231a7b56c7c79eaad0c4c267a58fbc3355cb8a063334a7224a8901ac8a594908d8
7
- data.tar.gz: 17fb7a62b96b1eb3b47dd297f8aedab8e02ffb2eacf3880d1b4ea7b0061ab4ba13dcc20993e76ba36d766d29f6ef8726823e5f73524b01eea5de96cba2455e96
6
+ metadata.gz: 2c66bf1334c00dacb13d2789f119cf5e0f2da723afd59e82948589e26e54e6e12bb5778b23cc758fe81a9d99d112c501e607eacc2247a3258bda60904d7ec65d
7
+ data.tar.gz: c81c4482233aa8fe86721de10332dc9f42ed03c4103ff0c77144a6fffc0f715e7964be2a0b935a04fbc586b4f78a2b445eebb9df5912076e910ab387add299cd
@@ -3,13 +3,16 @@
3
3
  module HTMLProofer
4
4
  class Attribute
5
5
  class Url < HTMLProofer::Attribute
6
- attr_reader :url, :size
6
+ attr_reader :url, :size, :source, :filename
7
7
 
8
8
  REMOTE_SCHEMES = ["http", "https"].freeze
9
9
 
10
- def initialize(runner, link_attribute, base_url: nil, extract_size: false)
10
+ def initialize(runner, link_attribute, base_url: nil, source: nil, filename: nil, extract_size: false)
11
11
  super
12
12
 
13
+ @source = source
14
+ @filename = filename
15
+
13
16
  if @raw_attribute.nil?
14
17
  @url = nil
15
18
  else
@@ -115,9 +118,29 @@ module HTMLProofer
115
118
  def exists?
116
119
  return true if base64?
117
120
 
118
- return @runner.checked_paths[absolute_path] if @runner.checked_paths.key?(absolute_path)
121
+ !resolved_path.nil?
122
+ end
123
+
124
+ def resolved_path
125
+ path_to_resolve = absolute_path
126
+
127
+ return @runner.resolved_paths[path_to_resolve] if @runner.resolved_paths.key?(path_to_resolve)
128
+
129
+ # extensionless URLs
130
+ path_with_extension = "#{path_to_resolve}#{@runner.options[:assume_extension]}"
131
+ resolved = if @runner.options[:assume_extension] && File.file?(path_with_extension)
132
+ path_with_extension # existence checked implicitly by File.file?
133
+ # implicit index support
134
+ elsif File.directory?(path_to_resolve) && !unslashed_directory?(path_to_resolve)
135
+ path_with_index = File.join(path_to_resolve, @runner.options[:directory_index_file])
136
+ path_with_index if File.file?(path_with_index)
137
+ # explicit file or directory
138
+ elsif File.exist?(path_to_resolve)
139
+ path_to_resolve
140
+ end
141
+ @runner.resolved_paths[path_to_resolve] = resolved
119
142
 
120
- @runner.checked_paths[absolute_path] = File.exist?(absolute_path)
143
+ resolved
121
144
  end
122
145
 
123
146
  def base64?
@@ -125,47 +148,23 @@ module HTMLProofer
125
148
  end
126
149
 
127
150
  def absolute_path
128
- path = file_path || @runner.current_filename
151
+ path = full_path || @filename
129
152
 
130
153
  File.expand_path(path, Dir.pwd)
131
154
  end
132
155
 
133
- def file_path
156
+ def full_path
134
157
  return if path.nil? || path.empty?
135
158
 
136
- path_dot_ext = ""
137
-
138
- path_dot_ext = path + @runner.options[:assume_extension] unless blank?(@runner.options[:assume_extension])
139
-
140
159
  base = if absolute_path?(path) # path relative to root
141
- # either overwrite with root_dir; or, if source is directory, use that; or, just get the current file's dirname
142
- @runner.options[:root_dir] || (File.directory?(@runner.current_source) ? @runner.current_source : File.dirname(@runner.current_source))
143
- # relative links, path is a file
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))
148
- File.dirname(@runner.current_filename)
149
- # relative links in nested dir, path is a file
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))
154
- File.dirname(@runner.current_filename)
155
- # relative link, path is a directory
160
+ # either overwrite with root_dir; or, if source is directory, use that; or, just get the source file's dirname
161
+ @runner.options[:root_dir] || (File.directory?(@source) ? @source : File.dirname(@source))
156
162
  else
157
- @runner.current_filename
158
- end
159
-
160
- file = File.join(base, path)
161
-
162
- if @runner.options[:assume_extension] && File.file?("#{file}#{@runner.options[:assume_extension]}")
163
- file = "#{file}#{@runner.options[:assume_extension]}"
164
- elsif File.directory?(file) && !unslashed_directory?(file) # implicit index support
165
- file = File.join(file, @runner.options[:directory_index_file])
163
+ # path relative to the file where the link is defined
164
+ File.dirname(@filename)
166
165
  end
167
166
 
168
- file
167
+ File.join(base, path)
169
168
  end
170
169
 
171
170
  def unslashed_directory?(file)
@@ -19,16 +19,14 @@ module HTMLProofer
19
19
  if @favicon.url.protocol_relative?
20
20
  add_failure(
21
21
  "favicon link #{@favicon.url} is a protocol-relative URL, use explicit https:// instead",
22
- line: @favicon.line,
23
- content: @favicon.content,
22
+ element: @favicon,
24
23
  )
25
24
  elsif @favicon.url.remote?
26
25
  add_to_external_urls(@favicon.url, @favicon.line)
27
26
  elsif !@favicon.url.exists?
28
27
  add_failure(
29
28
  "internal favicon #{@favicon.url.raw_attribute} does not exist",
30
- line: @favicon.line,
31
- content: @favicon.content,
29
+ element: @favicon,
32
30
  )
33
31
  end
34
32
  else
@@ -14,41 +14,37 @@ module HTMLProofer
14
14
  # screenshot filenames should return because of terrible names
15
15
  add_failure(
16
16
  "image has a terrible filename (#{@img.url.raw_attribute})",
17
- line: @img.line,
18
- content: @img.content,
17
+ element: @img,
19
18
  ) if terrible_filename?
20
19
 
21
20
  # does the image exist?
22
21
  if missing_src?
23
- add_failure("image has no src or srcset attribute", line: @img.line, content: @img.content)
22
+ add_failure("image has no src or srcset attribute", element: @img)
24
23
  elsif @img.url.protocol_relative?
25
24
  add_failure(
26
25
  "image link #{@img.url} is a protocol-relative URL, use explicit https:// instead",
27
- line: @img.line,
28
- content: @img.content,
26
+ element: @img,
29
27
  )
30
28
  elsif @img.url.remote?
31
29
  add_to_external_urls(@img.url, @img.line)
32
30
  elsif !@img.url.exists? && !@img.multiple_srcsets? && !@img.multiple_sizes?
33
31
  add_failure(
34
32
  "internal image #{@img.url.raw_attribute} does not exist",
35
- line: @img.line,
36
- content: @img.content,
33
+ element: @img,
37
34
  )
38
35
  elsif @img.multiple_srcsets? || @img.multiple_sizes?
39
36
  @img.srcsets_wo_sizes.each do |srcset|
40
- srcset_url = HTMLProofer::Attribute::Url.new(@runner, srcset, base_url: @img.base_url, extract_size: true)
37
+ srcset_url = HTMLProofer::Attribute::Url.new(@runner, srcset, base_url: @img.base_url, source: @img.url.source, filename: @img.url.filename, extract_size: true)
41
38
 
42
39
  if srcset_url.protocol_relative?
43
40
  add_failure(
44
41
  "image link #{srcset_url.url} is a protocol-relative URL, use explicit https:// instead",
45
- line: @img.line,
46
- content: @img.content,
42
+ element: @img,
47
43
  )
48
44
  elsif srcset_url.remote?
49
45
  add_to_external_urls(srcset_url.url, @img.line)
50
46
  elsif !srcset_url.exists?
51
- add_failure("internal image #{srcset} does not exist", line: @img.line, content: @img.content)
47
+ add_failure("internal image #{srcset} does not exist", element: @img)
52
48
  end
53
49
  end
54
50
  end
@@ -58,22 +54,19 @@ module HTMLProofer
58
54
  if missing_alt_tag? && !ignore_missing_alt?
59
55
  add_failure(
60
56
  "image #{@img.url.raw_attribute} does not have an alt attribute",
61
- line: @img.line,
62
- content: @img.content,
57
+ element: @img,
63
58
  )
64
59
  elsif (empty_alt_tag? || alt_all_spaces?) && !ignore_empty_alt?
65
60
  add_failure(
66
61
  "image #{@img.url.raw_attribute} has an alt attribute, but no content",
67
- line: @img.line,
68
- content: @img.content,
62
+ element: @img,
69
63
  )
70
64
  end
71
65
  end
72
66
 
73
67
  add_failure(
74
68
  "image #{@img.url.raw_attribute} uses the http scheme",
75
- line: @img.line,
76
- content: @img.content,
69
+ element: @img,
77
70
  ) if @runner.enforce_https? && @img.url.http?
78
71
  end
79
72
 
@@ -10,7 +10,7 @@ module HTMLProofer
10
10
  next if @link.ignore?
11
11
 
12
12
  if !allow_hash_href? && @link.node["href"] == "#"
13
- add_failure("linking to internal hash #, which points to nowhere", line: @link.line, content: @link.content)
13
+ add_failure("linking to internal hash #, which points to nowhere", element: @link)
14
14
  next
15
15
  end
16
16
 
@@ -18,21 +18,20 @@ module HTMLProofer
18
18
  if blank?(@link.url.raw_attribute)
19
19
  next if allow_missing_href?
20
20
 
21
- add_failure("'#{@link.node.name}' tag is missing a reference", line: @link.line, content: @link.content)
21
+ add_failure("'#{@link.node.name}' tag is missing a reference", element: @link)
22
22
  next
23
23
  end
24
24
 
25
25
  # is it even a valid URL?
26
26
  unless @link.url.valid?
27
- add_failure("#{@link.href} is an invalid URL", line: @link.line, content: @link.content)
27
+ add_failure("#{@link.href} is an invalid URL", element: @link)
28
28
  next
29
29
  end
30
30
 
31
31
  if @link.url.protocol_relative?
32
32
  add_failure(
33
33
  "#{@link.url} is a protocol-relative URL, use explicit https:// instead",
34
- line: @link.line,
35
- content: @link.content,
34
+ element: @link,
36
35
  )
37
36
  next
38
37
  end
@@ -50,7 +49,7 @@ module HTMLProofer
50
49
  next if @link.node["rel"] == "dns-prefetch"
51
50
 
52
51
  unless @link.url.path?
53
- add_failure("#{@link.url.raw_attribute} is an invalid URL", line: @link.line, content: @link.content)
52
+ add_failure("#{@link.url.raw_attribute} is an invalid URL", element: @link)
54
53
  next
55
54
  end
56
55
 
@@ -60,8 +59,7 @@ module HTMLProofer
60
59
  if @link.url.unslashed_directory?(@link.url.absolute_path)
61
60
  add_failure(
62
61
  "internally linking to a directory #{@link.url.raw_attribute} without trailing slash",
63
- line: @link.line,
64
- content: @link.content,
62
+ element: @link,
65
63
  )
66
64
  next
67
65
  end
@@ -88,7 +86,7 @@ module HTMLProofer
88
86
  when "http"
89
87
  return unless @runner.options[:enforce_https]
90
88
 
91
- add_failure("#{@link.url.raw_attribute} is not an HTTPS link", line: @link.line, content: @link.content)
89
+ add_failure("#{@link.url.raw_attribute} is not an HTTPS link", element: @link)
92
90
  end
93
91
  end
94
92
 
@@ -96,14 +94,12 @@ module HTMLProofer
96
94
  if @link.url.path.empty?
97
95
  add_failure(
98
96
  "#{@link.url.raw_attribute} contains no email address",
99
- line: @link.line,
100
- content: @link.content,
97
+ element: @link,
101
98
  ) unless ignore_empty_mailto?
102
99
  elsif !/#{URI::MailTo::EMAIL_REGEXP}/o.match?(@link.url.path)
103
100
  add_failure(
104
101
  "#{@link.url.raw_attribute} contains an invalid email address",
105
- line: @link.line,
106
- content: @link.content,
102
+ element: @link,
107
103
  )
108
104
  end
109
105
  end
@@ -111,8 +107,7 @@ module HTMLProofer
111
107
  def handle_tel
112
108
  add_failure(
113
109
  "#{@link.url.raw_attribute} contains no phone number",
114
- line: @link.line,
115
- content: @link.content,
110
+ element: @link,
116
111
  ) if @link.url.path.empty?
117
112
  end
118
113
 
@@ -130,16 +125,14 @@ module HTMLProofer
130
125
  if blank?(@link.node["integrity"]) && blank?(@link.node["crossorigin"])
131
126
  add_failure(
132
127
  "SRI and CORS not provided in: #{@link.url.raw_attribute}",
133
- line: @link.line,
134
- content: @link.content,
128
+ element: @link,
135
129
  )
136
130
  elsif blank?(@link.node["integrity"])
137
- add_failure("Integrity is missing in: #{@link.url.raw_attribute}", line: @link.line, content: @link.content)
131
+ add_failure("Integrity is missing in: #{@link.url.raw_attribute}", element: @link)
138
132
  elsif blank?(@link.node["crossorigin"])
139
133
  add_failure(
140
134
  "CORS not provided for external resource in: #{@link.link.url.raw_attribute}",
141
- line: @link.line,
142
- content: @link.content,
135
+ element: @link,
143
136
  )
144
137
  end
145
138
  end
@@ -11,24 +11,22 @@ module HTMLProofer
11
11
 
12
12
  # does the open_graph exist?
13
13
  if missing_content?
14
- add_failure("open graph has no content attribute", line: @open_graph.line, content: @open_graph.content)
14
+ add_failure("open graph has no content attribute", element: @open_graph)
15
15
  elsif empty_content?
16
- add_failure("open graph content attribute is empty", line: @open_graph.line, content: @open_graph.content)
16
+ add_failure("open graph content attribute is empty", element: @open_graph)
17
17
  elsif !@open_graph.url.valid?
18
- add_failure("#{@open_graph.src} is an invalid URL", line: @open_graph.line)
18
+ add_failure("#{@open_graph.src} is an invalid URL", element: @open_graph)
19
19
  elsif @open_graph.url.protocol_relative?
20
20
  add_failure(
21
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,
22
+ element: @open_graph,
24
23
  )
25
24
  elsif @open_graph.url.remote?
26
25
  add_to_external_urls(@open_graph.url, @open_graph.line)
27
26
  else
28
27
  add_failure(
29
28
  "internal open graph #{@open_graph.url.raw_attribute} does not exist",
30
- line: @open_graph.line,
31
- content: @open_graph.content,
29
+ element: @open_graph,
32
30
  ) unless @open_graph.url.exists?
33
31
  end
34
32
  end
@@ -12,12 +12,11 @@ module HTMLProofer
12
12
 
13
13
  # does the script exist?
14
14
  if missing_src?
15
- add_failure("script is empty and has no src attribute", line: @script.line, content: @script.content)
15
+ add_failure("script is empty and has no src attribute", element: @script)
16
16
  elsif @script.url.protocol_relative?
17
17
  add_failure(
18
18
  "script link #{@script.url} is a protocol-relative URL, use explicit https:// instead",
19
- line: @script.line,
20
- content: @script.content,
19
+ element: @script,
21
20
  )
22
21
  elsif @script.url.remote?
23
22
  add_to_external_urls(@script.url, @script.line)
@@ -25,8 +24,7 @@ module HTMLProofer
25
24
  elsif !@script.url.exists?
26
25
  add_failure(
27
26
  "internal script reference #{@script.src} does not exist",
28
- line: @script.line,
29
- content: @script.content,
27
+ element: @script,
30
28
  )
31
29
  end
32
30
  end
@@ -42,20 +40,17 @@ module HTMLProofer
42
40
  if blank?(@script.node["integrity"]) && blank?(@script.node["crossorigin"])
43
41
  add_failure(
44
42
  "SRI and CORS not provided in: #{@script.url.raw_attribute}",
45
- line: @script.line,
46
- content: @script.content,
43
+ element: @script,
47
44
  )
48
45
  elsif blank?(@script.node["integrity"])
49
46
  add_failure(
50
47
  "Integrity is missing in: #{@script.url.raw_attribute}",
51
- line: @script.line,
52
- content: @script.content,
48
+ element: @script,
53
49
  )
54
50
  elsif blank?(@script.node["crossorigin"])
55
51
  add_failure(
56
52
  "CORS not provided for external resource in: #{@script.url.raw_attribute}",
57
- line: @script.line,
58
- content: @script.content,
53
+ element: @script,
59
54
  )
60
55
  end
61
56
  end
@@ -24,14 +24,14 @@ module HTMLProofer
24
24
  raise NotImplementedError, "HTMLProofer::Check subclasses must implement #run"
25
25
  end
26
26
 
27
- def add_failure(description, line: nil, status: nil, content: nil)
27
+ def add_failure(description, element: nil, line: nil, status: nil, content: nil)
28
28
  @failures << Failure.new(
29
29
  @runner.current_filename,
30
30
  short_name,
31
31
  description,
32
- line: line,
32
+ line: element.nil? ? line : element.line,
33
33
  status: status,
34
- content: content,
34
+ content: element.nil? ? content : element.content,
35
35
  )
36
36
  end
37
37
 
@@ -45,8 +45,8 @@ module HTMLProofer
45
45
  @internal_urls[url_string] = [] if @internal_urls[url_string].nil?
46
46
 
47
47
  metadata = {
48
- source: @runner.current_source,
49
- filename: @runner.current_filename,
48
+ source: url.source,
49
+ filename: url.filename,
50
50
  line: line,
51
51
  base_url: base_url,
52
52
  found: false,
@@ -59,7 +59,7 @@ module HTMLProofer
59
59
 
60
60
  @external_urls[url_string] = [] if @external_urls[url_string].nil?
61
61
 
62
- @external_urls[url_string] << { filename: @runner.current_filename, line: line }
62
+ @external_urls[url_string] << { filename: url.filename, line: line }
63
63
  end
64
64
 
65
65
  class << self
@@ -16,7 +16,7 @@ module HTMLProofer
16
16
  swap_attributes!
17
17
 
18
18
  @base_url = base_url
19
- @url = Attribute::Url.new(runner, link_attribute, base_url: base_url)
19
+ @url = Attribute::Url.new(runner, link_attribute, base_url: base_url, source: @runner.current_source, filename: @runner.current_filename)
20
20
 
21
21
  @line = node.line
22
22
  @content = node.content
@@ -6,8 +6,8 @@ module HTMLProofer
6
6
  class Runner
7
7
  include HTMLProofer::Utils
8
8
 
9
- attr_reader :options, :cache, :logger, :internal_urls, :external_urls, :checked_paths, :current_check
10
- attr_accessor :current_filename, :current_source, :reporter
9
+ attr_reader :options, :cache, :logger, :internal_urls, :external_urls, :resolved_paths, :current_check, :current_filename, :current_source
10
+ attr_accessor :reporter
11
11
 
12
12
  URL_TYPES = [:external, :internal].freeze
13
13
 
@@ -26,7 +26,7 @@ module HTMLProofer
26
26
 
27
27
  @before_request = []
28
28
 
29
- @checked_paths = {}
29
+ @resolved_paths = {}
30
30
 
31
31
  @current_check = nil
32
32
  @current_source = nil
@@ -29,15 +29,11 @@ module HTMLProofer
29
29
  matched_count_to_log = pluralize(matched_files.count, "reference", "references")
30
30
  @logger.log(:debug, "(#{i + 1} / #{links.count}) Internal link #{link}: Checking #{matched_count_to_log}")
31
31
  matched_files.each do |metadata|
32
- url = HTMLProofer::Attribute::Url.new(@runner, link, base_url: metadata[:base_url])
32
+ url = HTMLProofer::Attribute::Url.new(@runner, link, base_url: metadata[:base_url], source: metadata[:source], filename: metadata[:filename])
33
33
 
34
- @runner.current_source = metadata[:source]
35
- @runner.current_filename = metadata[:filename]
36
-
37
- target_file_path = url.absolute_path
38
- unless file_exists?(target_file_path)
34
+ unless url.exists?
39
35
  @failed_checks << Failure.new(
40
- @runner.current_filename,
36
+ metadata[:filename],
41
37
  "Links > Internal",
42
38
  "internally linking to #{url}, which does not exist",
43
39
  line: metadata[:line],
@@ -51,6 +47,7 @@ module HTMLProofer
51
47
  hash_exists = hash_exists_for_url?(url)
52
48
  if hash_exists.nil?
53
49
  # the hash needs to be checked in the target file, we collect the url and metadata
50
+ target_file_path = url.resolved_path
54
51
  unless file_paths_hashes_to_check.key?(target_file_path)
55
52
  file_paths_hashes_to_check[target_file_path] = {}
56
53
  end
@@ -62,7 +59,7 @@ module HTMLProofer
62
59
  end
63
60
  unless hash_exists
64
61
  @failed_checks << Failure.new(
65
- @runner.current_filename,
62
+ metadata[:filename],
66
63
  "Links > Internal",
67
64
  "internally linking to #{url}; the file exists, but the hash '#{url.hash}' does not",
68
65
  line: metadata[:line],
@@ -109,12 +106,6 @@ module HTMLProofer
109
106
  @failed_checks
110
107
  end
111
108
 
112
- private def file_exists?(absolute_path)
113
- return @runner.checked_paths[absolute_path] if @runner.checked_paths.key?(absolute_path)
114
-
115
- @runner.checked_paths[absolute_path] = File.exist?(absolute_path)
116
- end
117
-
118
109
  # verify the hash w/o just based on the URL, w/o looking at the target file
119
110
  # => returns nil if the has could not be verified
120
111
  private def hash_exists_for_url?(url)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HTMLProofer
4
- VERSION = "5.0.5"
4
+ VERSION = "5.0.6"
5
5
  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.5
4
+ version: 5.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Garen Torikian
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-03-07 00:00:00.000000000 Z
11
+ date: 2023-03-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable