theme-check 0.8.3 → 0.9.0
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/.github/workflows/theme-check.yml +3 -0
- data/CHANGELOG.md +15 -0
- data/CONTRIBUTING.md +2 -1
- data/README.md +4 -1
- data/config/default.yml +37 -0
- data/docs/checks/content_for_header_modification.md +42 -0
- data/docs/checks/parser_blocking_script_tag.md +53 -0
- data/exe/theme-check-language-server +1 -2
- data/lib/theme_check.rb +8 -1
- data/lib/theme_check/analyzer.rb +72 -16
- data/lib/theme_check/check.rb +31 -6
- data/lib/theme_check/checks.rb +9 -1
- data/lib/theme_check/checks/content_for_header_modification.rb +41 -0
- data/lib/theme_check/checks/img_width_and_height.rb +18 -49
- data/lib/theme_check/checks/missing_template.rb +1 -0
- data/lib/theme_check/checks/parser_blocking_javascript.rb +6 -38
- data/lib/theme_check/checks/parser_blocking_script_tag.rb +20 -0
- data/lib/theme_check/checks/template_length.rb +3 -0
- data/lib/theme_check/checks/valid_html_translation.rb +1 -0
- data/lib/theme_check/config.rb +2 -0
- data/lib/theme_check/disabled_check.rb +6 -4
- data/lib/theme_check/disabled_checks.rb +25 -9
- data/lib/theme_check/html_check.rb +7 -0
- data/lib/theme_check/html_node.rb +52 -0
- data/lib/theme_check/html_visitor.rb +36 -0
- data/lib/theme_check/json_file.rb +8 -0
- data/lib/theme_check/language_server.rb +1 -0
- data/lib/theme_check/language_server/completion_providers/filter_completion_provider.rb +1 -0
- data/lib/theme_check/language_server/diagnostics_tracker.rb +64 -0
- data/lib/theme_check/language_server/handler.rb +31 -26
- data/lib/theme_check/language_server/server.rb +1 -1
- data/lib/theme_check/liquid_check.rb +0 -4
- data/lib/theme_check/offense.rb +18 -0
- data/lib/theme_check/template.rb +8 -0
- data/lib/theme_check/theme.rb +7 -2
- data/lib/theme_check/version.rb +1 -1
- data/lib/theme_check/visitor.rb +2 -11
- metadata +10 -2
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "forwardable"
|
3
|
+
|
4
|
+
module ThemeCheck
|
5
|
+
class HtmlNode
|
6
|
+
extend Forwardable
|
7
|
+
attr_reader :template
|
8
|
+
|
9
|
+
def_delegators :@value, :content, :attributes
|
10
|
+
|
11
|
+
def initialize(value, template)
|
12
|
+
@value = value
|
13
|
+
@template = template
|
14
|
+
end
|
15
|
+
|
16
|
+
def literal?
|
17
|
+
@value.name == "text"
|
18
|
+
end
|
19
|
+
|
20
|
+
def children
|
21
|
+
@value.children.map { |child| HtmlNode.new(child, template) }
|
22
|
+
end
|
23
|
+
|
24
|
+
def parent
|
25
|
+
HtmlNode.new(@value.parent, template)
|
26
|
+
end
|
27
|
+
|
28
|
+
def name
|
29
|
+
if @value.name == "#document-fragment"
|
30
|
+
"document"
|
31
|
+
else
|
32
|
+
@value.name
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def value
|
37
|
+
if literal?
|
38
|
+
@value.content
|
39
|
+
else
|
40
|
+
@value
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def markup
|
45
|
+
@value.to_html
|
46
|
+
end
|
47
|
+
|
48
|
+
def line_number
|
49
|
+
@value.line
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "nokogumbo"
|
3
|
+
require "forwardable"
|
4
|
+
|
5
|
+
module ThemeCheck
|
6
|
+
class HtmlVisitor
|
7
|
+
attr_reader :checks
|
8
|
+
|
9
|
+
def initialize(checks)
|
10
|
+
@checks = checks
|
11
|
+
end
|
12
|
+
|
13
|
+
def visit_template(template)
|
14
|
+
doc = parse(template)
|
15
|
+
visit(HtmlNode.new(doc, template))
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def parse(template)
|
21
|
+
Nokogiri::HTML5.fragment(template.source)
|
22
|
+
end
|
23
|
+
|
24
|
+
def visit(node)
|
25
|
+
call_checks(:"on_#{node.name}", node)
|
26
|
+
node.children.each { |child| visit(child) }
|
27
|
+
unless node.literal?
|
28
|
+
call_checks(:"after_#{node.name}", node)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def call_checks(method, *args)
|
33
|
+
checks.call(method, *args)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -9,6 +9,7 @@ require_relative "language_server/completion_helper"
|
|
9
9
|
require_relative "language_server/completion_provider"
|
10
10
|
require_relative "language_server/completion_engine"
|
11
11
|
require_relative "language_server/document_link_engine"
|
12
|
+
require_relative "language_server/diagnostics_tracker"
|
12
13
|
|
13
14
|
Dir[__dir__ + "/language_server/completion_providers/*.rb"].each do |file|
|
14
15
|
require file
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ThemeCheck
|
4
|
+
module LanguageServer
|
5
|
+
class DiagnosticsTracker
|
6
|
+
def initialize
|
7
|
+
@previously_reported_files = Set.new
|
8
|
+
@single_files_offenses = {}
|
9
|
+
@first_run = true
|
10
|
+
end
|
11
|
+
|
12
|
+
def first_run?
|
13
|
+
@first_run
|
14
|
+
end
|
15
|
+
|
16
|
+
def build_diagnostics(offenses, analyzed_files: nil)
|
17
|
+
reported_files = Set.new
|
18
|
+
new_single_file_offenses = {}
|
19
|
+
|
20
|
+
offenses.group_by(&:template).each do |template, template_offenses|
|
21
|
+
next unless template
|
22
|
+
reported_offenses = template_offenses
|
23
|
+
previous_offenses = @single_files_offenses[template.path]
|
24
|
+
if analyzed_files.nil? || analyzed_files.include?(template.path)
|
25
|
+
# We re-analyzed the file, so we know the template_offenses are update to date.
|
26
|
+
reported_single_file_offenses = reported_offenses.select(&:single_file?)
|
27
|
+
if reported_single_file_offenses.any?
|
28
|
+
new_single_file_offenses[template.path] = reported_single_file_offenses
|
29
|
+
end
|
30
|
+
elsif previous_offenses
|
31
|
+
# Merge in the previous ones, if some
|
32
|
+
reported_offenses |= previous_offenses
|
33
|
+
end
|
34
|
+
yield template.path, reported_offenses
|
35
|
+
reported_files << template.path
|
36
|
+
end
|
37
|
+
|
38
|
+
@single_files_offenses.each do |path, _|
|
39
|
+
# Already reported above, skip
|
40
|
+
next if reported_files.include?(path)
|
41
|
+
|
42
|
+
if analyzed_files.nil? || analyzed_files.include?(path)
|
43
|
+
# We re-analyzed this file, if it was not reported, all offenses in it got fixed
|
44
|
+
yield path, []
|
45
|
+
new_single_file_offenses[path] = nil
|
46
|
+
end
|
47
|
+
# NOTE: No need to re-report previous offenses as LSP should keep them around until
|
48
|
+
# we clear them.
|
49
|
+
reported_files << path
|
50
|
+
end
|
51
|
+
|
52
|
+
# Publish diagnostics with empty array if all issues on a previously reported template
|
53
|
+
# have been fixed.
|
54
|
+
(@previously_reported_files - reported_files).each do |path|
|
55
|
+
yield path, []
|
56
|
+
end
|
57
|
+
|
58
|
+
@previously_reported_files = reported_files
|
59
|
+
@single_files_offenses.merge!(new_single_file_offenses)
|
60
|
+
@first_run = false
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
require "benchmark"
|
2
3
|
|
3
4
|
module ThemeCheck
|
4
5
|
module LanguageServer
|
@@ -19,7 +20,7 @@ module ThemeCheck
|
|
19
20
|
|
20
21
|
def initialize(server)
|
21
22
|
@server = server
|
22
|
-
@
|
23
|
+
@diagnostics_tracker = DiagnosticsTracker.new
|
23
24
|
end
|
24
25
|
|
25
26
|
def on_initialize(id, params)
|
@@ -52,6 +53,7 @@ module ThemeCheck
|
|
52
53
|
end
|
53
54
|
|
54
55
|
def on_text_document_did_open(_id, params)
|
56
|
+
return unless @diagnostics_tracker.first_run?
|
55
57
|
relative_path = relative_path_from_text_document_uri(params)
|
56
58
|
@storage.write(relative_path, text_document_text(params))
|
57
59
|
analyze_and_send_offenses(text_document_uri(params))
|
@@ -124,17 +126,32 @@ module ThemeCheck
|
|
124
126
|
ignored_patterns: config.ignored_patterns
|
125
127
|
)
|
126
128
|
theme = ThemeCheck::Theme.new(storage)
|
127
|
-
|
128
|
-
offenses = analyze(theme, config)
|
129
|
-
log("Found #{theme.all.size} templates, and #{offenses.size} offenses")
|
130
|
-
send_diagnostics(offenses)
|
131
|
-
end
|
132
|
-
|
133
|
-
def analyze(theme, config)
|
134
129
|
analyzer = ThemeCheck::Analyzer.new(theme, config.enabled_checks)
|
135
|
-
|
136
|
-
|
137
|
-
|
130
|
+
|
131
|
+
if @diagnostics_tracker.first_run?
|
132
|
+
# Analyze the full theme on first run
|
133
|
+
log("Checking #{config.root}")
|
134
|
+
offenses = nil
|
135
|
+
time = Benchmark.measure do
|
136
|
+
offenses = analyzer.analyze_theme
|
137
|
+
end
|
138
|
+
log("Found #{offenses.size} offenses in #{format("%0.2f", time.real)}s")
|
139
|
+
send_diagnostics(offenses)
|
140
|
+
else
|
141
|
+
# Analyze selected files
|
142
|
+
relative_path = Pathname.new(@storage.relative_path(absolute_path))
|
143
|
+
file = theme[relative_path]
|
144
|
+
# Skip if not a theme file
|
145
|
+
if file
|
146
|
+
log("Checking #{relative_path}")
|
147
|
+
offenses = nil
|
148
|
+
time = Benchmark.measure do
|
149
|
+
offenses = analyzer.analyze_files([file])
|
150
|
+
end
|
151
|
+
log("Found #{offenses.size} new offenses in #{format("%0.2f", time.real)}s")
|
152
|
+
send_diagnostics(offenses, [absolute_path])
|
153
|
+
end
|
154
|
+
end
|
138
155
|
end
|
139
156
|
|
140
157
|
def completions(relative_path, line, col)
|
@@ -145,22 +162,10 @@ module ThemeCheck
|
|
145
162
|
@document_link_engine.document_links(relative_path)
|
146
163
|
end
|
147
164
|
|
148
|
-
def send_diagnostics(offenses)
|
149
|
-
|
150
|
-
|
151
|
-
offenses.group_by(&:template).each do |template, template_offenses|
|
152
|
-
next unless template
|
153
|
-
send_diagnostic(template.path, template_offenses)
|
154
|
-
reported_files << template.path
|
165
|
+
def send_diagnostics(offenses, analyzed_files = nil)
|
166
|
+
@diagnostics_tracker.build_diagnostics(offenses, analyzed_files: analyzed_files) do |path, diagnostic_offenses|
|
167
|
+
send_diagnostic(path, diagnostic_offenses)
|
155
168
|
end
|
156
|
-
|
157
|
-
# Publish diagnostics with empty array if all issues on a previously reported template
|
158
|
-
# have been solved.
|
159
|
-
(@previously_reported_files - reported_files).each do |path|
|
160
|
-
send_diagnostic(path, [])
|
161
|
-
end
|
162
|
-
|
163
|
-
@previously_reported_files = reported_files
|
164
169
|
end
|
165
170
|
|
166
171
|
def send_diagnostic(path, offenses)
|
@@ -52,7 +52,7 @@ module ThemeCheck
|
|
52
52
|
response_body = JSON.dump(response)
|
53
53
|
log(JSON.pretty_generate(response)) if $DEBUG
|
54
54
|
|
55
|
-
@out.write("Content-Length: #{response_body.
|
55
|
+
@out.write("Content-Length: #{response_body.bytesize}\r\n")
|
56
56
|
@out.write("\r\n")
|
57
57
|
@out.write(response_body)
|
58
58
|
@out.flush
|
@@ -16,9 +16,5 @@ module ThemeCheck
|
|
16
16
|
ATTR = /[a-z0-9-]+/i
|
17
17
|
HTML_ATTRIBUTE = /#{ATTR}(?:=#{QUOTED_LIQUID_ATTRIBUTE})?/omix
|
18
18
|
HTML_ATTRIBUTES = /(?:#{HTML_ATTRIBUTE}|\s)*/omix
|
19
|
-
|
20
|
-
def add_offense(message, node: nil, template: node&.template, markup: nil, line_number: nil, &block)
|
21
|
-
offenses << Offense.new(check: self, message: message, template: template, node: node, markup: markup, line_number: line_number, correction: block)
|
22
|
-
end
|
23
19
|
end
|
24
20
|
end
|
data/lib/theme_check/offense.rb
CHANGED
@@ -114,6 +114,24 @@ module ThemeCheck
|
|
114
114
|
end
|
115
115
|
end
|
116
116
|
|
117
|
+
def whole_theme?
|
118
|
+
check.whole_theme?
|
119
|
+
end
|
120
|
+
|
121
|
+
def single_file?
|
122
|
+
check.single_file?
|
123
|
+
end
|
124
|
+
|
125
|
+
def ==(other)
|
126
|
+
other.is_a?(Offense) &&
|
127
|
+
check == other.check &&
|
128
|
+
message == other.message &&
|
129
|
+
template == other.template &&
|
130
|
+
node == other.node &&
|
131
|
+
markup == other.markup &&
|
132
|
+
line_number == other.line_number
|
133
|
+
end
|
134
|
+
|
117
135
|
def to_s
|
118
136
|
if template
|
119
137
|
"#{message} at #{location}"
|
data/lib/theme_check/template.rb
CHANGED
data/lib/theme_check/theme.rb
CHANGED
@@ -52,8 +52,13 @@ module ThemeCheck
|
|
52
52
|
@all ||= json + liquid + assets
|
53
53
|
end
|
54
54
|
|
55
|
-
def [](
|
56
|
-
|
55
|
+
def [](name_or_relative_path)
|
56
|
+
case name_or_relative_path
|
57
|
+
when Pathname
|
58
|
+
all.find { |t| t.relative_path == name_or_relative_path }
|
59
|
+
else
|
60
|
+
all.find { |t| t.name == name_or_relative_path }
|
61
|
+
end
|
57
62
|
end
|
58
63
|
|
59
64
|
def templates
|
data/lib/theme_check/version.rb
CHANGED
data/lib/theme_check/visitor.rb
CHANGED
@@ -3,14 +3,13 @@ module ThemeCheck
|
|
3
3
|
class Visitor
|
4
4
|
attr_reader :checks
|
5
5
|
|
6
|
-
def initialize(checks)
|
6
|
+
def initialize(checks, disabled_checks)
|
7
7
|
@checks = checks
|
8
|
+
@disabled_checks = disabled_checks
|
8
9
|
end
|
9
10
|
|
10
11
|
def visit_template(template)
|
11
|
-
@disabled_checks = DisabledChecks.new
|
12
12
|
visit(Node.new(template.root, nil, template))
|
13
|
-
remove_disabled_offenses
|
14
13
|
rescue Liquid::Error => exception
|
15
14
|
exception.template_name = template.name
|
16
15
|
call_checks(:on_error, exception)
|
@@ -35,13 +34,5 @@ module ThemeCheck
|
|
35
34
|
def call_checks(method, *args)
|
36
35
|
checks.call(method, *args)
|
37
36
|
end
|
38
|
-
|
39
|
-
def remove_disabled_offenses
|
40
|
-
checks.disableable.each do |check|
|
41
|
-
check.offenses.reject! do |offense|
|
42
|
-
@disabled_checks.disabled?(offense.code_name, offense.start_index)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
37
|
end
|
47
38
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: theme-check
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marc-André Cournoyer
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-05-
|
11
|
+
date: 2021-05-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: liquid
|
@@ -72,6 +72,7 @@ files:
|
|
72
72
|
- docs/checks/CHECK_DOCS_TEMPLATE.md
|
73
73
|
- docs/checks/asset_size_css.md
|
74
74
|
- docs/checks/asset_size_javascript.md
|
75
|
+
- docs/checks/content_for_header_modification.md
|
75
76
|
- docs/checks/convert_include_to_render.md
|
76
77
|
- docs/checks/default_locale.md
|
77
78
|
- docs/checks/deprecated_filter.md
|
@@ -84,6 +85,7 @@ files:
|
|
84
85
|
- docs/checks/missing_template.md
|
85
86
|
- docs/checks/nested_snippet.md
|
86
87
|
- docs/checks/parser_blocking_javascript.md
|
88
|
+
- docs/checks/parser_blocking_script_tag.md
|
87
89
|
- docs/checks/remote_asset.md
|
88
90
|
- docs/checks/required_directories.md
|
89
91
|
- docs/checks/required_layout_theme_object.md
|
@@ -109,6 +111,7 @@ files:
|
|
109
111
|
- lib/theme_check/checks.rb
|
110
112
|
- lib/theme_check/checks/asset_size_css.rb
|
111
113
|
- lib/theme_check/checks/asset_size_javascript.rb
|
114
|
+
- lib/theme_check/checks/content_for_header_modification.rb
|
112
115
|
- lib/theme_check/checks/convert_include_to_render.rb
|
113
116
|
- lib/theme_check/checks/default_locale.rb
|
114
117
|
- lib/theme_check/checks/deprecated_filter.rb
|
@@ -121,6 +124,7 @@ files:
|
|
121
124
|
- lib/theme_check/checks/missing_template.rb
|
122
125
|
- lib/theme_check/checks/nested_snippet.rb
|
123
126
|
- lib/theme_check/checks/parser_blocking_javascript.rb
|
127
|
+
- lib/theme_check/checks/parser_blocking_script_tag.rb
|
124
128
|
- lib/theme_check/checks/remote_asset.rb
|
125
129
|
- lib/theme_check/checks/required_directories.rb
|
126
130
|
- lib/theme_check/checks/required_layout_theme_object.rb
|
@@ -143,6 +147,9 @@ files:
|
|
143
147
|
- lib/theme_check/disabled_checks.rb
|
144
148
|
- lib/theme_check/exceptions.rb
|
145
149
|
- lib/theme_check/file_system_storage.rb
|
150
|
+
- lib/theme_check/html_check.rb
|
151
|
+
- lib/theme_check/html_node.rb
|
152
|
+
- lib/theme_check/html_visitor.rb
|
146
153
|
- lib/theme_check/in_memory_storage.rb
|
147
154
|
- lib/theme_check/json_check.rb
|
148
155
|
- lib/theme_check/json_file.rb
|
@@ -156,6 +163,7 @@ files:
|
|
156
163
|
- lib/theme_check/language_server/completion_providers/render_snippet_completion_provider.rb
|
157
164
|
- lib/theme_check/language_server/completion_providers/tag_completion_provider.rb
|
158
165
|
- lib/theme_check/language_server/constants.rb
|
166
|
+
- lib/theme_check/language_server/diagnostics_tracker.rb
|
159
167
|
- lib/theme_check/language_server/document_link_engine.rb
|
160
168
|
- lib/theme_check/language_server/handler.rb
|
161
169
|
- lib/theme_check/language_server/protocol.rb
|