theme-check 0.3.0 → 0.5.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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +7 -0
  3. data/CHANGELOG.md +50 -0
  4. data/CONTRIBUTING.md +5 -2
  5. data/README.md +9 -4
  6. data/RELEASING.md +2 -2
  7. data/config/default.yml +7 -0
  8. data/data/shopify_liquid/tags.yml +27 -0
  9. data/docs/checks/CHECK_DOCS_TEMPLATE.md +47 -0
  10. data/docs/checks/asset_size_javascript.md +79 -0
  11. data/docs/checks/convert_include_to_render.md +48 -0
  12. data/docs/checks/default_locale.md +46 -0
  13. data/docs/checks/deprecated_filter.md +46 -0
  14. data/docs/checks/liquid_tag.md +65 -0
  15. data/docs/checks/matching_schema_translations.md +93 -0
  16. data/docs/checks/matching_translations.md +72 -0
  17. data/docs/checks/missing_enable_comment.md +50 -0
  18. data/docs/checks/missing_required_template_files.md +26 -0
  19. data/docs/checks/missing_template.md +40 -0
  20. data/docs/checks/nested_snippet.md +69 -0
  21. data/docs/checks/parser_blocking_javascript.md +97 -0
  22. data/docs/checks/required_directories.md +25 -0
  23. data/docs/checks/required_layout_theme_object.md +28 -0
  24. data/docs/checks/space_inside_braces.md +63 -0
  25. data/docs/checks/syntax_error.md +49 -0
  26. data/docs/checks/template_length.md +50 -0
  27. data/docs/checks/translation_key_exists.md +63 -0
  28. data/docs/checks/undefined_object.md +53 -0
  29. data/docs/checks/unknown_filter.md +45 -0
  30. data/docs/checks/unused_assign.md +47 -0
  31. data/docs/checks/unused_snippet.md +32 -0
  32. data/docs/checks/valid_html_translation.md +53 -0
  33. data/docs/checks/valid_json.md +60 -0
  34. data/docs/checks/valid_schema.md +50 -0
  35. data/lib/theme_check.rb +4 -0
  36. data/lib/theme_check/asset_file.rb +34 -0
  37. data/lib/theme_check/check.rb +19 -9
  38. data/lib/theme_check/checks/asset_size_javascript.rb +74 -0
  39. data/lib/theme_check/checks/convert_include_to_render.rb +1 -1
  40. data/lib/theme_check/checks/default_locale.rb +1 -0
  41. data/lib/theme_check/checks/deprecated_filter.rb +1 -1
  42. data/lib/theme_check/checks/liquid_tag.rb +3 -3
  43. data/lib/theme_check/checks/matching_schema_translations.rb +1 -0
  44. data/lib/theme_check/checks/matching_translations.rb +1 -0
  45. data/lib/theme_check/checks/missing_enable_comment.rb +1 -0
  46. data/lib/theme_check/checks/missing_required_template_files.rb +1 -2
  47. data/lib/theme_check/checks/missing_template.rb +1 -0
  48. data/lib/theme_check/checks/nested_snippet.rb +1 -0
  49. data/lib/theme_check/checks/parser_blocking_javascript.rb +2 -1
  50. data/lib/theme_check/checks/required_directories.rb +1 -1
  51. data/lib/theme_check/checks/required_layout_theme_object.rb +1 -1
  52. data/lib/theme_check/checks/space_inside_braces.rb +1 -0
  53. data/lib/theme_check/checks/syntax_error.rb +1 -0
  54. data/lib/theme_check/checks/template_length.rb +1 -0
  55. data/lib/theme_check/checks/translation_key_exists.rb +1 -0
  56. data/lib/theme_check/checks/undefined_object.rb +29 -10
  57. data/lib/theme_check/checks/unknown_filter.rb +1 -0
  58. data/lib/theme_check/checks/unused_assign.rb +5 -3
  59. data/lib/theme_check/checks/unused_snippet.rb +1 -0
  60. data/lib/theme_check/checks/valid_html_translation.rb +1 -0
  61. data/lib/theme_check/checks/valid_json.rb +1 -0
  62. data/lib/theme_check/checks/valid_schema.rb +1 -0
  63. data/lib/theme_check/cli.rb +22 -6
  64. data/lib/theme_check/config.rb +2 -2
  65. data/lib/theme_check/in_memory_storage.rb +1 -1
  66. data/lib/theme_check/language_server.rb +10 -0
  67. data/lib/theme_check/language_server/completion_engine.rb +38 -0
  68. data/lib/theme_check/language_server/completion_helper.rb +25 -0
  69. data/lib/theme_check/language_server/completion_provider.rb +24 -0
  70. data/lib/theme_check/language_server/completion_providers/filter_completion_provider.rb +47 -0
  71. data/lib/theme_check/language_server/completion_providers/object_completion_provider.rb +31 -0
  72. data/lib/theme_check/language_server/completion_providers/tag_completion_provider.rb +31 -0
  73. data/lib/theme_check/language_server/handler.rb +62 -6
  74. data/lib/theme_check/language_server/position_helper.rb +27 -0
  75. data/lib/theme_check/language_server/protocol.rb +41 -0
  76. data/lib/theme_check/language_server/server.rb +6 -1
  77. data/lib/theme_check/language_server/tokens.rb +55 -0
  78. data/lib/theme_check/offense.rb +51 -14
  79. data/lib/theme_check/regex_helpers.rb +15 -0
  80. data/lib/theme_check/remote_asset_file.rb +44 -0
  81. data/lib/theme_check/shopify_liquid.rb +1 -0
  82. data/lib/theme_check/shopify_liquid/tag.rb +16 -0
  83. data/lib/theme_check/theme.rb +7 -1
  84. data/lib/theme_check/version.rb +1 -1
  85. metadata +44 -2
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  module ThemeCheck
3
+ Position = Struct.new(:line, :column)
4
+
3
5
  class Offense
