theme-check 0.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.
Files changed (70) hide show
  1. checksums.yaml +7 -0
  2. data/.github/probots.yml +3 -0
  3. data/.github/workflows/theme-check.yml +28 -0
  4. data/.gitignore +13 -0
  5. data/.rubocop.yml +18 -0
  6. data/CODE_OF_CONDUCT.md +74 -0
  7. data/CONTRIBUTING.md +132 -0
  8. data/Gemfile +26 -0
  9. data/Guardfile +7 -0
  10. data/LICENSE.md +8 -0
  11. data/README.md +71 -0
  12. data/Rakefile +14 -0
  13. data/bin/liquid-server +4 -0
  14. data/config/default.yml +63 -0
  15. data/data/shopify_liquid/filters.yml +174 -0
  16. data/data/shopify_liquid/objects.yml +81 -0
  17. data/dev.yml +23 -0
  18. data/docs/preview.png +0 -0
  19. data/exe/theme-check +6 -0
  20. data/exe/theme-check-language-server +12 -0
  21. data/lib/theme_check.rb +25 -0
  22. data/lib/theme_check/analyzer.rb +43 -0
  23. data/lib/theme_check/check.rb +92 -0
  24. data/lib/theme_check/checks.rb +12 -0
  25. data/lib/theme_check/checks/convert_include_to_render.rb +13 -0
  26. data/lib/theme_check/checks/default_locale.rb +12 -0
  27. data/lib/theme_check/checks/liquid_tag.rb +48 -0
  28. data/lib/theme_check/checks/matching_schema_translations.rb +73 -0
  29. data/lib/theme_check/checks/matching_translations.rb +29 -0
  30. data/lib/theme_check/checks/missing_required_template_files.rb +29 -0
  31. data/lib/theme_check/checks/missing_template.rb +25 -0
  32. data/lib/theme_check/checks/nested_snippet.rb +46 -0
  33. data/lib/theme_check/checks/required_directories.rb +24 -0
  34. data/lib/theme_check/checks/required_layout_theme_object.rb +40 -0
  35. data/lib/theme_check/checks/space_inside_braces.rb +58 -0
  36. data/lib/theme_check/checks/syntax_error.rb +29 -0
  37. data/lib/theme_check/checks/template_length.rb +18 -0
  38. data/lib/theme_check/checks/translation_key_exists.rb +35 -0
  39. data/lib/theme_check/checks/undefined_object.rb +86 -0
  40. data/lib/theme_check/checks/unknown_filter.rb +25 -0
  41. data/lib/theme_check/checks/unused_assign.rb +54 -0
  42. data/lib/theme_check/checks/unused_snippet.rb +34 -0
  43. data/lib/theme_check/checks/valid_html_translation.rb +43 -0
  44. data/lib/theme_check/checks/valid_json.rb +14 -0
  45. data/lib/theme_check/checks/valid_schema.rb +13 -0
  46. data/lib/theme_check/checks_tracking.rb +8 -0
  47. data/lib/theme_check/cli.rb +78 -0
  48. data/lib/theme_check/config.rb +108 -0
  49. data/lib/theme_check/json_check.rb +11 -0
  50. data/lib/theme_check/json_file.rb +47 -0
  51. data/lib/theme_check/json_helpers.rb +9 -0
  52. data/lib/theme_check/language_server.rb +11 -0
  53. data/lib/theme_check/language_server/handler.rb +117 -0
  54. data/lib/theme_check/language_server/server.rb +140 -0
  55. data/lib/theme_check/liquid_check.rb +13 -0
  56. data/lib/theme_check/locale_diff.rb +69 -0
  57. data/lib/theme_check/node.rb +117 -0
  58. data/lib/theme_check/offense.rb +104 -0
  59. data/lib/theme_check/parsing_helpers.rb +17 -0
  60. data/lib/theme_check/printer.rb +74 -0
  61. data/lib/theme_check/shopify_liquid.rb +3 -0
  62. data/lib/theme_check/shopify_liquid/filter.rb +18 -0
  63. data/lib/theme_check/shopify_liquid/object.rb +16 -0
  64. data/lib/theme_check/tags.rb +146 -0
  65. data/lib/theme_check/template.rb +73 -0
  66. data/lib/theme_check/theme.rb +60 -0
  67. data/lib/theme_check/version.rb +4 -0
  68. data/lib/theme_check/visitor.rb +37 -0
  69. data/theme-check.gemspec +28 -0
  70. 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
Binary file
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "theme_check"
5
+
6
+ ThemeCheck::Cli.new.run!(ARGV)
@@ -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
@@ -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