theme-check 1.5.2 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/theme-check.yml +12 -4
  3. data/CHANGELOG.md +37 -0
  4. data/docs/api/html_check.md +7 -7
  5. data/docs/api/liquid_check.md +10 -10
  6. data/docs/checks/convert_include_to_render.md +1 -1
  7. data/docs/checks/missing_enable_comment.md +1 -1
  8. data/lib/theme_check/analyzer.rb +46 -17
  9. data/lib/theme_check/asset_file.rb +13 -2
  10. data/lib/theme_check/check.rb +3 -3
  11. data/lib/theme_check/checks/asset_size_css.rb +15 -0
  12. data/lib/theme_check/checks/asset_size_css_stylesheet_tag.rb +18 -1
  13. data/lib/theme_check/checks/convert_include_to_render.rb +2 -1
  14. data/lib/theme_check/checks/html_parsing_error.rb +2 -2
  15. data/lib/theme_check/checks/matching_translations.rb +1 -1
  16. data/lib/theme_check/checks/missing_required_template_files.rb +21 -7
  17. data/lib/theme_check/checks/missing_template.rb +6 -6
  18. data/lib/theme_check/checks/nested_snippet.rb +2 -2
  19. data/lib/theme_check/checks/required_layout_theme_object.rb +2 -2
  20. data/lib/theme_check/checks/syntax_error.rb +5 -5
  21. data/lib/theme_check/checks/template_length.rb +2 -2
  22. data/lib/theme_check/checks/translation_key_exists.rb +3 -1
  23. data/lib/theme_check/checks/undefined_object.rb +7 -7
  24. data/lib/theme_check/checks/unused_assign.rb +4 -4
  25. data/lib/theme_check/checks/unused_snippet.rb +8 -6
  26. data/lib/theme_check/checks/valid_json.rb +1 -1
  27. data/lib/theme_check/checks.rb +4 -2
  28. data/lib/theme_check/cli.rb +7 -4
  29. data/lib/theme_check/corrector.rb +21 -12
  30. data/lib/theme_check/disabled_check.rb +3 -3
  31. data/lib/theme_check/disabled_checks.rb +9 -9
  32. data/lib/theme_check/file_system_storage.rb +7 -2
  33. data/lib/theme_check/html_node.rb +40 -32
  34. data/lib/theme_check/html_visitor.rb +24 -12
  35. data/lib/theme_check/in_memory_storage.rb +5 -1
  36. data/lib/theme_check/json_check.rb +2 -2
  37. data/lib/theme_check/json_file.rb +9 -4
  38. data/lib/theme_check/language_server/diagnostics_tracker.rb +8 -8
  39. data/lib/theme_check/language_server/handler.rb +88 -6
  40. data/lib/theme_check/language_server/messenger.rb +57 -0
  41. data/lib/theme_check/language_server/server.rb +105 -40
  42. data/lib/theme_check/language_server.rb +1 -0
  43. data/lib/theme_check/{template.rb → liquid_file.rb} +6 -20
  44. data/lib/theme_check/liquid_node.rb +291 -0
  45. data/lib/theme_check/{visitor.rb → liquid_visitor.rb} +4 -4
  46. data/lib/theme_check/locale_diff.rb +5 -5
  47. data/lib/theme_check/node.rb +12 -230
  48. data/lib/theme_check/offense.rb +41 -15
  49. data/lib/theme_check/position.rb +1 -1
  50. data/lib/theme_check/regex_helpers.rb +1 -15
  51. data/lib/theme_check/theme.rb +1 -1
  52. data/lib/theme_check/theme_file.rb +18 -1
  53. data/lib/theme_check/theme_file_rewriter.rb +57 -0
  54. data/lib/theme_check/version.rb +1 -1
  55. data/lib/theme_check.rb +11 -9
  56. data/theme-check.gemspec +2 -1
  57. metadata +23 -6
@@ -5,13 +5,13 @@ module ThemeCheck
5
5
 
6
6
  MAX_SOURCE_EXCERPT_SIZE = 120
7
7
 
8
- attr_reader :check, :message, :template, :node, :markup, :line_number, :correction
8
+ attr_reader :check, :message, :theme_file, :node, :markup, :line_number, :correction
9
9
 
