theme-check 0.10.2 → 1.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dc5f5b1f71dce3de919836a4b8cd55e2ae3994e12c8118a69050840fac21b0e6
4
- data.tar.gz: bc190dcdae4c5ec62b8d3e9a6d0a3d1c9ea6fc9b052e843455faf1ed1fc0d92d
3
+ metadata.gz: 94b918e53777cfb70c65dacd9d9bfbdb6f4463597c8f9c81969e1baef89df7a1
4
+ data.tar.gz: 7e45af9a3dfeab1eafdff5533df68a9e0d67007d94661a2c974c0c2fece61095
5
5
  SHA512:
6
- metadata.gz: 24724968d6b6f792e522289b3a62e200d5a2dc568286f8b5044a4b72253bfeb54aafae140dff38d2bfa9e5cb871d1f65c5c575661bb5b5132f73c36919e1b4f1
7
- data.tar.gz: aaf053c7dbe25615daadaef936f58435e84180664b03b9f77edf7eee247581ef6b3ddadcf04816922e738db047693e1ca75a6e5bcfec139d42d2d3c0595fe49c
6
+ metadata.gz: ea1b75ca11a66aefe5eef421f577d53716cb180799863185d36fad21a9033b5cf52579df3e593e41867513da410adc7d16de723f35b3a5435e50098b7af2a348
7
+ data.tar.gz: ceab091f6bf7317d899cb5459601b7dfb5294e6e4be962a421b33bad33c74fd730001dea90687f81f754d57e5cdedc5b39d0efb5d95d6c016ed965f7e4e86a9f
data/CHANGELOG.md CHANGED
@@ -1,4 +1,18 @@
1
1
 
2
+ v1.0.0 / 2021-06-28
3
+ ==================
4
+
5
+ * Convert `AssetSizeCSS` to `HtmlCheck`
6
+ * Add `DeprecateLazysizes` & `DeprecateBgsizes` checks
7
+ * Allow hardcoded CDN urls in `RemoteAsset`
8
+ * Bump `LiquidTag` `min_consecutive_statements` default to 5
9
+ * Exclude {% javascript %} and {% stylesheet %} from line counts in `TemplateLength`
10
+ * Bump `TemplateLength` `max_length` default to 500
11
+ * Fix `StringScanner#skip(String)` not being supported on some Rubies
12
+ * Fix `ParsingHelpers#outside_of_strings` handling of empty strings
13
+ * Update to support new `{% render %}` syntax
14
+ * Converted `AssetSizeJavaScript` to `HtmlCheck`
15
+
2
16
  v0.10.2 / 2021-06-18
3
17
  ==================
4
18
 
data/config/default.yml CHANGED
@@ -12,7 +12,7 @@ ConvertIncludeToRender:
12
12
  LiquidTag:
13
13
  enabled: true
14
14
  ignore: []
15
- min_consecutive_statements: 4
15
+ min_consecutive_statements: 5
16
16
 
17
17
  MissingTemplate:
18
18
  enabled: true
@@ -38,9 +38,13 @@ SyntaxError:
38
38
  TemplateLength:
39
39
  enabled: true
40
40
  ignore: []
41
- max_length: 200
41
+ max_length: 500
42
42
  # Exclude content of {% schema %} in line count
43
43
  exclude_schema: true
44
+ # Exclude content of {% stylesheet %} in line count
45
+ exclude_stylesheet: true
46
+ # Exclude content of {% javascript %} in line count
47
+ exclude_javascript: true
44
48
 
45
49
  UnknownFilter:
46
50
  enabled: true
@@ -99,6 +103,14 @@ DeprecatedFilter:
99
103
  enabled: true
100
104
  ignore: []
101
105
 
106
+ DeprecateLazysizes:
107
+ enabled: true
108
+ ignore: []
109
+
110
+ DeprecateBgsizes:
111
+ enabled: true
112
+ ignore: []
113
+
102
114
  MissingEnableComment:
103
115
  enabled: true
104
116
  ignore: []
@@ -109,16 +121,20 @@ ParserBlockingJavaScript:
109
121
 
110
122
  ParserBlockingScriptTag:
111
123
  enabled: true
124
+ ignore: []
112
125
 
113
126
  AssetSizeJavaScript:
114
127
  enabled: false
115
- ignore: []
116
128
  threshold_in_bytes: 10_000
117
129
  ignore: []
