theme-check 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/probots.yml +3 -0
- data/.github/workflows/theme-check.yml +28 -0
- data/.gitignore +13 -0
- data/.rubocop.yml +18 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/CONTRIBUTING.md +132 -0
- data/Gemfile +26 -0
- data/Guardfile +7 -0
- data/LICENSE.md +8 -0
- data/README.md +71 -0
- data/Rakefile +14 -0
- data/bin/liquid-server +4 -0
- data/config/default.yml +63 -0
- data/data/shopify_liquid/filters.yml +174 -0
- data/data/shopify_liquid/objects.yml +81 -0
- data/dev.yml +23 -0
- data/docs/preview.png +0 -0
- data/exe/theme-check +6 -0
- data/exe/theme-check-language-server +12 -0
- data/lib/theme_check.rb +25 -0
- data/lib/theme_check/analyzer.rb +43 -0
- data/lib/theme_check/check.rb +92 -0
- data/lib/theme_check/checks.rb +12 -0
- data/lib/theme_check/checks/convert_include_to_render.rb +13 -0
- data/lib/theme_check/checks/default_locale.rb +12 -0
- data/lib/theme_check/checks/liquid_tag.rb +48 -0
- data/lib/theme_check/checks/matching_schema_translations.rb +73 -0
- data/lib/theme_check/checks/matching_translations.rb +29 -0
- data/lib/theme_check/checks/missing_required_template_files.rb +29 -0
- data/lib/theme_check/checks/missing_template.rb +25 -0
- data/lib/theme_check/checks/nested_snippet.rb +46 -0
- data/lib/theme_check/checks/required_directories.rb +24 -0
- data/lib/theme_check/checks/required_layout_theme_object.rb +40 -0
- data/lib/theme_check/checks/space_inside_braces.rb +58 -0
- data/lib/theme_check/checks/syntax_error.rb +29 -0
- data/lib/theme_check/checks/template_length.rb +18 -0
- data/lib/theme_check/checks/translation_key_exists.rb +35 -0
- data/lib/theme_check/checks/undefined_object.rb +86 -0
- data/lib/theme_check/checks/unknown_filter.rb +25 -0
- data/lib/theme_check/checks/unused_assign.rb +54 -0
- data/lib/theme_check/checks/unused_snippet.rb +34 -0
- data/lib/theme_check/checks/valid_html_translation.rb +43 -0
- data/lib/theme_check/checks/valid_json.rb +14 -0
- data/lib/theme_check/checks/valid_schema.rb +13 -0
- data/lib/theme_check/checks_tracking.rb +8 -0
- data/lib/theme_check/cli.rb +78 -0
- data/lib/theme_check/config.rb +108 -0
- data/lib/theme_check/json_check.rb +11 -0
- data/lib/theme_check/json_file.rb +47 -0
- data/lib/theme_check/json_helpers.rb +9 -0
- data/lib/theme_check/language_server.rb +11 -0
- data/lib/theme_check/language_server/handler.rb +117 -0
- data/lib/theme_check/language_server/server.rb +140 -0
- data/lib/theme_check/liquid_check.rb +13 -0
- data/lib/theme_check/locale_diff.rb +69 -0
- data/lib/theme_check/node.rb +117 -0
- data/lib/theme_check/offense.rb +104 -0
- data/lib/theme_check/parsing_helpers.rb +17 -0
- data/lib/theme_check/printer.rb +74 -0
- data/lib/theme_check/shopify_liquid.rb +3 -0
- data/lib/theme_check/shopify_liquid/filter.rb +18 -0
- data/lib/theme_check/shopify_liquid/object.rb +16 -0
- data/lib/theme_check/tags.rb +146 -0
- data/lib/theme_check/template.rb +73 -0
- data/lib/theme_check/theme.rb +60 -0
- data/lib/theme_check/version.rb +4 -0
- data/lib/theme_check/visitor.rb +37 -0
- data/theme-check.gemspec +28 -0
- metadata +156 -0
@@ -0,0 +1,174 @@
|
|
1
|
+
---
|
2
|
+
Liquid::StandardFilters:
|
3
|
+
- url_encode
|
4
|
+
- where
|
5
|
+
- uniq
|
6
|
+
- escape
|
7
|
+
- replace
|
8
|
+
- remove
|
9
|
+
- h
|
10
|
+
- upcase
|
11
|
+
- downcase
|
12
|
+
- capitalize
|
13
|
+
- date
|
14
|
+
- last
|
15
|
+
- split
|
16
|
+
- size
|
17
|
+
- append
|
18
|
+
- reverse
|
19
|
+
- join
|
20
|
+
- concat
|
21
|
+
- prepend
|
22
|
+
- escape_once
|
23
|
+
- url_decode
|
24
|
+
- truncatewords
|
25
|
+
- strip_html
|
26
|
+
- strip
|
27
|
+
- lstrip
|
28
|
+
- rstrip
|
29
|
+
- strip_newlines
|
30
|
+
- plus
|
31
|
+
- sort_natural
|
32
|
+
- compact
|
33
|
+
- replace_first
|
34
|
+
- remove_first
|
35
|
+
- newline_to_br
|
36
|
+
- minus
|
37
|
+
- divided_by
|
38
|
+
- at_least
|
39
|
+
- at_most
|
40
|
+
- sort
|
41
|
+
- default
|
42
|
+
- modulo
|
43
|
+
- slice
|
44
|
+
- abs
|
45
|
+
- map
|
46
|
+
- floor
|
47
|
+
- ceil
|
48
|
+
- round
|
49
|
+
- truncate
|
50
|
+
- first
|
51
|
+
- times
|
52
|
+
FormFilter:
|
53
|
+
- payment_button
|
54
|
+
- payment_terms
|
55
|
+
- installments_pricing
|
56
|
+
- default_errors
|
57
|
+
DateFilter:
|
58
|
+
- date
|
59
|
+
I18nFilter:
|
60
|
+
- translate
|
61
|
+
- t
|
62
|
+
- date
|
63
|
+
- sentence
|
64
|
+
- time_tag
|
65
|
+
UrlFilter:
|
66
|
+
- image_url
|
67
|
+
- stylesheet_tag
|
68
|
+
- script_tag
|
69
|
+
- img_tag
|
70
|
+
- shopify_asset_url
|
71
|
+
- payment_type_img_url
|
72
|
+
- payment_type_svg_tag
|
73
|
+
- placeholder_svg_tag
|
74
|
+
- link_to
|
75
|
+
- asset_url
|
76
|
+
- img_url
|
77
|
+
- asset_img_url
|
78
|
+
- global_asset_url
|
79
|
+
- file_url
|
80
|
+
- file_img_url
|
81
|
+
- product_img_url
|
82
|
+
- collection_img_url
|
83
|
+
- article_img_url
|
84
|
+
JsonFilter:
|
85
|
+
- json
|
86
|
+
ColorFilter:
|
87
|
+
- color_contrast
|
88
|
+
- color_difference
|
89
|
+
- brightness_difference
|
90
|
+
- hex_to_rgba
|
91
|
+
- color_to_rgb
|
92
|
+
- color_to_hsl
|
93
|
+
- color_to_hex
|
94
|
+
- color_extract
|
95
|
+
- color_brightness
|
96
|
+
- color_modify
|
97
|
+
- color_lighten
|
98
|
+
- color_darken
|
99
|
+
- color_saturate
|
100
|
+
- color_desaturate
|
101
|
+
- color_mix
|
102
|
+
MoneyFilter:
|
103
|
+
- money_without_currency
|
104
|
+
- money_without_trailing_zeros
|
105
|
+
- money
|
106
|
+
- money_with_currency
|
107
|
+
StringFilter:
|
108
|
+
- handleize
|
109
|
+
- url_param_escape
|
110
|
+
- url_escape
|
111
|
+
- camelcase
|
112
|
+
- camelize
|
113
|
+
- encode_url_component
|
114
|
+
- format_code
|
115
|
+
- md5
|
116
|
+
- handle
|
117
|
+
CollectionFilter:
|
118
|
+
- within
|
119
|
+
- link_to_vendor
|
120
|
+
- url_for_vendor
|
121
|
+
- link_to_type
|
122
|
+
- url_for_type
|
123
|
+
- sort_by
|
124
|
+
TagFilter:
|
125
|
+
- link_to_add_tag
|
126
|
+
- link_to_remove_tag
|
127
|
+
- link_to_tag
|
128
|
+
- highlight_active_tag
|
129
|
+
CryptoFilter:
|
130
|
+
- hmac_sha1
|
131
|
+
- sha256
|
132
|
+
- hmac_sha256
|
133
|
+
- md5
|
134
|
+
- sha1
|
135
|
+
CustomerAccountFilter:
|
136
|
+
- customer_login_link
|
137
|
+
- customer_logout_link
|
138
|
+
- customer_register_link
|
139
|
+
- recover_password_link
|
140
|
+
- delete_customer_address_link
|
141
|
+
- edit_customer_address_link
|
142
|
+
- cancel_customer_order_link
|
143
|
+
CurrencyFormFilter:
|
144
|
+
- currency_selector
|
145
|
+
PaginationFilter:
|
146
|
+
- default_pagination
|
147
|
+
WeightFilter:
|
148
|
+
- weight
|
149
|
+
- weight_with_unit
|
150
|
+
- unit
|
151
|
+
TextFilter:
|
152
|
+
- pad_spaces
|
153
|
+
- paragraphize
|
154
|
+
- highlight
|
155
|
+
- format_address
|
156
|
+
- excerpt
|
157
|
+
- pluralize
|
158
|
+
FontFilter:
|
159
|
+
- font_face
|
160
|
+
- font_url
|
161
|
+
- font_modify
|
162
|
+
DistanceFilter:
|
163
|
+
- distance_from
|
164
|
+
MediaFilter:
|
165
|
+
- external_video_url
|
166
|
+
- external_video_tag
|
167
|
+
- video_tag
|
168
|
+
- model_viewer_tag
|
169
|
+
- media_tag
|
170
|
+
ThemeFilter:
|
171
|
+
- theme_url
|
172
|
+
- link_to_theme
|
173
|
+
DebugFilter:
|
174
|
+
- debug
|
@@ -0,0 +1,81 @@
|
|
1
|
+
---
|
2
|
+
- additional_checkout_buttons
|
3
|
+
- address
|
4
|
+
- all_country_option_tags
|
5
|
+
- all_products
|
6
|
+
- article
|
7
|
+
- articles
|
8
|
+
- block
|
9
|
+
- blog
|
10
|
+
- blogs
|
11
|
+
- canonical_url
|
12
|
+
- cart
|
13
|
+
- checkout
|
14
|
+
- collection
|
15
|
+
- collections
|
16
|
+
- comment
|
17
|
+
- content_for_additional_checkout_buttons
|
18
|
+
- content_for_header
|
19
|
+
- content_for_index
|
20
|
+
- content_for_layout
|
21
|
+
- country_option_tags
|
22
|
+
- currency
|
23
|
+
- current_page
|
24
|
+
- current_tags
|
25
|
+
- customer
|
26
|
+
- customer_address
|
27
|
+
- discount_allocation
|
28
|
+
- discount_application
|
29
|
+
- external_video
|
30
|
+
- font
|
31
|
+
- forloop
|
32
|
+
- form
|
33
|
+
- fulfillment
|
34
|
+
- gift_card
|
35
|
+
- handle
|
36
|
+
- image
|
37
|
+
- images
|
38
|
+
- line_item
|
39
|
+
- link
|
40
|
+
- linklist
|
41
|
+
- linklists
|
42
|
+
- location
|
43
|
+
- metafield
|
44
|
+
- model
|
45
|
+
- model_source
|
46
|
+
- order
|
47
|
+
- page
|
48
|
+
- page_description
|
49
|
+
- page_image
|
50
|
+
- page_title
|
51
|
+
- pages
|
52
|
+
- paginate
|
53
|
+
- part
|
54
|
+
- policy
|
55
|
+
- powered_by_link
|
56
|
+
- product
|
57
|
+
- product_option
|
58
|
+
- recommendations
|
59
|
+
- request
|
60
|
+
- routes
|
61
|
+
- script
|
62
|
+
- scripts
|
63
|
+
- search
|
64
|
+
- section
|
65
|
+
- selling_plan
|
66
|
+
- selling_plan_allocation
|
67
|
+
- selling_plan_group
|
68
|
+
- settings
|
69
|
+
- shipping_method
|
70
|
+
- shop
|
71
|
+
- shop_locale
|
72
|
+
- store_availability
|
73
|
+
- tablerow
|
74
|
+
- tax_line
|
75
|
+
- template
|
76
|
+
- theme
|
77
|
+
- transaction
|
78
|
+
- unit_price_measurement
|
79
|
+
- variant
|
80
|
+
- video
|
81
|
+
- video_source
|
data/dev.yml
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
name: theme-check
|
2
|
+
|
3
|
+
type: ruby
|
4
|
+
|
5
|
+
up:
|
6
|
+
- ruby: 2.7.1
|
7
|
+
- bundler
|
8
|
+
|
9
|
+
commands:
|
10
|
+
check:
|
11
|
+
desc: 'Check a theme'
|
12
|
+
syntax:
|
13
|
+
argument: file
|
14
|
+
run: bundle exec theme-check
|
15
|
+
test:
|
16
|
+
syntax:
|
17
|
+
argument: file
|
18
|
+
optional: args...
|
19
|
+
run: bundle exec rake test
|
20
|
+
style:
|
21
|
+
run: bundle exec rake rubocop
|
22
|
+
language-server:
|
23
|
+
run: bundle exec theme-check-language-server
|
data/docs/preview.png
ADDED
Binary file
|
data/exe/theme-check
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'theme_check'
|
5
|
+
|
6
|
+
if ENV["THEME_CHECK_DEBUG"] == "true"
|
7
|
+
$DEBUG = true
|
8
|
+
end
|
9
|
+
# Force encoding to UTF-8 to fix VSCode
|
10
|
+
Encoding.default_external = Encoding::UTF_8
|
11
|
+
status_code = ThemeCheck::LanguageServer.start
|
12
|
+
exit! status_code
|
data/lib/theme_check.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "liquid"
|
3
|
+
|
4
|
+
require_relative "theme_check/analyzer"
|
5
|
+
require_relative "theme_check/check"
|
6
|
+
require_relative "theme_check/checks_tracking"
|
7
|
+
require_relative "theme_check/cli"
|
8
|
+
require_relative "theme_check/liquid_check"
|
9
|
+
require_relative "theme_check/locale_diff"
|
10
|
+
require_relative "theme_check/json_check"
|
11
|
+
require_relative "theme_check/json_file"
|
12
|
+
require_relative "theme_check/json_helpers"
|
13
|
+
require_relative "theme_check/language_server"
|
14
|
+
require_relative "theme_check/checks"
|
15
|
+
require_relative "theme_check/config"
|
16
|
+
require_relative "theme_check/node"
|
17
|
+
require_relative "theme_check/offense"
|
18
|
+
require_relative "theme_check/printer"
|
19
|
+
require_relative "theme_check/shopify_liquid"
|
20
|
+
require_relative "theme_check/tags"
|
21
|
+
require_relative "theme_check/template"
|
22
|
+
require_relative "theme_check/theme"
|
23
|
+
require_relative "theme_check/visitor"
|
24
|
+
|
25
|
+
Dir[__dir__ + "/theme_check/checks/*.rb"].each { |file| require file }
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module ThemeCheck
|
3
|
+
class Analyzer
|
4
|
+
attr_reader :offenses
|
5
|
+
|
6
|
+
def initialize(theme, checks = Check.all.map(&:new))
|
7
|
+
@theme = theme
|
8
|
+
@offenses = []
|
9
|
+
|
10
|
+
@liquid_checks = Checks.new
|
11
|
+
@json_checks = Checks.new
|
12
|
+
|
13
|
+
checks.each do |check|
|
14
|
+
check.theme = @theme
|
15
|
+
check.offenses = @offenses
|
16
|
+
|
17
|
+
case check
|
18
|
+
when LiquidCheck
|
19
|
+
@liquid_checks << check
|
20
|
+
when JsonCheck
|
21
|
+
@json_checks << check
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
@visitor = Visitor.new(@liquid_checks)
|
26
|
+
end
|
27
|
+
|
28
|
+
def analyze_theme
|
29
|
+
@offenses.clear
|
30
|
+
@theme.liquid.each { |template| @visitor.visit_template(template) }
|
31
|
+
@theme.json.each { |json_file| @json_checks.call(:on_file, json_file) }
|
32
|
+
@liquid_checks.call(:on_end)
|
33
|
+
@json_checks.call(:on_end)
|
34
|
+
@offenses
|
35
|
+
end
|
36
|
+
|
37
|
+
def analyze_file(path)
|
38
|
+
path = Pathname.new(path)
|
39
|
+
analyze_theme
|
40
|
+
@offenses.reject! { |offense| offense.template.path != path }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative "json_helpers"
|
3
|
+
|
4
|
+
module ThemeCheck
|
5
|
+
class Check
|
6
|
+
include JsonHelpers
|
7
|
+
|
8
|
+
attr_accessor :theme
|
9
|
+
attr_accessor :offenses
|
10
|
+
attr_accessor :options
|
11
|
+
|
12
|
+
SEVERITIES = [
|
13
|
+
:error,
|
14
|
+
:suggestion,
|
15
|
+
:style,
|
16
|
+
]
|
17
|
+
|
18
|
+
CATEGORIES = [
|
19
|
+
:liquid,
|
20
|
+
:translation,
|
21
|
+
:json,
|
22
|
+
]
|
23
|
+
|
24
|
+
class << self
|
25
|
+
def all
|
26
|
+
@all ||= []
|
27
|
+
end
|
28
|
+
|
29
|
+
def severity(severity = nil)
|
30
|
+
if severity
|
31
|
+
unless SEVERITIES.include?(severity)
|
32
|
+
raise ArgumentError, "unknown severity. Use: #{SEVERITIES.join(', ')}"
|
33
|
+
end
|
34
|
+
@severity = severity
|
35
|
+
end
|
36
|
+
@severity if defined?(@severity)
|
37
|
+
end
|
38
|
+
|
39
|
+
def category(category = nil)
|
40
|
+
if category
|
41
|
+
unless CATEGORIES.include?(category)
|
42
|
+
raise ArgumentError, "unknown category. Use: #{CATEGORIES.join(', ')}"
|
43
|
+
end
|
44
|
+
@category = category
|
45
|
+
end
|
46
|
+
@category if defined?(@category)
|
47
|
+
end
|
48
|
+
|
49
|
+
def doc(doc = nil)
|
50
|
+
@doc = doc if doc
|
51
|
+
@doc if defined?(@doc)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def severity
|
56
|
+
self.class.severity
|
57
|
+
end
|
58
|
+
|
59
|
+
def category
|
60
|
+
self.class.category
|
61
|
+
end
|
62
|
+
|
63
|
+
def doc
|
64
|
+
self.class.doc
|
65
|
+
end
|
66
|
+
|
67
|
+
def code_name
|
68
|
+
self.class.name.demodulize
|
69
|
+
end
|
70
|
+
|
71
|
+
def ignore!
|
72
|
+
@ignored = true
|
73
|
+
end
|
74
|
+
|
75
|
+
def unignore!
|
76
|
+
@ignored = false
|
77
|
+
end
|
78
|
+
|
79
|
+
def ignored?
|
80
|
+
defined?(@ignored) && @ignored
|
81
|
+
end
|
82
|
+
|
83
|
+
def to_s
|
84
|
+
s = +"#{code_name}:\n"
|
85
|
+
properties = { severity: severity, category: category, doc: doc }.merge(options)
|
86
|
+
properties.each_pair do |name, value|
|
87
|
+
s << " #{name}: #{value}\n" if value
|
88
|
+
end
|
89
|
+
s
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|