theme-check 0.10.2 → 1.3.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 (78) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/theme-check.yml +2 -6
  3. data/CHANGELOG.md +51 -0
  4. data/CONTRIBUTING.md +1 -1
  5. data/README.md +39 -0
  6. data/RELEASING.md +34 -2
  7. data/bin/theme-check +29 -0
  8. data/bin/theme-check-language-server +29 -0
  9. data/config/default.yml +46 -3
  10. data/config/nothing.yml +11 -0
  11. data/config/theme_app_extension.yml +168 -0
  12. data/data/shopify_liquid/objects.yml +2 -0
  13. data/docs/checks/app_block_valid_tags.md +40 -0
  14. data/docs/checks/asset_size_app_block_css.md +52 -0
  15. data/docs/checks/asset_size_app_block_javascript.md +57 -0
  16. data/docs/checks/asset_size_css_stylesheet_tag.md +50 -0
  17. data/docs/checks/deprecate_bgsizes.md +66 -0
  18. data/docs/checks/deprecate_lazysizes.md +61 -0
  19. data/docs/checks/liquid_tag.md +2 -2
  20. data/docs/checks/missing_template.md +25 -0
  21. data/docs/checks/pagination_size.md +44 -0
  22. data/docs/checks/template_length.md +12 -2
  23. data/docs/checks/undefined_object.md +5 -0
  24. data/lib/theme_check/analyzer.rb +25 -21
  25. data/lib/theme_check/asset_file.rb +3 -15
  26. data/lib/theme_check/bug.rb +3 -1
  27. data/lib/theme_check/check.rb +26 -4
  28. data/lib/theme_check/checks/app_block_valid_tags.rb +36 -0
  29. data/lib/theme_check/checks/asset_size_app_block_css.rb +44 -0
  30. data/lib/theme_check/checks/asset_size_app_block_javascript.rb +44 -0
  31. data/lib/theme_check/checks/asset_size_css.rb +11 -74
  32. data/lib/theme_check/checks/asset_size_css_stylesheet_tag.rb +24 -0
  33. data/lib/theme_check/checks/asset_size_javascript.rb +11 -37
  34. data/lib/theme_check/checks/convert_include_to_render.rb +3 -1
  35. data/lib/theme_check/checks/deprecate_bgsizes.rb +14 -0
  36. data/lib/theme_check/checks/deprecate_lazysizes.rb +16 -0
  37. data/lib/theme_check/checks/img_lazy_loading.rb +2 -7
  38. data/lib/theme_check/checks/img_width_and_height.rb +3 -3
  39. data/lib/theme_check/checks/liquid_tag.rb +2 -2
  40. data/lib/theme_check/checks/missing_template.rb +21 -5
  41. data/lib/theme_check/checks/pagination_size.rb +65 -0
  42. data/lib/theme_check/checks/parser_blocking_javascript.rb +1 -1
  43. data/lib/theme_check/checks/remote_asset.rb +4 -2
  44. data/lib/theme_check/checks/space_inside_braces.rb +27 -7
  45. data/lib/theme_check/checks/template_length.rb +18 -4
  46. data/lib/theme_check/checks/undefined_object.rb +1 -1
  47. data/lib/theme_check/checks/valid_html_translation.rb +1 -1
  48. data/lib/theme_check/checks.rb +11 -1
  49. data/lib/theme_check/cli.rb +52 -15
  50. data/lib/theme_check/config.rb +56 -10
  51. data/lib/theme_check/corrector.rb +4 -0
  52. data/lib/theme_check/exceptions.rb +29 -27
  53. data/lib/theme_check/file_system_storage.rb +12 -0
  54. data/lib/theme_check/html_check.rb +1 -0
  55. data/lib/theme_check/html_node.rb +37 -16
  56. data/lib/theme_check/html_visitor.rb +17 -3
  57. data/lib/theme_check/json_check.rb +2 -2
  58. data/lib/theme_check/json_file.rb +2 -29
  59. data/lib/theme_check/json_printer.rb +26 -0
  60. data/lib/theme_check/language_server/constants.rb +8 -0
  61. data/lib/theme_check/language_server/document_link_engine.rb +40 -4
  62. data/lib/theme_check/language_server/handler.rb +6 -2
  63. data/lib/theme_check/language_server/server.rb +13 -2
  64. data/lib/theme_check/liquid_check.rb +0 -12
  65. data/lib/theme_check/node.rb +6 -4
  66. data/lib/theme_check/offense.rb +56 -3
  67. data/lib/theme_check/parsing_helpers.rb +7 -4
  68. data/lib/theme_check/position.rb +98 -14
  69. data/lib/theme_check/regex_helpers.rb +20 -0
  70. data/lib/theme_check/tags.rb +62 -8
  71. data/lib/theme_check/template.rb +3 -32
  72. data/lib/theme_check/theme.rb +2 -0
  73. data/lib/theme_check/theme_file.rb +40 -0
  74. data/lib/theme_check/version.rb +1 -1
  75. data/lib/theme_check.rb +16 -0
  76. data/theme-check.gemspec +1 -1
  77. metadata +26 -7
  78. data/bin/liquid-server +0 -4