118
130
 
119
131
  AssetSizeCSS:
120
132
  enabled: false
133
+ threshold_in_bytes: 100_000
121
134
  ignore: []
135
+
136
+ AssetSizeCSSStylesheetTag:
137
+ enabled: false
122
138
  threshold_in_bytes: 100_000
123
139
  ignore: []
124
140
 
@@ -40,6 +40,7 @@
40
40
  - linklist
41
41
  - linklists
42
42
  - location
43
+ - localization
43
44
  - metafield
44
45
  - model
45
46
  - model_source
@@ -55,6 +56,7 @@
55
56
  - powered_by_link
56
57
  - product
57
58
  - product_option
59
+ - product_variant
58
60
  - recommendations
59
61
  - request
60
62
  - routes
@@ -0,0 +1,50 @@
1
+ # Check Title (`AssetSizeCSSStylesheetTag`)
2
+
3
+ The `stylesheet_tag` filter generates a link tag that points to a given stylesheet. This rule exists to prevent large CSS bundles (for speed).
4
+
5
+ ## Check Details
6
+
7
+ This rule disallows the use of too much CSS in themes, as configured by `threshold_in_bytes`.
8
+
9
+ :-1: Examples of **incorrect** code for this check:
10
+ ```liquid
11
+ <!-- Here, assets/theme.css is **greater** than `threshold_in_bytes` compressed. -->
12
+ {{ 'theme.css' | asset_url | stylesheet_tag }}
13
+ ```
14
+
15
+ :+1: Example of **correct** code for this check:
16
+ ```liquid
17
+ <!-- Here, assets/theme.css is **less** than `threshold_in_bytes` compressed. -->
18
+ {{ 'theme.css' | asset_url | stylesheet_tag }}
19
+ ```
20
+
21
+ ## Check Options
22
+
23
+ The default configuration for this check is the following:
24
+
25
+ ```yaml
26
+ AssetSizeCSSStylesheetTag:
27
+ enabled: false
28
+ threshold_in_bytes: 100_000
29
+ ```
30
+
31
+ ### `threshold_in_bytes`
32
+
33
+ The `threshold_in_bytes` option (default: `100_000`) determines the maximum allowed compressed size in bytes that a single CSS file can take.
34
+
35
+ ## When Not To Use It
36
+
37
+ This rule is safe to disable.
38
+
39
+ ## Version
40
+
41
+ This check has been introduced in Theme Check 1.0.0
42
+
43
+ ## Resources
44
+
45
+ - [The Performance Inequality Gap](https://infrequently.org/2021/03/the-performance-inequality-gap/)
46
+ - [Rule Source][codesource]
47
+ - [Documentation Source][docsource]
48
+
49
+ [codesource]: /lib/theme_check/checks/asset_size_css_stylesheet_tag.rb
50
+ [docsource]: /docs/checks/asset_size_css_stylesheet_tag.md
@@ -0,0 +1,66 @@
1
+ # Deprecate Bgsizes (`DeprecateBgsizes`)
2
+
3
+ The lazySizes bgset extension allows you to define multiple background images with a width descriptor. The extension will then load the best image size for the current viewport and device (https://github.com/aFarkas/lazysizes/tree/gh-pages/plugins/bgset)
4
+
5
+
6
+ ## Check Details
7
+
8
+ This check is aimed at discouraging the use of the lazySizes bgset plugin
9
+
10
+ :-1: Examples of **incorrect** code for this check:
11
+
12
+ ```liquid
13
+
14
+ <!-- Reports use of "lazyload" class and "data-bgset" attribute -->
15
+
16
+ <script src="ls.bgset.min.js"></script>
17
+ <script src="lazysizes.min.js"></script>
18
+ <div class="lazyload" data-bgset="image-200.jpg 200w, image-300.jpg 300w, image-400.jpg 400w" data-sizes="auto">
19
+ </div>
20
+
21
+ ```
22
+
23
+ :+1: Examples of **correct** code for this check:
24
+
25
+ ```liquid
26
+
27
+ <!-- Uses the CSS image-set() attribute instead of "data-bgset" -->
28
+ <!-- CSS Stylesheet -->
29
+ .box {
30
+ background-image: -webkit-image-set(
31
+ url("small-balloons.jpg") 1x,
32
+ url("large-balloons.jpg") 2x);
33
+ background-image: image-set(
34
+ url("small-balloons.jpg") 1x,
35
+ url("large-balloons.jpg") 2x);
36
+ }
37
+
38
+ <!-- HTML -->
39
+ <div class="box"></div>
40
+
41
+ ```
42
+
43
+ ## Check Options
44
+
45
+ The default configuration for this check is the following:
46
+
47
+ ```yaml
48
+ DeprecateBgsizes:
49
+ enabled: true
50
+ ```
51
+
52
+ ## When Not To Use It
53
+
54
+ You should disable this rule in older browsers that don't support the CSS image-set attribute.
55
+
56
+ ## Version
57
+
58
+ This check has been introduced in Theme Check 1.0.0.
59
+
60
+ ## Resources
61
+
62
+ - [Rule Source][codesource]
63
+ - [Documentation Source][docsource]
64
+
65
+ [codesource]: /lib/theme_check/checks/deprecate_bgsizes.rb
66
+ [docsource]: /docs/checks/deprecate_bgsizes.md
@@ -0,0 +1,61 @@
1
+ # Deprecate lazySizes (`DeprecateLazysizes`)
2
+
3
+ [lazysizes](https://github.com/aFarkas/lazysizes) is a common JavaScript library used to lazy load images, iframes and scripts.
4
+
5
+ ## Check Details
6
+
7
+ This check is aimed at discouraging the use of the lazysizes JavaScript library
8
+
9
+ :-1: Examples of **incorrect** code for this check:
10
+
11
+ ```liquid
12
+
13
+ <!-- Reports use of "lazyload" class -->
14
+ <img src="a.jpg" class="lazyload">
15
+
16
+ <!-- Reports use of "data-srcset" and "data-sizes" attribute. Reports data-sizes="auto" -->
17
+ <img
18
+ alt="House by the lake"
19
+ data-sizes="auto"
20
+ data-srcset="small.jpg 500w,
21
+ medium.jpg 640w,
22
+ big.jpg 1024w"
23
+ data-src="medium.jpg"
24
+ class="lazyload"
25
+ />
26
+
27
+ ```
28
+
29
+ :+1: Examples of **correct** code for this check:
30
+
31
+ ```liquid
32
+
33
+ <!-- Does not use lazySizes library. Instead uses native "loading" attribute -->
34
+ <img src="a.jpg" loading="lazy">
35
+
36
+ ```
37
+
38
+ ## Check Options
39
+
40
+ The default configuration for this check is the following:
41
+
42
+ ```yaml
43
+ DeprecateLazysizes:
44
+ enabled: true
45
+ ```
46
+
47
+ ## When Not To Use It
48
+
49
+ You should disable this rule if you want to support lazy loading of images in older browser that don't support the loading="lazy" attribute yet.
50
+
51
+ ## Version
52
+
53
+ This check has been introduced in Theme Check 1.0.0.
54
+
55
+ ## Resources
56
+
57
+ - [Rule Source][codesource]
58
+ - [Documentation Source][docsource]
59
+
60
+ [codesource]: /lib/theme_check/checks/deprecate_lazysizes.rb
61
+ [docsource]: /docs/checks/deprecate_lazysizes.md
@@ -39,12 +39,12 @@ The default configuration for this check is the following:
39
39
  ```yaml
40
40
  LiquidTag:
41
41
  enabled: true
42
- min_consecutive_statements: 4
42
+ min_consecutive_statements: 5
43
43
  ```
44
44
 
45
45
  ### `min_consecutive_statements`
46
46
 
47
- The `min_consecutive_statements` option (Default: `4`) determines the maximum (inclusive) number of consecutive statements before the check recommends a refactor.
47
+ The `min_consecutive_statements` option (Default: `5`) determines the maximum (inclusive) number of consecutive statements before the check recommends a refactor.
48
48
 
49
49
  ## When Not To Use It
50
50
 
@@ -21,8 +21,10 @@ The default configuration for this check is the following:
21
21
  ```yaml
22
22
  TemplateLength:
23
23
  enabled: true
24
- max_length: 200
24
+ max_length: 500
25
25
  exclude_schema: true
26
+ exclude_stylesheet: true
27
+ exclude_javascript: true
26
28
  ```
27
29
 
28
30
  ### `max_length`
@@ -31,7 +33,15 @@ The `max_length` (Default: `200`) option determines the maximum number of lines
31
33
 
32
34
  ### `exclude_schema`
33
35
 
34
- The `exclude_schema` (Default: `true`) option determines if the schema lines from a template should be excluded from the line count.
36
+ The `exclude_schema` (Default: `true`) option determines if the lines inside `{% schema %}` blocks from a template should be excluded from the line count.
37
+
38
+ ### `exclude_stylesheet`
39
+
40
+ The `exclude_stylesheet` (Default: `true`) option determines if the lines inside `{% stylesheet %}` blocks from a template should be excluded from the line count.
41
+
42
+ ### `exclude_javascript`
43
+
44
+ The `exclude_javascript` (Default: `true`) option determines if the lines inside `{% javascript %}` blocks from a template should be excluded from the line count.
35
45
 
36
46
  ## When Not To Use It
37
47
 
@@ -1,89 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
  module ThemeCheck
3
- class AssetSizeCSS < LiquidCheck
3
+ class AssetSizeCSS < HtmlCheck
4
4
  include RegexHelpers
5
5
  severity :error
6
- category :performance
6
+ category :html, :performance
7
7
  doc docs_url(__FILE__)
8
8
 
9
- Link = Struct.new(:href, :index)
10
-
11
- LINK_TAG_HREF = %r{
12
- <link
13
- (?=[^>]+?rel=['"]?stylesheet['"]?) # Make sure rel=stylesheet is in the link with lookahead
14
- [^>]+ # any non closing tag character
15
- href= # href attribute start
16
- (?<href>#{QUOTED_LIQUID_ATTRIBUTE}) # href attribute value (may contain liquid)
17
- [^>]* # any non closing character till the end
18
- >
19
- }omix
20
- STYLESHEET_TAG = %r{
21
- #{Liquid::VariableStart} # VariableStart
22
- (?:(?!#{Liquid::VariableEnd}).)*? # anything that isn't followed by a VariableEnd
23
- \|\s*asset_url\s* # | asset_url
24
- \|\s*stylesheet_tag\s* # | stylesheet_tag
25
- #{Liquid::VariableEnd} # VariableEnd
26
- }omix
27
-
28
9
  attr_reader :threshold_in_bytes
29
10
 
30
11
  def initialize(threshold_in_bytes: 100_000)
31
12
  @threshold_in_bytes = threshold_in_bytes
32
13
  end
33
14
 
34
- def on_document(node)
35
- @node = node
36
- @source = node.template.source
37
- record_offenses
38
- end
39
-
40
- def record_offenses
41
- stylesheets(@source).each do |stylesheet|
42
- file_size = href_to_file_size(stylesheet.href)
43
- next if file_size.nil?
44
- next if file_size <= threshold_in_bytes
45
- add_offense(
46
- "CSS on every page load exceding compressed size threshold (#{threshold_in_bytes} Bytes).",
47
- node: @node,
48
- markup: stylesheet.href,
49
- line_number: @source[0...stylesheet.index].count("\n") + 1
50
- )
51
- end
52
- end
53
-
54
- def stylesheets(source)
55
- stylesheet_links = matches(source, LINK_TAG_HREF)
56
- .map do |m|
57
- Link.new(
58
- m[:href].gsub(START_OR_END_QUOTE, ""),
59
- m.begin(:href),
60
- )
61
- end
62
-
63
- stylesheet_tags = matches(source, STYLESHEET_TAG)
64
- .map do |m|
65
- Link.new(
66
- m[0],
67
- m.begin(0),
68
- )
69
- end
70
-
71
- stylesheet_links + stylesheet_tags
72
- end
73
-
74
- def href_to_file_size(href)
75
- # asset_url (+ optional stylesheet_tag) variables
76
- if href =~ /^#{VARIABLE}$/o && href =~ /asset_url/ && href =~ Liquid::QuotedString
77
- asset_id = Regexp.last_match(0).gsub(START_OR_END_QUOTE, "")
78
- asset = @theme.assets.find { |a| a.name.end_with?("/" + asset_id) }
79
- return if asset.nil?
80
- asset.gzipped_size
81
-
82
- # remote URLs
83
- elsif href =~ %r{^(https?:)?//}
84
- asset = RemoteAssetFile.from_src(href)
85
- asset.gzipped_size
86
- end
15
+ def on_link(node)
16
+ return if node.attributes['rel']&.value != "stylesheet"
17
+ file_size = href_to_file_size(node.attributes['href']&.value)
18
+ return if file_size.nil?
19
+ return if file_size <= threshold_in_bytes
20
+ add_offense(
21
+ "CSS on every page load exceeding compressed size threshold (#{threshold_in_bytes} Bytes).",
22
+ node: node
23
+ )
87
24
  end
88
25
  end
89
26
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+ module ThemeCheck
3
+ class AssetSizeCSSStylesheetTag < LiquidCheck
4
+ include RegexHelpers
5
+ severity :error
6
+ category :liquid, :performance
7
+ doc docs_url(__FILE__)
8
+
9
+ def initialize(threshold_in_bytes: 100_000)
10
+ @threshold_in_bytes = threshold_in_bytes
11
+ end
12
+
13
+ def on_variable(node)
14
+ used_filters = node.value.filters.map { |name, *_rest| name }
15
+ return unless used_filters.include?("stylesheet_tag")
16
+ file_size = href_to_file_size('{{' + node.markup + '}}')
17
+ return if file_size <= @threshold_in_bytes
18
+ add_offense(
19
+ "CSS on every page load exceeding compressed size threshold (#{@threshold_in_bytes} Bytes).",
20
+ node: node
21
+ )
22
+ end
23
+ end
24
+ end
@@ -3,52 +3,26 @@ module ThemeCheck
3
3
  # Reports errors when trying to use too much JavaScript on page load
4
4
  # Encourages the use of the Import on Interaction pattern [1].
5
5
  # [1]: https://addyosmani.com/blog/import-on-interaction/
6
- class AssetSizeJavaScript < LiquidCheck
6
+ class AssetSizeJavaScript < HtmlCheck
7
7
  include RegexHelpers
8
8
  severity :error
9
- category :performance
9
+ category :html, :performance
10
10
  doc docs_url(__FILE__)
11
11
 
12
- Script = Struct.new(:src, :match)
13
-
14
- SCRIPT_TAG_SRC = %r{
15
- <script
16
- [^>]+ # any non closing tag character
17
- src= # src attribute start
18
- (?<src>#{QUOTED_LIQUID_ATTRIBUTE}) # src attribute value (may contain liquid)
19
- [^>]* # any non closing character till the end
20
- >
21
- }omix
22
-
23
12
  attr_reader :threshold_in_bytes
24
13
 
25
14
  def initialize(threshold_in_bytes: 10000)
26
15
  @threshold_in_bytes = threshold_in_bytes
27
16
  end
28
17
 
29
- def on_document(node)
30
- @node = node
31
- @source = node.template.source
32
- record_offenses
33
- end
34
-
35
- def record_offenses
36
- scripts(@source).each do |script|
37
- file_size = src_to_file_size(script.src)
38
- next if file_size.nil?
39
- next if file_size <= threshold_in_bytes
40
- add_offense(
41
- "JavaScript on every page load exceding compressed size threshold (#{threshold_in_bytes} Bytes), consider using the import on interaction pattern.",
42
- node: @node,
43
- markup: script.src,
44
- line_number: @source[0...script.match.begin(:src)].count("\n") + 1
45
- )
46
- end
47
- end
48
-
49
- def scripts(source)
50
- matches(source, SCRIPT_TAG_SRC)
51
- .map { |m| Script.new(m[:src].gsub(START_OR_END_QUOTE, ""), m) }
18
+ def on_script(node)
19
+ file_size = src_to_file_size(node.attributes['src']&.value)
20
+ return if file_size.nil?
21
+ return if file_size <= threshold_in_bytes
22
+ add_offense(
23
+ "JavaScript on every page load exceeds compressed size threshold (#{threshold_in_bytes} Bytes), consider using the import on interaction pattern.",
24
+ node: node
25
+ )
52
26
  end
53
27
 
54
28
  def src_to_file_size(src)
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+ module ThemeCheck
3
+ class DeprecateBgsizes < HtmlCheck
4
+ severity :suggestion
5
+ category :html, :performance
6
+ doc docs_url(__FILE__)
7
+
8
+ def on_div(node)
9
+ class_list = node.attributes["class"]&.value&.split(" ")
10
+ add_offense("Use the native loading=\"lazy\" attribute instead of lazysizes", node: node) if class_list&.include?("lazyload")
11
+ add_offense("Use the CSS imageset attribute instead of data-bgset", node: node) if node.attributes["data-bgset"]
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+ module ThemeCheck
3
+ class DeprecateLazysizes < HtmlCheck
4
+ severity :suggestion
5
+ category :html, :performance
6
+ doc docs_url(__FILE__)
7
+
8
+ def on_img(node)
9
+ class_list = node.attributes["class"]&.value&.split(" ")
10
+ add_offense("Use the native loading=\"lazy\" attribute instead of lazysizes", node: node) if class_list&.include?("lazyload")
11
+ add_offense("Use the native srcset attribute instead of data-srcset", node: node) if node.attributes["data-srcset"]
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"
14
+ end
15
+ end
16
+ end
@@ -10,12 +10,7 @@ module ThemeCheck
10
10
  def on_img(node)
11
11
  loading = node.attributes["loading"]&.value&.downcase
12
12
  return if ACCEPTED_LOADING_VALUES.include?(loading)
13
-
14
- class_list = node.attributes["class"]&.value&.split(" ")
15
-
16
- if class_list&.include?("lazyload")
17
- add_offense("Use the native loading=\"lazy\" attribute instead of lazysizes", node: node)
18
- elsif loading == "auto"
13
+ if loading == "auto"
19
14
  add_offense("Prefer loading=\"lazy\" to defer loading of images", node: node)
20
15
  else
21
16
  add_offense("Add a loading=\"lazy\" attribute to defer loading of images", node: node)
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
  module ThemeCheck
3
- # Recommends using {% liquid ... %} if 4 or more consecutive {% ... %} are found.
3
+ # Recommends using {% liquid ... %} if 5 or more consecutive {% ... %} are found.
4
4
  class LiquidTag < LiquidCheck
5
5
  severity :suggestion
6
6
  category :liquid
7
7
  doc docs_url(__FILE__)
8
8
 
9
- def initialize(min_consecutive_statements: 4)
9
+ def initialize(min_consecutive_statements: 5)
10
10
  @first_statement = nil
11
11
  @consecutive_statements = 0
12
12
  @min_consecutive_statements = min_consecutive_statements
@@ -9,6 +9,7 @@ module ThemeCheck
9
9
  PROTOCOL = %r{(https?:)?//}
10
10
  ABSOLUTE_PATH = %r{\A/[^/]}im
11
11
  RELATIVE_PATH = %r{\A(?!#{PROTOCOL})[^/\{]}oim
12
+ CDN_ROOT = "https://cdn.shopify.com/"
12
13
 
13
14
  def on_element(node)
14
15
  return unless TAGS.include?(node.name)
@@ -17,6 +18,7 @@ module ThemeCheck
17
18
  return if resource_url.nil? || resource_url.empty?
18
19
 
19
20
  # Ignore if URL is Liquid, taken care of by AssetUrlFilters check
21
+ return if resource_url.start_with?(CDN_ROOT)
20
22
  return if resource_url =~ ABSOLUTE_PATH
21
23
  return if resource_url =~ RELATIVE_PATH
22
24
  return if url_hosted_by_shopify?(resource_url)
@@ -5,9 +5,11 @@ module ThemeCheck
5
5
  category :liquid
6
6
  doc docs_url(__FILE__)
7
7
 
8
- def initialize(max_length: 200, exclude_schema: true)
8
+ def initialize(max_length: 500, exclude_schema: true, exclude_stylesheet: true, exclude_javascript: true)
9
9
  @max_length = max_length
10
10
  @exclude_schema = exclude_schema
11
+ @exclude_stylesheet = exclude_stylesheet
12
+ @exclude_javascript = exclude_javascript
11
13
  end
12
14
 
13
15
  def on_document(_node)
@@ -15,9 +17,15 @@ module ThemeCheck
15
17
  end
16
18
 
17
19
  def on_schema(node)
18
- if @exclude_schema
19
- @excluded_lines += node.value.nodelist.join.count("\n")
20
- end
20
+ exclude_node_lines(node) if @exclude_schema
21
+ end
22
+
23
+ def on_stylesheet(node)
24
+ exclude_node_lines(node) if @exclude_stylesheet
25
+ end
26
+
27
+ def on_javascript(node)
28
+ exclude_node_lines(node) if @exclude_javascript
21
29
  end
22
30
 
23
31
  def after_document(node)
@@ -26,5 +34,11 @@ module ThemeCheck
26
34
  add_offense("Template has too many lines [#{lines}/#{@max_length}]", template: node.template)
27
35
  end
28
36
  end
37
+
38
+ private
39
+
40
+ def exclude_node_lines(node)
41
+ @excluded_lines += node.value.nodelist.join.count("\n")
42
+ end
29
43
  end
30
44
  end
@@ -3,5 +3,7 @@
3
3
  module ThemeCheck
4
4
  class HtmlCheck < Check
5
5
  extend ChecksTracking
6
+ VARIABLE = /#{Liquid::VariableStart}.*?#{Liquid::VariableEnd}/om
7
+ START_OR_END_QUOTE = /(^['"])|(['"]$)/
6
8
  end
7
9
  end
@@ -5,17 +5,5 @@ module ThemeCheck
5
5
  class LiquidCheck < Check
6
6
  extend ChecksTracking
7
7
  include ParsingHelpers
8
-
9
- # TODO: remove this once all regex checks are migrate to HtmlCheck# TODO: remove this once all regex checks are migrate to HtmlCheck
10
- TAG = /#{Liquid::TagStart}.*?#{Liquid::TagEnd}/om
11
- VARIABLE = /#{Liquid::VariableStart}.*?#{Liquid::VariableEnd}/om
12
- START_OR_END_QUOTE = /(^['"])|(['"]$)/
13
- QUOTED_LIQUID_ATTRIBUTE = %r{
14
- '(?:#{TAG}|#{VARIABLE}|[^'])*'| # any combination of tag/variable or non straight quote inside straight quotes
15
- "(?:#{TAG}|#{VARIABLE}|[^"])*" # any combination of tag/variable or non double quotes inside double quotes
16
- }omix
17
- ATTR = /[a-z0-9-]+/i
18
- HTML_ATTRIBUTE = /#{ATTR}(?:=#{QUOTED_LIQUID_ATTRIBUTE})?/omix
19
- HTML_ATTRIBUTES = /(?:#{HTML_ATTRIBUTE}|\s)*/omix
20
8
  end
21
9
  end
@@ -7,8 +7,10 @@ module ThemeCheck
7
7
 
8
8
  while scanner.scan(/.*?("|')/)
9
9
  yield scanner.matched[0..-2]
10
+ quote = scanner.matched[-1] == "'" ? "'" : "\""
10
11
  # Skip to the end of the string
11
- scanner.skip_until(scanner.matched[-1] == "'" ? /[^\\]'/ : /[^\\]"/)
12
+ # Check for empty string first, since follow regexp uses lookahead
13
+ scanner.skip(/#{quote}/) || scanner.skip_until(/[^\\]#{quote}/)
12
14
  end
13
15
 
14
16
  yield scanner.rest if scanner.rest?
@@ -2,6 +2,8 @@
2
2
 
3
3
  module ThemeCheck
4
4
  module RegexHelpers
5
+ VARIABLE = /#{Liquid::VariableStart}.*?#{Liquid::VariableEnd}/om
6
+ START_OR_END_QUOTE = /(^['"])|(['"]$)/
5
7
  def matches(s, re)
6
8
  start_at = 0
7
9
  matches = []
@@ -11,5 +13,20 @@ module ThemeCheck
11
13
  end
12
14
  matches
13
15
  end
16
+
17
+ def href_to_file_size(href)
18
+ # asset_url (+ optional stylesheet_tag) variables
19
+ if href =~ /^#{VARIABLE}$/o && href =~ /asset_url/ && href =~ Liquid::QuotedString
20
+ asset_id = Regexp.last_match(0).gsub(START_OR_END_QUOTE, "")
21
+ asset = @theme.assets.find { |a| a.name.end_with?("/" + asset_id) }
22
+ return if asset.nil?
23
+ asset.gzipped_size
24
+
25
+ # remote URLs
26
+ elsif href =~ %r{^(https?:)?//}
27
+ asset = RemoteAssetFile.from_src(href)
28
+ asset.gzipped_size
29
+ end
30
+ end
14
31
  end
15
32
  end
@@ -125,6 +125,42 @@ module ThemeCheck
125
125
  end
126
126
  end
127
127
 
128
+ class Render < Liquid::Tag
129
+ SYNTAX = /((?:#{Liquid::QuotedString}|#{Liquid::VariableSegment})+)(\s+(with|#{Liquid::Render::FOR})\s+(#{Liquid::QuotedFragment}+))?(\s+(?:as)\s+(#{Liquid::VariableSegment}+))?/o
130
+
131
+ disable_tags "include"
132
+
133
+ attr_reader :template_name_expr, :attributes
134
+
135
+ def initialize(tag_name, markup, options)
136
+ super
137
+
138
+ raise SyntaxError, options[:locale].t("errors.syntax.render") unless markup =~ SYNTAX
139
+
140
+ template_name = Regexp.last_match(1)
141
+ with_or_for = Regexp.last_match(3)
142
+ variable_name = Regexp.last_match(4)
143
+
144
+ @alias_name = Regexp.last_match(6)
145
+ @variable_name_expr = variable_name ? parse_expression(variable_name) : nil
146
+ @template_name_expr = parse_expression(template_name)
147
+ @for = (with_or_for == Liquid::Render::FOR)
148
+
149
+ @attributes = {}
150
+ markup.scan(Liquid::TagAttributes) do |key, value|
151
+ @attributes[key] = parse_expression(value)
152
+ end
153
+ end
154
+
155
+ class ParseTreeVisitor < Liquid::ParseTreeVisitor
156
+ def children
157
+ [
158
+ @node.template_name_expr,
159
+ ] + @node.attributes.values
160
+ end
161
+ end
162
+ end
163
+
128
164
  class Style < Liquid::Block; end
129
165
 
130
166
  class Schema < Liquid::Raw; end
@@ -135,6 +171,7 @@ module ThemeCheck
135
171
 
136
172
  Liquid::Template.register_tag('form', Form)
137
173
  Liquid::Template.register_tag('layout', Layout)
174
+ Liquid::Template.register_tag('render', Render)
138
175
  Liquid::Template.register_tag('paginate', Paginate)
139
176
  Liquid::Template.register_tag('section', Section)
140
177
  Liquid::Template.register_tag('style', Style)
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module ThemeCheck
3
- VERSION = "0.10.2"
3
+ VERSION = "1.0.0"
4
4
  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: 0.10.2
4
+ version: 1.0.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-06-18 00:00:00.000000000 Z
11
+ date: 2021-06-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: liquid
@@ -75,11 +75,14 @@ files:
75
75
  - docs/api/liquid_check.md
76
76
  - docs/checks/TEMPLATE.md.erb
77
77
  - docs/checks/asset_size_css.md
78
+ - docs/checks/asset_size_css_stylesheet_tag.md
78
79
  - docs/checks/asset_size_javascript.md
79
80
  - docs/checks/asset_url_filters.md
80
81
  - docs/checks/content_for_header_modification.md
81
82
  - docs/checks/convert_include_to_render.md
82
83
  - docs/checks/default_locale.md
84
+ - docs/checks/deprecate_bgsizes.md
85
+ - docs/checks/deprecate_lazysizes.md
83
86
  - docs/checks/deprecated_filter.md
84
87
  - docs/checks/html_parsing_error.md
85
88
  - docs/checks/img_lazy_loading.md
@@ -118,11 +121,14 @@ files:
118
121
  - lib/theme_check/checks.rb
119
122
  - lib/theme_check/checks/TEMPLATE.rb.erb
120
123
  - lib/theme_check/checks/asset_size_css.rb
124
+ - lib/theme_check/checks/asset_size_css_stylesheet_tag.rb
121
125
  - lib/theme_check/checks/asset_size_javascript.rb
122
126
  - lib/theme_check/checks/asset_url_filters.rb
123
127
  - lib/theme_check/checks/content_for_header_modification.rb
124
128
  - lib/theme_check/checks/convert_include_to_render.rb
125
129
  - lib/theme_check/checks/default_locale.rb
130
+ - lib/theme_check/checks/deprecate_bgsizes.rb
131
+ - lib/theme_check/checks/deprecate_lazysizes.rb
126
132
  - lib/theme_check/checks/deprecated_filter.rb
127
133
  - lib/theme_check/checks/html_parsing_error.rb
128
134
  - lib/theme_check/checks/img_lazy_loading.rb
@@ -227,7 +233,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
227
233
  - !ruby/object:Gem::Version
228
234
  version: '0'
229
235
  requirements: []
230
- rubygems_version: 3.2.17
236
+ rubygems_version: 3.2.20
231
237
  signing_key:
232
238
  specification_version: 4
233
239
  summary: A Shopify Theme Linter