10
10
  def initialize(
11
11
  check:, # instance of a ThemeCheck::Check
12
12
  message: nil, # error message for the offense
13
- template: nil, # Template
14
- node: nil, # Node or HtmlNode
13
+ theme_file: nil, # ThemeFile
14
+ node: nil, # Node
15
15
  markup: nil, # string
16
16
  line_number: nil, # line number of the error (1-indexed)
17
17
  # node_markup_offset is the index inside node.markup to start
@@ -39,11 +39,11 @@ module ThemeCheck
39
39
  end
40
40
 
41
41
  @node = node
42
- @template = nil
42
+ @theme_file = nil
43
43
  if node
44
- @template = node.template
45
- elsif template
46
- @template = template
44
+ @theme_file = node.theme_file
45
+ elsif theme_file
46
+ @theme_file = theme_file
47
47
  end
48
48
 
49
49
  @markup = if markup
@@ -62,7 +62,7 @@ module ThemeCheck
62
62
 
63
63
  @position = Position.new(
64
64
  @markup,
65
- @template&.source,
65
+ @theme_file&.source,
66
66
  line_number_1_indexed: @line_number,
67
67
  node_markup_offset: node_markup_offset,
68
68
  node_markup: node&.markup
@@ -72,7 +72,7 @@ module ThemeCheck
72
72
  def source_excerpt
73
73
  return unless line_number
74
74
  @source_excerpt ||= begin
75
- excerpt = template.source_excerpt(line_number)
75
+ excerpt = theme_file.source_excerpt(line_number)
76
76
  if excerpt.size > MAX_SOURCE_EXCERPT_SIZE
77
77
  excerpt[0, MAX_SOURCE_EXCERPT_SIZE - 3] + '...'
78
78
  else
@@ -126,12 +126,12 @@ module ThemeCheck
126
126
  end
127
127
 
128
128
  def location
129
- tokens = [template&.relative_path, line_number].compact
129
+ tokens = [theme_file&.relative_path, line_number].compact
130
130
  tokens.join(":") if tokens.any?
131
131
  end
132
132
 
133
133
  def location_range
134
- tokens = [template&.relative_path, start_index, end_index].compact
134
+ tokens = [theme_file&.relative_path, start_index, end_index].compact
135
135
  tokens.join(":") if tokens.any?
136
136
  end
137
137
 
@@ -141,9 +141,35 @@ module ThemeCheck
141
141
 
142
142
  def correct
143
143
  if correctable?
144
- corrector = Corrector.new(template: template)
144
+ corrector = Corrector.new(theme_file: theme_file)
145
145
  correction.call(corrector)
146
146
  end
147
+ rescue => e
148
+ ThemeCheck.bug(<<~EOS)
149
+ Exception while running `Offense#correct`:
150
+ ```
151
+ #{e.class}: #{e.message}
152
+ #{e.backtrace.join("\n ")}
153
+ ```
154
+
155
+ Offense:
156
+ ```
157
+ #{JSON.pretty_generate(to_h)}
158
+ ```
159
+ Check options:
160
+ ```
161
+ #{check.options.pretty_inspect}
162
+ ```
163
+ Markup:
164
+ ```
165
+ #{markup}
166
+ ```
167
+ Node.Markup:
168
+ ```
169
+ #{node&.markup}
170
+ ```
171
+ EOS
172
+ exit(2)
147
173
  end
148
174
 
149
175
  def whole_theme?
@@ -165,7 +191,7 @@ module ThemeCheck
165
191
  alias_method :eql?, :==
166
192
 
167
193
  def to_s
168
- if template
194
+ if theme_file
169
195
  "#{message} at #{location}"
170
196
  else
171
197
  message
@@ -173,7 +199,7 @@ module ThemeCheck
173
199
  end
174
200
 
175
201
  def to_s_range
176
- if template
202
+ if theme_file
177
203
  "#{message} at #{location_range}"
178
204
  else
179
205
  message
@@ -183,7 +209,7 @@ module ThemeCheck
183
209
  def to_h
184
210
  {
185
211
  check: check.code_name,
186
- path: template&.relative_path,
212
+ path: theme_file&.relative_path,
187
213
  severity: check.severity_value,
188
214
  start_line: start_line,
189
215
  start_column: start_column,
@@ -104,7 +104,7 @@ module ThemeCheck
104
104
  end
105
105
 
106
106
  def can_find_needle?
107
- !!contents.index(@needle)
107
+ !!contents.index(@needle, start_offset)
108
108
  end
109
109
 
110
110
  def entire_line_needle
@@ -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
@@ -23,7 +23,7 @@ module ThemeCheck
23
23
  def liquid
24
24
  @liquid ||= @storage.files
25
25
  .select { |path| LIQUID_REGEX.match?(path) }
26
- .map { |path| Template.new(path, @storage) }
26
+ .map { |path| LiquidFile.new(path, @storage) }
27
27
  end
28
28
 
29
29
  def json
@@ -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 ||= @storage.read(@relative_path)
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?
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'parser'
4
+
5
+ module ThemeCheck
6
+ class ThemeFileRewriter
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
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module ThemeCheck
3
- VERSION = "1.5.2"
3
+ VERSION = "1.7.0"
4
4
  end
data/lib/theme_check.rb CHANGED
@@ -4,20 +4,23 @@ require "liquid"
4
4
  require_relative "theme_check/version"
5
5
  require_relative "theme_check/bug"
6
6
  require_relative "theme_check/exceptions"
7
+ require_relative "theme_check/theme_file_rewriter"
7
8
  require_relative "theme_check/theme_file"
9
+ require_relative "theme_check/liquid_file"
10
+ require_relative "theme_check/asset_file"
11
+ require_relative "theme_check/json_file"
8
12
  require_relative "theme_check/analyzer"
9
13
  require_relative "theme_check/check"
10
14
  require_relative "theme_check/checks_tracking"
15
+ require_relative "theme_check/liquid_check"
16
+ require_relative "theme_check/html_check"
17
+ require_relative "theme_check/json_check"
11
18
  require_relative "theme_check/cli"
12
19
  require_relative "theme_check/disabled_check"
13
20
  require_relative "theme_check/disabled_checks"
14
- require_relative "theme_check/liquid_check"
15
21
  require_relative "theme_check/locale_diff"
16
- require_relative "theme_check/asset_file"
17
22
  require_relative "theme_check/remote_asset_file"
18
23
  require_relative "theme_check/regex_helpers"
19
- require_relative "theme_check/json_check"
20
- require_relative "theme_check/json_file"
21
24
  require_relative "theme_check/json_helpers"
22
25
  require_relative "theme_check/position_helper"
23
26
  require_relative "theme_check/position"
@@ -25,22 +28,21 @@ require_relative "theme_check/language_server"
25
28
  require_relative "theme_check/checks"
26
29
  require_relative "theme_check/config"
27
30
  require_relative "theme_check/node"
31
+ require_relative "theme_check/liquid_node"
32
+ require_relative "theme_check/html_node"
28
33
  require_relative "theme_check/offense"
29
34
  require_relative "theme_check/printer"
30
35
  require_relative "theme_check/json_printer"
31
36
  require_relative "theme_check/shopify_liquid"
32
- require_relative "theme_check/storage"
33
37
  require_relative "theme_check/string_helpers"
38
+ require_relative "theme_check/storage"
34
39
  require_relative "theme_check/file_system_storage"
35
40
  require_relative "theme_check/in_memory_storage"
36
41
  require_relative "theme_check/tags"
37
- require_relative "theme_check/template"
38
42
  require_relative "theme_check/theme"
39
- require_relative "theme_check/visitor"
40
43
  require_relative "theme_check/corrector"
41
- require_relative "theme_check/html_node"
44
+ require_relative "theme_check/liquid_visitor"
42
45
  require_relative "theme_check/html_visitor"
43
- require_relative "theme_check/html_check"
44
46
 
45
47
  Dir[__dir__ + "/theme_check/checks/*.rb"].each { |file| require file }
46
48
 
data/theme-check.gemspec CHANGED
@@ -24,6 +24,7 @@ Gem::Specification.new do |spec|
24
24
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
25
  spec.require_paths = ["lib"]
26
26
 
27
- spec.add_dependency('liquid', '>= 5.0.1')
27
+ spec.add_dependency('liquid', '>= 5.1.0')
28
28
  spec.add_dependency('nokogiri', '>= 1.12')
29
+ spec.add_dependency('parser', '~> 3')
29
30
  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: 1.5.2
4
+ version: 1.7.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-09-09 00:00:00.000000000 Z
11
+ date: 2021-09-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: liquid
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 5.0.1
19
+ version: 5.1.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 5.0.1
26
+ version: 5.1.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: nokogiri
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -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
@@ -203,12 +217,16 @@ files:
203
217
  - lib/theme_check/language_server/document_link_providers/render_document_link_provider.rb
204
218
  - lib/theme_check/language_server/document_link_providers/section_document_link_provider.rb
205
219
  - lib/theme_check/language_server/handler.rb
220
+ - lib/theme_check/language_server/messenger.rb
206
221
  - lib/theme_check/language_server/protocol.rb
207
222
  - lib/theme_check/language_server/server.rb
208
223
  - lib/theme_check/language_server/tokens.rb
209
224
  - lib/theme_check/language_server/uri_helper.rb
210
225
  - lib/theme_check/language_server/variable_lookup_finder.rb
211
226
  - lib/theme_check/liquid_check.rb
227
+ - lib/theme_check/liquid_file.rb
228
+ - lib/theme_check/liquid_node.rb
229
+ - lib/theme_check/liquid_visitor.rb
212
230
  - lib/theme_check/locale_diff.rb
213
231
  - lib/theme_check/node.rb
214
232
  - lib/theme_check/offense.rb
@@ -228,11 +246,10 @@ files:
228
246
  - lib/theme_check/storage.rb
229
247
  - lib/theme_check/string_helpers.rb
230
248
  - lib/theme_check/tags.rb
231
- - lib/theme_check/template.rb
232
249
  - lib/theme_check/theme.rb
233
250
  - lib/theme_check/theme_file.rb
251
+ - lib/theme_check/theme_file_rewriter.rb
234
252
  - lib/theme_check/version.rb
235
- - lib/theme_check/visitor.rb
236
253
  - packaging/homebrew/theme_check.base.rb
237
254
  - theme-check.gemspec
238
255
  homepage: https://github.com/Shopify/theme-check