@@ -2,6 +2,11 @@
2
2
 
3
3
  module ThemeCheck
4
4
  module RegexHelpers
5
+ LIQUID_TAG = /#{Liquid::TagStart}.*?#{Liquid::TagEnd}/om
6
+ LIQUID_VARIABLE = /#{Liquid::VariableStart}.*?#{Liquid::VariableEnd}/om
7
+ LIQUID_TAG_OR_VARIABLE = /#{LIQUID_TAG}|#{LIQUID_VARIABLE}/om
8
+ START_OR_END_QUOTE = /(^['"])|(['"]$)/
9
+
5
10
  def matches(s, re)
6
11
  start_at = 0
7
12
  matches = []
@@ -11,5 +16,20 @@ module ThemeCheck
11
16
  end
12
17
  matches
13
18
  end
19
+
20
+ def href_to_file_size(href)
21
+ # asset_url (+ optional stylesheet_tag) variables
22
+ if href =~ /^#{LIQUID_VARIABLE}$/o && href =~ /asset_url/ && href =~ Liquid::QuotedString
23
+ asset_id = Regexp.last_match(0).gsub(START_OR_END_QUOTE, "")
24
+ asset = @theme.assets.find { |a| a.name.end_with?("/" + asset_id) }
25
+ return if asset.nil?
26
+ asset.gzipped_size
27
+
28
+ # remote URLs
29
+ elsif href =~ %r{^(https?:)?//}
30
+ asset = RemoteAssetFile.from_src(href)
31
+ asset.gzipped_size
32
+ end
33
+ end
14
34
  end
15
35
  end
@@ -125,6 +125,42 @@ module ThemeCheck
125
125
  end
126
126
  end
127
127
 
128
+ class Render < Liquid::Tag
129
+ SYNTAX = /((?:#{Liquid::QuotedString}|#{Liquid::VariableSegment})+)(\s+(with|#{Liquid::Render::FOR})\s+(#{Liquid::QuotedFragment}+))?(\s+(?:as)\s+(#{Liquid::VariableSegment}+))?/o
130
+
131
+ disable_tags "include"
132
+
133
+ attr_reader :template_name_expr, :attributes
134
+
135
+ def initialize(tag_name, markup, options)
136
+ super
137
+
138
+ raise SyntaxError, options[:locale].t("errors.syntax.render") unless markup =~ SYNTAX
139
+
140
+ template_name = Regexp.last_match(1)
141
+ with_or_for = Regexp.last_match(3)
142
+ variable_name = Regexp.last_match(4)
143
+
144
+ @alias_name = Regexp.last_match(6)
145
+ @variable_name_expr = variable_name ? parse_expression(variable_name) : nil
146
+ @template_name_expr = parse_expression(template_name)
147
+ @for = (with_or_for == Liquid::Render::FOR)
148
+
149
+ @attributes = {}
150
+ markup.scan(Liquid::TagAttributes) do |key, value|
151
+ @attributes[key] = parse_expression(value)
152
+ end
153
+ end
154
+
155
+ class ParseTreeVisitor < Liquid::ParseTreeVisitor
156
+ def children
157
+ [
158
+ @node.template_name_expr,
159
+ ] + @node.attributes.values
160
+ end
161
+ end
162
+ end
163
+
128
164
  class Style < Liquid::Block; end
129
165
 
130
166
  class Schema < Liquid::Raw; end
@@ -133,13 +169,31 @@ module ThemeCheck
133
169
 
134
170
  class Stylesheet < Liquid::Raw; end
135
171
 
136
- Liquid::Template.register_tag('form', Form)
137
- Liquid::Template.register_tag('layout', Layout)
138
- Liquid::Template.register_tag('paginate', Paginate)
139
- Liquid::Template.register_tag('section', Section)
140
- Liquid::Template.register_tag('style', Style)
141
- Liquid::Template.register_tag('schema', Schema)
142
- Liquid::Template.register_tag('javascript', Javascript)
143
- Liquid::Template.register_tag('stylesheet', Stylesheet)
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
144
198
  end
145
199
  end
@@ -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
@@ -7,6 +7,8 @@ module ThemeCheck
7
7
  LIQUID_REGEX = /\.liquid$/i
8
8
  JSON_REGEX = /\.json$/i
9
9
 
10
+ attr_accessor :storage
11
+
10
12
  def initialize(storage)
11
13
  @storage = storage
12
14
  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
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module ThemeCheck
3
- VERSION = "0.10.2"
3
+ VERSION = "1.3.0"
4
4
  end
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"
@@ -26,6 +27,7 @@ require_relative "theme_check/config"
26
27
  require_relative "theme_check/node"
27
28
  require_relative "theme_check/offense"
28
29
  require_relative "theme_check/printer"
30
+ require_relative "theme_check/json_printer"
29
31
  require_relative "theme_check/shopify_liquid"
30
32
  require_relative "theme_check/storage"
31
33
  require_relative "theme_check/string_helpers"
@@ -45,3 +47,17 @@ Dir[__dir__ + "/theme_check/checks/*.rb"].each { |file| require file }
45
47
  # UTF-8 is the default internal and external encoding, like in Rails & Shopify.
46
48
  Encoding.default_external = Encoding::UTF_8
47
49
  Encoding.default_internal = Encoding::UTF_8
50
+
51
+ module ThemeCheck
52
+ def self.with_liquid_c_disabled
53
+ if defined?(Liquid::C)
54
+ was_enabled = Liquid::C.enabled
55
+ Liquid::C.enabled = false if was_enabled
56
+ end
57
+ yield
58
+ ensure
59
+ if defined?(Liquid::C) && was_enabled
60
+ Liquid::C.enabled = true
61
+ end
62
+ end
63
+ end
data/theme-check.gemspec CHANGED
@@ -25,5 +25,5 @@ Gem::Specification.new do |spec|
25
25
  spec.require_paths = ["lib"]
26
26
 
27
27
  spec.add_dependency('liquid', '>= 5.0.1')
28
- spec.add_dependency('nokogumbo')
28
+ spec.add_dependency('nokogiri', '>= 1.12')
29
29
  end
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: 0.10.2
4
+ version: 1.3.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-18 00:00:00.000000000 Z
11
+ date: 2021-08-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: liquid
@@ -25,19 +25,19 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: 5.0.1
27
27
  - !ruby/object:Gem::Dependency
28
- name: nokogumbo
28
+ name: nokogiri
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: '1.12'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: '1.12'
41
41
  description:
42
42
  email:
43
43
  - marcandre.cournoyer@shopify.com
@@ -60,8 +60,11 @@ files:
60
60
  - README.md
61
61
  - RELEASING.md
62
62
  - Rakefile
63
- - bin/liquid-server
63
+ - bin/theme-check
64
+ - bin/theme-check-language-server
64
65
  - config/default.yml
66
+ - config/nothing.yml
67
+ - config/theme_app_extension.yml
65
68
  - data/shopify_liquid/deprecated_filters.yml
66
69
  - data/shopify_liquid/filters.yml
67
70
  - data/shopify_liquid/objects.yml
@@ -74,12 +77,18 @@ files:
74
77
  - docs/api/json_check.md
75
78
  - docs/api/liquid_check.md
76
79
  - docs/checks/TEMPLATE.md.erb
80
+ - docs/checks/app_block_valid_tags.md
81
+ - docs/checks/asset_size_app_block_css.md
82
+ - docs/checks/asset_size_app_block_javascript.md
77
83
  - docs/checks/asset_size_css.md
84
+ - docs/checks/asset_size_css_stylesheet_tag.md
78
85
  - docs/checks/asset_size_javascript.md
79
86
  - docs/checks/asset_url_filters.md
80
87
  - docs/checks/content_for_header_modification.md
81
88
  - docs/checks/convert_include_to_render.md
82
89
  - docs/checks/default_locale.md
90
+ - docs/checks/deprecate_bgsizes.md
91
+ - docs/checks/deprecate_lazysizes.md
83
92
  - docs/checks/deprecated_filter.md
84
93
  - docs/checks/html_parsing_error.md
85
94
  - docs/checks/img_lazy_loading.md
@@ -91,6 +100,7 @@ files:
91
100
  - docs/checks/missing_required_template_files.md
92
101
  - docs/checks/missing_template.md
93
102
  - docs/checks/nested_snippet.md
103
+ - docs/checks/pagination_size.md
94
104
  - docs/checks/parser_blocking_javascript.md
95
105
  - docs/checks/parser_blocking_script_tag.md
96
106
  - docs/checks/remote_asset.md
@@ -117,12 +127,18 @@ files:
117
127
  - lib/theme_check/check.rb
118
128
  - lib/theme_check/checks.rb
119
129
  - lib/theme_check/checks/TEMPLATE.rb.erb
130
+ - lib/theme_check/checks/app_block_valid_tags.rb
131
+ - lib/theme_check/checks/asset_size_app_block_css.rb
132
+ - lib/theme_check/checks/asset_size_app_block_javascript.rb
120
133
  - lib/theme_check/checks/asset_size_css.rb
134
+ - lib/theme_check/checks/asset_size_css_stylesheet_tag.rb
121
135
  - lib/theme_check/checks/asset_size_javascript.rb
122
136
  - lib/theme_check/checks/asset_url_filters.rb
123
137
  - lib/theme_check/checks/content_for_header_modification.rb
124
138
  - lib/theme_check/checks/convert_include_to_render.rb
125
139
  - lib/theme_check/checks/default_locale.rb
140
+ - lib/theme_check/checks/deprecate_bgsizes.rb
141
+ - lib/theme_check/checks/deprecate_lazysizes.rb
126
142
  - lib/theme_check/checks/deprecated_filter.rb
127
143
  - lib/theme_check/checks/html_parsing_error.rb
128
144
  - lib/theme_check/checks/img_lazy_loading.rb
@@ -134,6 +150,7 @@ files:
134
150
  - lib/theme_check/checks/missing_required_template_files.rb
135
151
  - lib/theme_check/checks/missing_template.rb
136
152
  - lib/theme_check/checks/nested_snippet.rb
153
+ - lib/theme_check/checks/pagination_size.rb
137
154
  - lib/theme_check/checks/parser_blocking_javascript.rb
138
155
  - lib/theme_check/checks/parser_blocking_script_tag.rb
139
156
  - lib/theme_check/checks/remote_asset.rb
@@ -165,6 +182,7 @@ files:
165
182
  - lib/theme_check/json_check.rb
166
183
  - lib/theme_check/json_file.rb
167
184
  - lib/theme_check/json_helpers.rb
185
+ - lib/theme_check/json_printer.rb
168
186
  - lib/theme_check/language_server.rb
169
187
  - lib/theme_check/language_server/completion_engine.rb
170
188
  - lib/theme_check/language_server/completion_helper.rb
@@ -203,6 +221,7 @@ files:
203
221
  - lib/theme_check/tags.rb
204
222
  - lib/theme_check/template.rb
205
223
  - lib/theme_check/theme.rb
224
+ - lib/theme_check/theme_file.rb
206
225
  - lib/theme_check/version.rb
207
226
  - lib/theme_check/visitor.rb
208
227
  - packaging/homebrew/theme_check.base.rb
@@ -227,7 +246,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
227
246
  - !ruby/object:Gem::Version
228
247
  version: '0'
229
248
  requirements: []
230
- rubygems_version: 3.2.17
249
+ rubygems_version: 3.2.20
231
250
  signing_key:
232
251
  specification_version: 4
233
252
  summary: A Shopify Theme Linter
data/bin/liquid-server DELETED
@@ -1,4 +0,0 @@
1
- #!/usr/bin/env bash
2
- dev="/opt/dev/bin/dev"
3
- cd "$($dev project-path theme-check)"
4
- "$dev" language-server