theme-check 1.5.0 → 1.6.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/.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
|