theme-check 1.10.1 → 1.11.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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +29 -0
  3. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  4. data/.github/workflows/cla.yml +22 -0
  5. data/.github/workflows/theme-check.yml +1 -1
  6. data/CHANGELOG.md +58 -0
  7. data/README.md +7 -8
  8. data/config/default.yml +5 -0
  9. data/config/theme_app_extension.yml +1 -0
  10. data/data/shopify_liquid/filters.yml +18 -0
  11. data/data/shopify_liquid/theme_app_extension_objects.yml +2 -0
  12. data/dev.yml +1 -1
  13. data/docs/api/check.md +1 -1
  14. data/docs/checks/TEMPLATE.md.erb +1 -1
  15. data/docs/checks/asset_preload.md +60 -0
  16. data/docs/checks/asset_size_javascript.md +2 -2
  17. data/docs/checks/missing_enable_comment.md +3 -3
  18. data/docs/checks/nested_snippet.md +8 -8
  19. data/docs/checks/schema_json_format.md +1 -1
  20. data/docs/checks/translation_key_exists.md +4 -4
  21. data/docs/checks/valid_html_translation.md +1 -1
  22. data/lib/theme_check/analyzer.rb +18 -3
  23. data/lib/theme_check/check.rb +6 -1
  24. data/lib/theme_check/checks/asset_preload.rb +20 -0
  25. data/lib/theme_check/checks/deprecated_filter.rb +29 -5
  26. data/lib/theme_check/checks/missing_enable_comment.rb +4 -0
  27. data/lib/theme_check/checks/missing_required_template_files.rb +5 -1
  28. data/lib/theme_check/checks/missing_template.rb +5 -1
  29. data/lib/theme_check/checks/translation_key_exists.rb +1 -0
  30. data/lib/theme_check/checks/undefined_object.rb +9 -1
  31. data/lib/theme_check/checks/unused_assign.rb +6 -1
  32. data/lib/theme_check/checks/unused_snippet.rb +50 -2
  33. data/lib/theme_check/config.rb +4 -3
  34. data/lib/theme_check/disabled_checks.rb +11 -4
  35. data/lib/theme_check/file_system_storage.rb +2 -0
  36. data/lib/theme_check/in_memory_storage.rb +1 -1
  37. data/lib/theme_check/json_printer.rb +1 -1
  38. data/lib/theme_check/language_server/bridge.rb +31 -6
  39. data/lib/theme_check/language_server/diagnostics_engine.rb +80 -34
  40. data/lib/theme_check/language_server/diagnostics_manager.rb +27 -6
  41. data/lib/theme_check/language_server/execute_command_providers/run_checks_execute_command_provider.rb +7 -6
  42. data/lib/theme_check/language_server/handler.rb +90 -8
  43. data/lib/theme_check/language_server/server.rb +42 -14
  44. data/lib/theme_check/language_server/versioned_in_memory_storage.rb +17 -2
  45. data/lib/theme_check/liquid_file.rb +22 -1
  46. data/lib/theme_check/liquid_node.rb +33 -1
  47. data/lib/theme_check/liquid_visitor.rb +1 -1
  48. data/lib/theme_check/schema_helper.rb +1 -1
  49. data/lib/theme_check/shopify_liquid/object.rb +4 -0
  50. data/lib/theme_check/tags.rb +20 -3
  51. data/lib/theme_check/version.rb +1 -1
  52. data/theme-check.gemspec +2 -2
  53. metadata +12 -7
  54. data/.github/probots.yml +0 -3
@@ -12,6 +12,16 @@ module ThemeCheck
12
12
  version: ThemeCheck::VERSION,
13
13
  }
14
14
 
