theme-check 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -0
  3. data/CONTRIBUTING.md +1 -1
  4. data/bin/theme-check +29 -0
  5. data/bin/theme-check-language-server +29 -0
  6. data/config/default.yml +11 -0
  7. data/config/theme_app_extension.yml +15 -0
  8. data/docs/checks/app_block_valid_tags.md +40 -0
  9. data/docs/checks/asset_size_app_block_css.md +1 -1
  10. data/docs/checks/missing_template.md +25 -0
  11. data/docs/checks/pagination_size.md +44 -0
  12. data/docs/checks/undefined_object.md +5 -0
  13. data/lib/theme_check/check.rb +2 -2
  14. data/lib/theme_check/checks/app_block_valid_tags.rb +36 -0
  15. data/lib/theme_check/checks/asset_size_css.rb +3 -3
  16. data/lib/theme_check/checks/asset_size_javascript.rb +2 -2
  17. data/lib/theme_check/checks/convert_include_to_render.rb +3 -1
  18. data/lib/theme_check/checks/deprecate_bgsizes.rb +1 -1
  19. data/lib/theme_check/checks/deprecate_lazysizes.rb +2 -2
  20. data/lib/theme_check/checks/img_lazy_loading.rb +1 -1
  21. data/lib/theme_check/checks/img_width_and_height.rb +3 -3
  22. data/lib/theme_check/checks/missing_template.rb +21 -5
  23. data/lib/theme_check/checks/pagination_size.rb +65 -0
  24. data/lib/theme_check/checks/parser_blocking_javascript.rb +1 -1
  25. data/lib/theme_check/checks/remote_asset.rb +2 -2
  26. data/lib/theme_check/checks/space_inside_braces.rb +26 -6
  27. data/lib/theme_check/checks/undefined_object.rb +1 -1
  28. data/lib/theme_check/checks/valid_html_translation.rb +1 -1
  29. data/lib/theme_check/checks.rb +11 -1
  30. data/lib/theme_check/cli.rb +18 -2
  31. data/lib/theme_check/corrector.rb +4 -0
  32. data/lib/theme_check/file_system_storage.rb +12 -0
  33. data/lib/theme_check/html_check.rb +0 -1
  34. data/lib/theme_check/html_node.rb +37 -16
  35. data/lib/theme_check/html_visitor.rb +17 -3
  36. data/lib/theme_check/json_check.rb +2 -2
  37. data/lib/theme_check/json_printer.rb +26 -0
  38. data/lib/theme_check/language_server/handler.rb +6 -2
  39. data/lib/theme_check/node.rb +6 -4
  40. data/lib/theme_check/offense.rb +56 -3
  41. data/lib/theme_check/parsing_helpers.rb +4 -3
  42. data/lib/theme_check/position.rb +98 -14
  43. data/lib/theme_check/regex_helpers.rb +5 -2
  44. data/lib/theme_check/theme.rb +2 -0
  45. data/lib/theme_check/version.rb +1 -1
  46. data/lib/theme_check.rb +1 -0
  47. data/theme-check.gemspec +1 -1
  48. metadata +12 -10
  49. data/bin/liquid-server +0 -4
  50. data/exe/theme-check-language-server.bat +0 -3
  51. data/exe/theme-check.bat +0 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 28cb25e47867151bea85360a9f07667f46ea30ad90285f16cc74e85370ad39d9
4
- data.tar.gz: 2023811dad002a72f00e2c26562ff3e6b5f2f49c748d44968fd94d1f9e72300f
3
+ metadata.gz: 8bec2f54c12487d444bebd3bb0abad48ec133c4e9504be29857a58c87d82f589
4
+ data.tar.gz: 2cacd6af05aa3c2af8d40167a04532ed998d24049df7b277f70baf50f0a4e401
5
5
  SHA512:
