theme-check 0.9.0 → 0.9.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e5970832846bda5a0e7cb27c99ebef32382050c911350d1d208211849bef7d55
4
- data.tar.gz: 89d3bb2d5a261c817dddfbf50ad9ac31a589f88fe4f2a2df23b8c5aaad51c4db
3
+ metadata.gz: a114e025e51ad2a09395b4ae0dca33e9417942a76ed781fdd639e7d7d1b35928
4
+ data.tar.gz: ff3c7f9b43f5ccae262cd22c8547d308a71e214cdd7f924208c25122624a48dc
5
5
  SHA512:
6
- metadata.gz: 2ee4f610dc461c6e70e870723f801ddb0f1e5381eebfc6622030af68486c2c6650c11e530be38456cf0df8666ecc5e78b26d16cf60428142e04f0ebde45edf9f
7
- data.tar.gz: 36053d9337a817da4334a5341be1877f04d86b3f4d88606a2acccb2028c0a3a07227086183de5aa06bd44e9beeebd0a4650d08b746fdfbced854e945469d61a3
6
+ metadata.gz: 3e4ead0f1d63cc68dfbaff6dd5462f08b9008c04dd87fae9499875cf967e501c68327adec0ac3c1f253bbdbf1343d14ddeb63fe58b4c9f4cb24f494315898d70
7
+ data.tar.gz: 62baa63bcf203d2bd0a7894787011f23d363cb6192920ac67c2ce0dfbe89f382c461a3d5a989c23234e5e1a9db7bfd9d10c4801bca121c1993a082b58887705d
data/CHANGELOG.md CHANGED
@@ -1,4 +1,10 @@
1
1
 
2
+ v0.9.1 / 2021-06-04
3
+ ==================
4
+
5
+ * Convert `RemoteAsset` into an `HtmlCheck`
6
+ * Move Liquid logic from `RemoteAsset` to a new `AssetUrlFilters` check
7
+
2
8
  v0.9.0 / 2021-05-28
3
9
  ==================
4
10
 
data/config/default.yml CHANGED
@@ -130,6 +130,10 @@ RemoteAsset:
130
130
  enabled: true
131
131
  ignore: []
132
132
 
133
+ AssetUrlFilters:
134
+ enabled: true
135
+ ignore: []
136
+
133
137
  ContentForHeaderModification:
134
138
  enabled: true
135
139
  ignore: []
@@ -0,0 +1,56 @@
1
+ # Ensure `asset_url` filters are used when serving assets (`AssetUrlFilters`)
2
+
3
+ See the [`RemoteAsset` check documentation][remote_asset] for a detailed explanation on why remote assets are discouraged.
4
+
5
+ ## Check Details
6
+
7
+ This check is aimed at eliminating unnecessary HTTP connections.
8
+
9
+ :-1: Examples of **incorrect** code for this check:
10
+
11
+ ```liquid
12
+ <!-- Using multiple CDNs -->
13
+ {{ "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" | stylesheet_tag }}
14
+
15
+ <!-- Missing img_url filter -->
16
+ {{ url | img_tag }}
17
+ ```
18
+
19
+ :+1: Examples of **correct** code for this check:
20
+
21
+ ```liquid
22
+ {{ 'bootstrap.min.css' | asset_url | stylesheet_tag }}
23
+
24
+ <!-- Images -->
25
+ {{ url | img_url | img_tag }}
26
+ ```
27
+
28
+ Use the [`assets_url`](asset_url) or [`img_url`](img_url) filter to load the files in your theme's `assets/` folder from the Shopify CDN.
29
+
30
+ ## Check Options
31
+
32
+ The default configuration for this check is the following:
33
+
34
+ ```yaml
35
+ AssetUrlFilters:
36
+ enabled: true
37
+ ```
38
+
39
+ ## When Not To Use It
40
+
41
+ When the remote content is highly dynamic.
42
+
43
+ ## Version
44
+
45
+ This check has been introduced in Theme Check 0.9.1.
46
+
47
+ ## Resources
48
+
49
+ - [Rule Source][codesource]
50
+ - [Documentation Source][docsource]
51
+
52
+ [codesource]: /lib/theme_check/checks/remote_asset_filters.rb
53
+ [docsource]: /docs/checks/remote_asset_filters.md
54
+ [remote_asset]: /docs/checks/remote_asset.md
55
+ [asset_url]: https://shopify.dev/docs/themes/liquid/reference/filters/url-filters#assert_url
56
+ [img_url]: https://shopify.dev/docs/themes/liquid/reference/filters/url-filters#img_url
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+ module ThemeCheck
3
+ class AssetUrlFilters < LiquidCheck
4
+ severity :suggestion
5
+ categories :liquid, :performance
6
+ doc docs_url(__FILE__)
7
+
8
+ HTML_FILTERS = [
9
+ 'stylesheet_tag',
10
+ 'script_tag',
11
+ 'img_tag',
12
+ ]
13
+ ASSET_URL_FILTERS = [
14
+ 'asset_url',
15
+ 'asset_img_url',
16
+ 'file_img_url',
17
+ 'file_url',
18
+ 'global_asset_url',
19
+ 'img_url',
20
+ 'payment_type_img_url',
21
+ 'shopify_asset_url',
22
+ ]
23
+
24
+ def on_variable(node)
25
+ record_variable_offense(node)
26
+ end
27
+
28
+ private
29
+
30
+ def record_variable_offense(variable_node)
31
+ # We flag HTML tags with URLs not hosted by Shopify
32
+ return if !html_resource_drop?(variable_node) || variable_hosted_by_shopify?(variable_node)
33
+ add_offense("Use one of the asset_url filters to serve assets", node: variable_node)
34
+ end
35
+
36
+ def html_resource_drop?(variable_node)
37
+ variable_node.value.filters
38
+ .any? { |(filter_name, *_filter_args)| HTML_FILTERS.include?(filter_name) }
39
+ end
40
+
41
+ def variable_hosted_by_shopify?(variable_node)
42
+ variable_node.value.filters
43
+ .any? { |(filter_name, *_filter_args)| ASSET_URL_FILTERS.include?(filter_name) }
44
+ end
45
+ end
46
+ end
@@ -1,99 +1,41 @@
1
1
  # frozen_string_literal: true