15
+ # https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#fileOperationFilter
16
+ FILE_OPERATION_FILTER = {
17
+ filters: [{
18
+ scheme: 'file',
19
+ pattern: {
20
+ glob: '**/*',
21
+ },
22
+ }],
23
+ }
24
+
15
25
  CAPABILITIES = {
16
26
  completionProvider: {
17
27
  triggerCharacters: ['.', '{{ ', '{% '],
@@ -33,6 +43,13 @@ module ThemeCheck
33
43
  willSave: false,
34
44
  save: true,
35
45
  },
46
+ workspace: {
47
+ fileOperations: {
48
+ didCreate: FILE_OPERATION_FILTER,
49
+ didDelete: FILE_OPERATION_FILTER,
50
+ willRename: FILE_OPERATION_FILTER,
51
+ },
52
+ },
36
53
  }
37
54
 
38
55
  def initialize(bridge)
@@ -55,7 +72,12 @@ module ThemeCheck
55
72
  @diagnostics_engine = DiagnosticsEngine.new(@storage, @bridge, @diagnostics_manager)
56
73
  @execute_command_engine = ExecuteCommandEngine.new
57
74
  @execute_command_engine << CorrectionExecuteCommandProvider.new(@storage, @bridge, @diagnostics_manager)
58
- @execute_command_engine << RunChecksExecuteCommandProvider.new(@diagnostics_engine, @root_path, config_for_path(@root_path))
75
+ @execute_command_engine << RunChecksExecuteCommandProvider.new(
76
+ @diagnostics_engine,
77
+ @storage,
78
+ config_for_path(@root_path),
79
+ @configuration,
80
+ )
59
81
  @code_action_engine = CodeActionEngine.new(@storage, @diagnostics_manager)
60
82
  @bridge.send_response(id, {
61
83
  capabilities: CAPABILITIES,
@@ -65,6 +87,7 @@ module ThemeCheck
65
87
 
66
88
  def on_initialized(_id, _params)
67
89
  return unless @configuration
90
+
68
91
  @configuration.fetch
69
92
  @configuration.register_did_change_capability
70
93
  end
@@ -91,9 +114,17 @@ module ThemeCheck
91
114
 
92
115
  def on_text_document_did_close(_id, params)
93
116
  relative_path = relative_path_from_text_document_uri(params)
94
- file_system_content = Pathname.new(text_document_uri(params)).read(mode: 'rb', encoding: 'UTF-8')
95
- # On close, the file system becomes the source of truth
96
- @storage.write(relative_path, file_system_content, nil)
117
+ begin
118
+ file_system_content = Pathname.new(text_document_uri(params)).read(mode: 'rb', encoding: 'UTF-8')
119
+ # On close, the file system becomes the source of truth
120
+ @storage.write(relative_path, file_system_content, nil)
121
+
122
+ # the file no longer exists because either the user deleted it, or the user renamed it.
123
+ rescue Errno::ENOENT
124
+ @storage.remove(relative_path)
125
+ ensure
126
+ @diagnostics_engine.clear_diagnostics(relative_path) if @configuration.only_single_file?
127
+ end
97
128
  end
98
129
 
99
130
  def on_text_document_did_save(_id, params)
@@ -125,6 +156,52 @@ module ThemeCheck
125
156
  ))
126
157
  end
127
158
 