6
- metadata.gz: f3a5339873aea7a325cbc3f3715e9166b1f7734226e3d9ac7b400f048629a514f3eec5d559c77eaf70febacda35416b8332d8d1a6ebefa1d9a34f29474a4e41d
7
- data.tar.gz: 19eec11d1eb86188fe170bce61f884072340d848e800b2bb2b344cddf3561d60594e4f066199b7f9157b54da81ce8afebc5e6db0f3dbfbc5fac208c95d2b5ed8
6
+ metadata.gz: 95a61ee91b1a575dead56345172c5472cdb1c314b94aef37814f311ab54d39263a70d51192ea5d276188d06e8ddc32715f9693f7089157e3376bd7c885b1d30a
7
+ data.tar.gz: 6fe39a2b8944ceb34e48b5a4a84cbb1f544d870b9c38f36dff33ff2e226f76feabb612d9f9e98ce31c2c68209014b46d76adcd0a4dd37224aee3c2ee266e50d0
data/CHANGELOG.md CHANGED
@@ -1,4 +1,20 @@
1
1
 
2
+ v1.3.0 / 2021-08-26
3
+ ==================
4
+
5
+ * Add `--output json` option for the CLI ([#392](https://github.com/shopify/theme-check/issues/392))
6
+ * Add PaginationSize check ([#359](https://github.com/shopify/theme-check/issues/359))
7
+ * Add ConvertIncludeToRender auto corrector ([#341](https://github.com/shopify/theme-check/issues/341))
8
+ * Add MissingTemplate auto corrector ([#388](https://github.com/shopify/theme-check/issues/388))
9
+ * Add `MissingTemplate` `ignore_missing` option ([#394](https://github.com/shopify/theme-check/issues/394))
10
+ * Fix Windows duplicate .bat file problem ([#400](https://github.com/shopify/theme-check/issues/400))
11
+ * Fix substring highlighting inside nodes ([#386](https://github.com/shopify/theme-check/issues/386))
12
+ * Add check for forbidden tags in theme app extension blocks ([#383](https://github.com/shopify/theme-check/issues/383))
13
+ * Improve HTML parsing of liquid attributes ([#381](https://github.com/shopify/theme-check/issues/381))
14
+ * Handle escaped file URIs in language server ([#360](https://github.com/shopify/theme-check/issues/360)) ([#382](https://github.com/shopify/theme-check/issues/382))
15
+ * Change asset size errors into suggestions ([#378](https://github.com/shopify/theme-check/issues/378))
16
+ * Switch to nokogiri 1.12, since it includes html5 support directly now ([#391](https://github.com/shopify/theme-check/issues/391))
17
+
2
18
  v1.2.0 / 2021-07-15
3
19
  ==================
4
20
 
data/CONTRIBUTING.md CHANGED
@@ -31,7 +31,7 @@ bundle exec rake
31
31
  ## Checking a theme
32
32
 
33
33
  ```
34
- bundle exec theme-check /path/to/your/theme
34
+ bin/theme-check /path/to/your/theme
35
35
  ```
36
36
 
37
37
  ## Creating a new "Check"
data/bin/theme-check ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'theme-check' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("theme-check", "theme-check")
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'theme-check-language-server' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("theme-check", "theme-check-language-server")
data/config/default.yml CHANGED
@@ -23,6 +23,7 @@ LiquidTag:
23
23
  MissingTemplate:
24
24
  enabled: true
25
25
  ignore: []
26
+ ignore_missing: []
26
27
 
27
28
  NestedSnippet:
28
29
  enabled: true
@@ -177,3 +178,13 @@ AssetSizeAppBlockCSS:
177
178
  enabled: false
178
179
  ignore: []
179
180
  threshold_in_bytes: 100_000
181
+
182
+ AppBlockValidTags:
183
+ enabled: false
184
+ ignore: []
185
+
186
+ PaginationSize:
187
+ enabled: true
188
+ ignore: []
189
+ min_size: 1
190
+ max_size: 50
@@ -23,6 +23,7 @@ LiquidTag:
23
23
  MissingTemplate:
24
24
  enabled: true
25
25
  ignore: []
26
+ ignore_missing: []
26
27
 
27
28
  NestedSnippet:
28
29
  enabled: true
@@ -110,11 +111,13 @@ ParserBlockingScriptTag:
110
111
 
111
112
  AssetSizeJavaScript:
112
113
  enabled: true
114
+ severity: suggestion
113
115
  ignore: []
114
116
  threshold_in_bytes: 10_000
115
117
 
116
118
  AssetSizeCSS:
117
119
  enabled: true
120
+ severity: suggestion
118
121
  ignore: []
119
122
  threshold_in_bytes: 100_000
120
123
 
@@ -144,10 +147,22 @@ HtmlParsingError:
144
147
 
145
148
  AssetSizeAppBlockJavaScript:
146
149
  enabled: true
150
+ severity: suggestion
147
151
  ignore: []
148
152
  threshold_in_bytes: 10_000
149
153
 
150
154
  AssetSizeAppBlockCSS:
151
155
  enabled: true
156
+ severity: suggestion
152
157
  ignore: []
153
158
  threshold_in_bytes: 100_000
159
+
160
+ AppBlockValidTags:
161
+ enabled: true
162
+ ignore: []
163
+
164
+ PaginationSize:
165
+ enabled: true
166
+ ignore: []
167
+ min_size: 1
168
+ max_size: 50
@@ -0,0 +1,40 @@
1
+ # Reject Forbidden Tags from Theme App Extension Blocks (`AppBlockValidTags`)
2
+
3
+ This rule exists to prevent theme app extension blocks from containing forbidden tags in their liquid code.
4
+
5
+ ## Check Details
6
+
7
+ This rule verifies none of the below tags are used in theme app extension blocks.
8
+
9
+ - `{% javascript %}`
10
+ - `{% stylesheet %}`
11
+ - `{% include 'foo' %}`
12
+ - `{% layout 'foo' %}`
13
+ - `{% section 'foo' %}`
14
+
15
+ :-1: **Incorrect** code for this check occurs with the use of any of the above tags in the liquid code of theme app extension blocks.
16
+
17
+ ## Check Options
18
+
19
+ The default configuration for theme app extensions is the following:
20
+
21
+ ```yaml
22
+ AppBlockValidTags:
23
+ enabled: true
24
+ ```
25
+
26
+ ## When Not To Use It
27
+
28
+ This rule should not be disabled locally.
29
+
30
+ ## Version
31
+
32
+ This check has been introduced in 1.3.0
33
+
34
+ ## Resources
35
+
36
+ - [Rule Source][codesource]
37
+ - [Documentation Source][docsource]
38
+
39
+ [codesource]: /lib/theme_check/checks/app_block_valid_tags.rb
40
+ [docsource]: /docs/checks/app_block_valid_tags.md
@@ -23,7 +23,7 @@ The default configuration is the following:
23
23
 
24
24
  ```yaml
25
25
  AssetSizeAppBlockCSS:
26
- enabled: false
26
+ enabled: true
27
27
  threshold_in_bytes: 100_000
28
28
  ```
29
29
 
@@ -25,8 +25,33 @@ The default configuration for this check is the following:
25
25
  ```yaml
26
26
  MissingTemplate:
27
27
  enabled: true
28
+ ignore_missing: []
28
29
  ```
29
30
 
31
+ ### `ignore_missing`
32
+
33
+ Specify a list of patterns of missing template files to ignore.
34
+
35
+ While the `ignore` option will ignore all occurrences of `MissingTemplate` according to the file in which they appear, `ignore_missing` allows ignoring all occurrences of `MissingTemplate` based on the target template, the template being rendered.
36
+
37
+ For example:
38
+
39
+ ```yaml
40
+ MissingTemplate:
41
+ ignore_missing:
42
+ - snippets/icon-*
43
+ ```
44
+
45
+ Would ignore offenses on `{% render 'icon-missing' %}` across all theme files.
46
+
47
+ ```yaml
48
+ MissingTemplate:
49
+ ignore:
50
+ - templates/index.liquid
51
+ ```
52
+
53
+ Would ignore all `MissingTemplate` in `templates/index.liquid`, no mater the file being rendered.
54
+
30
55
  ## Version
31
56
 
32
57
  This check has been introduced in Theme Check 0.1.0.
@@ -0,0 +1,44 @@
1
+ # Ensure `paginate` tags are used with performant sizes
2
+
3
+ ## Check Details
4
+
5
+ This check is aimed at keeping response times low.
6
+
7
+ :-1: Examples of **incorrect** code for this check:
8
+
9
+ ```liquid
10
+ <!-- Using too large of page size -->
11
+ {% paginate collection.products by 999 %}
12
+ ```
13
+
14
+ :+1: Examples of **correct** code for this check:
15
+
16
+ ```liquid
17
+ {% paginate collection.products by 12 %}
18
+ ```
19
+
20
+ Use sizes that are integers below the `max_size`, and above the `min_size`.
21
+
22
+ ## Check Options
23
+
24
+ The default configuration for this check is the following:
25
+
26
+ ```yaml
27
+ PaginationSize:
28
+ enabled: true
29
+ ignore: []
30
+ min_size: 1
31
+ max_size: 50
32
+ ```
33
+
34
+ ## When Not To Use It
35
+
36
+ N/A
37
+
38
+ ## Version
39
+
40
+ This check has been introduced in Theme Check 1.3.0.
41
+
42
+ ## Resources
43
+
44
+ [paginate]: https://shopify.dev/api/liquid/objects/paginate
@@ -33,8 +33,13 @@ The default configuration for this check is the following:
33
33
  ```yaml
34
34
  UndefinedObject:
35
35
  enabled: true
36
+ exclude_snippets: true
36
37
  ```
37
38
 
39
+ ### `exclude_snippets`
40
+
41
+ The `exclude_snippets` (Default: `true`) option determines whether to check for undefined objects in snippets file (as objects _may_ be defined as arguments)
42
+
38
43
  ## When Not To Use It
39
44
 
40
45
  It is discouraged to disable this rule.
@@ -91,8 +91,8 @@ module ThemeCheck
91
91
  @offenses ||= []
92
92
  end
93
93
 
94
- def add_offense(message, node: nil, template: node&.template, markup: nil, line_number: nil, &block)
95
- offenses << Offense.new(check: self, message: message, template: template, node: node, markup: markup, line_number: line_number, correction: block)
94
+ def add_offense(message, node: nil, template: node&.template, markup: nil, line_number: nil, node_markup_offset: 0, &block)
95
+ offenses << Offense.new(check: self, message: message, template: template, node: node, markup: markup, line_number: line_number, node_markup_offset: node_markup_offset, correction: block)
96
96
  end
97
97
 
98
98
  def severity
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+ module ThemeCheck
3
+ # Reports errors when invalid tags are used in a Theme App
4
+ # Extension block
5
+ class AppBlockValidTags < LiquidCheck
6
+ severity :error
7
+ category :liquid
8
+ doc docs_url(__FILE__)
9
+
10
+ # Don't allow this check to be disabled with a comment,
11
+ # since we need to be able to enforce this server-side
12
+ can_disable false
13
+
14
+ OFFENSE_MSG = "Theme app extension blocks cannot contain %s tags"
15
+
16
+ def on_javascript(node)
17
+ add_offense(OFFENSE_MSG % 'javascript', node: node)
18
+ end
19
+
20
+ def on_stylesheet(node)
21
+ add_offense(OFFENSE_MSG % 'stylesheet', node: node)
22
+ end
23
+
24
+ def on_include(node)
25
+ add_offense(OFFENSE_MSG % 'include', node: node)
26
+ end
27
+
28
+ def on_layout(node)
29
+ add_offense(OFFENSE_MSG % 'layout', node: node)
30
+ end
31
+
32
+ def on_section(node)
33
+ add_offense(OFFENSE_MSG % 'section', node: node)
34
+ end
35
+ end
36
+ end
@@ -13,12 +13,12 @@ module ThemeCheck
13
13
  end
14
14
 
15
15
  def on_link(node)
16
- return if node.attributes['rel']&.value != "stylesheet"
17
- file_size = href_to_file_size(node.attributes['href']&.value)
16
+ return if node.attributes['rel'] != "stylesheet"
17
+ file_size = href_to_file_size(node.attributes['href'])
18
18
  return if file_size.nil?
19
19
  return if file_size <= threshold_in_bytes
20
20
  add_offense(
21
- "CSS on every page load exceeding compressed size threshold (#{threshold_in_bytes} Bytes).",
21
+ "CSS on every page load exceeding compressed size threshold (#{threshold_in_bytes} Bytes)",
22
22
  node: node
23
23
  )
24
24
  end
@@ -16,7 +16,7 @@ module ThemeCheck
16
16
  end
17
17
 
18
18
  def on_script(node)
19
- file_size = src_to_file_size(node.attributes['src']&.value)
19
+ file_size = src_to_file_size(node.attributes['src'])
20
20
  return if file_size.nil?
21
21
  return if file_size <= threshold_in_bytes
22
22
  add_offense(
@@ -28,7 +28,7 @@ module ThemeCheck
28
28
  def src_to_file_size(src)
29
29
  # We're kind of intentionally only looking at {{ 'asset' | asset_url }} or full urls in here.
30
30
  # More complicated liquid statements are not in scope.
31
- if src =~ /^#{VARIABLE}$/o && src =~ /asset_url/ && src =~ Liquid::QuotedString
31
+ if src =~ /^#{LIQUID_VARIABLE}$/o && src =~ /asset_url/ && src =~ Liquid::QuotedString
32
32
  asset_id = Regexp.last_match(0).gsub(START_OR_END_QUOTE, "")
33
33
  asset = @theme.assets.find { |a| a.name.end_with?("/" + asset_id) }
34
34
  return if asset.nil?
@@ -7,7 +7,9 @@ module ThemeCheck
7
7
  doc docs_url(__FILE__)
8
8
 
9
9
  def on_include(node)
10
- add_offense("`include` is deprecated - convert it to `render`", node: node)
10
+ add_offense("`include` is deprecated - convert it to `render`", node: node) do |corrector|
11
+ corrector.replace(node, "render \'#{node.value.template_name_expr}\' ")
12
+ end
11
13
  end
12
14
  end
13
15
  end
@@ -6,7 +6,7 @@ module ThemeCheck
6
6
  doc docs_url(__FILE__)
7
7
 
8
8
  def on_div(node)
9
- class_list = node.attributes["class"]&.value&.split(" ")
9
+ class_list = node.attributes["class"]&.split(" ")
10
10
  add_offense("Use the native loading=\"lazy\" attribute instead of lazysizes", node: node) if class_list&.include?("lazyload")
11
11
  add_offense("Use the CSS imageset attribute instead of data-bgset", node: node) if node.attributes["data-bgset"]
12
12
  end
@@ -6,11 +6,11 @@ module ThemeCheck
6
6
  doc docs_url(__FILE__)
7
7
 
8
8
  def on_img(node)
9
- class_list = node.attributes["class"]&.value&.split(" ")
9
+ class_list = node.attributes["class"]&.split(" ")
10
10
  add_offense("Use the native loading=\"lazy\" attribute instead of lazysizes", node: node) if class_list&.include?("lazyload")
11
11
  add_offense("Use the native srcset attribute instead of data-srcset", node: node) if node.attributes["data-srcset"]
12
12
  add_offense("Use the native sizes attribute instead of data-sizes", node: node) if node.attributes["data-sizes"]
13
- add_offense("Do not set the data-sizes attribute to auto", node: node) if node.attributes["data-sizes"]&.value == "auto"
13
+ add_offense("Do not set the data-sizes attribute to auto", node: node) if node.attributes["data-sizes"] == "auto"
14
14
  end
15
15
  end
16
16
  end
@@ -8,7 +8,7 @@ module ThemeCheck
8
8
  ACCEPTED_LOADING_VALUES = %w[lazy eager]
9
9
 
10
10
  def on_img(node)
11
- loading = node.attributes["loading"]&.value&.downcase
11
+ loading = node.attributes["loading"]&.downcase
12
12
  return if ACCEPTED_LOADING_VALUES.include?(loading)
13
13
  if loading == "auto"
14
14
  add_offense("Prefer loading=\"lazy\" to defer loading of images", node: node)