theme-check 0.10.2 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/theme-check.yml +2 -6
- data/CHANGELOG.md +51 -0
- data/CONTRIBUTING.md +1 -1
- data/README.md +39 -0
- data/RELEASING.md +34 -2
- data/bin/theme-check +29 -0
- data/bin/theme-check-language-server +29 -0
- data/config/default.yml +46 -3
- data/config/nothing.yml +11 -0
- data/config/theme_app_extension.yml +168 -0
- data/data/shopify_liquid/objects.yml +2 -0
- data/docs/checks/app_block_valid_tags.md +40 -0
- data/docs/checks/asset_size_app_block_css.md +52 -0
- data/docs/checks/asset_size_app_block_javascript.md +57 -0
- data/docs/checks/asset_size_css_stylesheet_tag.md +50 -0
- data/docs/checks/deprecate_bgsizes.md +66 -0
- data/docs/checks/deprecate_lazysizes.md +61 -0
- data/docs/checks/liquid_tag.md +2 -2
- data/docs/checks/missing_template.md +25 -0
- data/docs/checks/pagination_size.md +44 -0
- data/docs/checks/template_length.md +12 -2
- data/docs/checks/undefined_object.md +5 -0
- data/lib/theme_check/analyzer.rb +25 -21
- data/lib/theme_check/asset_file.rb +3 -15
- data/lib/theme_check/bug.rb +3 -1
- data/lib/theme_check/check.rb +26 -4
- data/lib/theme_check/checks/app_block_valid_tags.rb +36 -0
- data/lib/theme_check/checks/asset_size_app_block_css.rb +44 -0
- data/lib/theme_check/checks/asset_size_app_block_javascript.rb +44 -0
- data/lib/theme_check/checks/asset_size_css.rb +11 -74
- data/lib/theme_check/checks/asset_size_css_stylesheet_tag.rb +24 -0
- data/lib/theme_check/checks/asset_size_javascript.rb +11 -37
- data/lib/theme_check/checks/convert_include_to_render.rb +3 -1
- data/lib/theme_check/checks/deprecate_bgsizes.rb +14 -0
- data/lib/theme_check/checks/deprecate_lazysizes.rb +16 -0
- data/lib/theme_check/checks/img_lazy_loading.rb +2 -7
- data/lib/theme_check/checks/img_width_and_height.rb +3 -3
- data/lib/theme_check/checks/liquid_tag.rb +2 -2
- data/lib/theme_check/checks/missing_template.rb +21 -5
- data/lib/theme_check/checks/pagination_size.rb +65 -0
- data/lib/theme_check/checks/parser_blocking_javascript.rb +1 -1
- data/lib/theme_check/checks/remote_asset.rb +4 -2
- data/lib/theme_check/checks/space_inside_braces.rb +27 -7
- data/lib/theme_check/checks/template_length.rb +18 -4
- data/lib/theme_check/checks/undefined_object.rb +1 -1
- data/lib/theme_check/checks/valid_html_translation.rb +1 -1
- data/lib/theme_check/checks.rb +11 -1
- data/lib/theme_check/cli.rb +52 -15
- data/lib/theme_check/config.rb +56 -10
- data/lib/theme_check/corrector.rb +4 -0
- data/lib/theme_check/exceptions.rb +29 -27
- data/lib/theme_check/file_system_storage.rb +12 -0
- data/lib/theme_check/html_check.rb +1 -0
- data/lib/theme_check/html_node.rb +37 -16
- data/lib/theme_check/html_visitor.rb +17 -3
- data/lib/theme_check/json_check.rb +2 -2
- data/lib/theme_check/json_file.rb +2 -29
- data/lib/theme_check/json_printer.rb +26 -0
- data/lib/theme_check/language_server/constants.rb +8 -0
- data/lib/theme_check/language_server/document_link_engine.rb +40 -4
- data/lib/theme_check/language_server/handler.rb +6 -2
- data/lib/theme_check/language_server/server.rb +13 -2
- data/lib/theme_check/liquid_check.rb +0 -12
- data/lib/theme_check/node.rb +6 -4
- data/lib/theme_check/offense.rb +56 -3
- data/lib/theme_check/parsing_helpers.rb +7 -4
- data/lib/theme_check/position.rb +98 -14
- data/lib/theme_check/regex_helpers.rb +20 -0
- data/lib/theme_check/tags.rb +62 -8
- data/lib/theme_check/template.rb +3 -32
- data/lib/theme_check/theme.rb +2 -0
- data/lib/theme_check/theme_file.rb +40 -0
- data/lib/theme_check/version.rb +1 -1
- data/lib/theme_check.rb +16 -0
- data/theme-check.gemspec +1 -1
- metadata +26 -7
- data/bin/liquid-server +0 -4
@@ -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,58 +3,32 @@ 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 <
|
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
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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'])
|
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)
|
55
29
|
# We're kind of intentionally only looking at {{ 'asset' | asset_url }} or full urls in here.
|
56
30
|
# More complicated liquid statements are not in scope.
|
57
|
-
if src =~ /^#{
|
31
|
+
if src =~ /^#{LIQUID_VARIABLE}$/o && src =~ /asset_url/ && src =~ Liquid::QuotedString
|
58
32
|
asset_id = Regexp.last_match(0).gsub(START_OR_END_QUOTE, "")
|
59
33
|
asset = @theme.assets.find { |a| a.name.end_with?("/" + asset_id) }
|
60
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
|
@@ -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"]&.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"]&.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"] == "auto"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -8,14 +8,9 @@ module ThemeCheck
|
|
8
8
|
ACCEPTED_LOADING_VALUES = %w[lazy eager]
|
9
9
|
|
10
10
|
def on_img(node)
|
11
|
-
loading = node.attributes["loading"]&.
|
11
|
+
loading = node.attributes["loading"]&.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)
|
@@ -9,8 +9,8 @@ module ThemeCheck
|
|
9
9
|
ENDS_IN_CSS_UNIT = /(cm|mm|in|px|pt|pc|em|ex|ch|rem|vw|vh|vmin|vmax|%)$/i
|
10
10
|
|
11
11
|
def on_img(node)
|
12
|
-
width = node.attributes["width"]
|
13
|
-
height = node.attributes["height"]
|
12
|
+
width = node.attributes["width"]
|
13
|
+
height = node.attributes["height"]
|
14
14
|
|
15
15
|
record_units_in_field_offenses("width", width, node: node)
|
16
16
|
record_units_in_field_offenses("height", height, node: node)
|
@@ -35,7 +35,7 @@ module ThemeCheck
|
|
35
35
|
return unless value =~ ENDS_IN_CSS_UNIT
|
36
36
|
value_without_units = value.gsub(ENDS_IN_CSS_UNIT, '')
|
37
37
|
add_offense(
|
38
|
-
"The #{attribute} attribute does not take units. Replace with \"#{value_without_units}\"
|
38
|
+
"The #{attribute} attribute does not take units. Replace with \"#{value_without_units}\"",
|
39
39
|
node: node,
|
40
40
|
)
|
41
41
|
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module ThemeCheck
|
3
|
-
# Recommends using {% liquid ... %} if
|
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:
|
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
|
@@ -7,20 +7,36 @@ module ThemeCheck
|
|
7
7
|
doc docs_url(__FILE__)
|
8
8
|
single_file false
|
9
9
|
|
10
|
+
def initialize(ignore_missing: [])
|
11
|
+
@ignore_missing = ignore_missing
|
12
|
+
end
|
13
|
+
|
10
14
|
def on_include(node)
|
11
15
|
template = node.value.template_name_expr
|
12
16
|
if template.is_a?(String)
|
13
|
-
|
14
|
-
add_offense("'snippets/#{template}.liquid' is not found", node: node)
|
15
|
-
end
|
17
|
+
add_missing_offense("snippets/#{template}", node: node)
|
16
18
|
end
|
17
19
|
end
|
20
|
+
|
18
21
|
alias_method :on_render, :on_include
|
19
22
|
|
20
23
|
def on_section(node)
|
21
24
|
template = node.value.section_name
|
22
|
-
|
23
|
-
|
25
|
+
add_missing_offense("sections/#{template}", node: node)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def ignore?(path)
|
31
|
+
@ignore_missing.any? { |pattern| File.fnmatch?(pattern, path) }
|
32
|
+
end
|
33
|
+
|
34
|
+
def add_missing_offense(name, node:)
|
35
|
+
path = "#{name}.liquid"
|
36
|
+
unless ignore?(path) || theme[name]
|
37
|
+
add_offense("'#{path}' is not found", node: node) do |corrector|
|
38
|
+
corrector.create(@theme, "#{name}.liquid", "")
|
39
|
+
end
|
24
40
|
end
|
25
41
|
end
|
26
42
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module ThemeCheck
|
3
|
+
class PaginationSize < LiquidCheck
|
4
|
+
severity :suggestion
|
5
|
+
categories :performance
|
6
|
+
doc docs_url(__FILE__)
|
7
|
+
|
8
|
+
attr_reader :min_size
|
9
|
+
attr_reader :max_size
|
10
|
+
|
11
|
+
def initialize(min_size: 1, max_size: 50)
|
12
|
+
@min_size = min_size
|
13
|
+
@max_size = max_size
|
14
|
+
end
|
15
|
+
|
16
|
+
def on_document(_node)
|
17
|
+
@paginations = {}
|
18
|
+
@schema_settings = {}
|
19
|
+
end
|
20
|
+
|
21
|
+
def on_paginate(node)
|
22
|
+
size = node.value.page_size
|
23
|
+
unless @paginations.key?(size)
|
24
|
+
@paginations[size] = []
|
25
|
+
end
|
26
|
+
@paginations[size].push(node)
|
27
|
+
end
|
28
|
+
|
29
|
+
def on_schema(node)
|
30
|
+
schema = JSON.parse(node.value.nodelist.join)
|
31
|
+
|
32
|
+
if (settings = schema["settings"])
|
33
|
+
@schema_settings = settings
|
34
|
+
end
|
35
|
+
rescue JSON::ParserError
|
36
|
+
# Ignored, handled in ValidSchema.
|
37
|
+
end
|
38
|
+
|
39
|
+
def after_document(_node)
|
40
|
+
@paginations.each_pair do |size, nodes|
|
41
|
+
numerical_size = if size.is_a?(Numeric)
|
42
|
+
size
|
43
|
+
else
|
44
|
+
get_setting_default_value(size.lookups.last)
|
45
|
+
end
|
46
|
+
if numerical_size.nil?
|
47
|
+
nodes.each { |node| add_offense("Default pagination size should be defined in the section settings", node: node) }
|
48
|
+
elsif numerical_size > @max_size || numerical_size < @min_size || !numerical_size.is_a?(Integer)
|
49
|
+
nodes.each { |node| add_offense("Pagination size must be a positive integer between #{@min_size} and #{@max_size}", node: node) }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def get_setting_default_value(setting_id)
|
57
|
+
setting = @schema_settings.select { |s| s['id'] == setting_id }
|
58
|
+
unless setting.empty?
|
59
|
+
return setting.last['default']
|
60
|
+
end
|
61
|
+
# Setting does not exist
|
62
|
+
nil
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -8,7 +8,7 @@ module ThemeCheck
|
|
8
8
|
|
9
9
|
def on_script(node)
|
10
10
|
return unless node.attributes["src"]
|
11
|
-
return if node.attributes["defer"] || node.attributes["async"] || node.attributes["type"]
|
11
|
+
return if node.attributes["defer"] || node.attributes["async"] || node.attributes["type"] == "module"
|
12
12
|
|
13
13
|
add_offense("Missing async or defer attribute on script tag", node: node)
|
14
14
|
end
|
@@ -9,21 +9,23 @@ 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)
|
15
16
|
|
16
|
-
resource_url = node.attributes["src"]
|
17
|
+
resource_url = node.attributes["src"] || node.attributes["href"]
|
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)
|
23
25
|
|
24
26
|
# Ignore non-stylesheet rel tags
|
25
27
|
rel = node.attributes["rel"]
|
26
|
-
return if rel && rel
|
28
|
+
return if rel && rel != "stylesheet"
|
27
29
|
|
28
30
|
add_offense(
|
29
31
|
"Asset should be served by the Shopify CDN for better performance.",
|
@@ -14,18 +14,38 @@ module ThemeCheck
|
|
14
14
|
return unless node.markup
|
15
15
|
return if :assign == node.type_name
|
16
16
|
|
17
|
-
outside_of_strings(node.markup) do |chunk|
|
17
|
+
outside_of_strings(node.markup) do |chunk, chunk_start|
|
18
18
|
chunk.scan(/([,:|]|==|<>|<=|>=|<|>|!=) +/) do |_match|
|
19
|
-
add_offense(
|
19
|
+
add_offense(
|
20
|
+
"Too many spaces after '#{Regexp.last_match(1)}'",
|
21
|
+
node: node,
|
22
|
+
markup: Regexp.last_match(0),
|
23
|
+
node_markup_offset: chunk_start + Regexp.last_match.begin(0)
|
24
|
+
)
|
20
25
|
end
|
21
26
|
chunk.scan(/([,:|]|==|<>|<=|>=|<\b|>\b|!=)(\S|\z)/) do |_match|
|
22
|
-
add_offense(
|
27
|
+
add_offense(
|
28
|
+
"Space missing after '#{Regexp.last_match(1)}'",
|
29
|
+
node: node,
|
30
|
+
markup: Regexp.last_match(0),
|
31
|
+
node_markup_offset: chunk_start + Regexp.last_match.begin(0),
|
32
|
+
)
|
23
33
|
end
|
24
34
|
chunk.scan(/ (\||==|<>|<=|>=|<|>|!=)+/) do |_match|
|
25
|
-
add_offense(
|
35
|
+
add_offense(
|
36
|
+
"Too many spaces before '#{Regexp.last_match(1)}'",
|
37
|
+
node: node,
|
38
|
+
markup: Regexp.last_match(0),
|
39
|
+
node_markup_offset: chunk_start + Regexp.last_match.begin(0)
|
40
|
+
)
|
26
41
|
end
|
27
42
|
chunk.scan(/(\A|\S)(?<match>\||==|<>|<=|>=|<|\b>|!=)/) do |_match|
|
28
|
-
add_offense(
|
43
|
+
add_offense(
|
44
|
+
"Space missing before '#{Regexp.last_match(1)}'",
|
45
|
+
node: node,
|
46
|
+
markup: Regexp.last_match(0),
|
47
|
+
node_markup_offset: chunk_start + Regexp.last_match.begin(0)
|
48
|
+
)
|
29
49
|
end
|
30
50
|
end
|
31
51
|
end
|
@@ -51,13 +71,13 @@ module ThemeCheck
|
|
51
71
|
end
|
52
72
|
|
53
73
|
def on_variable(node)
|
54
|
-
return if @ignore
|
74
|
+
return if @ignore || node.markup.empty?
|
55
75
|
if node.markup[0] != " "
|
56
76
|
add_offense("Space missing after '{{'", node: node) do |corrector|
|
57
77
|
corrector.insert_before(node, " ")
|
58
78
|
end
|
59
79
|
end
|
60
|
-
if node.markup[-1] != " "
|
80
|
+
if node.markup[-1] != " " && node.markup[-1] != "\n"
|
61
81
|
add_offense("Space missing before '}}'", node: node) do |corrector|
|
62
82
|
corrector.insert_after(node, " ")
|
63
83
|
end
|
@@ -5,9 +5,11 @@ module ThemeCheck
|
|
5
5
|
category :liquid
|
6
6
|
doc docs_url(__FILE__)
|
7
7
|
|
8
|
-
def initialize(max_length:
|
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
|
-
|
20
|
-
|
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
|