theme-check 1.5.0 → 1.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/theme-check.yml +12 -4
- data/CHANGELOG.md +34 -0
- data/CONTRIBUTING.md +58 -0
- data/Gemfile +3 -0
- data/docs/flamegraph.svg +18488 -0
- data/lib/theme_check/analyzer.rb +5 -0
- data/lib/theme_check/asset_file.rb +13 -2
- data/lib/theme_check/check.rb +1 -1
- data/lib/theme_check/checks/asset_size_css.rb +15 -0
- data/lib/theme_check/checks/asset_size_css_stylesheet_tag.rb +18 -1
- data/lib/theme_check/checks/convert_include_to_render.rb +2 -1
- data/lib/theme_check/checks/liquid_tag.rb +1 -1
- data/lib/theme_check/checks/missing_required_template_files.rb +21 -7
- data/lib/theme_check/checks/pagination_size.rb +30 -10
- data/lib/theme_check/checks/required_directories.rb +3 -1
- data/lib/theme_check/checks/space_inside_braces.rb +47 -24
- data/lib/theme_check/checks/translation_key_exists.rb +3 -1
- data/lib/theme_check/checks/unused_snippet.rb +3 -1
- data/lib/theme_check/checks.rb +2 -0
- data/lib/theme_check/cli.rb +32 -6
- data/lib/theme_check/corrector.rb +23 -10
- data/lib/theme_check/file_system_storage.rb +13 -2
- data/lib/theme_check/html_node.rb +4 -4
- data/lib/theme_check/html_visitor.rb +20 -8
- data/lib/theme_check/in_memory_storage.rb +8 -0
- data/lib/theme_check/json_file.rb +9 -4
- data/lib/theme_check/json_printer.rb +5 -1
- data/lib/theme_check/node.rb +118 -11
- data/lib/theme_check/offense.rb +26 -0
- data/lib/theme_check/position.rb +27 -16
- data/lib/theme_check/position_helper.rb +13 -15
- data/lib/theme_check/printer.rb +9 -5
- data/lib/theme_check/regex_helpers.rb +1 -15
- data/lib/theme_check/remote_asset_file.rb +4 -0
- data/lib/theme_check/template.rb +5 -19
- data/lib/theme_check/template_rewriter.rb +57 -0
- data/lib/theme_check/theme_file.rb +18 -1
- data/lib/theme_check/version.rb +1 -1
- data/lib/theme_check.rb +1 -0
- data/theme-check.gemspec +1 -0
- metadata +18 -2
@@ -7,31 +7,29 @@ module ThemeCheck
|
|
7
7
|
return 0 unless content.is_a?(String) && !content.empty?
|
8
8
|
return 0 unless row.is_a?(Integer) && col.is_a?(Integer)
|
9
9
|
i = 0
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
i += 1
|
17
|
-
line_size = lines[i].size
|
18
|
-
end
|
19
|
-
result += bounded(0, col, line_size - 1)
|
20
|
-
result
|
10
|
+
safe_row = bounded(0, row, content.count("\n"))
|
11
|
+
scanner = StringScanner.new(content)
|
12
|
+
scanner.scan_until(/\n/) while i < safe_row && (i += 1)
|
13
|
+
result = scanner.charpos || 0
|
14
|
+
scanner.scan_until(/\n|\z/)
|
15
|
+
bounded(result, result + col, scanner.pre_match.size)
|
21
16
|
end
|
22
17
|
|
23
18
|
def from_index_to_row_column(content, index)
|
24
19
|
return [0, 0] unless content.is_a?(String) && !content.empty?
|
25
20
|
return [0, 0] unless index.is_a?(Integer)
|
26
21
|
safe_index = bounded(0, index, content.size - 1)
|
27
|
-
|
28
|
-
row =
|
29
|
-
col =
|
22
|
+
content_up_to_index = content[0...safe_index]
|
23
|
+
row = content_up_to_index.count("\n")
|
24
|
+
col = 0
|
25
|
+
col += 1 while (safe_index -= 1) && safe_index >= 0 && content[safe_index] != "\n"
|
30
26
|
[row, col]
|
31
27
|
end
|
32
28
|
|
33
29
|
def bounded(a, x, b)
|
34
|
-
|
30
|
+
return a if x < a
|
31
|
+
return b if x > b
|
32
|
+
x
|
35
33
|
end
|
36
34
|
end
|
37
35
|
end
|
data/lib/theme_check/printer.rb
CHANGED
@@ -2,14 +2,18 @@
|
|
2
2
|
|
3
3
|
module ThemeCheck
|
4
4
|
class Printer
|
5
|
+
def initialize(out_stream = STDOUT)
|
6
|
+
@out = out_stream
|
7
|
+
end
|
8
|
+
|
5
9
|
def print(theme, offenses, auto_correct)
|
6
10
|
offenses.each do |offense|
|
7
11
|
print_offense(offense, auto_correct)
|
8
|
-
puts
|
12
|
+
@out.puts
|
9
13
|
end
|
10
14
|
|
11
15
|
correctable = offenses.select(&:correctable?)
|
12
|
-
puts "#{theme.all.size} files inspected, #{red(offenses.size.to_s + ' offenses')} detected, \
|
16
|
+
@out.puts "#{theme.all.size} files inspected, #{red(offenses.size.to_s + ' offenses')} detected, \
|
13
17
|
#{yellow(correctable.size.to_s + ' offenses')} #{auto_correct ? 'corrected' : 'auto-correctable'}"
|
14
18
|
end
|
15
19
|
|
@@ -26,15 +30,15 @@ module ThemeCheck
|
|
26
30
|
""
|
27
31
|
end
|
28
32
|
|
29
|
-
puts location +
|
33
|
+
@out.puts location +
|
30
34
|
colorized_severity(offense.severity) + ": " +
|
31
35
|
yellow(offense.check_name) + ": " +
|
32
36
|
corrected +
|
33
37
|
offense.message + "."
|
34
38
|
if offense.source_excerpt
|
35
|
-
puts "\t#{offense.source_excerpt}"
|
39
|
+
@out.puts "\t#{offense.source_excerpt}"
|
36
40
|
if offense.markup_start_in_excerpt
|
37
|
-
puts "\t" + (" " * offense.markup_start_in_excerpt) + ("^" * offense.markup.size)
|
41
|
+
@out.puts "\t" + (" " * offense.markup_start_in_excerpt) + ("^" * offense.markup.size)
|
38
42
|
end
|
39
43
|
end
|
40
44
|
end
|
@@ -5,6 +5,7 @@ module ThemeCheck
|
|
5
5
|
LIQUID_TAG = /#{Liquid::TagStart}.*?#{Liquid::TagEnd}/om
|
6
6
|
LIQUID_VARIABLE = /#{Liquid::VariableStart}.*?#{Liquid::VariableEnd}/om
|
7
7
|
LIQUID_TAG_OR_VARIABLE = /#{LIQUID_TAG}|#{LIQUID_VARIABLE}/om
|
8
|
+
HTML_LIQUID_PLACEHOLDER = /≬[0-9a-z]+#*≬/m
|
8
9
|
START_OR_END_QUOTE = /(^['"])|(['"]$)/
|
9
10
|
|
10
11
|
def matches(s, re)
|
@@ -16,20 +17,5 @@ module ThemeCheck
|
|
16
17
|
end
|
17
18
|
matches
|
18
19
|
end
|
19
|
-
|
20
|
-
def href_to_file_size(href)
|
21
|
-
# asset_url (+ optional stylesheet_tag) variables
|
22
|
-
if href =~ /^#{LIQUID_VARIABLE}$/o && href =~ /asset_url/ && href =~ Liquid::QuotedString
|
23
|
-
asset_id = Regexp.last_match(0).gsub(START_OR_END_QUOTE, "")
|
24
|
-
asset = @theme.assets.find { |a| a.name.end_with?("/" + asset_id) }
|
25
|
-
return if asset.nil?
|
26
|
-
asset.gzipped_size
|
27
|
-
|
28
|
-
# remote URLs
|
29
|
-
elsif href =~ %r{^(https?:)?//}
|
30
|
-
asset = RemoteAssetFile.from_src(href)
|
31
|
-
asset.gzipped_size
|
32
|
-
end
|
33
|
-
end
|
34
20
|
end
|
35
21
|
end
|
@@ -17,6 +17,8 @@ module ThemeCheck
|
|
17
17
|
|
18
18
|
def uri(src)
|
19
19
|
URI.parse(src.sub(%r{^//}, "https://"))
|
20
|
+
rescue URI::InvalidURIError
|
21
|
+
nil
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
@@ -26,6 +28,7 @@ module ThemeCheck
|
|
26
28
|
end
|
27
29
|
|
28
30
|
def content
|
31
|
+
return if @uri.nil?
|
29
32
|
return @content unless @content.nil?
|
30
33
|
|
31
34
|
res = Net::HTTP.start(@uri.hostname, @uri.port, use_ssl: @uri.scheme == 'https') do |http|
|
@@ -41,6 +44,7 @@ module ThemeCheck
|
|
41
44
|
end
|
42
45
|
|
43
46
|
def gzipped_size
|
47
|
+
return if @uri.nil?
|
44
48
|
@gzipped_size ||= content.bytesize
|
45
49
|
end
|
46
50
|
end
|
data/lib/theme_check/template.rb
CHANGED
@@ -3,10 +3,11 @@
|
|
3
3
|
module ThemeCheck
|
4
4
|
class Template < ThemeFile
|
5
5
|
def write
|
6
|
-
content =
|
6
|
+
content = rewriter.to_s
|
7
7
|
if source != content
|
8
|
-
@storage.write(@relative_path, content)
|
8
|
+
@storage.write(@relative_path, content.gsub("\n", @eol))
|
9
9
|
@source = content
|
10
|
+
@rewriter = nil
|
10
11
|
end
|
11
12
|
end
|
12
13
|
|
@@ -26,19 +27,8 @@ module ThemeCheck
|
|
26
27
|
name.start_with?('snippets')
|
27
28
|
end
|
28
29
|
|
29
|
-
def
|
30
|
-
|
31
|
-
@lines ||= source.split("\n", -1)
|
32
|
-
end
|
33
|
-
|
34
|
-
# Not entirely obvious but lines is mutable, corrections are to be
|
35
|
-
# applied on @lines.
|
36
|
-
def updated_content
|
37
|
-
lines.join("\n")
|
38
|
-
end
|
39
|
-
|
40
|
-
def excerpt(line)
|
41
|
-
lines[line - 1].strip
|
30
|
+
def rewriter
|
31
|
+
@rewriter ||= TemplateRewriter.new(@relative_path, source)
|
42
32
|
end
|
43
33
|
|
44
34
|
def source_excerpt(line)
|
@@ -46,10 +36,6 @@ module ThemeCheck
|
|
46
36
|
original_lines[line - 1].strip
|
47
37
|
end
|
48
38
|
|
49
|
-
def full_line(line)
|
50
|
-
lines[line - 1]
|
51
|
-
end
|
52
|
-
|
53
39
|
def parse
|
54
40
|
@ast ||= self.class.parse(source)
|
55
41
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'parser'
|
4
|
+
|
5
|
+
module ThemeCheck
|
6
|
+
class TemplateRewriter
|
7
|
+
def initialize(name, source)
|
8
|
+
@buffer = Parser::Source::Buffer.new(name, source: source)
|
9
|
+
@rewriter = Parser::Source::TreeRewriter.new(
|
10
|
+
@buffer
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
def insert_before(node, content)
|
15
|
+
@rewriter.insert_before(
|
16
|
+
range(node.start_index, node.end_index),
|
17
|
+
content
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
def insert_after(node, content)
|
22
|
+
@rewriter.insert_after(
|
23
|
+
range(node.start_index, node.end_index),
|
24
|
+
content
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
def replace(node, content)
|
29
|
+
@rewriter.replace(
|
30
|
+
range(node.start_index, node.end_index),
|
31
|
+
content
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
def wrap(node, insert_before, insert_after)
|
36
|
+
@rewriter.wrap(
|
37
|
+
range(node.start_index, node.end_index),
|
38
|
+
insert_before,
|
39
|
+
insert_after,
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_s
|
44
|
+
@rewriter.process
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def range(start_index, end_index)
|
50
|
+
Parser::Source::Range.new(
|
51
|
+
@buffer,
|
52
|
+
start_index,
|
53
|
+
end_index,
|
54
|
+
)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -6,6 +6,8 @@ module ThemeCheck
|
|
6
6
|
def initialize(relative_path, storage)
|
7
7
|
@relative_path = relative_path
|
8
8
|
@storage = storage
|
9
|
+
@source = nil
|
10
|
+
@eol = "\n"
|
9
11
|
end
|
10
12
|
|
11
13
|
def path
|
@@ -20,8 +22,23 @@ module ThemeCheck
|
|
20
22
|
relative_path.sub_ext('').to_s
|
21
23
|
end
|
22
24
|
|
25
|
+
# For the corrector to work properly, we should have a
|
26
|
+
# simple mental model of the internal representation of eol
|
27
|
+
# characters (Windows uses \r\n, Linux uses \n).
|
28
|
+
#
|
29
|
+
# Parser::Source::Buffer strips the \r from the source file, so if
|
30
|
+
# you are autocorrecting the file you might lose that info and
|
31
|
+
# cause a git diff. It also makes the node.start_index/end_index
|
32
|
+
# calculation break. That's not cool.
|
33
|
+
#
|
34
|
+
# So in here we track whether the source file has \r\n in it and
|
35
|
+
# we'll make sure that the file we write has the same eol as the
|
36
|
+
# source file.
|
23
37
|
def source
|
24
|
-
@source
|
38
|
+
return @source if @source
|
39
|
+
@source = @storage.read(@relative_path)
|
40
|
+
@eol = @source.include?("\r\n") ? "\r\n" : "\n"
|
41
|
+
@source = @source.gsub("\r\n", "\n")
|
25
42
|
end
|
26
43
|
|
27
44
|
def json?
|
data/lib/theme_check/version.rb
CHANGED
data/lib/theme_check.rb
CHANGED
@@ -34,6 +34,7 @@ require_relative "theme_check/string_helpers"
|
|
34
34
|
require_relative "theme_check/file_system_storage"
|
35
35
|
require_relative "theme_check/in_memory_storage"
|
36
36
|
require_relative "theme_check/tags"
|
37
|
+
require_relative "theme_check/template_rewriter"
|
37
38
|
require_relative "theme_check/template"
|
38
39
|
require_relative "theme_check/theme"
|
39
40
|
require_relative "theme_check/visitor"
|
data/theme-check.gemspec
CHANGED
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: 1.
|
4
|
+
version: 1.6.1
|
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-09-
|
11
|
+
date: 2021-09-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: liquid
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '1.12'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: parser
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3'
|
41
55
|
description:
|
42
56
|
email:
|
43
57
|
- marcandre.cournoyer@shopify.com
|
@@ -118,6 +132,7 @@ files:
|
|
118
132
|
- docs/checks/valid_html_translation.md
|
119
133
|
- docs/checks/valid_json.md
|
120
134
|
- docs/checks/valid_schema.md
|
135
|
+
- docs/flamegraph.svg
|
121
136
|
- docs/preview.png
|
122
137
|
- exe/theme-check
|
123
138
|
- exe/theme-check-language-server
|
@@ -228,6 +243,7 @@ files:
|
|
228
243
|
- lib/theme_check/string_helpers.rb
|
229
244
|
- lib/theme_check/tags.rb
|
230
245
|
- lib/theme_check/template.rb
|
246
|
+
- lib/theme_check/template_rewriter.rb
|
231
247
|
- lib/theme_check/theme.rb
|
232
248
|
- lib/theme_check/theme_file.rb
|
233
249
|
- lib/theme_check/version.rb
|