2
2
  module ThemeCheck
3
- class RemoteAsset < LiquidCheck
4
- include RegexHelpers
3
+ class RemoteAsset < HtmlCheck
5
4
  severity :suggestion
6
- categories :liquid, :performance
5
+ categories :html, :performance
7
6
  doc docs_url(__FILE__)
8
7
 
9
- OFFENSE_MESSAGE = "Asset should be served by the Shopify CDN for better performance."
10
-
11
- HTML_FILTERS = [
12
- 'stylesheet_tag',
13
- 'script_tag',
14
- 'img_tag',
15
- ]
16
- ASSET_URL_FILTERS = [
17
- 'asset_url',
18
- 'asset_img_url',
19
- 'file_img_url',
20
- 'file_url',
21
- 'global_asset_url',
22
- 'img_url',
23
- 'payment_type_img_url',
24
- 'shopify_asset_url',
25
- ]
26
-
27
- RESOURCE_TAG = %r{<(?<tag_name>img|script|link|source)#{HTML_ATTRIBUTES}/?>}oim
28
- RESOURCE_URL = /\s(?:src|href)=(?<resource_url>#{QUOTED_LIQUID_ATTRIBUTE})/oim
29
- ASSET_URL_FILTER = /[\|\s]*(#{ASSET_URL_FILTERS.join('|')})/omi
8
+ TAGS = %w[img script link source]
30
9
  PROTOCOL = %r{(https?:)?//}
31
10
  ABSOLUTE_PATH = %r{\A/[^/]}im
32
11
  RELATIVE_PATH = %r{\A(?!#{PROTOCOL})[^/\{]}oim
33
- REL = /\srel=(?<rel>#{QUOTED_LIQUID_ATTRIBUTE})/oim
34
-
35
- def on_variable(node)
36
- record_variable_offense(node)
37
- end
38
12
 
39
- def on_document(node)
40
- source = node.template.source
41
- record_html_offenses(node, source)
42
- end
13
+ def on_element(node)
14
+ return unless TAGS.include?(node.name)
43
15
 
44
- private
16
+ resource_url = node.attributes["src"]&.value || node.attributes["href"]&.value
17
+ return if resource_url.nil? || resource_url.empty?
45
18
 
46
- def record_variable_offense(variable_node)
47
- # We flag HTML tags with URLs not hosted by Shopify
48
- return if !html_resource_drop?(variable_node) || variable_hosted_by_shopify?(variable_node)
49
- add_offense(OFFENSE_MESSAGE, node: variable_node)
50
- end
19
+ # Ignore if URL is Liquid, taken care of by AssetUrlFilters check
20
+ return if resource_url =~ ABSOLUTE_PATH
21
+ return if resource_url =~ RELATIVE_PATH
22
+ return if url_hosted_by_shopify?(resource_url)
51
23
 
52
- def html_resource_drop?(variable_node)
53
- variable_node.value.filters
54
- .any? { |(filter_name, *_filter_args)| HTML_FILTERS.include?(filter_name) }
55
- end
24
+ # Ignore non-stylesheet rel tags
25
+ rel = node.attributes["rel"]
26
+ return if rel && rel.value != "stylesheet"
56
27
 
57
- def variable_hosted_by_shopify?(variable_node)
58
- variable_node.value.filters
59
- .any? { |(filter_name, *_filter_args)| ASSET_URL_FILTERS.include?(filter_name) }
28
+ add_offense(
29
+ "Asset should be served by the Shopify CDN for better performance.",
30
+ node: node,
31
+ )
60
32
  end
61
33
 
62
- # This part is slightly more complicated because we don't have an
63
- # HTML AST. We have to resort to looking at the HTML with regexes
64
- # to figure out if we have a resource (stylesheet, script, or media)
65
- # that points to a remote domain.
66
- def record_html_offenses(node, source)
67
- matches(source, RESOURCE_TAG).each do |match|
68
- tag = match[0]
69
-
70
- # We don't flag stuff without URLs
71
- next unless tag =~ RESOURCE_URL
72
- resource_match = Regexp.last_match
73
- resource_url = resource_match[:resource_url].gsub(START_OR_END_QUOTE, '')
74
-
75
- next if non_stylesheet_link?(tag)
76
- next if url_hosted_by_shopify?(resource_url)
77
- next if resource_url =~ ABSOLUTE_PATH
78
- next if resource_url =~ RELATIVE_PATH
79
- next if resource_url.empty?
80
-
81
- start = match.begin(0) + resource_match.begin(:resource_url)
82
- add_offense(
83
- OFFENSE_MESSAGE,
84
- node: node,
85
- markup: resource_url,
86
- line_number: source[0...start].count("\n") + 1,
87
- )
88
- end
89
- end
90
-
91
- def non_stylesheet_link?(tag)
92
- tag =~ REL && !(Regexp.last_match[:rel] =~ /\A['"]stylesheet['"]\Z/)
93
- end
34
+ private
94
35
 
95
36
  def url_hosted_by_shopify?(url)
96
- url =~ /\A#{VARIABLE}\Z/oim && url =~ ASSET_URL_FILTER
37
+ url.start_with?(Liquid::VariableStart) &&
38
+ AssetUrlFilters::ASSET_URL_FILTERS.any? { |filter| url.include?(filter) }
97
39
  end
98
40
  end
99
41
  end
@@ -17,6 +17,10 @@ module ThemeCheck
17
17
  @value.name == "text"
18
18
  end
19
19
 
20
+ def element?
21
+ @value.element?
22
+ end
23
+
20
24
  def children
21
25
  @value.children.map { |child| HtmlNode.new(child, template) }
22
26
  end
@@ -22,10 +22,12 @@ module ThemeCheck
22
22
  end
23
23
 
24
24
  def visit(node)
25
+ call_checks(:on_element, node) if node.element?
25
26
  call_checks(:"on_#{node.name}", node)
26
27
  node.children.each { |child| visit(child) }
27
28
  unless node.literal?
28
29
  call_checks(:"after_#{node.name}", node)
30
+ call_checks(:after_element, node) if node.element?
29
31
  end
30
32
  end
31
33
 
@@ -6,6 +6,7 @@ module ThemeCheck
6
6
  extend ChecksTracking
7
7
  include ParsingHelpers
8
8
 
9
+ # TODO: remove this once all regex checks are migrate to HtmlCheck# TODO: remove this once all regex checks are migrate to HtmlCheck
9
10
  TAG = /#{Liquid::TagStart}.*?#{Liquid::TagEnd}/om
10
11
  VARIABLE = /#{Liquid::VariableStart}.*?#{Liquid::VariableEnd}/om
11
12
  START_OR_END_QUOTE = /(^['"])|(['"]$)/
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module ThemeCheck
3
- VERSION = "0.9.0"
3
+ VERSION = "0.9.1"
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.9.0
4
+ version: 0.9.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-05-28 00:00:00.000000000 Z
11
+ date: 2021-06-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: liquid
@@ -72,6 +72,7 @@ files:
72
72
  - docs/checks/CHECK_DOCS_TEMPLATE.md
73
73
  - docs/checks/asset_size_css.md
74
74
  - docs/checks/asset_size_javascript.md
75
+ - docs/checks/asset_url_filters.md
75
76
  - docs/checks/content_for_header_modification.md
76
77
  - docs/checks/convert_include_to_render.md
77
78
  - docs/checks/default_locale.md
@@ -111,6 +112,7 @@ files:
111
112
  - lib/theme_check/checks.rb
112
113
  - lib/theme_check/checks/asset_size_css.rb
113
114
  - lib/theme_check/checks/asset_size_javascript.rb
115
+ - lib/theme_check/checks/asset_url_filters.rb
114
116
  - lib/theme_check/checks/content_for_header_modification.rb
115
117
  - lib/theme_check/checks/convert_include_to_render.rb
116
118
  - lib/theme_check/checks/default_locale.rb