theme-check 1.0.0 → 1.1.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 +4 -4
- data/CHANGELOG.md +13 -0
- data/README.md +39 -0
- data/config/default.yml +16 -0
- data/config/nothing.yml +11 -0
- data/config/theme_app_extension.yml +153 -0
- data/docs/checks/asset_size_app_block_css.md +52 -0
- data/docs/checks/asset_size_app_block_javascript.md +57 -0
- data/lib/theme_check.rb +15 -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 +23 -1
- 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/cli.rb +34 -13
- data/lib/theme_check/config.rb +56 -10
- data/lib/theme_check/exceptions.rb +29 -27
- data/lib/theme_check/json_file.rb +2 -29
- 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/tags.rb +26 -9
- data/lib/theme_check/template.rb +3 -32
- data/lib/theme_check/theme_file.rb +40 -0
- data/lib/theme_check/version.rb +1 -1
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: adc4aaf3260408a9b52d9afaa59662308f173a5d5dcd0f3663cbcc68da1d7f39
|
4
|
+
data.tar.gz: 50cd7e0d42fda99ad3816a846c25868c38b92ea521e0be759c515548dd82f70b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7ffad3310e441edd678143de233584a09167ffff1e09b96109cef417d360d797821dc9ef3491af4564608cd3b35aa59be41ebea6bb76030e1544d53bc9db8d02
|
7
|
+
data.tar.gz: 30b6d8f3b58b95c833a78bc30ceea6cfcfa35d563e3d184b6aee51817965be87b352c2dbad5ff67a74f2a64479fe1945c11db738c1bfb6e64f610ae15b862cb3
|
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,17 @@
|
|
1
1
|
|
2
|
+
v1.1.0 / 2021-07-06
|
3
|
+
==================
|
4
|
+
|
5
|
+
* Add `--fail-level` CLI flag to configure exit code
|
6
|
+
* Refactor all theme file classes to inherit from `ThemeFile`
|
7
|
+
* Fix `undefined method liquid?` error when scanning from LSP
|
8
|
+
* Adding asset document links
|
9
|
+
* Allow initializing theme app extension configuration files
|
10
|
+
* Allow disabling registering mock Liquid tags w/ `ThemeCheck::Tags.register_tags = false`
|
11
|
+
* Support Theme App Extensions
|
12
|
+
* Add checks for theme app extension block JS/CSS
|
13
|
+
* Disable Liquid::C when parsing Liquid templates
|
14
|
+
|
2
15
|
v1.0.0 / 2021-06-28
|
3
16
|
==================
|
4
17
|
|
data/README.md
CHANGED
@@ -100,6 +100,8 @@ TemplateLength:
|
|
100
100
|
# Or ignore certain paths
|
101
101
|
ignore:
|
102
102
|
- snippets/icon-*
|
103
|
+
# Or change the severity (error|suggestion|style)
|
104
|
+
severity: suggestion
|
103
105
|
|
104
106
|
# Enable a custom check
|
105
107
|
MyCustomCheck
|
@@ -141,3 +143,40 @@ Disable checks for the _entire document_ by placing the comment on the first lin
|
|
141
143
|
|
142
144
|
{%assign x = 1%}
|
143
145
|
```
|
146
|
+
|
147
|
+
## Exit Code and `--fail-level`
|
148
|
+
|
149
|
+
Use the `--fail-level` (default: `error`) flag to configure the exit code of theme-check. Useful in CI scenarios.
|
150
|
+
|
151
|
+
Example:
|
152
|
+
|
153
|
+
```
|
154
|
+
# Make CI fail on styles warnings, suggestions, and errors
|
155
|
+
theme-check --fail-level style path_to_theme
|
156
|
+
|
157
|
+
# Make CI fail on suggestions, and errors
|
158
|
+
theme-check --fail-level suggestion path_to_theme
|
159
|
+
|
160
|
+
# Make CI fail on errors
|
161
|
+
theme-check path_to_theme
|
162
|
+
```
|
163
|
+
|
164
|
+
There are three fail levels:
|
165
|
+
|
166
|
+
- `error`
|
167
|
+
- `suggestion`
|
168
|
+
- `style`
|
169
|
+
|
170
|
+
Exit code meanings:
|
171
|
+
|
172
|
+
- 0: Success!
|
173
|
+
- 1: Your code doesn't pass the checks
|
174
|
+
- 2: There's a bug in theme-check
|
175
|
+
|
176
|
+
If you would like to change the severity of a check, you can do so with the `severity` attribute. Example:
|
177
|
+
|
178
|
+
```yaml
|
179
|
+
DeprecateLazysizes:
|
180
|
+
enabled: true
|
181
|
+
severity: error
|
182
|
+
```
|
data/config/default.yml
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
root: .
|
2
2
|
|
3
|
+
extends: :nothing
|
4
|
+
|
3
5
|
require: []
|
4
6
|
|
7
|
+
include_categories: []
|
8
|
+
|
9
|
+
exclude_categories: []
|
10
|
+
|
5
11
|
ignore:
|
6
12
|
- node_modules/*
|
7
13
|
|
@@ -161,3 +167,13 @@ ImgLazyLoading:
|
|
161
167
|
HtmlParsingError:
|
162
168
|
enabled: true
|
163
169
|
ignore: []
|
170
|
+
|
171
|
+
AssetSizeAppBlockJavaScript:
|
172
|
+
enabled: false
|
173
|
+
ignore: []
|
174
|
+
threshold_in_bytes: 10_000
|
175
|
+
|
176
|
+
AssetSizeAppBlockCSS:
|
177
|
+
enabled: false
|
178
|
+
ignore: []
|
179
|
+
threshold_in_bytes: 100_000
|
data/config/nothing.yml
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
root: .
|
2
|
+
|
3
|
+
extends: :nothing
|
4
|
+
|
5
|
+
require: []
|
6
|
+
|
7
|
+
include_categories: []
|
8
|
+
|
9
|
+
exclude_categories: []
|
10
|
+
|
11
|
+
ignore:
|
12
|
+
- node_modules/*
|
13
|
+
|
14
|
+
ConvertIncludeToRender:
|
15
|
+
enabled: true
|
16
|
+
ignore: []
|
17
|
+
|
18
|
+
LiquidTag:
|
19
|
+
enabled: true
|
20
|
+
ignore: []
|
21
|
+
min_consecutive_statements: 4
|
22
|
+
|
23
|
+
MissingTemplate:
|
24
|
+
enabled: true
|
25
|
+
ignore: []
|
26
|
+
|
27
|
+
NestedSnippet:
|
28
|
+
enabled: true
|
29
|
+
ignore: []
|
30
|
+
max_nesting_level: 3
|
31
|
+
|
32
|
+
RequiredLayoutThemeObject:
|
33
|
+
enabled: true
|
34
|
+
ignore: []
|
35
|
+
|
36
|
+
SpaceInsideBraces:
|
37
|
+
enabled: true
|
38
|
+
ignore: []
|
39
|
+
|
40
|
+
SyntaxError:
|
41
|
+
enabled: true
|
42
|
+
ignore: []
|
43
|
+
|
44
|
+
TemplateLength:
|
45
|
+
enabled: true
|
46
|
+
ignore: []
|
47
|
+
max_length: 200
|
48
|
+
# Exclude content of {% schema %} in line count
|
49
|
+
exclude_schema: true
|
50
|
+
|
51
|
+
UnknownFilter:
|
52
|
+
enabled: true
|
53
|
+
ignore: []
|
54
|
+
|
55
|
+
UnusedAssign:
|
56
|
+
enabled: true
|
57
|
+
ignore: []
|
58
|
+
|
59
|
+
UnusedSnippet:
|
60
|
+
enabled: true
|
61
|
+
ignore: []
|
62
|
+
|
63
|
+
MatchingSchemaTranslations:
|
64
|
+
enabled: true
|
65
|
+
ignore: []
|
66
|
+
|
67
|
+
MatchingTranslations:
|
68
|
+
enabled: true
|
69
|
+
ignore: []
|
70
|
+
|
71
|
+
TranslationKeyExists:
|
72
|
+
enabled: true
|
73
|
+
ignore: []
|
74
|
+
|
75
|
+
ValidHTMLTranslation:
|
76
|
+
enabled: true
|
77
|
+
ignore: []
|
78
|
+
|
79
|
+
ValidJson:
|
80
|
+
enabled: true
|
81
|
+
ignore: []
|
82
|
+
|
83
|
+
ValidSchema:
|
84
|
+
enabled: true
|
85
|
+
ignore: []
|
86
|
+
|
87
|
+
UndefinedObject:
|
88
|
+
enabled: true
|
89
|
+
ignore: []
|
90
|
+
exclude_snippets: true
|
91
|
+
|
92
|
+
RequiredDirectories:
|
93
|
+
enabled: false
|
94
|
+
ignore: []
|
95
|
+
|
96
|
+
DeprecatedFilter:
|
97
|
+
enabled: true
|
98
|
+
ignore: []
|
99
|
+
|
100
|
+
MissingEnableComment:
|
101
|
+
enabled: true
|
102
|
+
ignore: []
|
103
|
+
|
104
|
+
ParserBlockingJavaScript:
|
105
|
+
enabled: true
|
106
|
+
ignore: []
|
107
|
+
|
108
|
+
ParserBlockingScriptTag:
|
109
|
+
enabled: true
|
110
|
+
|
111
|
+
AssetSizeJavaScript:
|
112
|
+
enabled: true
|
113
|
+
ignore: []
|
114
|
+
threshold_in_bytes: 10_000
|
115
|
+
|
116
|
+
AssetSizeCSS:
|
117
|
+
enabled: true
|
118
|
+
ignore: []
|
119
|
+
threshold_in_bytes: 100_000
|
120
|
+
|
121
|
+
ImgWidthAndHeight:
|
122
|
+
enabled: true
|
123
|
+
ignore: []
|
124
|
+
|
125
|
+
RemoteAsset:
|
126
|
+
enabled: true
|
127
|
+
ignore: []
|
128
|
+
|
129
|
+
AssetUrlFilters:
|
130
|
+
enabled: true
|
131
|
+
ignore: []
|
132
|
+
|
133
|
+
ContentForHeaderModification:
|
134
|
+
enabled: true
|
135
|
+
ignore: []
|
136
|
+
|
137
|
+
ImgLazyLoading:
|
138
|
+
enabled: true
|
139
|
+
ignore: []
|
140
|
+
|
141
|
+
HtmlParsingError:
|
142
|
+
enabled: true
|
143
|
+
ignore: []
|
144
|
+
|
145
|
+
AssetSizeAppBlockJavaScript:
|
146
|
+
enabled: true
|
147
|
+
ignore: []
|
148
|
+
threshold_in_bytes: 10_000
|
149
|
+
|
150
|
+
AssetSizeAppBlockCSS:
|
151
|
+
enabled: true
|
152
|
+
ignore: []
|
153
|
+
threshold_in_bytes: 100_000
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# Prevent Large CSS bundles (`AssetSizeAppBlockCSS`)
|
2
|
+
|
3
|
+
This rule exists to prevent large CSS bundles from being included via Theme App Extensions (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/app.css is **greater** than `threshold_in_bytes` compressed. -->
|
12
|
+
{% schema %}
|
13
|
+
{
|
14
|
+
...
|
15
|
+
"stylesheet": "app.css"
|
16
|
+
}
|
17
|
+
{% endschema %}
|
18
|
+
```
|
19
|
+
|
20
|
+
## Check Options
|
21
|
+
|
22
|
+
The default configuration is the following:
|
23
|
+
|
24
|
+
```yaml
|
25
|
+
AssetSizeAppBlockCSS:
|
26
|
+
enabled: false
|
27
|
+
threshold_in_bytes: 100_000
|
28
|
+
```
|
29
|
+
|
30
|
+
### `threshold_in_bytes`
|
31
|
+
|
32
|
+
The `threshold_in_bytes` option (default: `100_000`) determines the maximum allowed compressed size in bytes that a single CSS file can take.
|
33
|
+
|
34
|
+
This includes theme and remote stylesheets.
|
35
|
+
|
36
|
+
## When Not To Use It
|
37
|
+
|
38
|
+
This rule should not be disabled locally since the check will be enforced when
|
39
|
+
promoting new versions of the extension.
|
40
|
+
|
41
|
+
## Version
|
42
|
+
|
43
|
+
This check has been introduced in 1.1.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_app_block_css.rb
|
52
|
+
[docsource]: /docs/checks/asset_size_app_block_css.md
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# Prevent Abuse on Server Rendered App Blocks (`AssetSizeAppBlockJavaScript`)
|
2
|
+
|
3
|
+
For server rendered app blocks, it is an anti-pattern to execute large JavaScript bundles on every page load
|
4
|
+
|
5
|
+
This doesn't mean they don't have a reason to exist. For instance, chat widgets are mini applications embedded inside web pages. Designing such an app with server rendered updates would be absurd. However, if only 10% of the users interact with the chat widget, the other 90% should not have to execute the entire bundle on every page load.
|
6
|
+
|
7
|
+
The natural solution to this problem is to implement the chat widget using the [Import on Interaction Pattern][ioip].
|
8
|
+
|
9
|
+
## Check Details
|
10
|
+
|
11
|
+
This rule disallows the use of block JavaScript files and external scripts to have a compressed size greater than a configured `threshold_in_bytes`.
|
12
|
+
|
13
|
+
:-1: Examples of **incorrect** code for this check:
|
14
|
+
```liquid
|
15
|
+
<!-- Here assets/chat-widget.js is more than 10KB gzipped. -->
|
16
|
+
{% schema %}
|
17
|
+
{
|
18
|
+
...
|
19
|
+
"javascript": "chat-widget.js"
|
20
|
+
}
|
21
|
+
{% endschema %}
|
22
|
+
```
|
23
|
+
|
24
|
+
## Check Options
|
25
|
+
|
26
|
+
The default configuration is the following:
|
27
|
+
|
28
|
+
```yaml
|
29
|
+
AssetSizeAppBlockJavaScript:
|
30
|
+
enabled: true
|
31
|
+
threshold_in_bytes: 10000
|
32
|
+
```
|
33
|
+
|
34
|
+
### `threshold_in_bytes`
|
35
|
+
|
36
|
+
The `threshold_in_bytes` option (default: `10000`) determines the maximum allowed compressed size in bytes that a single JavaScript file can take.
|
37
|
+
|
38
|
+
This includes theme and remote scripts.
|
39
|
+
|
40
|
+
## When Not To Use It
|
41
|
+
|
42
|
+
This rule should not be disabled locally since the check will be enforced when
|
43
|
+
promoting new versions of the extension.
|
44
|
+
|
45
|
+
## Version
|
46
|
+
|
47
|
+
This check has been introduced in 1.1.0
|
48
|
+
|
49
|
+
## Resources
|
50
|
+
|
51
|
+
- [The Import On Interaction Pattern][ioip]
|
52
|
+
- [Rule Source][codesource]
|
53
|
+
- [Documentation Source][docsource]
|
54
|
+
|
55
|
+
[ioip]: https://addyosmani.com/blog/import-on-interaction/
|
56
|
+
[codesource]: /lib/theme_check/checks/asset_size_app_block_javascript.rb
|
57
|
+
[docsource]: /docs/checks/asset_size_app_block_javascript.md
|
data/lib/theme_check.rb
CHANGED
@@ -4,6 +4,7 @@ require "liquid"
|
|
4
4
|
require_relative "theme_check/version"
|
5
5
|
require_relative "theme_check/bug"
|
6
6
|
require_relative "theme_check/exceptions"
|
7
|
+
require_relative "theme_check/theme_file"
|
7
8
|
require_relative "theme_check/analyzer"
|
8
9
|
require_relative "theme_check/check"
|
9
10
|
require_relative "theme_check/checks_tracking"
|
@@ -45,3 +46,17 @@ Dir[__dir__ + "/theme_check/checks/*.rb"].each { |file| require file }
|
|
45
46
|
# UTF-8 is the default internal and external encoding, like in Rails & Shopify.
|
46
47
|
Encoding.default_external = Encoding::UTF_8
|
47
48
|
Encoding.default_internal = Encoding::UTF_8
|
49
|
+
|
50
|
+
module ThemeCheck
|
51
|
+
def self.with_liquid_c_disabled
|
52
|
+
if defined?(Liquid::C)
|
53
|
+
was_enabled = Liquid::C.enabled
|
54
|
+
Liquid::C.enabled = false if was_enabled
|
55
|
+
end
|
56
|
+
yield
|
57
|
+
ensure
|
58
|
+
if defined?(Liquid::C) && was_enabled
|
59
|
+
Liquid::C.enabled = true
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/theme_check/analyzer.rb
CHANGED
@@ -34,9 +34,11 @@ module ThemeCheck
|
|
34
34
|
|
35
35
|
liquid_visitor = Visitor.new(@liquid_checks, @disabled_checks)
|
36
36
|
html_visitor = HtmlVisitor.new(@html_checks)
|
37
|
-
|
38
|
-
|
39
|
-
|
37
|
+
ThemeCheck.with_liquid_c_disabled do
|
38
|
+
@theme.liquid.each do |template|
|
39
|
+
liquid_visitor.visit_template(template)
|
40
|
+
html_visitor.visit_template(template)
|
41
|
+
end
|
40
42
|
end
|
41
43
|
|
42
44
|
@theme.json.each { |json_file| @json_checks.call(:on_file, json_file) }
|
@@ -47,24 +49,26 @@ module ThemeCheck
|
|
47
49
|
def analyze_files(files)
|
48
50
|
reset
|
49
51
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
52
|
+
ThemeCheck.with_liquid_c_disabled do
|
53
|
+
# Call all checks that run on the whole theme
|
54
|
+
liquid_visitor = Visitor.new(@liquid_checks.whole_theme, @disabled_checks)
|
55
|
+
html_visitor = HtmlVisitor.new(@html_checks.whole_theme)
|
56
|
+
@theme.liquid.each do |template|
|
57
|
+
liquid_visitor.visit_template(template)
|
58
|
+
html_visitor.visit_template(template)
|
59
|
+
end
|
60
|
+
@theme.json.each { |json_file| @json_checks.whole_theme.call(:on_file, json_file) }
|
61
|
+
|
62
|
+
# Call checks that run on a single files, only on specified file
|
63
|
+
liquid_visitor = Visitor.new(@liquid_checks.single_file, @disabled_checks)
|
64
|
+
html_visitor = HtmlVisitor.new(@html_checks.single_file)
|
65
|
+
files.each do |file|
|
66
|
+
if file.liquid?
|
67
|
+
liquid_visitor.visit_template(file)
|
68
|
+
html_visitor.visit_template(file)
|
69
|
+
elsif file.json?
|
70
|
+
@json_checks.single_file.call(:on_file, file)
|
71
|
+
end
|
68
72
|
end
|
69
73
|
end
|
70
74
|
|
@@ -1,27 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require "pathname"
|
3
2
|
require "zlib"
|
4
3
|
|
5
4
|
module ThemeCheck
|
6
|
-
class AssetFile
|
5
|
+
class AssetFile < ThemeFile
|
7
6
|
def initialize(relative_path, storage)
|
8
|
-
|
9
|
-
@storage = storage
|
7
|
+
super
|
10
8
|
@loaded = false
|
11
9
|
@content = nil
|
12
10
|
end
|
13
11
|
|
14
|
-
|
15
|
-
@storage.path(@relative_path)
|
16
|
-
end
|
17
|
-
|
18
|
-
def relative_path
|
19
|
-
@relative_pathname ||= Pathname.new(@relative_path)
|
20
|
-
end
|
21
|
-
|
22
|
-
def content
|
23
|
-
@content ||= @storage.read(@relative_path)
|
24
|
-
end
|
12
|
+
alias_method :content, :source
|
25
13
|
|
26
14
|
def gzipped_size
|
27
15
|
@gzipped_size ||= Zlib.gzip(content).bytesize
|
data/lib/theme_check/bug.rb
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
require 'theme_check/version'
|
3
3
|
|
4
4
|
module ThemeCheck
|
5
|
+
class ThemeCheckError < StandardError; end
|
6
|
+
|
5
7
|
BUG_POSTAMBLE = <<~EOS
|
6
8
|
Theme Check Version: #{VERSION}
|
7
9
|
Ruby Version: #{RUBY_VERSION}
|
@@ -15,6 +17,6 @@ module ThemeCheck
|
|
15
17
|
EOS
|
16
18
|
|
17
19
|
def self.bug(message)
|
18
|
-
|
20
|
+
raise ThemeCheckError, message + BUG_POSTAMBLE
|
19
21
|
end
|
20
22
|
end
|
data/lib/theme_check/check.rb
CHANGED
@@ -9,12 +9,19 @@ module ThemeCheck
|
|
9
9
|
attr_accessor :options, :ignored_patterns
|
10
10
|
attr_writer :offenses
|
11
11
|
|
12
|
+
# The order matters.
|
12
13
|
SEVERITIES = [
|
13
14
|
:error,
|
14
15
|
:suggestion,
|
15
16
|
:style,
|
16
17
|
]
|
17
18
|
|
19
|
+
# [severity: sym] => number
|
20
|
+
SEVERITY_VALUES = SEVERITIES
|
21
|
+
.map
|
22
|
+
.with_index { |sev, i| [sev, i] }
|
23
|
+
.to_h
|
24
|
+
|
18
25
|
CATEGORIES = [
|
19
26
|
:liquid,
|
20
27
|
:translation,
|
@@ -38,6 +45,10 @@ module ThemeCheck
|
|
38
45
|
@severity if defined?(@severity)
|
39
46
|
end
|
40
47
|
|
48
|
+
def severity_value(severity)
|
49
|
+
SEVERITY_VALUES[severity]
|
50
|
+
end
|
51
|
+
|
41
52
|
def categories(*categories)
|
42
53
|
@categories ||= []
|
43
54
|
if categories.any?
|
@@ -85,7 +96,18 @@ module ThemeCheck
|
|
85
96
|
end
|
86
97
|
|
87
98
|
def severity
|
88
|
-
self.class.severity
|
99
|
+
@severity ||= self.class.severity
|
100
|
+
end
|
101
|
+
|
102
|
+
def severity=(severity)
|
103
|
+
unless SEVERITIES.include?(severity)
|
104
|
+
raise ArgumentError, "unknown severity. Use: #{SEVERITIES.join(', ')}"
|
105
|
+
end
|
106
|
+
@severity = severity
|
107
|
+
end
|
108
|
+
|
109
|
+
def severity_value
|
110
|
+
SEVERITY_VALUES[severity]
|
89
111
|
end
|
90
112
|
|
91
113
|
def categories
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module ThemeCheck
|
3
|
+
# Reports errors when too much CSS is being referenced from a Theme App
|
4
|
+
# Extension block
|
5
|
+
class AssetSizeAppBlockCSS < LiquidCheck
|
6
|
+
severity :error
|
7
|
+
category :performance
|
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
|
+
attr_reader :threshold_in_bytes
|
15
|
+
|
16
|
+
def initialize(threshold_in_bytes: 100_000)
|
17
|
+
@threshold_in_bytes = threshold_in_bytes
|
18
|
+
end
|
19
|
+
|
20
|
+
def on_schema(node)
|
21
|
+
schema = JSON.parse(node.value.nodelist.join)
|
22
|
+
|
23
|
+
if (stylesheet = schema["stylesheet"])
|
24
|
+
size = asset_size(stylesheet)
|
25
|
+
if size && size > threshold_in_bytes
|
26
|
+
add_offense(
|
27
|
+
"CSS in Theme App Extension blocks exceeds compressed size threshold (#{threshold_in_bytes} Bytes)",
|
28
|
+
node: node
|
29
|
+
)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
rescue JSON::ParserError
|
33
|
+
# Ignored, handled in ValidSchema.
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def asset_size(name)
|
39
|
+
asset = @theme["assets/#{name}"]
|
40
|
+
return if asset.nil?
|
41
|
+
asset.gzipped_size
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module ThemeCheck
|
3
|
+
# Reports errors when too much JS is being referenced from a Theme App
|
4
|
+
# Extension block
|
5
|
+
class AssetSizeAppBlockJavaScript < LiquidCheck
|
6
|
+
severity :error
|
7
|
+
category :performance
|
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
|
+
attr_reader :threshold_in_bytes
|
15
|
+
|
16
|
+
def initialize(threshold_in_bytes: 10_000)
|
17
|
+
@threshold_in_bytes = threshold_in_bytes
|
18
|
+
end
|
19
|
+
|
20
|
+
def on_schema(node)
|
21
|
+
schema = JSON.parse(node.value.nodelist.join)
|
22
|
+
|
23
|
+
if (javascript = schema["javascript"])
|
24
|
+
size = asset_size(javascript)
|
25
|
+
if size && size > threshold_in_bytes
|
26
|
+
add_offense(
|
27
|
+
"JavaScript in Theme App Extension blocks exceeds compressed size threshold (#{threshold_in_bytes} Bytes)",
|
28
|
+
node: node
|
29
|
+
)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
rescue JSON::ParserError
|
33
|
+
# Ignored, handled in ValidSchema.
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def asset_size(name)
|
39
|
+
asset = @theme["assets/#{name}"]
|
40
|
+
return if asset.nil?
|
41
|
+
asset.gzipped_size
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/theme_check/cli.rb
CHANGED
@@ -10,10 +10,11 @@ module ThemeCheck
|
|
10
10
|
def initialize
|
11
11
|
@path = "."
|
12
12
|
@command = :check
|
13
|
-
@
|
13
|
+
@include_categories = []
|
14
14
|
@exclude_categories = []
|
15
15
|
@auto_correct = false
|
16
16
|
@config_path = nil
|
17
|
+
@fail_level = :error
|
17
18
|
end
|
18
19
|
|
19
20
|
def option_parser(parser = OptionParser.new, help: true)
|
@@ -25,20 +26,27 @@ module ThemeCheck
|
|
25
26
|
@option_parser.separator("Basic Options:")
|
26
27
|
@option_parser.on(
|
27
28
|
"-C", "--config PATH",
|
28
|
-
"Use the config provided, overriding .theme-check.yml if present"
|
29
|
+
"Use the config provided, overriding .theme-check.yml if present",
|
30
|
+
"Use :theme_app_extension to use default checks for theme app extensions"
|
29
31
|
) { |path| @config_path = path }
|
30
32
|
@option_parser.on(
|
31
|
-
"-c", "--category CATEGORY",
|
32
|
-
"
|
33
|
-
) { |category| @
|
33
|
+
"-c", "--category CATEGORY", Check::CATEGORIES, "Only run this category of checks",
|
34
|
+
"Runs checks matching all categories when specified more than once"
|
35
|
+
) { |category| @include_categories << category.to_sym }
|
34
36
|
@option_parser.on(
|
35
|
-
"-x", "--exclude-category CATEGORY",
|
36
|
-
"
|
37
|
+
"-x", "--exclude-category CATEGORY", Check::CATEGORIES, "Exclude this category of checks",
|
38
|
+
"Excludes checks matching any category when specified more than once"
|
37
39
|
) { |category| @exclude_categories << category.to_sym }
|
38
40
|
@option_parser.on(
|
39
41
|
"-a", "--auto-correct",
|
40
42
|
"Automatically fix offenses"
|
41
43
|
) { @auto_correct = true }
|
44
|
+
@option_parser.on(
|
45
|
+
"--fail-level SEVERITY", Check::SEVERITIES,
|
46
|
+
"Minimum severity (error|suggestion|style) for exit with error code"
|
47
|
+
) do |severity|
|
48
|
+
@fail_level = severity.to_sym
|
49
|
+
end
|
42
50
|
|
43
51
|
@option_parser.separator("")
|
44
52
|
@option_parser.separator("Miscellaneous:")
|
@@ -77,6 +85,8 @@ module ThemeCheck
|
|
77
85
|
|
78
86
|
def parse(argv)
|
79
87
|
@path = option_parser.parse(argv).first || "."
|
88
|
+
rescue OptionParser::InvalidArgument => e
|
89
|
+
abort(e.message)
|
80
90
|
end
|
81
91
|
|
82
92
|
def run!
|
@@ -84,13 +94,13 @@ module ThemeCheck
|
|
84
94
|
@config = if @config_path
|
85
95
|
ThemeCheck::Config.new(
|
86
96
|
root: @path,
|
87
|
-
configuration: ThemeCheck::Config.
|
97
|
+
configuration: ThemeCheck::Config.load_config(@config_path)
|
88
98
|
)
|
89
99
|
else
|
90
100
|
ThemeCheck::Config.from_path(@path)
|
91
101
|
end
|
92
|
-
@config.
|
93
|
-
@config.exclude_categories = @exclude_categories
|
102
|
+
@config.include_categories = @include_categories unless @include_categories.empty?
|
103
|
+
@config.exclude_categories = @exclude_categories unless @exclude_categories.empty?
|
94
104
|
@config.auto_correct = @auto_correct
|
95
105
|
end
|
96
106
|
|
@@ -99,12 +109,16 @@ module ThemeCheck
|
|
99
109
|
|
100
110
|
def run
|
101
111
|
run!
|
112
|
+
exit(0)
|
102
113
|
rescue Abort => e
|
103
114
|
if e.message.empty?
|
104
115
|
exit(1)
|
105
116
|
else
|
106
117
|
abort(e.message)
|
107
118
|
end
|
119
|
+
rescue ThemeCheckError => e
|
120
|
+
STDERR.puts(e.message)
|
121
|
+
exit(2)
|
108
122
|
end
|
109
123
|
|
110
124
|
def self.parse_and_run!(argv)
|
@@ -130,11 +144,16 @@ module ThemeCheck
|
|
130
144
|
def init
|
131
145
|
dotfile_path = ThemeCheck::Config.find(@path)
|
132
146
|
if dotfile_path.nil?
|
133
|
-
|
147
|
+
config_name = if @config_path && @config_path[0] == ":"
|
148
|
+
"#{@config_path[1..]}.yml"
|
149
|
+
else
|
150
|
+
"default.yml"
|
151
|
+
end
|
152
|
+
File.write(File.join(@path, ThemeCheck::Config::DOTFILE), File.read(ThemeCheck::Config.bundled_config_path(config_name)))
|
134
153
|
|
135
154
|
puts "Writing new #{ThemeCheck::Config::DOTFILE} to #{@path}"
|
136
155
|
else
|
137
|
-
raise Abort, "#{ThemeCheck::Config::DOTFILE} already exists at #{@path}
|
156
|
+
raise Abort, "#{ThemeCheck::Config::DOTFILE} already exists at #{@path}"
|
138
157
|
end
|
139
158
|
end
|
140
159
|
|
@@ -157,7 +176,9 @@ module ThemeCheck
|
|
157
176
|
analyzer.analyze_theme
|
158
177
|
analyzer.correct_offenses
|
159
178
|
ThemeCheck::Printer.new.print(theme, analyzer.offenses, @config.auto_correct)
|
160
|
-
raise Abort, "" if analyzer.uncorrectable_offenses.any?
|
179
|
+
raise Abort, "" if analyzer.uncorrectable_offenses.any? do |offense|
|
180
|
+
offense.check.severity_value <= Check.severity_value(@fail_level)
|
181
|
+
end
|
161
182
|
end
|
162
183
|
end
|
163
184
|
end
|
data/lib/theme_check/config.rb
CHANGED
@@ -3,11 +3,11 @@
|
|
3
3
|
module ThemeCheck
|
4
4
|
class Config
|
5
5
|
DOTFILE = '.theme-check.yml'
|
6
|
-
|
6
|
+
BUNDLED_CONFIGS_DIR = "#{__dir__}/../../config"
|
7
7
|
BOOLEAN = [true, false]
|
8
8
|
|
9
9
|
attr_reader :root
|
10
|
-
attr_accessor :
|
10
|
+
attr_accessor :auto_correct
|
11
11
|
|
12
12
|
class << self
|
13
13
|
attr_reader :last_loaded_config
|
@@ -42,18 +42,46 @@ module ThemeCheck
|
|
42
42
|
YAML.load_file(absolute_path)
|
43
43
|
end
|
44
44
|
|
45
|
+
def bundled_config_path(name)
|
46
|
+
"#{BUNDLED_CONFIGS_DIR}/#{name}"
|
47
|
+
end
|
48
|
+
|
49
|
+
def load_bundled_config(name)
|
50
|
+
load_file(bundled_config_path(name))
|
51
|
+
end
|
52
|
+
|
53
|
+
def load_config(path)
|
54
|
+
if path[0] == ":"
|
55
|
+
load_bundled_config("#{path[1..]}.yml")
|
56
|
+
elsif path.is_a?(Symbol)
|
57
|
+
load_bundled_config("#{path}.yml")
|
58
|
+
else
|
59
|
+
load_file(path)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
45
63
|
def default
|
46
|
-
@default ||=
|
64
|
+
@default ||= load_config(":default")
|
47
65
|
end
|
48
66
|
end
|
49
67
|
|
50
68
|
def initialize(root: nil, configuration: nil, should_resolve_requires: true)
|
51
69
|
@configuration = if configuration
|
70
|
+
# TODO: Do we need to handle extends here? What base configuration
|
71
|
+
# should we validate against once Theme App Extensions has its own
|
72
|
+
# checks? :all?
|
52
73
|
validate_configuration(configuration)
|
53
74
|
else
|
54
75
|
{}
|
55
76
|
end
|
56
|
-
|
77
|
+
|
78
|
+
# Follow extends
|
79
|
+
extends = @configuration["extends"] || ":default"
|
80
|
+
while extends
|
81
|
+
extended_configuration = self.class.load_config(extends)
|
82
|
+
extends = extended_configuration["extends"]
|
83
|
+
@configuration = merge_configurations!(@configuration, extended_configuration)
|
84
|
+
end
|
57
85
|
|
58
86
|
@root = if root && @configuration.key?("root")
|
59
87
|
Pathname.new(root).join(@configuration["root"])
|
@@ -61,8 +89,6 @@ module ThemeCheck
|
|
61
89
|
Pathname.new(root)
|
62
90
|
end
|
63
91
|
|
64
|
-
@only_categories = []
|
65
|
-
@exclude_categories = []
|
66
92
|
@auto_correct = false
|
67
93
|
|
68
94
|
resolve_requires if @root && should_resolve_requires
|
@@ -87,16 +113,18 @@ module ThemeCheck
|
|
87
113
|
check_class = ThemeCheck.const_get(check_name)
|
88
114
|
|
89
115
|
next if check_class.categories.any? { |category| exclude_categories.include?(category) }
|
90
|
-
next if
|
116
|
+
next if include_categories.any? && !include_categories.all? { |category| check_class.categories.include?(category) }
|
91
117
|
|
92
118
|
options_for_check = options.transform_keys(&:to_sym)
|
93
119
|
options_for_check.delete(:enabled)
|
120
|
+
severity = options_for_check.delete(:severity)
|
94
121
|
ignored_patterns = options_for_check.delete(:ignore) || []
|
95
122
|
check = if options_for_check.empty?
|
96
123
|
check_class.new
|
97
124
|
else
|
98
125
|
check_class.new(**options_for_check)
|
99
126
|
end
|
127
|
+
check.severity = severity.to_sym if severity
|
100
128
|
check.ignored_patterns = ignored_patterns
|
101
129
|
check.options = options_for_check
|
102
130
|
check
|
@@ -107,6 +135,22 @@ module ThemeCheck
|
|
107
135
|
self["ignore"] || []
|
108
136
|
end
|
109
137
|
|
138
|
+
def include_categories
|
139
|
+
self["include_categories"] || []
|
140
|
+
end
|
141
|
+
|
142
|
+
def include_categories=(categories)
|
143
|
+
@configuration["include_categories"] = categories
|
144
|
+
end
|
145
|
+
|
146
|
+
def exclude_categories
|
147
|
+
self["exclude_categories"] || []
|
148
|
+
end
|
149
|
+
|
150
|
+
def exclude_categories=(categories)
|
151
|
+
@configuration["exclude_categories"] = categories
|
152
|
+
end
|
153
|
+
|
110
154
|
private
|
111
155
|
|
112
156
|
def check_name?(name)
|
@@ -133,6 +177,8 @@ module ThemeCheck
|
|
133
177
|
else
|
134
178
|
warn("bad configuration type for #{name}: expected a Hash, got #{value.inspect}")
|
135
179
|
end
|
180
|
+
elsif key == "severity"
|
181
|
+
valid_configuration[key] = value
|
136
182
|
elsif default.nil?
|
137
183
|
warn("unknown configuration: #{name}")
|
138
184
|
elsif BOOLEAN.include?(default) && !BOOLEAN.include?(value)
|
@@ -147,13 +193,13 @@ module ThemeCheck
|
|
147
193
|
valid_configuration
|
148
194
|
end
|
149
195
|
|
150
|
-
def
|
151
|
-
|
196
|
+
def merge_configurations!(configuration, extended_configuration)
|
197
|
+
extended_configuration.each do |key, default|
|
152
198
|
value = configuration[key]
|
153
199
|
|
154
200
|
case value
|
155
201
|
when Hash
|
156
|
-
|
202
|
+
merge_configurations!(value, default)
|
157
203
|
when nil
|
158
204
|
configuration[key] = default
|
159
205
|
end
|
@@ -1,32 +1,34 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require "net/http"
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
4
|
+
module ThemeCheck
|
5
|
+
TIMEOUT_EXCEPTIONS = [
|
6
|
+
Net::ReadTimeout,
|
7
|
+
Net::OpenTimeout,
|
8
|
+
Net::WriteTimeout,
|
9
|
+
Errno::ETIMEDOUT,
|
10
|
+
Timeout::Error,
|
11
|
+
]
|
11
12
|
|
12
|
-
CONNECTION_EXCEPTIONS = [
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
]
|
13
|
+
CONNECTION_EXCEPTIONS = [
|
14
|
+
IOError,
|
15
|
+
EOFError,
|
16
|
+
SocketError,
|
17
|
+
Errno::EINVAL,
|
18
|
+
Errno::ECONNRESET,
|
19
|
+
Errno::ECONNABORTED,
|
20
|
+
Errno::EPIPE,
|
21
|
+
Errno::ECONNREFUSED,
|
22
|
+
Errno::EAGAIN,
|
23
|
+
Errno::EHOSTUNREACH,
|
24
|
+
Errno::ENETUNREACH,
|
25
|
+
]
|
25
26
|
|
26
|
-
NET_HTTP_EXCEPTIONS = [
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
]
|
27
|
+
NET_HTTP_EXCEPTIONS = [
|
28
|
+
Net::HTTPBadResponse,
|
29
|
+
Net::HTTPHeaderSyntaxError,
|
30
|
+
Net::ProtocolError,
|
31
|
+
*TIMEOUT_EXCEPTIONS,
|
32
|
+
*CONNECTION_EXCEPTIONS,
|
33
|
+
]
|
34
|
+
end
|
@@ -1,29 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require "json"
|
3
|
-
require "pathname"
|
4
3
|
|
5
4
|
module ThemeCheck
|
6
|
-
class JsonFile
|
5
|
+
class JsonFile < ThemeFile
|
7
6
|
def initialize(relative_path, storage)
|
8
|
-
|
9
|
-
@storage = storage
|
7
|
+
super
|
10
8
|
@loaded = false
|
11
9
|
@content = nil
|
12
10
|
@parser_error = nil
|
13
11
|
end
|
14
12
|
|
15
|
-
def path
|
16
|
-
@storage.path(@relative_path)
|
17
|
-
end
|
18
|
-
|
19
|
-
def relative_path
|
20
|
-
@relative_pathname ||= Pathname.new(@relative_path)
|
21
|
-
end
|
22
|
-
|
23
|
-
def source
|
24
|
-
@source ||= @storage.read(@relative_path)
|
25
|
-
end
|
26
|
-
|
27
13
|
def content
|
28
14
|
load!
|
29
15
|
@content
|
@@ -34,23 +20,10 @@ module ThemeCheck
|
|
34
20
|
@parser_error
|
35
21
|
end
|
36
22
|
|
37
|
-
def name
|
38
|
-
relative_path.sub_ext('').to_s
|
39
|
-
end
|
40
|
-
|
41
23
|
def json?
|
42
24
|
true
|
43
25
|
end
|
44
26
|
|
45
|
-
def liquid?
|
46
|
-
false
|
47
|
-
end
|
48
|
-
|
49
|
-
def ==(other)
|
50
|
-
other.is_a?(JsonFile) && relative_path == other.relative_path
|
51
|
-
end
|
52
|
-
alias_method :eql?, :==
|
53
|
-
|
54
27
|
private
|
55
28
|
|
56
29
|
def load!
|
@@ -10,5 +10,13 @@ module ThemeCheck
|
|
10
10
|
^\s*render\s+'(?<partial>[^']*)'|
|
11
11
|
^\s*render\s+"(?<partial>[^"]*)"
|
12
12
|
}mix
|
13
|
+
ASSET_INCLUDE = %r{
|
14
|
+
\{\%-?\s*'(?<partial>[^']*)'\s*\|\s*asset_url|
|
15
|
+
\{\%-?\s*"(?<partial>[^"]*)"\s*\|\s*asset_url|
|
16
|
+
|
17
|
+
# in liquid tags the whole line is white space until the asset partial
|
18
|
+
^\s*'(?<partial>[^']*)'\s*\|\s*asset_url|
|
19
|
+
^\s*"(?<partial>[^"]*)"\s*\|\s*asset_url
|
20
|
+
}mix
|
13
21
|
end
|
14
22
|
end
|
@@ -13,7 +13,7 @@ module ThemeCheck
|
|
13
13
|
def document_links(relative_path)
|
14
14
|
buffer = @storage.read(relative_path)
|
15
15
|
return [] unless buffer
|
16
|
-
matches(buffer, PARTIAL_RENDER).map do |match|
|
16
|
+
snippet_matches = matches(buffer, PARTIAL_RENDER).map do |match|
|
17
17
|
start_line, start_character = from_index_to_row_column(
|
18
18
|
buffer,
|
19
19
|
match.begin(:partial),
|
@@ -25,7 +25,7 @@ module ThemeCheck
|
|
25
25
|
)
|
26
26
|
|
27
27
|
{
|
28
|
-
target:
|
28
|
+
target: snippet_link(match[:partial]),
|
29
29
|
range: {
|
30
30
|
start: {
|
31
31
|
line: start_line,
|
@@ -38,10 +38,46 @@ module ThemeCheck
|
|
38
38
|
},
|
39
39
|
}
|
40
40
|
end
|
41
|
+
asset_matches = matches(buffer, ASSET_INCLUDE).map do |match|
|
42
|
+
start_line, start_character = from_index_to_row_column(
|
43
|
+
buffer,
|
44
|
+
match.begin(:partial),
|
45
|
+
)
|
46
|
+
|
47
|
+
end_line, end_character = from_index_to_row_column(
|
48
|
+
buffer,
|
49
|
+
match.end(:partial)
|
50
|
+
)
|
51
|
+
|
52
|
+
{
|
53
|
+
target: asset_link(match[:partial]),
|
54
|
+
range: {
|
55
|
+
start: {
|
56
|
+
line: start_line,
|
57
|
+
character: start_character,
|
58
|
+
},
|
59
|
+
end: {
|
60
|
+
line: end_line,
|
61
|
+
character: end_character,
|
62
|
+
},
|
63
|
+
},
|
64
|
+
}
|
65
|
+
end
|
66
|
+
snippet_matches + asset_matches
|
67
|
+
end
|
68
|
+
|
69
|
+
def snippet_link(partial)
|
70
|
+
file_link('snippets', partial, '.liquid')
|
41
71
|
end
|
42
72
|
|
43
|
-
def
|
44
|
-
|
73
|
+
def asset_link(partial)
|
74
|
+
file_link('assets', partial, '')
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def file_link(directory, partial, extension)
|
80
|
+
"file://#{@storage.path(directory + '/' + partial + extension)}"
|
45
81
|
end
|
46
82
|
end
|
47
83
|
end
|
data/lib/theme_check/tags.rb
CHANGED
@@ -169,14 +169,31 @@ module ThemeCheck
|
|
169
169
|
|
170
170
|
class Stylesheet < Liquid::Raw; end
|
171
171
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
172
|
+
class << self
|
173
|
+
attr_writer :register_tags
|
174
|
+
|
175
|
+
def register_tags?
|
176
|
+
@register_tags
|
177
|
+
end
|
178
|
+
|
179
|
+
def register_tag(name, klass)
|
180
|
+
Liquid::Template.register_tag(name, klass)
|
181
|
+
end
|
182
|
+
|
183
|
+
def register_tags!
|
184
|
+
return if !register_tags? || (defined?(@registered_tags) && @registered_tags)
|
185
|
+
@registered_tags = true
|
186
|
+
register_tag('form', Form)
|
187
|
+
register_tag('layout', Layout)
|
188
|
+
register_tag('render', Render)
|
189
|
+
register_tag('paginate', Paginate)
|
190
|
+
register_tag('section', Section)
|
191
|
+
register_tag('style', Style)
|
192
|
+
register_tag('schema', Schema)
|
193
|
+
register_tag('javascript', Javascript)
|
194
|
+
register_tag('stylesheet', Stylesheet)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
self.register_tags = true
|
181
198
|
end
|
182
199
|
end
|
data/lib/theme_check/template.rb
CHANGED
@@ -1,25 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require "pathname"
|
3
2
|
|
4
3
|
module ThemeCheck
|
5
|
-
class Template
|
6
|
-
def initialize(relative_path, storage)
|
7
|
-
@storage = storage
|
8
|
-
@relative_path = relative_path
|
9
|
-
end
|
10
|
-
|
11
|
-
def path
|
12
|
-
@storage.path(@relative_path)
|
13
|
-
end
|
14
|
-
|
15
|
-
def relative_path
|
16
|
-
@relative_pathname ||= Pathname.new(@relative_path)
|
17
|
-
end
|
18
|
-
|
19
|
-
def source
|
20
|
-
@source ||= @storage.read(@relative_path)
|
21
|
-
end
|
22
|
-
|
4
|
+
class Template < ThemeFile
|
23
5
|
def write
|
24
6
|
content = updated_content
|
25
7
|
if source != content
|
@@ -28,14 +10,6 @@ module ThemeCheck
|
|
28
10
|
end
|
29
11
|
end
|
30
12
|
|
31
|
-
def name
|
32
|
-
relative_path.sub_ext('').to_s
|
33
|
-
end
|
34
|
-
|
35
|
-
def json?
|
36
|
-
false
|
37
|
-
end
|
38
|
-
|
39
13
|
def liquid?
|
40
14
|
true
|
41
15
|
end
|
@@ -88,16 +62,13 @@ module ThemeCheck
|
|
88
62
|
parse.root
|
89
63
|
end
|
90
64
|
|
91
|
-
def ==(other)
|
92
|
-
other.is_a?(Template) && relative_path == other.relative_path
|
93
|
-
end
|
94
|
-
alias_method :eql?, :==
|
95
|
-
|
96
65
|
def self.parse(source)
|
66
|
+
Tags.register_tags!
|
97
67
|
Liquid::Template.parse(
|
98
68
|
source,
|
99
69
|
line_numbers: true,
|
100
70
|
error_mode: :warn,
|
71
|
+
disable_liquid_c_nodes: true,
|
101
72
|
)
|
102
73
|
end
|
103
74
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "pathname"
|
3
|
+
|
4
|
+
module ThemeCheck
|
5
|
+
class ThemeFile
|
6
|
+
def initialize(relative_path, storage)
|
7
|
+
@relative_path = relative_path
|
8
|
+
@storage = storage
|
9
|
+
end
|
10
|
+
|
11
|
+
def path
|
12
|
+
@storage.path(@relative_path)
|
13
|
+
end
|
14
|
+
|
15
|
+
def relative_path
|
16
|
+
@relative_pathname ||= Pathname.new(@relative_path)
|
17
|
+
end
|
18
|
+
|
19
|
+
def name
|
20
|
+
relative_path.sub_ext('').to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
def source
|
24
|
+
@source ||= @storage.read(@relative_path)
|
25
|
+
end
|
26
|
+
|
27
|
+
def json?
|
28
|
+
false
|
29
|
+
end
|
30
|
+
|
31
|
+
def liquid?
|
32
|
+
false
|
33
|
+
end
|
34
|
+
|
35
|
+
def ==(other)
|
36
|
+
other.is_a?(self.class) && relative_path == other.relative_path
|
37
|
+
end
|
38
|
+
alias_method :eql?, :==
|
39
|
+
end
|
40
|
+
end
|
data/lib/theme_check/version.rb
CHANGED
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: 1.
|
4
|
+
version: 1.1.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
|
11
|
+
date: 2021-07-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: liquid
|
@@ -62,6 +62,8 @@ files:
|
|
62
62
|
- Rakefile
|
63
63
|
- bin/liquid-server
|
64
64
|
- config/default.yml
|
65
|
+
- config/nothing.yml
|
66
|
+
- config/theme_app_extension.yml
|
65
67
|
- data/shopify_liquid/deprecated_filters.yml
|
66
68
|
- data/shopify_liquid/filters.yml
|
67
69
|
- data/shopify_liquid/objects.yml
|
@@ -74,6 +76,8 @@ files:
|
|
74
76
|
- docs/api/json_check.md
|
75
77
|
- docs/api/liquid_check.md
|
76
78
|
- docs/checks/TEMPLATE.md.erb
|
79
|
+
- docs/checks/asset_size_app_block_css.md
|
80
|
+
- docs/checks/asset_size_app_block_javascript.md
|
77
81
|
- docs/checks/asset_size_css.md
|
78
82
|
- docs/checks/asset_size_css_stylesheet_tag.md
|
79
83
|
- docs/checks/asset_size_javascript.md
|
@@ -120,6 +124,8 @@ files:
|
|
120
124
|
- lib/theme_check/check.rb
|
121
125
|
- lib/theme_check/checks.rb
|
122
126
|
- lib/theme_check/checks/TEMPLATE.rb.erb
|
127
|
+
- lib/theme_check/checks/asset_size_app_block_css.rb
|
128
|
+
- lib/theme_check/checks/asset_size_app_block_javascript.rb
|
123
129
|
- lib/theme_check/checks/asset_size_css.rb
|
124
130
|
- lib/theme_check/checks/asset_size_css_stylesheet_tag.rb
|
125
131
|
- lib/theme_check/checks/asset_size_javascript.rb
|
@@ -209,6 +215,7 @@ files:
|
|
209
215
|
- lib/theme_check/tags.rb
|
210
216
|
- lib/theme_check/template.rb
|
211
217
|
- lib/theme_check/theme.rb
|
218
|
+
- lib/theme_check/theme_file.rb
|
212
219
|
- lib/theme_check/version.rb
|
213
220
|
- lib/theme_check/visitor.rb
|
214
221
|
- packaging/homebrew/theme_check.base.rb
|