4
6
  MAX_SOURCE_EXCERPT_SIZE = 120
5
7
 
@@ -35,6 +37,9 @@ module ThemeCheck
35
37
  elsif @node
36
38
  @node.line_number
37
39
  end
40
+
41
+ @start_position = nil
42
+ @end_position = nil
38
43
  end
39
44
 
40
45
  def source_excerpt
@@ -50,27 +55,19 @@ module ThemeCheck
50
55
  end
51
56
 
52
57
  def start_line
53
- return 0 unless line_number
54
- line_number - 1
58
+ start_position.line
55
59
  end
56
60
 
57
- def end_line
58
- if markup
59
- start_line + markup.count("\n")
60
- else
61
- start_line
62
- end
61
+ def start_column
62
+ start_position.column
63
63
  end
64
64
 
65
- def start_column
66
- return 0 unless line_number && markup
67
- template.full_line(start_line + 1).index(markup.split("\n", 2).first)
65
+ def end_line
66
+ end_position.line
68
67
  end
69
68
 
70
69
  def end_column
71
- return 0 unless line_number && markup
72
- markup_end = markup.split("\n").last
73
- template.full_line(end_line + 1).index(markup_end) + markup_end.size
70
+ end_position.column
74
71
  end
75
72
 
76
73
  def code_name
@@ -116,5 +113,45 @@ module ThemeCheck
116
113
  message
117
114
  end
118
115
  end
116
+
117
+ private
118
+
119
+ def full_line(line)
120
+ # Liquid::Template is 1-indexed.
121
+ template.full_line(line + 1)
122
+ end
123
+
124
+ def lines_of_content
125
+ @lines ||= markup.lines.map { |x| x.sub(/\n$/, '') }
126
+ end
127
+
128
+ # 0-indexed, inclusive
129
+ def start_position
130
+ return @start_position if @start_position
131
+ return @start_position = Position.new(0, 0) unless line_number && markup
132
+
133
+ position = Position.new
134
+ position.line = line_number - 1
135
+ position.column = full_line(position.line).index(lines_of_content.first) || 0
136
+
137
+ @start_position = position
138
+ end
139
+
140
+ # 0-indexed, exclusive. It's the line + col that are exclusive.
141
+ # This is why it doesn't make sense to calculate them separately.
142
+ def end_position
143
+ return @end_position if @end_position
144
+ return @end_position = Position.new(0, 0) unless line_number && markup
145
+
146
+ position = Position.new
147
+ position.line = start_line + lines_of_content.size - 1
148
+ position.column = if start_line == position.line
149
+ start_column + markup.size
150
+ else
151
+ lines_of_content.last.size
152
+ end
153
+
154
+ @end_position = position
155
+ end
119
156
  end