159
+ def on_workspace_did_create_files(_id, params)
160
+ paths = params[:files]
161
+ &.map { |file| file[:uri] }
162
+ &.map { |uri| file_path(uri) }
163
+ return unless paths
164
+
165
+ paths.each do |path|
166
+ relative_path = @storage.relative_path(path)
167
+ file_system_content = Pathname.new(path).read(mode: 'rb', encoding: 'UTF-8')
168
+ @storage.write(relative_path, file_system_content, nil)
169
+ end
170
+ end
171
+
172
+ def on_workspace_did_delete_files(_id, params)
173
+ absolute_paths = params[:files]
174
+ &.map { |file| file[:uri] }
175
+ &.map { |uri| file_path(uri) }
176
+ return unless absolute_paths
177
+
178
+ absolute_paths.each do |path|
179
+ relative_path = @storage.relative_path(path)
180
+ @storage.remove(relative_path)
181
+ end
182
+
183
+ analyze_and_send_offenses(absolute_paths)
184
+ end
185
+
186
+ # We're using workspace/willRenameFiles here because we want this to run
187
+ # before textDocument/didOpen and textDocumetn/didClose of the files
188
+ # (which might trigger another theme analysis).
189
+ def on_workspace_will_rename_files(id, params)
190
+ relative_paths = params[:files]
191
+ &.map { |file| [file[:oldUri], file[:newUri]] }
192
+ &.map { |(old_uri, new_uri)| [relative_path_from_uri(old_uri), relative_path_from_uri(new_uri)] }
193
+ return @bridge.send_response(id, nil) unless relative_paths
194
+
195
+ relative_paths.each do |(old_path, new_path)|
196
+ @storage.write(new_path, @storage.read(old_path), nil)
197
+ @storage.remove(old_path)
198
+ end
199
+ @bridge.send_response(id, nil)
200
+
201
+ absolute_paths = relative_paths.flatten(2).map { |p| @storage.path(p) }
202
+ analyze_and_send_offenses(absolute_paths)
203
+ end
204
+
128
205
  def on_workspace_execute_command(id, params)
