theme-check 0.1.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CONTRIBUTING.md +2 -0
- data/README.md +62 -1
- data/RELEASING.md +41 -0
- data/Rakefile +38 -4
- data/config/default.yml +18 -0
- data/data/shopify_liquid/deprecated_filters.yml +10 -0
- data/data/shopify_liquid/plus_objects.yml +15 -0
- data/dev.yml +2 -0
- data/lib/theme_check.rb +5 -0
- data/lib/theme_check/analyzer.rb +15 -5
- data/lib/theme_check/check.rb +11 -0
- data/lib/theme_check/checks.rb +10 -0
- data/lib/theme_check/checks/deprecated_filter.rb +22 -0
- data/lib/theme_check/checks/missing_enable_comment.rb +31 -0
- data/lib/theme_check/checks/missing_required_template_files.rb +12 -12
- data/lib/theme_check/checks/parser_blocking_javascript.rb +55 -0
- data/lib/theme_check/checks/space_inside_braces.rb +19 -7
- data/lib/theme_check/checks/template_length.rb +11 -3
- data/lib/theme_check/checks/undefined_object.rb +107 -34
- data/lib/theme_check/checks/valid_html_translation.rb +2 -2
- data/lib/theme_check/cli.rb +18 -4
- data/lib/theme_check/config.rb +97 -44
- data/lib/theme_check/corrector.rb +31 -0
- data/lib/theme_check/disabled_checks.rb +77 -0
- data/lib/theme_check/file_system_storage.rb +51 -0
- data/lib/theme_check/in_memory_storage.rb +37 -0
- data/lib/theme_check/json_file.rb +12 -10
- data/lib/theme_check/language_server/handler.rb +38 -13
- data/lib/theme_check/language_server/server.rb +2 -2
- data/lib/theme_check/liquid_check.rb +2 -2
- data/lib/theme_check/node.rb +13 -0
- data/lib/theme_check/offense.rb +25 -9
- data/lib/theme_check/packager.rb +51 -0
- data/lib/theme_check/printer.rb +13 -4
- data/lib/theme_check/shopify_liquid.rb +1 -0
- data/lib/theme_check/shopify_liquid/deprecated_filter.rb +28 -0
- data/lib/theme_check/shopify_liquid/object.rb +6 -0
- data/lib/theme_check/storage.rb +25 -0
- data/lib/theme_check/template.rb +32 -10
- data/lib/theme_check/theme.rb +14 -9
- data/lib/theme_check/version.rb +1 -1
- data/lib/theme_check/visitor.rb +14 -3
- data/packaging/homebrew/theme_check.base.rb +98 -0
- metadata +21 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a07597b217b1f596cd5e777726950e396934726f3572bc7660129bec2b3b30c8
|
4
|
+
data.tar.gz: 80e54966286e332f3308021b9347feb4cdb683497991b9bb451dcf58f138a2df
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4c7a1c159dd1b688618c95e1e5fb943a133b606878f57c91b12e5793b07022325c5cfb2e81c49cb45ea484cb3688c6f7c2b75af1b2a50f13da6db2ba0e8b0bb3
|
7
|
+
data.tar.gz: 83fe6a74375ecf2b58f14681c99bc672a710cd6bbc70cb5f58ff06332d4123171544f6cf73c6e7f5f750c1a870d17de0ce3bd3e1f9cbfca6e1bdc7fceb767b80
|
data/.gitignore
CHANGED
data/CONTRIBUTING.md
CHANGED
data/README.md
CHANGED
@@ -30,13 +30,32 @@ Theme Check currently checks for the following:
|
|
30
30
|
✅ Unmatching translation keys in locale files
|
31
31
|
✅ Using unknown translation keys in `{{ 'missing_key' | t }}`
|
32
32
|
✅ Using several `{% ... %}` instead of `{% liquid ... %}`
|
33
|
-
✅ Undefined [objects](https://shopify.dev/docs/themes/liquid/reference/objects)
|
33
|
+
✅ Undefined [objects](https://shopify.dev/docs/themes/liquid/reference/objects)
|
34
|
+
✅ Deprecated filters
|
35
|
+
✅ Missing `theme-check-enable` comment
|
34
36
|
|
35
37
|
And many more to come! Suggestions welcome ([create an issue](https://github.com/Shopify/theme-check/issues)).
|
36
38
|
|
39
|
+
## Requirements
|
40
|
+
|
41
|
+
- Ruby 2.7+
|
42
|
+
|
37
43
|
## Installation
|
38
44
|
|
45
|
+
Theme Check is available through Homebrew _or_ RubyGems.
|
46
|
+
|
47
|
+
**Homebrew**
|
48
|
+
|
49
|
+
You’ll need to run `brew tap` first to add Shopify’s third-party repositories to Homebrew.
|
50
|
+
|
51
|
+
```sh
|
52
|
+
brew tap shopify/shopify
|
53
|
+
brew install theme-check
|
39
54
|
```
|
55
|
+
|
56
|
+
**RubyGems**
|
57
|
+
|
58
|
+
```sh
|
40
59
|
gem install theme-check
|
41
60
|
```
|
42
61
|
|
@@ -61,11 +80,53 @@ Add a `.theme-check.yml` file at the root of your theme to configure:
|
|
61
80
|
# be uploaded to Shopify.
|
62
81
|
root: dist
|
63
82
|
|
83
|
+
# It is possible to extend theme-check with custom checks
|
84
|
+
require:
|
85
|
+
- ./path/to/my_custom_check.rb
|
86
|
+
|
64
87
|
# Disable some checks
|
65
88
|
TemplateLength:
|
66
89
|
enabled: false
|
67
90
|
# Or configure options
|
68
91
|
max_length: 300
|
92
|
+
|
93
|
+
# Enable a custom check
|
94
|
+
MyCustomCheck
|
95
|
+
enabled: true
|
69
96
|
```
|
70
97
|
|
71
98
|
See [config/default.yml](config/default.yml) for available options & defaults.
|
99
|
+
|
100
|
+
## Disable checks with comments
|
101
|
+
|
102
|
+
Use Liquid comments to disable and re-enable all checks for a section of your template:
|
103
|
+
|
104
|
+
```liquid
|
105
|
+
{% comment %}theme-check-disable{% endcomment %}
|
106
|
+
{% assign x = 1 %}
|
107
|
+
{% comment %}theme-check-enable{% endcomment %}
|
108
|
+
```
|
109
|
+
|
110
|
+
Disable a specific check by including it in the comment:
|
111
|
+
|
112
|
+
```liquid
|
113
|
+
{% comment %}theme-check-disable UnusedAssign{% endcomment %}
|
114
|
+
{% assign x = 1 %}
|
115
|
+
{% comment %}theme-check-enable UnusedAssign{% endcomment %}
|
116
|
+
```
|
117
|
+
|
118
|
+
Disable multiple checks by including them as a comma-separated list:
|
119
|
+
|
120
|
+
```liquid
|
121
|
+
{% comment %}theme-check-disable UnusedAssign,SpaceInsideBraces{% endcomment %}
|
122
|
+
{%assign x = 1%}
|
123
|
+
{% comment %}theme-check-enable UnusedAssign,SpaceInsideBraces{% endcomment %}
|
124
|
+
```
|
125
|
+
|
126
|
+
Disable checks for the _entire document_ by placing the comment on the first line:
|
127
|
+
|
128
|
+
```liquid
|
129
|
+
{% comment %}theme-check-disable SpaceInsideBraces{% endcomment %}
|
130
|
+
|
131
|
+
{%assign x = 1%}
|
132
|
+
```
|
data/RELEASING.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
## Releasing Theme Check
|
2
|
+
|
3
|
+
1. Check the Semantic Versioning page for info on how to version the new release: http://semver.org
|
4
|
+
|
5
|
+
2. Create a PR to update the version in `lib/theme_check/version.rb`
|
6
|
+
|
7
|
+
3. Merge your PR to master
|
8
|
+
|
9
|
+
4. On [Shipit](https://shipit.shopify.io/shopify/theme-check/rubygems), deploy your commit.
|
10
|
+
|
11
|
+
## Homebrew Release Process
|
12
|
+
|
13
|
+
1. Release `theme-check` on RubyGems by following the steps in the previous section.
|
14
|
+
|
15
|
+
2. Generate the homebrew formula.
|
16
|
+
|
17
|
+
```bash
|
18
|
+
rake package
|
19
|
+
```
|
20
|
+
|
21
|
+
3. Copy the formula over in the [`homebrew-shopify`](https://github.com/Shopify/homebrew-shopify) repository.
|
22
|
+
|
23
|
+
```bash
|
24
|
+
VERSION=X.X.X
|
25
|
+
cp packaging/builds/$VERSION/theme-check ../homebrew-shopify
|
26
|
+
```
|
27
|
+
|
28
|
+
4. Create a branch + a commit on the [`homebrew-shopify`](https://github.com/Shopify/homebrew-shopify) repository.
|
29
|
+
|
30
|
+
```bash
|
31
|
+
git checkout -b "bump/theme-check-$VERSION"
|
32
|
+
git add theme-check.rb
|
33
|
+
git commit -m "Bump theme-check version to $VERSION"
|
34
|
+
```
|
35
|
+
|
36
|
+
5. Create a pull-request for those changes on the [`homebrew-shopify`](https://github.com/Shopify/homebrew-shopify) repository.
|
37
|
+
|
38
|
+
```bash
|
39
|
+
# shortcut if you have `hub` installed
|
40
|
+
hub compare "master:bump/theme-check-$VERSION"
|
41
|
+
```
|
data/Rakefile
CHANGED
@@ -3,12 +3,46 @@ require "rake/testtask"
|
|
3
3
|
require "rubocop/rake_task"
|
4
4
|
require "bundler/gem_tasks"
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
namespace :tests do
|
7
|
+
task all: [:in_memory, :file_system]
|
8
|
+
|
9
|
+
Rake::TestTask.new(:suite) do |t|
|
10
|
+
t.libs << "test"
|
11
|
+
t.libs << "lib"
|
12
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
13
|
+
end
|
14
|
+
|
15
|
+
desc("Runs the tests with InMemoryStorage")
|
16
|
+
task :in_memory do
|
17
|
+
ENV["THEME_STORAGE"] = 'InMemoryStorage'
|
18
|
+
puts "Running tests with #{ENV['THEME_STORAGE']}"
|
19
|
+
Rake::Task['tests:suite'].execute
|
20
|
+
end
|
21
|
+
|
22
|
+
desc("Runs the tests with FileSystemStorage")
|
23
|
+
task :file_system do
|
24
|
+
ENV["THEME_STORAGE"] = 'FileSystemStorage'
|
25
|
+
puts "Running tests with #{ENV['THEME_STORAGE']}"
|
26
|
+
Rake::Task['tests:suite'].execute
|
27
|
+
end
|
10
28
|
end
|
11
29
|
|
30
|
+
task(test: 'tests:all')
|
31
|
+
|
12
32
|
RuboCop::RakeTask.new
|
13
33
|
|
14
34
|
task default: [:test, :rubocop]
|
35
|
+
|
36
|
+
namespace :package do
|
37
|
+
require 'theme_check/packager'
|
38
|
+
|
39
|
+
task all: [:homebrew]
|
40
|
+
|
41
|
+
desc("Builds a Homebrew package of the CLI")
|
42
|
+
task :homebrew do
|
43
|
+
ThemeCheck::Packager.new.build_homebrew
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
desc("Builds all distribution packages of the CLI")
|
48
|
+
task(package: 'package:all')
|
data/config/default.yml
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
root: .
|
2
|
+
|
3
|
+
require: []
|
4
|
+
|
5
|
+
ignore:
|
6
|
+
- node_modules/*
|
7
|
+
|
1
8
|
ConvertIncludeToRender:
|
2
9
|
enabled: true
|
3
10
|
|
@@ -22,6 +29,8 @@ SyntaxError:
|
|
22
29
|
TemplateLength:
|
23
30
|
enabled: true
|
24
31
|
max_length: 200
|
32
|
+
# Exclude content of {% schema %} in line count
|
33
|
+
exclude_schema: true
|
25
34
|
|
26
35
|
UnknownFilter:
|
27
36
|
enabled: true
|
@@ -61,3 +70,12 @@ UndefinedObject:
|
|
61
70
|
|
62
71
|
RequiredDirectories:
|
63
72
|
enabled: true
|
73
|
+
|
74
|
+
DeprecatedFilter:
|
75
|
+
enabled: true
|
76
|
+
|
77
|
+
MissingEnableComment:
|
78
|
+
enabled: true
|
79
|
+
|
80
|
+
ParserBlockingJavaScript:
|
81
|
+
enabled: true
|
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
- alternative_payment_methods
|
3
|
+
- breadcrumb
|
4
|
+
- checkout_html_classes
|
5
|
+
- checkout_scripts
|
6
|
+
- checkout_stylesheets
|
7
|
+
- content_for_footer
|
8
|
+
- content_for_logo
|
9
|
+
- content_for_order_summary
|
10
|
+
- direction
|
11
|
+
- locale
|
12
|
+
- order_summary_toggle
|
13
|
+
- page_title
|
14
|
+
- skip_to_content_link
|
15
|
+
- tracking_code
|
data/dev.yml
CHANGED
data/lib/theme_check.rb
CHANGED
@@ -5,6 +5,7 @@ require_relative "theme_check/analyzer"
|
|
5
5
|
require_relative "theme_check/check"
|
6
6
|
require_relative "theme_check/checks_tracking"
|
7
7
|
require_relative "theme_check/cli"
|
8
|
+
require_relative "theme_check/disabled_checks"
|
8
9
|
require_relative "theme_check/liquid_check"
|
9
10
|
require_relative "theme_check/locale_diff"
|
10
11
|
require_relative "theme_check/json_check"
|
@@ -17,9 +18,13 @@ require_relative "theme_check/node"
|
|
17
18
|
require_relative "theme_check/offense"
|
18
19
|
require_relative "theme_check/printer"
|
19
20
|
require_relative "theme_check/shopify_liquid"
|
21
|
+
require_relative "theme_check/storage"
|
22
|
+
require_relative "theme_check/file_system_storage"
|
23
|
+
require_relative "theme_check/in_memory_storage"
|
20
24
|
require_relative "theme_check/tags"
|
21
25
|
require_relative "theme_check/template"
|
22
26
|
require_relative "theme_check/theme"
|
23
27
|
require_relative "theme_check/visitor"
|
28
|
+
require_relative "theme_check/corrector"
|
24
29
|
|
25
30
|
Dir[__dir__ + "/theme_check/checks/*.rb"].each { |file| require file }
|
data/lib/theme_check/analyzer.rb
CHANGED
@@ -3,9 +3,10 @@ module ThemeCheck
|
|
3
3
|
class Analyzer
|
4
4
|
attr_reader :offenses
|
5
5
|
|
6
|
-
def initialize(theme, checks = Check.all.map(&:new))
|
6
|
+
def initialize(theme, checks = Check.all.map(&:new), auto_correct = false)
|
7
7
|
@theme = theme
|
8
8
|
@offenses = []
|
9
|
+
@auto_correct = auto_correct
|
9
10
|
|
10
11
|
@liquid_checks = Checks.new
|
11
12
|
@json_checks = Checks.new
|
@@ -34,10 +35,19 @@ module ThemeCheck
|
|
34
35
|
@offenses
|
35
36
|
end
|
36
37
|
|
37
|
-
def
|
38
|
-
|
39
|
-
|
40
|
-
|
38
|
+
def uncorrectable_offenses
|
39
|
+
unless @auto_correct
|
40
|
+
return @offenses
|
41
|
+
end
|
42
|
+
|
43
|
+
@offenses.select { |offense| !offense.correctable? }
|
44
|
+
end
|
45
|
+
|
46
|
+
def correct_offenses
|
47
|
+
if @auto_correct
|
48
|
+
@offenses.each(&:correct)
|
49
|
+
@theme.liquid.each(&:write)
|
50
|
+
end
|
41
51
|
end
|
42
52
|
end
|
43
53
|
end
|
data/lib/theme_check/check.rb
CHANGED
@@ -50,6 +50,13 @@ module ThemeCheck
|
|
50
50
|
@doc = doc if doc
|
51
51
|
@doc if defined?(@doc)
|
52
52
|
end
|
53
|
+
|
54
|
+
def can_disable(disableable = nil)
|
55
|
+
unless disableable.nil?
|
56
|
+
@can_disable = disableable
|
57
|
+
end
|
58
|
+
defined?(@can_disable) ? @can_disable : true
|
59
|
+
end
|
53
60
|
end
|
54
61
|
|
55
62
|
def severity
|
@@ -80,6 +87,10 @@ module ThemeCheck
|
|
80
87
|
defined?(@ignored) && @ignored
|
81
88
|
end
|
82
89
|
|
90
|
+
def can_disable?
|
91
|
+
self.class.can_disable
|
92
|
+
end
|
93
|
+
|
83
94
|
def to_s
|
84
95
|
s = +"#{code_name}:\n"
|
85
96
|
properties = { severity: severity, category: category, doc: doc }.merge(options)
|
data/lib/theme_check/checks.rb
CHANGED
@@ -8,5 +8,15 @@ module ThemeCheck
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
end
|
11
|
+
|
12
|
+
def always_enabled
|
13
|
+
self.class.new(reject(&:can_disable?))
|
14
|
+
end
|
15
|
+
|
16
|
+
def except_for(disabled_checks)
|
17
|
+
still_enabled = reject { |check| disabled_checks.all.include?(check.code_name) }
|
18
|
+
|
19
|
+
self.class.new((always_enabled + still_enabled).uniq)
|
20
|
+
end
|
11
21
|
end
|
12
22
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module ThemeCheck
|
3
|
+
class DeprecatedFilter < LiquidCheck
|
4
|
+
doc "https://shopify.dev/docs/themes/liquid/reference/filters/deprecated-filters"
|
5
|
+
category :liquid
|
6
|
+
severity :suggestion
|
7
|
+
|
8
|
+
def on_variable(node)
|
9
|
+
used_filters = node.value.filters.map { |name, *_rest| name }
|
10
|
+
used_filters.each do |filter|
|
11
|
+
alternatives = ShopifyLiquid::DeprecatedFilter.alternatives(filter)
|
12
|
+
next unless alternatives
|
13
|
+
|
14
|
+
alternatives = alternatives.map { |alt| "`#{alt}`" }
|
15
|
+
add_offense(
|
16
|
+
"Deprecated filter `#{filter}`, consider using an alternative: #{alternatives.join(', ')}",
|
17
|
+
node: node,
|
18
|
+
)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module ThemeCheck
|
3
|
+
class MissingEnableComment < LiquidCheck
|
4
|
+
severity :error
|
5
|
+
|
6
|
+
# Don't allow this check to be disabled with a comment,
|
7
|
+
# as we need to be able to check for disabled checks.
|
8
|
+
can_disable false
|
9
|
+
|
10
|
+
def on_document(_node)
|
11
|
+
@disabled_checks = DisabledChecks.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def on_comment(node)
|
15
|
+
@disabled_checks.update(node)
|
16
|
+
end
|
17
|
+
|
18
|
+
def after_document(node)
|
19
|
+
return if @disabled_checks.full_document_disabled?
|
20
|
+
return unless @disabled_checks.any?
|
21
|
+
|
22
|
+
message = if @disabled_checks.all_disabled?
|
23
|
+
"All checks were"
|
24
|
+
else
|
25
|
+
@disabled_checks.all.join(', ') + " " + (@disabled_checks.all.size == 1 ? "was" : "were")
|
26
|
+
end
|
27
|
+
|
28
|
+
add_offense("#{message} disabled but not re-enabled with theme-check-enable", node: node)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -9,21 +9,21 @@ module ThemeCheck
|
|
9
9
|
category :liquid
|
10
10
|
doc "https://shopify.dev/docs/themes/theme-templates"
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
REQUIRED_LIQUID_FILES = %w(layout/theme)
|
13
|
+
REQUIRED_TEMPLATE_FILES = %w(
|
14
|
+
index product collection cart blog article page list-collections search 404
|
15
|
+
gift_card customers/account customers/activate_account customers/addresses
|
16
|
+
customers/login customers/order customers/register customers/reset_password password
|
17
|
+
)
|
16
18
|
.map { |file| "templates/#{file}" }
|
17
19
|
|
18
20
|
def on_end
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
def add_missing_file_offense(file)
|
26
|
-
add_offense("Theme is missing '#{file}.liquid' file")
|
21
|
+
(REQUIRED_LIQUID_FILES - theme.liquid.map(&:name)).each do |file|
|
22
|
+
add_offense("'#{file}.liquid' is missing")
|
23
|
+
end
|
24
|
+
(REQUIRED_TEMPLATE_FILES - (theme.liquid + theme.json).map(&:name)).each do |file|
|
25
|
+
add_offense("'#{file}.liquid' or '#{file}.json' is missing")
|
26
|
+
end
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|