diff --git a/lib/html-proofer/cache.rb b/lib/html-proofer/cache.rb
index 2e143f79..18304320 100644
--- a/lib/html-proofer/cache.rb
+++ b/lib/html-proofer/cache.rb
@@ -109,8 +109,13 @@ def detect_url_changes(found)
additions
end
+ # TODO: Garbage performance--both the external and internal
+ # caches need access to this file. Write a proper versioned
+ # schema in the future
def write
- File.write(cache_file, @cache_log.to_json)
+ file = {}
+ file = JSON.parse(File.read(cache_file)) if File.exist?(cache_file)
+ File.write(cache_file, file.merge(@cache_log).to_json)
end
def load?
diff --git a/lib/html-proofer/check/links.rb b/lib/html-proofer/check/links.rb
index 5754b692..27b7b3a2 100644
--- a/lib/html-proofer/check/links.rb
+++ b/lib/html-proofer/check/links.rb
@@ -59,11 +59,8 @@ def run
add_to_external_urls(@link.href || @link.src)
next
elsif @link.internal?
- if @link.exists? || @link.hash
- add_to_internal_urls(@link.href, InternalLink.new(@link, @path, line, content))
- else
- add_issue("internally linking to #{@link.href}, which does not exist", line: line, content: content)
- end
+ add_to_internal_urls(@link.href, InternalLink.new(@link, @path, line, content))
+ add_issue("internally linking to #{@link.href}, which does not exist", line: line, content: content) if !@link.exists? && !@link.hash
end
end
diff --git a/lib/html-proofer/element.rb b/lib/html-proofer/element.rb
index fc3a5f65..ab781c51 100644
--- a/lib/html-proofer/element.rb
+++ b/lib/html-proofer/element.rb
@@ -24,7 +24,7 @@ def initialize(obj, check, logger)
raise e
end
- @aria_hidden = defined?(@aria_hidden) && @aria_hidden == 'true' ? true : false
+ @aria_hidden = defined?(@aria_hidden) && @aria_hidden == 'true'
@data_proofer_ignore = defined?(@data_proofer_ignore)
diff --git a/lib/html-proofer/runner.rb b/lib/html-proofer/runner.rb
index 08480cf9..4ce75018 100644
--- a/lib/html-proofer/runner.rb
+++ b/lib/html-proofer/runner.rb
@@ -63,7 +63,9 @@ def check_list_of_links
swap(url, @options[:url_swap])
end
end
- @external_urls = Hash[*@src.map { |s| [s, nil] }.flatten]
+ @external_urls = @src.each_with_object({}) do |url, hash|
+ hash[url] = nil
+ end
validate_external_urls
end
@@ -123,7 +125,7 @@ def check_parsed(html, path)
end
external_urls = check.external_urls
- external_urls = Hash[check.external_urls.map { |url, file| [swap(url, @options[:url_swap]), file] }] if @options[:url_swap]
+ external_urls = check.external_urls.map { |url, file| [swap(url, @options[:url_swap]), file] }.to_h if @options[:url_swap]
result[:external_urls].merge!(external_urls)
result[:failures].concat(check.issues)
end
diff --git a/lib/html-proofer/url_validator.rb b/lib/html-proofer/url_validator.rb
index 4cf85c11..4f1e3b16 100644
--- a/lib/html-proofer/url_validator.rb
+++ b/lib/html-proofer/url_validator.rb
@@ -85,7 +85,7 @@ def extract_domain_path(uri)
# for HEAD. If we've decided to check for hashes, we must do a GET--HEAD is
# not available as an option.
def external_link_checker(external_urls)
- external_urls = Hash[external_urls.sort]
+ external_urls = external_urls.sort.to_h
count = external_urls.length
check_text = pluralize(count, 'external link', 'external links')
diff --git a/spec/html-proofer/cache_spec.rb b/spec/html-proofer/cache_spec.rb
index 7c5b97a0..1ec5489a 100644
--- a/spec/html-proofer/cache_spec.rb
+++ b/spec/html-proofer/cache_spec.rb
@@ -247,4 +247,58 @@ def read_cache(cache_file)
Timecop.return
end
end
+
+ it 'does recheck failures, regardless of external-only cache' do
+ cache_file_name = '.external.log'
+ cache_location = File.join(storage_dir, cache_file_name)
+
+ file = "#{FIXTURES_DIR}/cache/external_example.html"
+
+ new_time = Time.local(2021, 0o1, 27, 12, 0, 0)
+ Timecop.freeze(new_time)
+
+ File.delete(cache_location) if File.exist?(cache_location)
+
+ run_proofer(file, :file, external_only: true, links_only: true, cache: { timeframe: '1d', cache_file: cache_file_name }.merge(default_cache_options))
+
+ cache = JSON.parse(File.read(cache_location))
+
+ expect(cache.keys.count).to eq(1)
+ expect(cache.keys[0]).to eq('https://github.com/gjtorikian/html-proofer')
+
+ run_proofer(file, :file, links_only: true, cache: { timeframe: '1d', cache_file: cache_file_name }.merge(default_cache_options))
+
+ cache = JSON.parse(File.read(cache_location))
+ expect(cache.keys.count).to eq(1)
+ expect(cache.keys[0]).to eq('https://github.com/gjtorikian/html-proofer')
+
+ Timecop.return
+ end
+
+ it 'does recheck failures, regardless of external and internal cache' do
+ cache_file_name = '.internal_and_external.log'
+ cache_location = File.join(storage_dir, cache_file_name)
+
+ file = "#{FIXTURES_DIR}/cache/internal_and_external_example.html"
+
+ new_time = Time.local(2021, 0o1, 27, 12, 0, 0)
+ Timecop.freeze(new_time)
+
+ File.delete(cache_location) if File.exist?(cache_location)
+
+ run_proofer(file, :file, external_only: true, links_only: true, cache: { timeframe: '1d', cache_file: cache_file_name }.merge(default_cache_options))
+
+ cache = JSON.parse(File.read(cache_location))
+
+ expect(cache.keys.count).to eq(1)
+ expect(cache.keys[0]).to eq('https://github.com/gjtorikian/html-proofer')
+
+ run_proofer(file, :file, links_only: true, cache: { timeframe: '1d', cache_file: cache_file_name }.merge(default_cache_options))
+
+ cache = JSON.parse(File.read(cache_location))
+ expect(cache.keys.count).to eq(2)
+ expect(cache.keys[0]).to eq('https://github.com/gjtorikian/html-proofer')
+
+ Timecop.return
+ end
end
diff --git a/spec/html-proofer/fixtures/cache/.external.log b/spec/html-proofer/fixtures/cache/.external.log
new file mode 100644
index 00000000..d147adeb
--- /dev/null
+++ b/spec/html-proofer/fixtures/cache/.external.log
@@ -0,0 +1 @@
+{"https://github.com/gjtorikian/html-proofer":{"time":"2021-01-27 12:00:00 +0000","filenames":["spec/html-proofer/fixtures/cache/external_example.html"],"status":200,"message":""}}
\ No newline at end of file
diff --git a/spec/html-proofer/fixtures/cache/.internal_and_external.log b/spec/html-proofer/fixtures/cache/.internal_and_external.log
new file mode 100644
index 00000000..17c57ce2
--- /dev/null
+++ b/spec/html-proofer/fixtures/cache/.internal_and_external.log
@@ -0,0 +1 @@
+{"https://github.com/gjtorikian/html-proofer":{"time":"2021-01-27 12:00:00 +0000","filenames":["spec/html-proofer/fixtures/cache/internal_and_external_example.html"],"status":200,"message":""},"/somewhere.html":{"time":"2021-01-27 12:00:00 +0000","filenames":["spec/html-proofer/fixtures/cache/internal_and_external_example.html"],"status":200,"message":""}}
\ No newline at end of file
diff --git a/spec/html-proofer/fixtures/cache/external_example.html b/spec/html-proofer/fixtures/cache/external_example.html
new file mode 100644
index 00000000..09c7add9
--- /dev/null
+++ b/spec/html-proofer/fixtures/cache/external_example.html
@@ -0,0 +1,11 @@
+
+
+
+ Example
+
+
+ The amazing HTMLProofer
+
+
diff --git a/spec/html-proofer/fixtures/cache/internal_and_external_example.html b/spec/html-proofer/fixtures/cache/internal_and_external_example.html
new file mode 100644
index 00000000..1e486d38
--- /dev/null
+++ b/spec/html-proofer/fixtures/cache/internal_and_external_example.html
@@ -0,0 +1,13 @@
+
+
+
+ Example
+
+
+ The amazing HTMLProofer
+
+ Somewhere
+
+
diff --git a/spec/html-proofer/fixtures/vcr_cassettes/cache/external_example_html_external_only_true_links_only_true_cache_timeframe_1d_cache_file_external_log_storage_dir_spec/html-proofer/fixtures/cache_log_level_error_type_file_.yml b/spec/html-proofer/fixtures/vcr_cassettes/cache/external_example_html_external_only_true_links_only_true_cache_timeframe_1d_cache_file_external_log_storage_dir_spec/html-proofer/fixtures/cache_log_level_error_type_file_.yml
new file mode 100644
index 00000000..07a15211
--- /dev/null
+++ b/spec/html-proofer/fixtures/vcr_cassettes/cache/external_example_html_external_only_true_links_only_true_cache_timeframe_1d_cache_file_external_log_storage_dir_spec/html-proofer/fixtures/cache_log_level_error_type_file_.yml
@@ -0,0 +1,76 @@
+---
+http_interactions:
+- request:
+ method: head
+ uri: https://github.com/gjtorikian/html-proofer
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ User-Agent:
+ - Mozilla/5.0 (compatible; HTML Proofer/3.18.5; +https://github.com/gjtorikian/html-proofer)
+ Accept:
+ - application/xml,application/xhtml+xml,text/html;q=0.9, text/plain;q=0.8,image/png,*/*;q=0.5
+ Expect:
+ - ''
+ response:
+ status:
+ code: 200
+ message: ''
+ headers:
+ server:
+ - GitHub.com
+ date:
+ - Sun, 21 Feb 2021 16:32:07 GMT
+ content-type:
+ - text/html; charset=utf-8
+ vary:
+ - X-PJAX, Accept-Encoding, Accept, X-Requested-With
+ etag:
+ - W/"caacf53a5a6580b9579b48c4e7c35847"
+ cache-control:
+ - max-age=0, private, must-revalidate
+ strict-transport-security:
+ - max-age=31536000; includeSubdomains; preload
+ x-frame-options:
+ - deny
+ x-content-type-options:
+ - nosniff
+ x-xss-protection:
+ - 1; mode=block
+ referrer-policy:
+ - no-referrer-when-downgrade
+ expect-ct:
+ - max-age=2592000, report-uri="https://api.github.com/_private/browser/errors"
+ content-security-policy:
+ - 'default-src ''none''; base-uri ''self''; block-all-mixed-content; connect-src
+ ''self'' uploads.github.com www.githubstatus.com collector.githubapp.com api.github.com
+ github-cloud.s3.amazonaws.com github-production-repository-file-5c1aeb.s3.amazonaws.com
+ github-production-upload-manifest-file-7fdce7.s3.amazonaws.com github-production-user-asset-6210df.s3.amazonaws.com
+ cdn.optimizely.com logx.optimizely.com/v1/events wss://alive.github.com online.visualstudio.com/api/v1/locations;
+ font-src github.githubassets.com; form-action ''self'' github.com gist.github.com;
+ frame-ancestors ''none''; frame-src render.githubusercontent.com; img-src
+ ''self'' data: github.githubassets.com identicons.github.com collector.githubapp.com
+ github-cloud.s3.amazonaws.com user-images.githubusercontent.com/ *.githubusercontent.com;
+ manifest-src ''self''; media-src ''none''; script-src github.githubassets.com;
+ style-src ''unsafe-inline'' github.githubassets.com; worker-src github.com/socket-worker-5029ae85.js
+ gist.github.com/socket-worker-5029ae85.js'
+ set-cookie:
+ - _gh_sess=FVxpDGIyyH6A21E%2FHQIg7c18Or8RAQkAqP7S77pa12Gdkt2ht0muVqUEqOFoBCJJI8izF1QaH7NCYDWku3Hk50ic5uaGJnjAPFWI2kX5q6OYQhseU33bO7q0r%2Fl6kdojyfURMLs8Ic7zzZ%2BJxdLlZh8xS0KEeVpX1omvlULMT169y0322Wrsw9YtBBgEtMHinHsyWBDkjSwZxh5y9%2BW7jFx4vPMvBlnao7RTHRAoSPQ3SFW2SdrE76IuSFt89Y7VGOn0EKD%2Fb71JU0Byv8xK1w%3D%3D--8NQJ2ZGl9U%2FqC3M5--1dw7YpQmajE2qqT5%2FQDmug%3D%3D;
+ Path=/; HttpOnly; Secure; SameSite=Lax
+ - _octo=GH1.1.168931837.1613925128; Path=/; Domain=github.com; Expires=Mon,
+ 21 Feb 2022 16:32:08 GMT; Secure; SameSite=Lax
+ - logged_in=no; Path=/; Domain=github.com; Expires=Mon, 21 Feb 2022 16:32:08
+ GMT; HttpOnly; Secure; SameSite=Lax
+ accept-ranges:
+ - bytes
+ x-github-request-id:
+ - EA4B:61B0:217BDFF:269EF9E:60328B08
+ body:
+ encoding: UTF-8
+ string: ''
+ http_version: '2'
+ adapter_metadata:
+ effective_url: https://github.com/gjtorikian/html-proofer
+ recorded_at: Wed, 27 Jan 2021 12:00:00 GMT
+recorded_with: VCR 2.9.3
diff --git a/spec/html-proofer/fixtures/vcr_cassettes/cache/internal_and_external_example_html_external_only_true_links_only_true_cache_timeframe_1d_cache_file_internal_and_external_log_storage_dir_spec/html-proofer/fixtures/cache_log_level_error_type_file_.yml b/spec/html-proofer/fixtures/vcr_cassettes/cache/internal_and_external_example_html_external_only_true_links_only_true_cache_timeframe_1d_cache_file_internal_and_external_log_storage_dir_spec/html-proofer/fixtures/cache_log_level_error_type_file_.yml
new file mode 100644
index 00000000..7af71169
--- /dev/null
+++ b/spec/html-proofer/fixtures/vcr_cassettes/cache/internal_and_external_example_html_external_only_true_links_only_true_cache_timeframe_1d_cache_file_internal_and_external_log_storage_dir_spec/html-proofer/fixtures/cache_log_level_error_type_file_.yml
@@ -0,0 +1,76 @@
+---
+http_interactions:
+- request:
+ method: head
+ uri: https://github.com/gjtorikian/html-proofer
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ User-Agent:
+ - Mozilla/5.0 (compatible; HTML Proofer/3.18.5; +https://github.com/gjtorikian/html-proofer)
+ Accept:
+ - application/xml,application/xhtml+xml,text/html;q=0.9, text/plain;q=0.8,image/png,*/*;q=0.5
+ Expect:
+ - ''
+ response:
+ status:
+ code: 200
+ message: ''
+ headers:
+ server:
+ - GitHub.com
+ date:
+ - Sun, 21 Feb 2021 16:32:07 GMT
+ content-type:
+ - text/html; charset=utf-8
+ vary:
+ - X-PJAX, Accept-Encoding, Accept, X-Requested-With
+ etag:
+ - W/"caacf53a5a6580b9579b48c4e7c35847"
+ cache-control:
+ - max-age=0, private, must-revalidate
+ strict-transport-security:
+ - max-age=31536000; includeSubdomains; preload
+ x-frame-options:
+ - deny
+ x-content-type-options:
+ - nosniff
+ x-xss-protection:
+ - 1; mode=block
+ referrer-policy:
+ - no-referrer-when-downgrade
+ expect-ct:
+ - max-age=2592000, report-uri="https://api.github.com/_private/browser/errors"
+ content-security-policy:
+ - 'default-src ''none''; base-uri ''self''; block-all-mixed-content; connect-src
+ ''self'' uploads.github.com www.githubstatus.com collector.githubapp.com api.github.com
+ github-cloud.s3.amazonaws.com github-production-repository-file-5c1aeb.s3.amazonaws.com
+ github-production-upload-manifest-file-7fdce7.s3.amazonaws.com github-production-user-asset-6210df.s3.amazonaws.com
+ cdn.optimizely.com logx.optimizely.com/v1/events wss://alive.github.com online.visualstudio.com/api/v1/locations;
+ font-src github.githubassets.com; form-action ''self'' github.com gist.github.com;
+ frame-ancestors ''none''; frame-src render.githubusercontent.com; img-src
+ ''self'' data: github.githubassets.com identicons.github.com collector.githubapp.com
+ github-cloud.s3.amazonaws.com user-images.githubusercontent.com/ *.githubusercontent.com;
+ manifest-src ''self''; media-src ''none''; script-src github.githubassets.com;
+ style-src ''unsafe-inline'' github.githubassets.com; worker-src github.com/socket-worker-5029ae85.js
+ gist.github.com/socket-worker-5029ae85.js'
+ set-cookie:
+ - _gh_sess=46RoTpx1xZeM6V2gyQ6RUJMiXmvy%2BbxrEcxPIktSfACs4M3XPgtmOKjITU9cFKOkqb21u%2FA25dQxwAv7y7KInm6XJK3P6xEc9uPTU65y8vpt%2FRN9QK9cfcEyhRQ2k7T1TRRltkalm0G3nOhNZnb1EoUcibLEuDYkJwpTFVBagH55cOSsINz%2BjwLd4dd4BO6k3tV2HjKE6YVHZdGeaq1sIxth7n8LDrp8916Ygm0TAVy7UG71UZC2cQPwz0pRu9VwYUpuDc0PzXWNwsz2Ey74bg%3D%3D--jSHIFDa3UTkzqp%2BP--adTIajHGBxFj%2FQ332TDFrw%3D%3D;
+ Path=/; HttpOnly; Secure; SameSite=Lax
+ - _octo=GH1.1.1571982095.1613925127; Path=/; Domain=github.com; Expires=Mon,
+ 21 Feb 2022 16:32:07 GMT; Secure; SameSite=Lax
+ - logged_in=no; Path=/; Domain=github.com; Expires=Mon, 21 Feb 2022 16:32:07
+ GMT; HttpOnly; Secure; SameSite=Lax
+ accept-ranges:
+ - bytes
+ x-github-request-id:
+ - EA49:128D6:119821F:145FC7E:60328B07
+ body:
+ encoding: UTF-8
+ string: ''
+ http_version: '2'
+ adapter_metadata:
+ effective_url: https://github.com/gjtorikian/html-proofer
+ recorded_at: Wed, 27 Jan 2021 12:00:00 GMT
+recorded_with: VCR 2.9.3