120
157
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ThemeCheck
4
+ module RegexHelpers
5
+ def matches(s, re)
6
+ start_at = 0
7
+ matches = []
8
+ while (m = s.match(re, start_at))
9
+ matches.push(m)
10
+ start_at = m.end(0)
11
+ end
12
+ matches
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+ require "net/http"
3
+ require "pathname"
4
+
5
+ module ThemeCheck
6
+ class RemoteAssetFile
7
+ class << self
8
+ def cache
9
+ @cache ||= {}
10
+ end
11
+
12
+ def from_src(src)
13
+ key = uri(src).to_s
14
+ cache[key] = RemoteAssetFile.new(src) unless cache.key?(key)
15
+ cache[key]
16
+ end
17
+
18
+ def uri(src)
19
+ URI.parse(src.sub(%r{^//}, "https://"))
20
+ end
21
+ end
22
+
23
+ def initialize(src)
24
+ @uri = RemoteAssetFile.uri(src)
25
+ @content = nil
26
+ end
27
+
28
+ def content
29
+ return @content unless @content.nil?
30
+
31
+ res = Net::HTTP.start(@uri.hostname, @uri.port, use_ssl: @uri.scheme == 'https') do |http|
32
+ req = Net::HTTP::Get.new(@uri)
33
+ req['Accept-Encoding'] = 'gzip, deflate, br'
34
+ http.request(req)
35
+ end
36
+
37
+ @content = res.body
38
+ end
39
+
40
+ def gzipped_size
41
+ @gzipped_size ||= @content.bytesize
42
+ end
43
+ end
44
+ end
@@ -2,3 +2,4 @@
2
2
  require_relative 'shopify_liquid/deprecated_filter'
3
3
  require_relative 'shopify_liquid/filter'
4
4
  require_relative 'shopify_liquid/object'
5
+ require_relative 'shopify_liquid/tag'
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+ require 'yaml'
3
+
4
+ module ThemeCheck
5
+ module ShopifyLiquid
6
+ module Tag
7
+ extend self
8
+
9
+ def labels
10
+ @tags ||= begin
11
+ YAML.load(File.read("#{__dir__}/../../../data/shopify_liquid/tags.yml"))
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -11,6 +11,12 @@ module ThemeCheck
11
11
  @storage = storage
12
12
  end
13
13
 
14
+ def assets
15
+ @assets ||= @storage.files
16
+ .select { |path| path.starts_with?("assets/") }
17
+ .map { |path| AssetFile.new(path, @storage) }
18
+ end
19
+
14
20
  def liquid
15
21
  @liquid ||= @storage.files
16
22
  .select { |path| LIQUID_REGEX.match?(path) }
@@ -43,7 +49,7 @@ module ThemeCheck
43
49
  end
44
50
 
45
51
  def all
46
- @all ||= json + liquid
52
+ @all ||= json + liquid + assets
47
53
  end
48
54
 
49
55
  def [](name)
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module ThemeCheck
3
- VERSION = "0.3.0"
3
+ VERSION = "0.5.0"
4
4
  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.3.0
4
+ version: 0.5.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-02-16 00:00:00.000000000 Z
11
+ date: 2021-03-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: liquid
@@ -65,6 +65,7 @@ files:
65
65
  - ".github/workflows/theme-check.yml"
66
66
  - ".gitignore"
67
67
  - ".rubocop.yml"
68
+ - CHANGELOG.md
68
69
  - CODE_OF_CONDUCT.md
69
70
  - CONTRIBUTING.md
70
71
  - Gemfile
@@ -79,14 +80,43 @@ files:
79
80
  - data/shopify_liquid/filters.yml
80
81
  - data/shopify_liquid/objects.yml
81
82
  - data/shopify_liquid/plus_objects.yml
83
+ - data/shopify_liquid/tags.yml
82
84
  - dev.yml
85
+ - docs/checks/CHECK_DOCS_TEMPLATE.md
86
+ - docs/checks/asset_size_javascript.md
87
+ - docs/checks/convert_include_to_render.md
88
+ - docs/checks/default_locale.md
89
+ - docs/checks/deprecated_filter.md
90
+ - docs/checks/liquid_tag.md
91
+ - docs/checks/matching_schema_translations.md
92
+ - docs/checks/matching_translations.md
93
+ - docs/checks/missing_enable_comment.md
94
+ - docs/checks/missing_required_template_files.md
95
+ - docs/checks/missing_template.md
96
+ - docs/checks/nested_snippet.md
97
+ - docs/checks/parser_blocking_javascript.md
98
+ - docs/checks/required_directories.md
99
+ - docs/checks/required_layout_theme_object.md
100
+ - docs/checks/space_inside_braces.md
101
+ - docs/checks/syntax_error.md
102
+ - docs/checks/template_length.md
103
+ - docs/checks/translation_key_exists.md
104
+ - docs/checks/undefined_object.md
105
+ - docs/checks/unknown_filter.md
106
+ - docs/checks/unused_assign.md
107
+ - docs/checks/unused_snippet.md
108
+ - docs/checks/valid_html_translation.md
109
+ - docs/checks/valid_json.md
110
+ - docs/checks/valid_schema.md
83
111
  - docs/preview.png
84
112
  - exe/theme-check
85
113
  - exe/theme-check-language-server
86
114
  - lib/theme_check.rb
87
115
  - lib/theme_check/analyzer.rb
116
+ - lib/theme_check/asset_file.rb
88
117
  - lib/theme_check/check.rb
89
118
  - lib/theme_check/checks.rb
119
+ - lib/theme_check/checks/asset_size_javascript.rb
90
120
  - lib/theme_check/checks/convert_include_to_render.rb
91
121
  - lib/theme_check/checks/default_locale.rb
92
122
  - lib/theme_check/checks/deprecated_filter.rb
@@ -122,8 +152,17 @@ files:
122
152
  - lib/theme_check/json_file.rb
123
153
  - lib/theme_check/json_helpers.rb
124
154
  - lib/theme_check/language_server.rb
155
+ - lib/theme_check/language_server/completion_engine.rb
156
+ - lib/theme_check/language_server/completion_helper.rb
157
+ - lib/theme_check/language_server/completion_provider.rb
158
+ - lib/theme_check/language_server/completion_providers/filter_completion_provider.rb
159
+ - lib/theme_check/language_server/completion_providers/object_completion_provider.rb
160
+ - lib/theme_check/language_server/completion_providers/tag_completion_provider.rb
125
161
  - lib/theme_check/language_server/handler.rb
162
+ - lib/theme_check/language_server/position_helper.rb
163
+ - lib/theme_check/language_server/protocol.rb
126
164
  - lib/theme_check/language_server/server.rb
165
+ - lib/theme_check/language_server/tokens.rb
127
166
  - lib/theme_check/liquid_check.rb
128
167
  - lib/theme_check/locale_diff.rb
129
168
  - lib/theme_check/node.rb
@@ -131,10 +170,13 @@ files:
131
170
  - lib/theme_check/packager.rb
132
171
  - lib/theme_check/parsing_helpers.rb
133
172
  - lib/theme_check/printer.rb
173
+ - lib/theme_check/regex_helpers.rb
174
+ - lib/theme_check/remote_asset_file.rb
134
175
  - lib/theme_check/shopify_liquid.rb
135
176
  - lib/theme_check/shopify_liquid/deprecated_filter.rb
136
177
  - lib/theme_check/shopify_liquid/filter.rb
137
178
  - lib/theme_check/shopify_liquid/object.rb
179
+ - lib/theme_check/shopify_liquid/tag.rb
138
180
  - lib/theme_check/storage.rb
139
181
  - lib/theme_check/tags.rb
140
182
  - lib/theme_check/template.rb