nanoc-checking 1.0.2 → 1.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/NEWS.md +12 -0
- data/README.md +2 -2
- data/lib/nanoc/checking/checks/external_links.rb +12 -4
- data/lib/nanoc/checking/checks/internal_links.rb +3 -3
- data/lib/nanoc/checking/checks/mixed_content.rb +1 -1
- data/lib/nanoc/checking/link_collector.rb +130 -0
- data/lib/nanoc/checking/version.rb +1 -1
- data/lib/nanoc/checking.rb +1 -0
- metadata +11 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b380e10a13a38c13d712399af8308a0cb67b533094287649eb30283fceba9be3
|
4
|
+
data.tar.gz: bd6715348e5527f23bedf1812b56bc49d75e5827b5bb318a5165bf5cf689077f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 61e31cc485a14e7a75199c65df33d172dd69caad7d00be40725ec55ca5203f052213846b974dd842be2a33d021d10be184a1266810f9fdcddf89db1a7def572d
|
7
|
+
data.tar.gz: 2472f804af1d3facea1b840d89280070042b27fc03d91475b91db5e41a6783261a84ac62f83d6ea25811112ee85ff045e5a9110bc8ca398f08b4650dcfbc65ae
|
data/NEWS.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
# nanoc-checking news
|
2
2
|
|
3
|
+
## 1.0.4 (2024-04-19)
|
4
|
+
|
5
|
+
Enhancements:
|
6
|
+
|
7
|
+
- Added support for `javascript:` pseudo-URLs (#1698)
|
8
|
+
|
9
|
+
## 1.0.3 (2024-03-15)
|
10
|
+
|
11
|
+
Fixes:
|
12
|
+
|
13
|
+
- Restore compatibility with Nanoc 4.12.20
|
14
|
+
|
3
15
|
## 1.0.2 (2022-01-15)
|
4
16
|
|
5
17
|
Fixes:
|
data/README.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# nanoc-checking
|
2
2
|
|
3
|
-
This provides the `check` command and associated functionality for [Nanoc](https://nanoc.
|
3
|
+
This provides the `check` command and associated functionality for [Nanoc](https://nanoc.app).
|
4
4
|
|
5
|
-
For details, see the [Checking correctness of Nanoc sites](https://nanoc.
|
5
|
+
For details, see the [Checking correctness of Nanoc sites](https://nanoc.app/doc/testing/) chapter of the Nanoc documentation.
|
@@ -13,7 +13,7 @@ module Nanoc
|
|
13
13
|
# Find all broken external hrefs
|
14
14
|
# TODO: de-duplicate this (duplicated in internal links check)
|
15
15
|
filenames = output_html_filenames.reject { |f| excluded_file?(f) }
|
16
|
-
hrefs_with_filenames = ::Nanoc::
|
16
|
+
hrefs_with_filenames = ::Nanoc::Checking::LinkCollector.new(filenames, :external).filenames_per_href
|
17
17
|
results = select_invalid(hrefs_with_filenames.keys.shuffle)
|
18
18
|
|
19
19
|
# Report them
|
@@ -21,7 +21,7 @@ module Nanoc
|
|
21
21
|
filenames = hrefs_with_filenames[res.href]
|
22
22
|
filenames.each do |filename|
|
23
23
|
add_issue(
|
24
|
-
"broken reference to
|
24
|
+
"broken reference to <#{res.href}>: #{res.explanation}",
|
25
25
|
subject: filename,
|
26
26
|
)
|
27
27
|
end
|
@@ -43,6 +43,13 @@ module Nanoc
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def validate(href)
|
46
|
+
# Skip javascript: URLs
|
47
|
+
#
|
48
|
+
# This needs to be handled explicitly, because URI.parse does not
|
49
|
+
# like `javascript:` URLs -- presumably because those are not
|
50
|
+
# technically valid URLs.
|
51
|
+
return nil if href.start_with?('javascript:')
|
52
|
+
|
46
53
|
# Parse
|
47
54
|
url = nil
|
48
55
|
begin
|
@@ -71,7 +78,8 @@ module Nanoc
|
|
71
78
|
next
|
72
79
|
end
|
73
80
|
|
74
|
-
|
81
|
+
case res.code
|
82
|
+
when /^3..$/
|
75
83
|
if i == 4
|
76
84
|
return Result.new(href, 'too many redirects')
|
77
85
|
end
|
@@ -87,7 +95,7 @@ module Nanoc
|
|
87
95
|
end
|
88
96
|
|
89
97
|
url = URI.parse(location)
|
90
|
-
|
98
|
+
when '200'
|
91
99
|
return nil
|
92
100
|
else
|
93
101
|
return Result.new(href, res.code)
|
@@ -18,14 +18,14 @@ module Nanoc
|
|
18
18
|
def run
|
19
19
|
# TODO: de-duplicate this (duplicated in external links check)
|
20
20
|
filenames = output_html_filenames
|
21
|
-
uris = ::Nanoc::
|
21
|
+
uris = ::Nanoc::Checking::LinkCollector.new(filenames, :internal).filenames_per_href
|
22
22
|
|
23
23
|
uris.each_pair do |href, fns|
|
24
24
|
fns.each do |filename|
|
25
25
|
next if valid?(href, filename)
|
26
26
|
|
27
27
|
add_issue(
|
28
|
-
"broken reference to
|
28
|
+
"broken reference to <#{href}>",
|
29
29
|
subject: filename,
|
30
30
|
)
|
31
31
|
end
|
@@ -89,7 +89,7 @@ module Nanoc
|
|
89
89
|
# FIXME: do not depend on current working directory
|
90
90
|
origin = File.absolute_path(origin)
|
91
91
|
|
92
|
-
relative_origin = origin[@config.output_dir.size
|
92
|
+
relative_origin = origin[@config.output_dir.size..]
|
93
93
|
excludes = config.fetch(:exclude_origins, [])
|
94
94
|
excludes.any? { |pattern| Regexp.new(pattern).match(relative_origin) }
|
95
95
|
end
|
@@ -14,7 +14,7 @@ module Nanoc
|
|
14
14
|
|
15
15
|
def run
|
16
16
|
filenames = output_html_filenames
|
17
|
-
resource_uris_with_filenames = ::Nanoc::
|
17
|
+
resource_uris_with_filenames = ::Nanoc::Checking::LinkCollector.new(filenames).filenames_per_resource_uri
|
18
18
|
|
19
19
|
resource_uris_with_filenames.each_pair do |uri, fns|
|
20
20
|
next unless guaranteed_insecure?(uri)
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ::Nanoc
|
4
|
+
module Checking
|
5
|
+
class LinkCollector
|
6
|
+
# HTML5 element attributes
|
7
|
+
URI_ATTRS = {
|
8
|
+
'a' => %i[href ping],
|
9
|
+
'area' => %i[href ping],
|
10
|
+
'audio' => %i[src],
|
11
|
+
'base' => %i[href],
|
12
|
+
'blockquote' => %i[cite],
|
13
|
+
'form' => %i[action],
|
14
|
+
'iframe' => %i[src],
|
15
|
+
'img' => %i[src srcset],
|
16
|
+
'link' => %i[href],
|
17
|
+
'object' => %i[data],
|
18
|
+
'script' => %i[src],
|
19
|
+
'source' => %i[src srcset],
|
20
|
+
'video' => %i[poster src],
|
21
|
+
}.freeze
|
22
|
+
# HTML+RDFa global URI attributes
|
23
|
+
GLOBAL_ATTRS = %i[about resource].freeze
|
24
|
+
|
25
|
+
def initialize(filenames, mode = nil)
|
26
|
+
@filenames = filenames
|
27
|
+
@filter =
|
28
|
+
case mode
|
29
|
+
when nil
|
30
|
+
->(_h) { true }
|
31
|
+
when :external
|
32
|
+
->(h) { external_href?(h) }
|
33
|
+
when :internal
|
34
|
+
->(h) { internal_href?(h) }
|
35
|
+
else
|
36
|
+
raise ArgumentError, 'Expected mode argument to be :internal, :external or nil'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def filenames_per_href
|
41
|
+
grouped_filenames { |filename| hrefs_in_file(filename) }
|
42
|
+
end
|
43
|
+
|
44
|
+
def filenames_per_resource_uri
|
45
|
+
grouped_filenames { |filename| resource_uris_in_file(filename) }
|
46
|
+
end
|
47
|
+
|
48
|
+
def external_href?(href)
|
49
|
+
return false if internal_href?(href)
|
50
|
+
|
51
|
+
href =~ %r{^(//|[a-z-]+:)}
|
52
|
+
end
|
53
|
+
|
54
|
+
def internal_href?(href)
|
55
|
+
return false if href.nil?
|
56
|
+
|
57
|
+
href.start_with?('file:/')
|
58
|
+
end
|
59
|
+
|
60
|
+
# all links
|
61
|
+
def hrefs_in_file(filename)
|
62
|
+
uris_in_file filename, nil
|
63
|
+
end
|
64
|
+
|
65
|
+
# embedded resources, used by the mixed-content checker
|
66
|
+
def resource_uris_in_file(filename)
|
67
|
+
uris_in_file filename, %w[audio base form iframe img link object script source video]
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def grouped_filenames
|
73
|
+
require 'nokogiri'
|
74
|
+
grouped_filenames = {}
|
75
|
+
@filenames.each do |filename|
|
76
|
+
yield(filename).each do |resouce_uri|
|
77
|
+
grouped_filenames[resouce_uri] ||= Set.new
|
78
|
+
grouped_filenames[resouce_uri] << filename
|
79
|
+
end
|
80
|
+
end
|
81
|
+
grouped_filenames
|
82
|
+
end
|
83
|
+
|
84
|
+
def uris_in_file(filename, tag_names)
|
85
|
+
uris = Set.new
|
86
|
+
base_uri = URI("file://#{filename}")
|
87
|
+
doc = Nokogiri::HTML(::File.read(filename))
|
88
|
+
doc.traverse do |tag|
|
89
|
+
next unless tag_names.nil? || tag_names.include?(tag.name)
|
90
|
+
|
91
|
+
attrs = []
|
92
|
+
attrs += URI_ATTRS[tag.name] unless URI_ATTRS[tag.name].nil?
|
93
|
+
attrs += GLOBAL_ATTRS if tag_names.nil?
|
94
|
+
next if attrs.nil?
|
95
|
+
|
96
|
+
attrs.each do |attr_name|
|
97
|
+
next if tag[attr_name].nil?
|
98
|
+
|
99
|
+
if attr_name == :srcset
|
100
|
+
uris = uris.merge(tag[attr_name].split(',').map { |v| v.strip.split[0].strip }.compact)
|
101
|
+
elsif %i[about ping resource].include?(attr_name)
|
102
|
+
uris = uris.merge(tag[attr_name].split.map(&:strip).compact)
|
103
|
+
else
|
104
|
+
uris << tag[attr_name.to_s]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Strip fragment
|
110
|
+
uris.map! { |uri| uri.gsub(/#.*$/, '') }
|
111
|
+
|
112
|
+
# Resolve paths relative to the filename, return invalid URIs as-is
|
113
|
+
uris.map! do |uri|
|
114
|
+
if uri.start_with?('//')
|
115
|
+
# Don’t modify protocol-relative URLs. They’re absolute!
|
116
|
+
uri
|
117
|
+
else
|
118
|
+
begin
|
119
|
+
URI.join(base_uri, uri).to_s
|
120
|
+
rescue
|
121
|
+
uri
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
uris.select(&@filter)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
data/lib/nanoc/checking.rb
CHANGED
@@ -13,6 +13,7 @@ require_relative 'checking/check'
|
|
13
13
|
require_relative 'checking/checks'
|
14
14
|
require_relative 'checking/command_runners'
|
15
15
|
require_relative 'checking/dsl'
|
16
|
+
require_relative 'checking/link_collector'
|
16
17
|
require_relative 'checking/runner'
|
17
18
|
require_relative 'checking/loader'
|
18
19
|
require_relative 'checking/issue'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nanoc-checking
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Denis Defreyne
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-04-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nanoc-cli
|
@@ -19,7 +19,7 @@ dependencies:
|
|
19
19
|
version: '4.12'
|
20
20
|
- - ">="
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: 4.12.
|
22
|
+
version: 4.12.5
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -29,7 +29,7 @@ dependencies:
|
|
29
29
|
version: '4.12'
|
30
30
|
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: 4.12.
|
32
|
+
version: 4.12.5
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: nanoc-core
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -39,7 +39,7 @@ dependencies:
|
|
39
39
|
version: '4.12'
|
40
40
|
- - ">="
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version: 4.12.
|
42
|
+
version: 4.12.5
|
43
43
|
type: :runtime
|
44
44
|
prerelease: false
|
45
45
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -49,7 +49,7 @@ dependencies:
|
|
49
49
|
version: '4.12'
|
50
50
|
- - ">="
|
51
51
|
- !ruby/object:Gem::Version
|
52
|
-
version: 4.12.
|
52
|
+
version: 4.12.5
|
53
53
|
description: Provides checking functionality for Nanoc
|
54
54
|
email: denis+rubygems@denis.ws
|
55
55
|
executables: []
|
@@ -74,14 +74,16 @@ files:
|
|
74
74
|
- lib/nanoc/checking/commands/check.rb
|
75
75
|
- lib/nanoc/checking/dsl.rb
|
76
76
|
- lib/nanoc/checking/issue.rb
|
77
|
+
- lib/nanoc/checking/link_collector.rb
|
77
78
|
- lib/nanoc/checking/loader.rb
|
78
79
|
- lib/nanoc/checking/runner.rb
|
79
80
|
- lib/nanoc/checking/version.rb
|
80
|
-
homepage: https://nanoc.
|
81
|
+
homepage: https://nanoc.app/
|
81
82
|
licenses:
|
82
83
|
- MIT
|
83
84
|
metadata:
|
84
85
|
rubygems_mfa_required: 'true'
|
86
|
+
source_code_uri: https://github.com/nanoc/nanoc/tree/nanoc-checking-v1.0.4/nanoc-checking
|
85
87
|
post_install_message:
|
86
88
|
rdoc_options: []
|
87
89
|
require_paths:
|
@@ -90,14 +92,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
90
92
|
requirements:
|
91
93
|
- - ">="
|
92
94
|
- !ruby/object:Gem::Version
|
93
|
-
version: '2.
|
95
|
+
version: '2.7'
|
94
96
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
97
|
requirements:
|
96
98
|
- - ">="
|
97
99
|
- !ruby/object:Gem::Version
|
98
100
|
version: '0'
|
99
101
|
requirements: []
|
100
|
-
rubygems_version: 3.
|
102
|
+
rubygems_version: 3.5.9
|
101
103
|
signing_key:
|
102
104
|
specification_version: 4
|
103
105
|
summary: Checking support for Nanoc
|