129
206
  @bridge.send_response(id, @execute_command_engine.execute(
130
207
  params[:command],
@@ -159,6 +236,10 @@ module ThemeCheck
159
236
  file_path(params.dig(:textDocument, :uri))
160
237
  end
161
238
 
239
+ def relative_path_from_uri(uri)
240
+ @storage.relative_path(file_path(uri))
241
+ end
242
+
162
243
  def relative_path_from_text_document_uri(params)
163
244
  @storage.relative_path(text_document_uri(params))
164
245
  end
@@ -185,15 +266,16 @@ module ThemeCheck
185
266
  params.dig(:contentChanges, 0, :text)
186
267
  end
187
268
 
188
- def config_for_path(path)
269
+ def config_for_path(path_or_paths)
270
+ path = path_or_paths.is_a?(Array) ? path_or_paths[0] : path_or_paths
189
271
  root = ThemeCheck::Config.find(path) || @root_path
190
272
  ThemeCheck::Config.from_path(root)
191
273
  end
192
274
 
193
- def analyze_and_send_offenses(absolute_path, only_single_file: nil)
275
+ def analyze_and_send_offenses(absolute_path_or_paths, only_single_file: nil)
194
276
  @diagnostics_engine.analyze_and_send_offenses(
195
- absolute_path,
196
- config_for_path(absolute_path),
277
+ absolute_path_or_paths,
278
+ config_for_path(absolute_path_or_paths),
197
279
  only_single_file: only_single_file.nil? ? @configuration.only_single_file? : only_single_file
198
280
  )
199
281
  end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'json'
3
4
  require 'stringio'
5
+ require 'timeout'
4
6
 
5
7
  module ThemeCheck
6
8
  module LanguageServer
@@ -45,10 +47,29 @@ module ThemeCheck
45
47
  def listen
46
48
  start_handler_threads
47
49
  start_json_rpc_thread
48
- status_code = status_code_from_error(@error.pop)
50
+ err = @error.pop
51
+ status_code = status_code_from_error(err)
52
+
53
+ if status_code > 0
54
+ # For a reason I can't comprehend, this hangs but prints
55
+ # anyway. So it's wrapped in this ugly timeout...
56
+ Timeout.timeout(1) do
57
+ $stderr.puts err.full_message
58
+ end
59
+
60
+ # Warn user of error, otherwise server might restart
61
+ # without telling you.
62
+ @bridge.send_notification("window/showMessage", {
63
+ type: 1,
64
+ message: "A theme-check-language-server error has occurred, search OUTPUT logs for details.",
65
+ })
66
+ end
67
+
49
68
  cleanup(status_code)
50
69
  rescue SignalException
51
70
  0
71
+ rescue StandardError
72
+ 2
52
73
  end
53
74
 
54
75
  def start_json_rpc_thread
@@ -65,36 +86,43 @@ module ThemeCheck
65
86
  else
66
87
  @queue << message
67
88
  end
68
- rescue Exception => e # rubocop:disable Lint/RescueException
69
- break @error << e
70
89
  end
90
+ rescue Exception => e # rubocop:disable Lint/RescueException
91
+ @bridge.log("rescuing #{e.class} in jsonrpc thread")
92
+ @error << e
71
93
  end
72
94
  end
73
95
 
74
96
  def start_handler_threads
75
97
  @number_of_threads.times do
76
98
  @handlers << Thread.new do
77
- loop do
78
- message = @queue.pop
79
- break if @queue.closed? && @queue.empty?
80
- handle_message(message)
81
- rescue Exception => e # rubocop:disable Lint/RescueException
82
- break @error << e
83
- end
99
+ handle_messages
84
100
  end
85
101
  end
86
102
  end
87
103
 
104
+ def handle_messages
105
+ loop do
106
+ message = @queue.pop
107
+ return if @queue.closed? && @queue.empty?
108
+
109
+ handle_message(message)
110
+ end
111
+ rescue Exception => e # rubocop:disable Lint/RescueException
112
+ @bridge.log("rescuing #{e.class} in handler thread")
113
+ @error << e
114
+ end
115
+
88
116
  def status_code_from_error(e)
89
117
  raise e
90
118
 
91
119
  # support ctrl+c and stuff
92
120
  rescue SignalException, DoneStreaming
93
121
  0
94
-
95
122
  rescue Exception => e # rubocop:disable Lint/RescueException
96
123
  raise e if should_raise_errors
97
- @bridge.log("#{e.class}: #{e.message}\n#{e.backtrace.join("\n")}")
124
+
125
+ @bridge.log("Fatal #{e.class}")
98
126
  2
99
127
  end
100
128
 
@@ -109,15 +137,14 @@ module ThemeCheck
109
137
  if @handler.respond_to?(method_name)
110
138
  @handler.send(method_name, id, params)
111
139
  end
112
-
113
140
  rescue DoneStreaming => e
114
141
  raise e
115
142
  rescue StandardError => e
116
143
  is_request = id
117
144
  raise e unless is_request
145
+
118
146
  # Errors obtained in request handlers should be sent
119
147
  # back as internal errors instead of closing the program.
120
- @bridge.log("#{e.class}: #{e.message}\n#{e.backtrace.join("\n")}")
121
148
  @bridge.send_internal_error(id, e)
122
149
  end
123
150
 
@@ -132,6 +159,7 @@ module ThemeCheck
132
159
  end
133
160
 
134
161
  def cleanup(status_code)
162
+ @bridge.log("Closing server... status code = #{status_code}")
135
163
  # Stop listenting to RPC calls
136
164
  @messenger.close_input
137
165
  # Wait for rpc loop to close
@@ -8,7 +8,7 @@ module ThemeCheck
8
8
 
9
9
  def initialize(files, root = "/dev/null")
10
10
  super(files, root)
11
- @versions = {}
11
+ @versions = {} # Hash<relative_path, number>
12
12
  @mutex = Mutex.new
13
13
  end
14
14
 
@@ -49,7 +49,11 @@ module ThemeCheck
49
49
  # - Only offer fixes on "clean" files (or offer the change but specify the version so the editor knows what to do with it)
50
50
  def write(relative_path, content, version)
51
51
  @mutex.synchronize do
52
- @versions[relative_path] = version
52
+ if version.nil?
53
+ @versions.delete(relative_path)
54
+ else
55
+ @versions[relative_path] = version
56
+ end
53
57
  super(relative_path, content)
54
58
  end
55
59
  end
@@ -58,6 +62,13 @@ module ThemeCheck
58
62
  @mutex.synchronize { [read(relative_path), version(relative_path)] }
59
63
  end
60
64
 
65
+ def remove(relative_path)
66
+ @mutex.synchronize do
67
+ @versions.delete(relative_path)
68
+ super(relative_path)
69
+ end
70
+ end
71
+
61
72
  def versioned?
62
73
  true
63
74
  end
@@ -65,5 +76,9 @@ module ThemeCheck
65
76
  def version(relative_path)
66
77
  @versions[relative_path.to_s]
67
78
  end
79
+
80
+ def opened_files
81
+ @versions.keys
82
+ end
68
83
  end
69
84
  end
@@ -33,7 +33,22 @@ module ThemeCheck
33
33
 
34
34
  def source_excerpt(line)
35
35
  original_lines = source.split("\n")
36
- original_lines[line - 1].strip
36
+ original_lines[bounded(0, line - 1, original_lines.size - 1)].strip
37
+ rescue => e
38
+ ThemeCheck.bug(<<~EOS)
39
+ Exception while running `source_excerpt(#{line})`:
40
+ ```
41
+ #{e.class}: #{e.message}
42
+ #{e.backtrace.join("\n ")}
43
+ ```
44
+
45
+ path: #{path}
46
+
47
+ source:
48
+ ```
49
+ #{source}
50
+ ```
51
+ EOS
37
52
  end
38
53
 
39
54
  def parse
@@ -57,5 +72,11 @@ module ThemeCheck
57
72
  disable_liquid_c_nodes: true,
58
73
  )
59
74
  end
75
+
76
+ private
77
+
78
+ def bounded(lower, x, upper)
79
+ [lower, [x, upper].min].max
80
+ end
60
81
  end
61
82
  end
@@ -7,6 +7,7 @@ module ThemeCheck
7
7
 
8
8
  def initialize(value, parent, theme_file)
9
9
  raise ArgumentError, "Expected a Liquid AST Node" if value.is_a?(LiquidNode)
10
+
10
11
  @value = value
11
12
  @parent = parent
12
13
  @theme_file = theme_file
@@ -37,7 +38,9 @@ module ThemeCheck
37
38
  node
38
39
  end
39
40
  end
40
- nodes.map { |node| LiquidNode.new(node, self, @theme_file) }
41
+ nodes
42
+ .reject(&:nil?) # We don't want nil nodes, and they can happen
43
+ .map { |node| LiquidNode.new(node, self, @theme_file) }
41
44
  end
42
45
  end
43
46
 
@@ -75,11 +78,13 @@ module ThemeCheck
75
78
 
76
79
  def inner_markup
77
80
  return '' unless block?
81
+
78
82
  @inner_markup ||= source[block_start_end_index...block_end_start_index]
79
83
  end
80
84
 
81
85
  def inner_json
82
86
  return nil unless schema?
87
+
83
88
  @inner_json ||= JSON.parse(inner_markup)
84
89
  rescue JSON::ParserError
85
90
  # Handled by ValidSchema
@@ -153,6 +158,11 @@ module ThemeCheck
153
158
  @value.is_a?(Liquid::Comment)
154
159
  end
155
160
 
161
+ # {% # comment %}
162
+ def inline_comment?
163
+ @value.is_a?(Liquid::InlineComment)
164
+ end
165
+
156
166
  # Top level node of every liquid_file.
157
167
  def document?
158
168
  @value.is_a?(Liquid::Document)
@@ -186,6 +196,7 @@ module ThemeCheck
186
196
 
187
197
  def filters
188
198
  raise TypeError, "Attempting to lookup filters of #{type_name}. Only variables have filters." unless variable?
199
+
189
200
  @value.filters
190
201
  end
191
202
 
@@ -193,6 +204,25 @@ module ThemeCheck
193
204
  theme_file&.source
194
205
  end
195
206
 
207
+ # For debugging purposes, this might be easier for the eyes.
208
+ def to_h
209
+ if literal?
210
+ return @value
211
+ elsif variable_lookup?
212
+ return {
213
+ type_name: type_name,
214
+ name: value.name.to_s,
215
+ lookups: children.map(&:to_h),
216
+ }
217
+ end
218
+
219
+ {
220
+ type_name: type_name,
221
+ markup: outer_markup,
222
+ children: children.map(&:to_h),
223
+ }
224
+ end
225
+
196
226
  def block_start_markup
197
227
  source[block_start_start_index...block_start_end_index]
198
228
  end
@@ -217,11 +247,13 @@ module ThemeCheck
217
247
 
218
248
  def block_end_start_index
219
249
  return block_start_end_index unless tag? && block?
250
+
220
251
  @block_end_start_index ||= block_end_match&.begin(0) || block_start_end_index
221
252
  end
222
253
 
223
254
  def block_end_end_index
224
255
  return block_end_start_index unless tag? && block?
256
+
225
257
  @block_end_end_index ||= block_end_match&.end(0) || block_start_end_index
226
258
  end
227
259
 
@@ -28,7 +28,7 @@ module ThemeCheck
28
28
  call_checks(:after_node, node)
29
29
  end
30
30
 
31
- @disabled_checks.update(node) if node.comment?
31
+ @disabled_checks.update(node) if node.comment? || node.inline_comment?
32
32
  end
33
33
 
34
34
  def call_checks(method, *args)
@@ -8,7 +8,7 @@ module ThemeCheck
8
8
  path.each_with_index.reduce(hash) do |pointer, (token, index)|
9
9
  if index == path.size - 1
10
10
  pointer[token] = value
11
- elsif !pointer.key?(token)
11
+ elsif !pointer.key?(token) || !pointer[token].is_a?(Hash)
12
12
  pointer[token] = {}
13
13
  end
14
14
  pointer[token]
@@ -13,6 +13,10 @@ module ThemeCheck
13
13
  def plus_labels
14
14
  @plus_labels ||= YAML.load(File.read("#{__dir__}/../../../data/shopify_liquid/plus_objects.yml"))
15
15
  end
16
+
17
+ def theme_app_extension_labels
18
+ @theme_app_extension_labels ||= YAML.load(File.read("#{__dir__}/../../../data/shopify_liquid/theme_app_extension_objects.yml"))
19
+ end
16
20
  end
17
21
  end
18
22
  end
@@ -125,16 +125,32 @@ module ThemeCheck
125
125
  end
126
126
 
127
127
  class Render < Liquid::Tag
128
- SYNTAX = /((?:#{Liquid::QuotedString}|#{Liquid::VariableSegment})+)(\s+(with|#{Liquid::Render::FOR})\s+(#{Liquid::QuotedFragment}+))?(\s+(?:as)\s+(#{Liquid::VariableSegment}+))?/o
128
+ SYNTAX = %r{
129
+ (
130
+ ## for {% render "snippet" %}
131
+ #{Liquid::QuotedString}+ |
132
+ ## for {% render block %}
133
+ ## We require the variable # segment to be at the beginning of the
134
+ ## string (with \A). This is to prevent code like {% render !foo! %}
135
+ ## from parsing
136
+ \A#{Liquid::VariableSegment}+
137
+ )
138
+ ## for {% render "snippet" with product as p %}
139
+ ## or {% render "snippet" for products p %}
140
+ (\s+(with|#{Liquid::Render::FOR})\s+(#{Liquid::QuotedFragment}+))?
141
+ (\s+(?:as)\s+(#{Liquid::VariableSegment}+))?
142
+ ## variables passed into the tag (e.g. {% render "snippet", var1: value1, var2: value2 %}
143
+ ## are not matched by this regex and are handled by Liquid::Render.initialize
144
+ }xo
129
145
 
130
146
  disable_tags "include"
131
147
 
132
- attr_reader :template_name_expr, :attributes
148
+ attr_reader :template_name_expr, :variable_name_expr, :attributes
133
149
 
134
150
  def initialize(tag_name, markup, options)
135
151
  super
136
152
 
137
- raise SyntaxError, options[:locale].t("errors.syntax.render") unless markup =~ SYNTAX
153
+ raise Liquid::SyntaxError, options[:locale].t("errors.syntax.render") unless markup =~ SYNTAX
138
154
 
139
155
  template_name = Regexp.last_match(1)
140
156
  with_or_for = Regexp.last_match(3)
@@ -155,6 +171,7 @@ module ThemeCheck
155
171
  def children
156
172
  [
157
173
  @node.template_name_expr,
174
+ @node.variable_name_expr,
158
175
  ] + @node.attributes.values
159
176
  end
160
177
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module ThemeCheck
3
- VERSION = "1.10.1"
3
+ VERSION = "1.11.0"
4
4
  end
data/theme-check.gemspec CHANGED
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
13
13
  spec.homepage = "https://github.com/Shopify/theme-check"
14
14
  spec.license = "MIT"
15
15
 
16
- spec.required_ruby_version = ">= 2.6"
16
+ spec.required_ruby_version = ">= 2.7"
17
17
 
18
18
  spec.metadata['allowed_push_host'] = 'https://rubygems.org'
19
19
 
@@ -24,7 +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.1.0')
27
+ spec.add_dependency('liquid', '>= 5.4.0')
28
28
  spec.add_dependency('nokogiri', '>= 1.12')
29
29
  spec.add_dependency('parser', '~> 3')
30
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.10.1
4
+ version: 1.11.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: 2022-02-24 00:00:00.000000000 Z
11
+ date: 2022-08-22 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.1.0
19
+ version: 5.4.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.1.0
26
+ version: 5.4.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: nokogiri
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -61,7 +61,9 @@ executables:
61
61
  extensions: []
62
62
  extra_rdoc_files: []
63
63
  files:
64
- - ".github/probots.yml"
64
+ - ".github/ISSUE_TEMPLATE/bug_report.md"
65
+ - ".github/ISSUE_TEMPLATE/feature_request.md"
66
+ - ".github/workflows/cla.yml"
65
67
  - ".github/workflows/theme-check.yml"
66
68
  - ".gitignore"
67
69
  - ".rubocop.yml"
@@ -84,6 +86,7 @@ files:
84
86
  - data/shopify_liquid/objects.yml
85
87
  - data/shopify_liquid/plus_objects.yml
86
88
  - data/shopify_liquid/tags.yml
89
+ - data/shopify_liquid/theme_app_extension_objects.yml
87
90
  - data/shopify_translation_keys.yml
88
91
  - dev.yml
89
92
  - docs/api/check.md
@@ -92,6 +95,7 @@ files:
92
95
  - docs/api/liquid_check.md
93
96
  - docs/checks/TEMPLATE.md.erb
94
97
  - docs/checks/app_block_valid_tags.md
98
+ - docs/checks/asset_preload.md
95
99
  - docs/checks/asset_size_app_block_css.md
96
100
  - docs/checks/asset_size_app_block_javascript.md
97
101
  - docs/checks/asset_size_css.md
@@ -152,6 +156,7 @@ files:
152
156
  - lib/theme_check/checks.rb
153
157
  - lib/theme_check/checks/TEMPLATE.rb.erb
154
158
  - lib/theme_check/checks/app_block_valid_tags.rb
159
+ - lib/theme_check/checks/asset_preload.rb
155
160
  - lib/theme_check/checks/asset_size_app_block_css.rb
156
161
  - lib/theme_check/checks/asset_size_app_block_javascript.rb
157
162
  - lib/theme_check/checks/asset_size_css.rb
@@ -293,14 +298,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
293
298
  requirements:
294
299
  - - ">="
295
300
  - !ruby/object:Gem::Version
296
- version: '2.6'
301
+ version: '2.7'
297
302
  required_rubygems_version: !ruby/object:Gem::Requirement
298
303
  requirements:
299
304
  - - ">="
300
305
  - !ruby/object:Gem::Version
301
306
  version: '0'
302
307
  requirements: []
303
- rubygems_version: 3.2.20
308
+ rubygems_version: 3.3.3
304
309
  signing_key:
305
310
  specification_version: 4
306
311
  summary: A Shopify Theme Linter
data/.github/probots.yml DELETED
@@ -1,3 +0,0 @@
1
- # .github/probots.yml
2
- enabled:
3
- - cla