theme-check 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +6 -3
- data/CHANGELOG.md +11 -0
- data/Gemfile +5 -3
- data/README.md +2 -0
- data/config/default.yml +8 -1
- data/data/shopify_translation_keys.yml +850 -0
- data/docs/checks/asset_size_css.md +52 -0
- data/docs/checks/img_width_and_height.md +79 -0
- data/docs/checks/parser_blocking_javascript.md +3 -3
- data/lib/theme_check/checks/asset_size_css.rb +89 -0
- data/lib/theme_check/checks/asset_size_javascript.rb +1 -7
- data/lib/theme_check/checks/img_width_and_height.rb +74 -0
- data/lib/theme_check/checks/parser_blocking_javascript.rb +5 -13
- data/lib/theme_check/checks/translation_key_exists.rb +16 -1
- data/lib/theme_check/cli.rb +19 -8
- data/lib/theme_check/config.rb +3 -0
- data/lib/theme_check/in_memory_storage.rb +11 -3
- data/lib/theme_check/language_server.rb +2 -0
- data/lib/theme_check/language_server/completion_engine.rb +1 -1
- data/lib/theme_check/language_server/completion_provider.rb +4 -0
- data/lib/theme_check/language_server/completion_providers/filter_completion_provider.rb +5 -1
- data/lib/theme_check/language_server/completion_providers/render_snippet_completion_provider.rb +43 -0
- data/lib/theme_check/language_server/constants.rb +10 -0
- data/lib/theme_check/language_server/document_link_engine.rb +47 -0
- data/lib/theme_check/language_server/handler.rb +33 -2
- data/lib/theme_check/language_server/server.rb +3 -2
- data/lib/theme_check/liquid_check.rb +11 -0
- data/lib/theme_check/remote_asset_file.rb +1 -1
- data/lib/theme_check/shopify_liquid/deprecated_filter.rb +4 -0
- data/lib/theme_check/version.rb +1 -1
- metadata +10 -2
@@ -0,0 +1,52 @@
|
|
1
|
+
# Prevent Large CSS bundles (`AssetSizeCSS`)
|
2
|
+
|
3
|
+
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 is the following.
|
24
|
+
|
25
|
+
```yaml
|
26
|
+
AssetSizeCSS:
|
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
|
+
This includes theme and remote stylesheets.
|
36
|
+
|
37
|
+
## When Not To Use It
|
38
|
+
|
39
|
+
This rule is safe to disable.
|
40
|
+
|
41
|
+
## Version
|
42
|
+
|
43
|
+
This check has been introduced in Theme Check 0.6.0.
|
44
|
+
|
45
|
+
## Resources
|
46
|
+
|
47
|
+
- [The Performance Inequality Gap](https://infrequently.org/2021/03/the-performance-inequality-gap/)
|
48
|
+
- [Rule Source][codesource]
|
49
|
+
- [Documentation Source][docsource]
|
50
|
+
|
51
|
+
[codesource]: /lib/theme_check/checks/asset_size_css.rb
|
52
|
+
[docsource]: /docs/checks/asset_size_css.md
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# Width and height attributes on image tags (`ImgWidthAndHeight`)
|
2
|
+
|
3
|
+
This check exists to prevent [cumulative layout shift][cls] (CLS) in themes.
|
4
|
+
|
5
|
+
The absence of `width` and `height` attributes on an `img` tag prevents the browser from knowing the aspect ratio of the image before it is downloaded. Unless another technique is used to allocate space, the browser will consider the image to be of height 0 until it is loaded.
|
6
|
+
|
7
|
+
This has numerous nefarious implications:
|
8
|
+
|
9
|
+
1. [This causes layout shift as images start appearing one after the other.][codepenshift] Text starts flying down the page as the image pushes it down.
|
10
|
+
2. [This breaks lazy loading.][codepenlazy] When all images have a height of 0px, every image is inside the viewport. And when everything is in the viewport, everything gets loaded. There's nothing lazy about it!
|
11
|
+
|
12
|
+
The fix is easy. Make sure the `width` and `height` attribute are set on the `img` tag and that the CSS width of the image is set.
|
13
|
+
|
14
|
+
Note: The width and height attributes of an image do not have units.
|
15
|
+
|
16
|
+
## Check Details
|
17
|
+
|
18
|
+
This check is aimed at eliminating content layout shift in themes by enforcing the use of the `width` and `height` attributes on `img` tags.
|
19
|
+
|
20
|
+
:-1: Examples of **incorrect** code for this check:
|
21
|
+
|
22
|
+
```liquid
|
23
|
+
<img alt="cat" src="cat.jpg">
|
24
|
+
<img alt="cat" src="cat.jpg" width="100px" height="100px">
|
25
|
+
<img alt="{{ image.alt }}" src="{{ image.src }}">
|
26
|
+
```
|
27
|
+
|
28
|
+
:+1: Examples of **correct** code for this check:
|
29
|
+
|
30
|
+
```liquid
|
31
|
+
<img alt="cat" src="cat.jpg" width="100" height="200">
|
32
|
+
<img
|
33
|
+
alt="{{ image.alt }}"
|
34
|
+
src="{{ image.src }}"
|
35
|
+
width="{{ image.width }}"
|
36
|
+
height="{{ image.height }}"
|
37
|
+
>
|
38
|
+
```
|
39
|
+
|
40
|
+
**NOTE:** The CSS `width` of the `img` should _also_ be set for the image to be responsive.
|
41
|
+
|
42
|
+
## Check Options
|
43
|
+
|
44
|
+
The default configuration for this check is the following:
|
45
|
+
|
46
|
+
```yaml
|
47
|
+
ImgWidthAndHeight:
|
48
|
+
enabled: true
|
49
|
+
```
|
50
|
+
|
51
|
+
## When Not To Use It
|
52
|
+
|
53
|
+
There are some cases where you can avoid content-layout shift without needing the width and height attributes:
|
54
|
+
|
55
|
+
- When the aspect-ratio of the displayed image should be independent of the uploaded image. In those cases, the solution is still the padding-top hack with an `overflow: hidden container`.
|
56
|
+
- When you are happy with the padding-top hack.
|
57
|
+
|
58
|
+
In those cases, it is fine to disable this check with the comment.
|
59
|
+
|
60
|
+
It is otherwise unwise to disable this check, since it would negatively impact the mobile search ranking of the merchants using your theme.
|
61
|
+
|
62
|
+
## Version
|
63
|
+
|
64
|
+
This check has been introduced in Theme Check 0.6.0.
|
65
|
+
|
66
|
+
## Resources
|
67
|
+
|
68
|
+
- [Cumulative Layout Shift Reference][cls]
|
69
|
+
- [Codepen illustrating the impact of width and height on layout shift][codepenshift]
|
70
|
+
- [Codepen illustrating the impact of width and height on lazy loading][codepenlazy]
|
71
|
+
- [Rule Source][codesource]
|
72
|
+
- [Documentation Source][docsource]
|
73
|
+
|
74
|
+
[cls]: https://web.dev/cls/
|
75
|
+
[codepenshift]: https://codepen.io/charlespwd/pen/YzpxPEp?editors=1100
|
76
|
+
[codepenlazy]: https://codepen.io/charlespwd/pen/abZmqXJ?editors=0111
|
77
|
+
[aspect-ratio]: https://caniuse.com/mdn-css_properties_aspect-ratio
|
78
|
+
[codesource]: /lib/theme_check/checks/img_aspect_ratio.rb
|
79
|
+
[docsource]: /docs/checks/img_aspect_ratio.md
|
@@ -31,13 +31,13 @@ This check is aimed at eliminating parser-blocking JavaScript on themes.
|
|
31
31
|
|
32
32
|
```liquid
|
33
33
|
<!-- Good. Using the asset_url filter + defer -->
|
34
|
-
<script src="{{ 'theme.js' | asset_url }}" defer
|
34
|
+
<script src="{{ 'theme.js' | asset_url }}" defer></script>
|
35
35
|
|
36
36
|
<!-- Also good. Using the asset_url filter + async -->
|
37
|
-
<script src="{{ 'theme.js' | asset_url }}" async
|
37
|
+
<script src="{{ 'theme.js' | asset_url }}" async></script>
|
38
38
|
|
39
39
|
<!-- Better than synchronous jQuery -->
|
40
|
-
<script src="https://code.jquery.com/jquery-3.6.0.min.js" defer
|
40
|
+
<script src="https://code.jquery.com/jquery-3.6.0.min.js" defer></script>
|
41
41
|
...
|
42
42
|
<button id="thing">Click me!</button>
|
43
43
|
<script>
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module ThemeCheck
|
3
|
+
class AssetSizeCSS < LiquidCheck
|
4
|
+
include RegexHelpers
|
5
|
+
severity :error
|
6
|
+
category :performance
|
7
|
+
doc docs_url(__FILE__)
|
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
|
+
attr_reader :threshold_in_bytes
|
29
|
+
|
30
|
+
def initialize(threshold_in_bytes: 100_000)
|
31
|
+
@threshold_in_bytes = threshold_in_bytes
|
32
|
+
end
|
33
|
+
|
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.ends_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
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -11,17 +11,11 @@ module ThemeCheck
|
|
11
11
|
|
12
12
|
Script = Struct.new(:src, :match)
|
13
13
|
|
14
|
-
TAG = /#{Liquid::TagStart}.*?#{Liquid::TagEnd}/om
|
15
|
-
VARIABLE = /#{Liquid::VariableStart}.*?#{Liquid::VariableEnd}/om
|
16
|
-
START_OR_END_QUOTE = /(^['"])|(['"]$)/
|
17
14
|
SCRIPT_TAG_SRC = %r{
|
18
15
|
<script
|
19
16
|
[^>]+ # any non closing tag character
|
20
17
|
src= # src attribute start
|
21
|
-
(?<src
|
22
|
-
'(?:#{TAG}|#{VARIABLE}|[^']+)*'| # any combination of tag/variable or non straight quote inside straight quotes
|
23
|
-
"(?:#{TAG}|#{VARIABLE}|[^"]+)*" # any combination of tag/variable or non double quotes inside double quotes
|
24
|
-
)
|
18
|
+
(?<src>#{QUOTED_LIQUID_ATTRIBUTE}) # src attribute value (may contain liquid)
|
25
19
|
[^>]* # any non closing character till the end
|
26
20
|
>
|
27
21
|
}omix
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module ThemeCheck
|
3
|
+
# Reports errors when trying to use parser-blocking script tags
|
4
|
+
class ImgWidthAndHeight < LiquidCheck
|
5
|
+
include RegexHelpers
|
6
|
+
severity :error
|
7
|
+
categories :liquid, :performance
|
8
|
+
doc docs_url(__FILE__)
|
9
|
+
|
10
|
+
# Not implemented with lookbehinds and lookaheads because performance was shit!
|
11
|
+
IMG_TAG = /<img#{HTML_ATTRIBUTES}>/oxim
|
12
|
+
SRC_ATTRIBUTE = /\s(src)=(#{QUOTED_LIQUID_ATTRIBUTE})/oxim
|
13
|
+
WIDTH_ATTRIBUTE = /\s(width)=(#{QUOTED_LIQUID_ATTRIBUTE})/oxim
|
14
|
+
HEIGHT_ATTRIBUTE = /\s(height)=(#{QUOTED_LIQUID_ATTRIBUTE})/oxim
|
15
|
+
|
16
|
+
FIELDS = [WIDTH_ATTRIBUTE, HEIGHT_ATTRIBUTE]
|
17
|
+
ENDS_IN_CSS_UNIT = /(cm|mm|in|px|pt|pc|em|ex|ch|rem|vw|vh|vmin|vmax|%)$/i
|
18
|
+
|
19
|
+
def on_document(node)
|
20
|
+
@source = node.template.source
|
21
|
+
@node = node
|
22
|
+
record_offenses
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def record_offenses
|
28
|
+
matches(@source, IMG_TAG).each do |img_match|
|
29
|
+
next unless img_match[0] =~ SRC_ATTRIBUTE
|
30
|
+
record_missing_field_offenses(img_match)
|
31
|
+
record_units_in_field_offenses(img_match)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def record_missing_field_offenses(img_match)
|
36
|
+
width = WIDTH_ATTRIBUTE.match(img_match[0])
|
37
|
+
height = HEIGHT_ATTRIBUTE.match(img_match[0])
|
38
|
+
return if width.present? && height.present?
|
39
|
+
missing_width = width.nil?
|
40
|
+
missing_height = height.nil?
|
41
|
+
error_message = if missing_width && missing_height
|
42
|
+
"Missing width and height attributes"
|
43
|
+
elsif missing_width
|
44
|
+
"Missing width attribute"
|
45
|
+
elsif missing_height
|
46
|
+
"Missing height attribute"
|
47
|
+
end
|
48
|
+
|
49
|
+
add_offense(
|
50
|
+
error_message,
|
51
|
+
node: @node,
|
52
|
+
markup: img_match[0],
|
53
|
+
line_number: @source[0...img_match.begin(0)].count("\n") + 1
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
57
|
+
def record_units_in_field_offenses(img_match)
|
58
|
+
FIELDS.each do |field|
|
59
|
+
field_match = field.match(img_match[0])
|
60
|
+
next if field_match.nil?
|
61
|
+
value = field_match[2].gsub(START_OR_END_QUOTE, '')
|
62
|
+
next unless value =~ ENDS_IN_CSS_UNIT
|
63
|
+
value_without_units = value.gsub(ENDS_IN_CSS_UNIT, '')
|
64
|
+
start = img_match.begin(0) + field_match.begin(2)
|
65
|
+
add_offense(
|
66
|
+
"The #{field_match[1]} attribute does not take units. Replace with \"#{value_without_units}\".",
|
67
|
+
node: @node,
|
68
|
+
markup: value,
|
69
|
+
line_number: @source[0...start].count("\n") + 1
|
70
|
+
)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -2,13 +2,14 @@
|
|
2
2
|
module ThemeCheck
|
3
3
|
# Reports errors when trying to use parser-blocking script tags
|
4
4
|
class ParserBlockingJavaScript < LiquidCheck
|
5
|
+
include RegexHelpers
|
5
6
|
severity :error
|
6
7
|
categories :liquid, :performance
|
7
8
|
doc docs_url(__FILE__)
|
8
9
|
|
9
10
|
PARSER_BLOCKING_SCRIPT_TAG = %r{
|
10
11
|
<script # Find the start of a script tag
|
11
|
-
(?=
|
12
|
+
(?=[^>]+?src=) # Make sure src= is in the script with a lookahead
|
12
13
|
(?:(?!defer|async|type=["']module['"]).)*? # Find tags that don't have defer|async|type="module"
|
13
14
|
>
|
14
15
|
}xim
|
@@ -33,23 +34,14 @@ module ThemeCheck
|
|
33
34
|
)
|
34
35
|
end
|
35
36
|
|
36
|
-
# The trickiness here is matching on scripts that are defined on
|
37
|
-
# multiple lines (or repeat matches). This makes the line_number
|
38
|
-
# calculation a bit weird. So instead, we traverse the string in
|
39
|
-
# a very imperative way.
|
40
37
|
def record_offenses_from_regex(regex: nil, message: nil)
|
41
|
-
|
42
|
-
while (i = @source.index(regex, i))
|
43
|
-
script = @source.match(regex, i)[0]
|
44
|
-
|
38
|
+
matches(@source, regex).each do |match|
|
45
39
|
add_offense(
|
46
40
|
message,
|
47
41
|
node: @node,
|
48
|
-
markup:
|
49
|
-
line_number: @source[0...
|
42
|
+
markup: match[0],
|
43
|
+
line_number: @source[0...match.begin(0)].count("\n") + 1
|
50
44
|
)
|
51
|
-
|
52
|
-
i += script.size
|
53
45
|
end
|
54
46
|
end
|
55
47
|
end
|
@@ -1,5 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module ThemeCheck
|
3
|
+
module SystemTranslations
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def translations
|
7
|
+
@translations ||= begin
|
8
|
+
# loaded as a Set because the include? lookup will be much faster.
|
9
|
+
YAML.load(File.read("#{__dir__}/../../../data/shopify_translation_keys.yml")).to_set
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def include?(key)
|
14
|
+
translations.include?(key)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
3
18
|
class TranslationKeyExists < LiquidCheck
|
4
19
|
severity :error
|
5
20
|
category :translation
|
@@ -12,7 +27,7 @@ module ThemeCheck
|
|
12
27
|
return unless (key_node = node.children.first)
|
13
28
|
return unless key_node.value.is_a?(String)
|
14
29
|
|
15
|
-
unless key_exists?(key_node.value)
|
30
|
+
unless key_exists?(key_node.value) || SystemTranslations.include?(key_node.value)
|
16
31
|
add_offense(
|
17
32
|
"'#{key_node.value}' does not have a matching entry in '#{@theme.default_locale_json.relative_path}'",
|
18
33
|
node: node,
|
data/lib/theme_check/cli.rb
CHANGED
@@ -7,13 +7,14 @@ module ThemeCheck
|
|
7
7
|
Usage: theme-check [options] /path/to/your/theme
|
8
8
|
|
9
9
|
Options:
|
10
|
-
|
11
|
-
-
|
12
|
-
-
|
13
|
-
-
|
14
|
-
|
15
|
-
-
|
16
|
-
-
|
10
|
+
--init Generate a .theme-check.yml file in the current directory
|
11
|
+
-C, --config <path> Use the config provided, overriding .theme-check.yml if present
|
12
|
+
-c, --category <category> Only run this category of checks
|
13
|
+
-x, --exclude-category <category> Exclude this category of checks
|
14
|
+
-l, --list List enabled checks
|
15
|
+
-a, --auto-correct Automatically fix offenses
|
16
|
+
-h, --help Show this. Hi!
|
17
|
+
-v, --version Print Theme Check version
|
17
18
|
|
18
19
|
Description:
|
19
20
|
Theme Check helps you follow Shopify Themes & Liquid best practices by analyzing the
|
@@ -29,6 +30,7 @@ module ThemeCheck
|
|
29
30
|
only_categories = []
|
30
31
|
exclude_categories = []
|
31
32
|
auto_correct = false
|
33
|
+
config_path = nil
|
32
34
|
|
33
35
|
args = argv.dup
|
34
36
|
while (arg = args.shift)
|
@@ -37,6 +39,8 @@ module ThemeCheck
|
|
37
39
|
raise Abort, USAGE
|
38
40
|
when "--version", "-v"
|
39
41
|
command = :version
|
42
|
+
when "--config", "-C"
|
43
|
+
config_path = Pathname.new(args.shift)
|
40
44
|
when "--category", "-c"
|
41
45
|
only_categories << args.shift.to_sym
|
42
46
|
when "--exclude-category", "-x"
|
@@ -53,7 +57,14 @@ module ThemeCheck
|
|
53
57
|
end
|
54
58
|
|
55
59
|
unless [:version, :init].include?(command)
|
56
|
-
@config =
|
60
|
+
@config = if config_path.present?
|
61
|
+
ThemeCheck::Config.new(
|
62
|
+
root: @path,
|
63
|
+
configuration: ThemeCheck::Config.load_file(config_path)
|
64
|
+
)
|
65
|
+
else
|
66
|
+
ThemeCheck::Config.from_path(@path)
|
67
|
+
end
|
57
68
|
@config.only_categories = only_categories
|
58
69
|
@config.exclude_categories = exclude_categories
|
59
70
|
@config.auto_correct = auto_correct
|