xcop 0.9.0 → 0.10.1
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 +4 -4
- data/Gemfile +1 -0
- data/Gemfile.lock +25 -21
- data/README.md +1 -1
- data/Rakefile +1 -1
- data/bin/xcop +2 -2
- data/features/comments.feature +65 -0
- data/features/step_definitions/steps.rb +11 -10
- data/lib/xcop/cli.rb +14 -8
- data/lib/xcop/document.rb +116 -9
- data/lib/xcop/rake_task.rb +8 -7
- data/lib/xcop/version.rb +1 -1
- data/xcop.gemspec +5 -5
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fa89e4f1fcf4bd98059669b6fdd5dfae445a9c6fc43bbee41486f974b8d7af6e
|
|
4
|
+
data.tar.gz: 32f664bba8e5dc4450919c6af6f19146a80d97ef9bc5db595cbd4800afd8d9e2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9fc34e6689bb4f67f3f14c764f2443764daf856b6b4c5be763b07bc9b4ab0003b3841fdb38c3120478dfc9e1f93d23462c8021c4d189ec9a4cf69a60c588200d
|
|
7
|
+
data.tar.gz: 71fae53f841ad1cb2ff31e3ca741d4d167643099daad5d270aac8aaac86732b3851c659d18974a707d51f01f4fae1eb7742324681d3ce7aca3b295ddd38776a2
|
data/Gemfile
CHANGED
|
@@ -11,6 +11,7 @@ gem 'minitest', '~>6.0', require: false
|
|
|
11
11
|
gem 'minitest-reporters', '~>1.7', require: false
|
|
12
12
|
gem 'rake', '~>13.2', require: false
|
|
13
13
|
gem 'rubocop', '~>1.75', require: false
|
|
14
|
+
gem 'rubocop-elegant', '~>0.5', require: false
|
|
14
15
|
gem 'rubocop-minitest', '~>0.38', require: false
|
|
15
16
|
gem 'rubocop-performance', '~>1.25', require: false
|
|
16
17
|
gem 'rubocop-rake', '~>0.7', require: false
|
data/Gemfile.lock
CHANGED
|
@@ -13,9 +13,9 @@ GEM
|
|
|
13
13
|
ansi (1.6.0)
|
|
14
14
|
ast (2.4.3)
|
|
15
15
|
base64 (0.3.0)
|
|
16
|
-
bigdecimal (4.1.
|
|
16
|
+
bigdecimal (4.1.2)
|
|
17
17
|
builder (3.3.0)
|
|
18
|
-
cucumber (11.
|
|
18
|
+
cucumber (11.1.1)
|
|
19
19
|
base64 (~> 0.2)
|
|
20
20
|
builder (~> 3.2)
|
|
21
21
|
cucumber-ci-environment (> 9, < 12)
|
|
@@ -32,9 +32,9 @@ GEM
|
|
|
32
32
|
cucumber-gherkin (> 36, < 40)
|
|
33
33
|
cucumber-messages (> 31, < 33)
|
|
34
34
|
cucumber-tag-expressions (> 6, < 9)
|
|
35
|
-
cucumber-cucumber-expressions (19.0.
|
|
35
|
+
cucumber-cucumber-expressions (19.0.1)
|
|
36
36
|
bigdecimal
|
|
37
|
-
cucumber-gherkin (39.
|
|
37
|
+
cucumber-gherkin (39.1.0)
|
|
38
38
|
cucumber-messages (>= 31, < 33)
|
|
39
39
|
cucumber-html-formatter (23.1.0)
|
|
40
40
|
cucumber-messages (> 23, < 33)
|
|
@@ -45,7 +45,7 @@ GEM
|
|
|
45
45
|
docile (1.4.1)
|
|
46
46
|
drb (2.2.3)
|
|
47
47
|
ellipsized (0.3.0)
|
|
48
|
-
erb (6.0.
|
|
48
|
+
erb (6.0.5)
|
|
49
49
|
ffi (1.17.4-aarch64-linux-gnu)
|
|
50
50
|
ffi (1.17.4-aarch64-linux-musl)
|
|
51
51
|
ffi (1.17.4-arm-linux-gnu)
|
|
@@ -55,8 +55,8 @@ GEM
|
|
|
55
55
|
ffi (1.17.4-x86_64-darwin)
|
|
56
56
|
ffi (1.17.4-x86_64-linux-gnu)
|
|
57
57
|
ffi (1.17.4-x86_64-linux-musl)
|
|
58
|
-
json (2.
|
|
59
|
-
language_server-protocol (3.17.0.
|
|
58
|
+
json (2.20.0)
|
|
59
|
+
language_server-protocol (3.17.0.6)
|
|
60
60
|
lint_roller (1.1.0)
|
|
61
61
|
logger (1.7.0)
|
|
62
62
|
loog (0.8.0)
|
|
@@ -64,7 +64,7 @@ GEM
|
|
|
64
64
|
logger (~> 1.0)
|
|
65
65
|
memoist3 (1.0.0)
|
|
66
66
|
mini_mime (1.1.5)
|
|
67
|
-
minitest (6.0.
|
|
67
|
+
minitest (6.0.6)
|
|
68
68
|
drb (~> 2.0)
|
|
69
69
|
prism (~> 1.5)
|
|
70
70
|
minitest-reporters (1.8.0)
|
|
@@ -73,25 +73,25 @@ GEM
|
|
|
73
73
|
minitest (>= 5.0, < 7)
|
|
74
74
|
ruby-progressbar
|
|
75
75
|
multi_test (1.1.0)
|
|
76
|
-
nokogiri (1.19.
|
|
76
|
+
nokogiri (1.19.3-aarch64-linux-gnu)
|
|
77
77
|
racc (~> 1.4)
|
|
78
|
-
nokogiri (1.19.
|
|
78
|
+
nokogiri (1.19.3-aarch64-linux-musl)
|
|
79
79
|
racc (~> 1.4)
|
|
80
|
-
nokogiri (1.19.
|
|
80
|
+
nokogiri (1.19.3-arm-linux-gnu)
|
|
81
81
|
racc (~> 1.4)
|
|
82
|
-
nokogiri (1.19.
|
|
82
|
+
nokogiri (1.19.3-arm-linux-musl)
|
|
83
83
|
racc (~> 1.4)
|
|
84
|
-
nokogiri (1.19.
|
|
84
|
+
nokogiri (1.19.3-arm64-darwin)
|
|
85
85
|
racc (~> 1.4)
|
|
86
|
-
nokogiri (1.19.
|
|
86
|
+
nokogiri (1.19.3-x64-mingw-ucrt)
|
|
87
87
|
racc (~> 1.4)
|
|
88
|
-
nokogiri (1.19.
|
|
88
|
+
nokogiri (1.19.3-x86_64-darwin)
|
|
89
89
|
racc (~> 1.4)
|
|
90
|
-
nokogiri (1.19.
|
|
90
|
+
nokogiri (1.19.3-x86_64-linux-gnu)
|
|
91
91
|
racc (~> 1.4)
|
|
92
|
-
nokogiri (1.19.
|
|
92
|
+
nokogiri (1.19.3-x86_64-linux-musl)
|
|
93
93
|
racc (~> 1.4)
|
|
94
|
-
parallel (1.
|
|
94
|
+
parallel (1.28.0)
|
|
95
95
|
parser (3.3.11.1)
|
|
96
96
|
ast (~> 2.4.1)
|
|
97
97
|
racc
|
|
@@ -99,9 +99,9 @@ GEM
|
|
|
99
99
|
racc (1.8.1)
|
|
100
100
|
rainbow (3.1.1)
|
|
101
101
|
rake (13.4.2)
|
|
102
|
-
regexp_parser (2.
|
|
102
|
+
regexp_parser (2.12.0)
|
|
103
103
|
rexml (3.4.4)
|
|
104
|
-
rubocop (1.
|
|
104
|
+
rubocop (1.88.2)
|
|
105
105
|
json (~> 2.3)
|
|
106
106
|
language_server-protocol (~> 3.17.0.2)
|
|
107
107
|
lint_roller (~> 1.1.0)
|
|
@@ -115,6 +115,9 @@ GEM
|
|
|
115
115
|
rubocop-ast (1.49.1)
|
|
116
116
|
parser (>= 3.3.7.2)
|
|
117
117
|
prism (~> 1.7)
|
|
118
|
+
rubocop-elegant (0.7.1)
|
|
119
|
+
lint_roller (~> 1.1)
|
|
120
|
+
rubocop (~> 1.75)
|
|
118
121
|
rubocop-minitest (0.39.1)
|
|
119
122
|
lint_roller (~> 1.1)
|
|
120
123
|
rubocop (>= 1.75.0, < 2.0)
|
|
@@ -148,7 +151,7 @@ GEM
|
|
|
148
151
|
unicode-emoji (~> 4.1)
|
|
149
152
|
unicode-emoji (4.2.0)
|
|
150
153
|
win32ole (1.9.3)
|
|
151
|
-
yard (0.9.
|
|
154
|
+
yard (0.9.44)
|
|
152
155
|
|
|
153
156
|
PLATFORMS
|
|
154
157
|
aarch64-linux-gnu
|
|
@@ -170,6 +173,7 @@ DEPENDENCIES
|
|
|
170
173
|
minitest-reporters (~> 1.7)
|
|
171
174
|
rake (~> 13.2)
|
|
172
175
|
rubocop (~> 1.75)
|
|
176
|
+
rubocop-elegant (~> 0.5)
|
|
173
177
|
rubocop-minitest (~> 0.38)
|
|
174
178
|
rubocop-performance (~> 1.25)
|
|
175
179
|
rubocop-rake (~> 0.7)
|
data/README.md
CHANGED
|
@@ -122,7 +122,7 @@ To customize the files pattern, use the `files` parameter:
|
|
|
122
122
|
## How to use in Maven `pom.xml`?
|
|
123
123
|
|
|
124
124
|
You can integrate it with the help of
|
|
125
|
-
[maven-antrun-plugin](
|
|
125
|
+
[maven-antrun-plugin](https://maven.apache.org/plugins/maven-antrun-plugin/):
|
|
126
126
|
|
|
127
127
|
```xml
|
|
128
128
|
<project>
|
data/Rakefile
CHANGED
data/bin/xcop
CHANGED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2017-2026 Yegor Bugayenko
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
Feature: Comment Formatting
|
|
4
|
+
As an author of XML I want XCOP to enforce
|
|
5
|
+
a single canonical layout for XML comments
|
|
6
|
+
|
|
7
|
+
Scenario: Messy single-line comment is rejected
|
|
8
|
+
Given I have a "single.xml" file with content:
|
|
9
|
+
"""
|
|
10
|
+
<?xml version="1.0"?>
|
|
11
|
+
<a>
|
|
12
|
+
<!-- text -->
|
|
13
|
+
</a>
|
|
14
|
+
|
|
15
|
+
"""
|
|
16
|
+
When I run bin/xcop with "single.xml"
|
|
17
|
+
Then Exit code is not zero
|
|
18
|
+
|
|
19
|
+
Scenario: Messy single-line comment is fixed
|
|
20
|
+
Given I have a "single.xml" file with content:
|
|
21
|
+
"""
|
|
22
|
+
<?xml version="1.0"?>
|
|
23
|
+
<a>
|
|
24
|
+
<!-- text -->
|
|
25
|
+
</a>
|
|
26
|
+
|
|
27
|
+
"""
|
|
28
|
+
When I run bin/xcop with "--fix single.xml"
|
|
29
|
+
Then Exit code is zero
|
|
30
|
+
And I run bin/xcop with "single.xml"
|
|
31
|
+
Then Exit code is zero
|
|
32
|
+
And Stdout contains "single.xml looks good"
|
|
33
|
+
|
|
34
|
+
Scenario: Over-indented multi-line comment is rejected
|
|
35
|
+
Given I have a "multi.xml" file with content:
|
|
36
|
+
"""
|
|
37
|
+
<?xml version="1.0"?>
|
|
38
|
+
<a>
|
|
39
|
+
<!--
|
|
40
|
+
line1
|
|
41
|
+
line2
|
|
42
|
+
-->
|
|
43
|
+
</a>
|
|
44
|
+
|
|
45
|
+
"""
|
|
46
|
+
When I run bin/xcop with "multi.xml"
|
|
47
|
+
Then Exit code is not zero
|
|
48
|
+
|
|
49
|
+
Scenario: Over-indented multi-line comment is fixed
|
|
50
|
+
Given I have a "multi.xml" file with content:
|
|
51
|
+
"""
|
|
52
|
+
<?xml version="1.0"?>
|
|
53
|
+
<a>
|
|
54
|
+
<!--
|
|
55
|
+
line1
|
|
56
|
+
line2
|
|
57
|
+
-->
|
|
58
|
+
</a>
|
|
59
|
+
|
|
60
|
+
"""
|
|
61
|
+
When I run bin/xcop with "--fix multi.xml"
|
|
62
|
+
Then Exit code is zero
|
|
63
|
+
And I run bin/xcop with "multi.xml"
|
|
64
|
+
Then Exit code is zero
|
|
65
|
+
And Stdout contains "multi.xml looks good"
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
# SPDX-FileCopyrightText: Copyright (c) 2017-2026 Yegor Bugayenko
|
|
2
2
|
# SPDX-License-Identifier: MIT
|
|
3
3
|
|
|
4
|
+
require 'English'
|
|
4
5
|
require 'nokogiri'
|
|
5
|
-
require 'tmpdir'
|
|
6
6
|
require 'slop'
|
|
7
|
-
require '
|
|
7
|
+
require 'tmpdir'
|
|
8
8
|
|
|
9
9
|
Before do
|
|
10
10
|
@cwd = Dir.pwd
|
|
11
11
|
@dir = Dir.mktmpdir('test')
|
|
12
12
|
FileUtils.mkdir_p(@dir)
|
|
13
13
|
Dir.chdir(@dir)
|
|
14
|
-
@opts =
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
@opts =
|
|
15
|
+
Slop.parse(['-v', '-s', @dir]) do |o|
|
|
16
|
+
o.bool('-v', '--verbose')
|
|
17
|
+
o.string('-s', '--source')
|
|
18
|
+
end
|
|
18
19
|
end
|
|
19
20
|
|
|
20
21
|
After do
|
|
@@ -34,19 +35,19 @@ When(%r{^I run bin/xcop with "([^"]*)"$}) do |arg|
|
|
|
34
35
|
end
|
|
35
36
|
|
|
36
37
|
Then(/^Stdout contains "([^"]*)"$/) do |txt|
|
|
37
|
-
raise "STDOUT doesn't contain '#{txt}':\n#{@stdout}" unless @stdout.include?(txt)
|
|
38
|
+
raise(StandardError, "STDOUT doesn't contain '#{txt}':\n#{@stdout}") unless @stdout.include?(txt)
|
|
38
39
|
end
|
|
39
40
|
|
|
40
41
|
Then(/^Stdout is empty$/) do
|
|
41
|
-
raise "STDOUT is not empty:\n#{@stdout}" unless @stdout == ''
|
|
42
|
+
raise(StandardError, "STDOUT is not empty:\n#{@stdout}") unless @stdout == ''
|
|
42
43
|
end
|
|
43
44
|
|
|
44
45
|
Then(/^Exit code is zero$/) do
|
|
45
|
-
raise "Non-zero exit #{@exitstatus}:\n#{@stdout}" unless @exitstatus.zero?
|
|
46
|
+
raise(StandardError, "Non-zero exit #{@exitstatus}:\n#{@stdout}") unless @exitstatus.zero?
|
|
46
47
|
end
|
|
47
48
|
|
|
48
49
|
Then(/^Exit code is not zero$/) do
|
|
49
|
-
raise 'Zero exit code' if @exitstatus.zero?
|
|
50
|
+
raise(StandardError, 'Zero exit code') if @exitstatus.zero?
|
|
50
51
|
end
|
|
51
52
|
|
|
52
53
|
When(/^I run bash with "([^"]*)"$/) do |text|
|
data/lib/xcop/cli.rb
CHANGED
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
# SPDX-FileCopyrightText: Copyright (c) 2017-2026 Yegor Bugayenko
|
|
2
2
|
# SPDX-License-Identifier: MIT
|
|
3
3
|
|
|
4
|
-
require 'nokogiri'
|
|
5
4
|
require 'differ'
|
|
5
|
+
require 'nokogiri'
|
|
6
6
|
require 'rainbow'
|
|
7
|
-
require_relative 'version'
|
|
8
7
|
require_relative 'document'
|
|
8
|
+
require_relative 'version'
|
|
9
9
|
|
|
10
10
|
# Command line interface.
|
|
11
11
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
|
12
12
|
# Copyright:: Copyright (c) 2017-2026 Yegor Bugayenko
|
|
13
13
|
# License:: MIT
|
|
14
14
|
class Xcop::CLI
|
|
15
|
-
# Extensions recognized when a directory is passed as input.
|
|
16
15
|
EXTENSIONS = %w[xml xsd xhtml xsl html].freeze
|
|
17
16
|
|
|
18
17
|
def initialize(files, nocolor: false)
|
|
@@ -30,18 +29,25 @@ class Xcop::CLI
|
|
|
30
29
|
doc = Xcop::Document.new(f)
|
|
31
30
|
diff = doc.diff(nocolor: @nocolor)
|
|
32
31
|
unless diff.empty?
|
|
33
|
-
puts
|
|
34
|
-
raise "Invalid XML formatting in #{f}"
|
|
32
|
+
puts(diff)
|
|
33
|
+
raise(StandardError, "Invalid XML formatting in #{f}")
|
|
34
|
+
end
|
|
35
|
+
errors = doc.validate
|
|
36
|
+
unless errors.empty?
|
|
37
|
+
puts(errors.join("\n"))
|
|
38
|
+
raise(StandardError, "XSD validation failed in #{f}")
|
|
35
39
|
end
|
|
36
40
|
yield(f) if block_given?
|
|
37
41
|
end
|
|
38
42
|
end
|
|
39
43
|
|
|
40
|
-
# Fix them all.
|
|
44
|
+
# Fix them all. The block, when given, receives the file path and a
|
|
45
|
+
# status symbol that is +:fixed+ when the file was rewritten and
|
|
46
|
+
# +:untouched+ when the file was already canonical.
|
|
41
47
|
def fix
|
|
42
48
|
@files.each do |f|
|
|
43
|
-
Xcop::Document.new(f).fix
|
|
44
|
-
yield(f) if block_given?
|
|
49
|
+
status = Xcop::Document.new(f).fix
|
|
50
|
+
yield(f, status) if block_given?
|
|
45
51
|
end
|
|
46
52
|
end
|
|
47
53
|
end
|
data/lib/xcop/document.rb
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# SPDX-FileCopyrightText: Copyright (c) 2017-2026 Yegor Bugayenko
|
|
2
2
|
# SPDX-License-Identifier: MIT
|
|
3
3
|
|
|
4
|
-
require 'nokogiri'
|
|
5
4
|
require 'differ'
|
|
5
|
+
require 'nokogiri'
|
|
6
6
|
require 'rainbow'
|
|
7
|
+
require 'set'
|
|
7
8
|
require_relative 'version'
|
|
8
9
|
|
|
9
10
|
# One document.
|
|
@@ -19,21 +20,127 @@ class Xcop::Document
|
|
|
19
20
|
|
|
20
21
|
# Return the difference, if any (empty string if everything is clean).
|
|
21
22
|
def diff(nocolor: false)
|
|
22
|
-
|
|
23
|
-
ideal = xml.to_xml(indent: 2)
|
|
24
|
-
now = File.read(@path)
|
|
25
|
-
differ(ideal, now, nocolor: nocolor)
|
|
23
|
+
differ(ideal, File.read(@path), nocolor: nocolor)
|
|
26
24
|
end
|
|
27
25
|
|
|
28
|
-
# Fixes the document
|
|
26
|
+
# Fixes the document, returning +:fixed+ when the file content
|
|
27
|
+
# changed on disk and +:untouched+ when the file was already
|
|
28
|
+
# canonical.
|
|
29
29
|
def fix
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
File.write(@path,
|
|
30
|
+
canonical = ideal
|
|
31
|
+
return :untouched if canonical == File.read(@path)
|
|
32
|
+
File.write(@path, canonical)
|
|
33
|
+
:fixed
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Validates the document against its declared XSD schema, if any.
|
|
37
|
+
# Returns an array of error message strings (empty when valid or no
|
|
38
|
+
# schema declared); a declared but missing schema is itself an error.
|
|
39
|
+
def validate
|
|
40
|
+
xml = Nokogiri::XML(File.read(@path))
|
|
41
|
+
xsd = schema(xml)
|
|
42
|
+
return [] unless xsd
|
|
43
|
+
return ["schema file is absent at #{xsd}"] unless File.exist?(xsd)
|
|
44
|
+
Nokogiri::XML::Schema(File.read(xsd)).validate(xml).map(&:message)
|
|
33
45
|
end
|
|
34
46
|
|
|
47
|
+
XSI_NS = 'http://www.w3.org/2001/XMLSchema-instance'.freeze
|
|
48
|
+
|
|
35
49
|
private
|
|
36
50
|
|
|
51
|
+
# The canonical, well-formatted version of the document.
|
|
52
|
+
def ideal
|
|
53
|
+
xml = Nokogiri::XML(File.read(@path), &:noblanks)
|
|
54
|
+
reshape(xml)
|
|
55
|
+
text = xml.to_xml(indent: 2)
|
|
56
|
+
unused(xml).each do |prefix|
|
|
57
|
+
text =
|
|
58
|
+
if prefix.nil?
|
|
59
|
+
text.gsub(/\s+xmlns="[^"]*"/, '')
|
|
60
|
+
else
|
|
61
|
+
text.gsub(/\s+xmlns:#{Regexp.escape(prefix)}="[^"]*"/, '')
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
Nokogiri::XML(text, &:noblanks).to_xml(indent: 2)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Rewrites every comment node into one of two canonical shapes so that
|
|
68
|
+
# +diff+ and +--fix+ can report and correct sloppy comment layout. A
|
|
69
|
+
# comment whose text has no end-of-line character is collapsed onto a
|
|
70
|
+
# single line as +<!-- text -->+. A comment whose text spans several
|
|
71
|
+
# lines is re-emitted with +<!--+ and +-->+ each alone on their own
|
|
72
|
+
# line and every body line trimmed to the comment's own indent.
|
|
73
|
+
def reshape(xml)
|
|
74
|
+
xml.traverse do |node|
|
|
75
|
+
next unless node.comment?
|
|
76
|
+
node.native_content = canonical(node)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# The canonical inner text (the part between +<!--+ and +-->+) for a
|
|
81
|
+
# single comment node, indented to match the node's depth.
|
|
82
|
+
def canonical(node)
|
|
83
|
+
raw = node.content
|
|
84
|
+
body = raw.strip
|
|
85
|
+
return " #{body} " unless raw.include?("\n")
|
|
86
|
+
indent = ' ' * depth(node)
|
|
87
|
+
body = body.split("\n").map { |line| line.strip.empty? ? '' : indent + line.strip }.join("\n")
|
|
88
|
+
"\n#{body}\n#{indent}"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# The number of ancestor elements of +node+, which equals the number
|
|
92
|
+
# of two-space indentation levels that +to_xml+ places before it.
|
|
93
|
+
def depth(node)
|
|
94
|
+
levels = 0
|
|
95
|
+
parent = node.parent
|
|
96
|
+
while parent && parent.element?
|
|
97
|
+
levels += 1
|
|
98
|
+
parent = parent.parent
|
|
99
|
+
end
|
|
100
|
+
levels
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Returns the set of namespace prefixes that are declared in +xml+
|
|
104
|
+
# but never referenced by any element or attribute. A +nil+ entry in
|
|
105
|
+
# the set represents the default namespace.
|
|
106
|
+
#
|
|
107
|
+
# A prefix counts as "used" not only when it appears as an element or
|
|
108
|
+
# attribute QName, but also when it is referenced from an attribute
|
|
109
|
+
# value as a +prefix:+ token. XSLT and XPath routinely mention a
|
|
110
|
+
# prefix only inside +select+, +test+, +match+, +as+, +use+ and
|
|
111
|
+
# similar attributes (e.g. +as="xs:integer"+ or +select="eo:foo()"+),
|
|
112
|
+
# so stripping such a "declared but not QName-used" prefix would break
|
|
113
|
+
# the stylesheet. See #161.
|
|
114
|
+
def unused(xml)
|
|
115
|
+
used = Set.new
|
|
116
|
+
declared = Set.new
|
|
117
|
+
xml.traverse do |node|
|
|
118
|
+
next unless node.is_a?(Nokogiri::XML::Element)
|
|
119
|
+
used << node.namespace.prefix if node.namespace
|
|
120
|
+
node.attribute_nodes.each do |attr|
|
|
121
|
+
used << attr.namespace.prefix if attr.namespace
|
|
122
|
+
attr.value.scan(/([A-Za-z_][\w.-]*):/) { |m| used << m.first }
|
|
123
|
+
end
|
|
124
|
+
node.namespace_definitions.each { |ns| declared << ns.prefix }
|
|
125
|
+
end
|
|
126
|
+
declared - used
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def schema(xml)
|
|
130
|
+
root = xml.root
|
|
131
|
+
return unless root
|
|
132
|
+
plain = root.at_xpath('@xsi:noNamespaceSchemaLocation', 'xsi' => XSI_NS)
|
|
133
|
+
mapped = root.at_xpath('@xsi:schemaLocation', 'xsi' => XSI_NS)
|
|
134
|
+
location =
|
|
135
|
+
if plain
|
|
136
|
+
plain.value
|
|
137
|
+
elsif mapped
|
|
138
|
+
mapped.value.split.last
|
|
139
|
+
end
|
|
140
|
+
return unless location
|
|
141
|
+
File.expand_path(location, File.dirname(@path))
|
|
142
|
+
end
|
|
143
|
+
|
|
37
144
|
def differ(ideal, fact, nocolor: false)
|
|
38
145
|
return '' if ideal == fact
|
|
39
146
|
if nocolor
|
data/lib/xcop/rake_task.rb
CHANGED
|
@@ -18,9 +18,9 @@ class Xcop::RakeTask < Rake::TaskLib
|
|
|
18
18
|
@includes = %w[xml xsd xhtml xsl html].map { |e| "**/*.#{e}" }
|
|
19
19
|
@excludes = []
|
|
20
20
|
@quiet = false
|
|
21
|
-
desc
|
|
21
|
+
desc('Run Xcop') unless ::Rake.application.last_description
|
|
22
22
|
task(name, *args) do |_, task_args|
|
|
23
|
-
RakeFileUtils.
|
|
23
|
+
RakeFileUtils.__send__(:verbose, true) do
|
|
24
24
|
yield(*[self, task_args].slice(0, task_block.arity)) if block_given?
|
|
25
25
|
run
|
|
26
26
|
end
|
|
@@ -30,22 +30,23 @@ class Xcop::RakeTask < Rake::TaskLib
|
|
|
30
30
|
private
|
|
31
31
|
|
|
32
32
|
def run
|
|
33
|
-
puts
|
|
33
|
+
puts('Running xcop...') unless @quiet
|
|
34
34
|
bad = Dir.glob(@excludes)
|
|
35
35
|
good = Dir.glob(@includes).reject { |f| bad.include?(f) }
|
|
36
|
-
puts
|
|
36
|
+
puts("Inspecting #{pluralize(good.length, 'file')}...") unless @quiet
|
|
37
37
|
begin
|
|
38
38
|
Xcop::CLI.new(good).run do
|
|
39
|
-
print
|
|
39
|
+
print(Rainbow('.').green) unless @quiet
|
|
40
40
|
end
|
|
41
41
|
rescue StandardError => e
|
|
42
|
-
puts
|
|
42
|
+
puts(e.message)
|
|
43
43
|
abort(e.message)
|
|
44
44
|
end
|
|
45
45
|
return if @quiet
|
|
46
|
-
puts
|
|
46
|
+
puts(
|
|
47
47
|
"\n#{pluralize(good.length, 'file')} checked, " \
|
|
48
48
|
"everything looks #{Rainbow('pretty').green}"
|
|
49
|
+
)
|
|
49
50
|
end
|
|
50
51
|
|
|
51
52
|
def pluralize(num, text)
|
data/lib/xcop/version.rb
CHANGED
data/xcop.gemspec
CHANGED
|
@@ -8,7 +8,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
|
8
8
|
require_relative 'lib/xcop/version'
|
|
9
9
|
|
|
10
10
|
Gem::Specification.new do |s|
|
|
11
|
-
s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to?
|
|
11
|
+
s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to?(:required_rubygems_version=)
|
|
12
12
|
s.required_ruby_version = '>= 2.2'
|
|
13
13
|
s.name = 'xcop'
|
|
14
14
|
s.version = Xcop::VERSION
|
|
@@ -23,8 +23,8 @@ Gem::Specification.new do |s|
|
|
|
23
23
|
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
24
24
|
s.rdoc_options = ['--charset=UTF-8']
|
|
25
25
|
s.extra_rdoc_files = ['README.md', 'LICENSE.txt']
|
|
26
|
-
s.add_dependency
|
|
27
|
-
s.add_dependency
|
|
28
|
-
s.add_dependency
|
|
29
|
-
s.add_dependency
|
|
26
|
+
s.add_dependency('differ', '~>0.1.2')
|
|
27
|
+
s.add_dependency('nokogiri', '~>1.8')
|
|
28
|
+
s.add_dependency('rainbow', '~>3.0')
|
|
29
|
+
s.add_dependency('slop', '~>4.4')
|
|
30
30
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: xcop
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.10.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yegor Bugayenko
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-07-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: differ
|
|
@@ -85,6 +85,7 @@ files:
|
|
|
85
85
|
- bin/xcop
|
|
86
86
|
- cucumber.yml
|
|
87
87
|
- features/cli.feature
|
|
88
|
+
- features/comments.feature
|
|
88
89
|
- features/gem_package.feature
|
|
89
90
|
- features/rake.feature
|
|
90
91
|
- features/step_definitions/steps.rb
|