theme-check 1.3.0 → 1.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8bec2f54c12487d444bebd3bb0abad48ec133c4e9504be29857a58c87d82f589
4
- data.tar.gz: 2cacd6af05aa3c2af8d40167a04532ed998d24049df7b277f70baf50f0a4e401
3
+ metadata.gz: e154c11ed7f84b968edac05c97afb2611e816933d790347cdbdca63071d46e88
4
+ data.tar.gz: dd8fc72c420412ab3adfad64f3d11197f562904bd0171289debe8e440ca34c86
5
5
  SHA512:
6
- metadata.gz: 95a61ee91b1a575dead56345172c5472cdb1c314b94aef37814f311ab54d39263a70d51192ea5d276188d06e8ddc32715f9693f7089157e3376bd7c885b1d30a
7
- data.tar.gz: 6fe39a2b8944ceb34e48b5a4a84cbb1f544d870b9c38f36dff33ff2e226f76feabb612d9f9e98ce31c2c68209014b46d76adcd0a4dd37224aee3c2ee266e50d0
6
+ metadata.gz: 0315a3eb75f5cda96fe2be02d7533e07aa364fc7b3e08bdb2682edf50f30d13bc2c03099d015c73db2e1c6e7d06c90707068d596db044176ddcdaea4bfe3a65c
7
+ data.tar.gz: a7050df945829d05a0440464d0ac309d3cc55d9fdd9909259b95f2405beae746e799aad8beeb564508b0a543568dcd718edb9638c1307bb345051784818ea165
data/CHANGELOG.md CHANGED
@@ -1,4 +1,17 @@
1
1
 
2
+ v1.4.0 / 2021-08-30
3
+ ==================
4
+
5
+ * Add new object drop: `predictive_search`
6
+ * Bump `TemplateLength` `max_length` default
7
+ * Fix `RemoteAsset` incorrectly firing on structured data elements [#393](https://github.com/Shopify/theme-check/issues/393)
8
+ * Fix document links not working on open
9
+ * Fix `asset_url` document links
10
+ * Use better heuristics for `DeprecateLazysizes`
11
+ * Add support for `section` document links
12
+ * Add support for `include` document links
13
+ * Automatically creates the default translation file (`locales/en.default.json`) if it doesn't already exist.
14
+
2
15
  v1.3.0 / 2021-08-26
3
16
  ==================
4
17
 
data/config/default.yml CHANGED
@@ -45,7 +45,7 @@ SyntaxError:
45
45
  TemplateLength:
46
46
  enabled: true
47
47
  ignore: []
48
- max_length: 500
48
+ max_length: 600
49
49
  # Exclude content of {% schema %} in line count
50
50
  exclude_schema: true
51
51
  # Exclude content of {% stylesheet %} in line count
@@ -54,6 +54,7 @@
54
54
  - part
55
55
  - policy
56
56
  - powered_by_link
57
+ - predictive_search
57
58
  - product
58
59
  - product_option
59
60
  - product_variant
@@ -10,9 +10,6 @@ This check is aimed at discouraging the use of the lazysizes JavaScript library
10
10
 
11
11
  ```liquid
12
12
 
13
- <!-- Reports use of "lazyload" class -->
14
- <img src="a.jpg" class="lazyload">
15
-
16
13
  <!-- Reports use of "data-srcset" and "data-sizes" attribute. Reports data-sizes="auto" -->
17
14
  <img
18
15
  alt="House by the lake"
@@ -21,7 +21,7 @@ The default configuration for this check is the following:
21
21
  ```yaml
22
22
  TemplateLength:
23
23
  enabled: true
24
- max_length: 500
24
+ max_length: 600
25
25
  exclude_schema: true
26
26
  exclude_stylesheet: true
27
27
  exclude_javascript: true
@@ -87,6 +87,7 @@ module ThemeCheck
87
87
  if @auto_correct
88
88
  offenses.each(&:correct)
89
89
  @theme.liquid.each(&:write)
90
+ @theme.json.each(&:write)
90
91
  end
91
92
  end
92
93
 
@@ -7,7 +7,9 @@ module ThemeCheck
7
7
 
8
8
  def on_end
9
9
  return if @theme.default_locale_json
10
- add_offense("Default translation file not found (for example locales/en.default.json)")
10
+ add_offense("Default translation file not found (for example locales/en.default.json)") do |corrector|
11
+ corrector.create_default_locale_json(@theme)
12
+ end
11
13
  end
12
14
  end
13
15
  end
@@ -7,10 +7,13 @@ module ThemeCheck
7
7
 
8
8
  def on_img(node)
9
9
  class_list = node.attributes["class"]&.split(" ")
10
+ has_loading_lazy = node.attributes["loading"] == "lazy"
11
+ has_native_source = node.attributes["src"] || node.attributes["srcset"]
12
+ return if has_native_source && has_loading_lazy
13
+ has_lazysize_source = node.attributes["data-srcset"] || node.attributes["data-src"]
14
+ has_lazysize_class = class_list&.include?("lazyload")
15
+ return unless has_lazysize_class && has_lazysize_source
10
16
  add_offense("Use the native loading=\"lazy\" attribute instead of lazysizes", node: node) if class_list&.include?("lazyload")
11
- add_offense("Use the native srcset attribute instead of data-srcset", node: node) if node.attributes["data-srcset"]
12
- add_offense("Use the native sizes attribute instead of data-sizes", node: node) if node.attributes["data-sizes"]
13
- add_offense("Do not set the data-sizes attribute to auto", node: node) if node.attributes["data-sizes"] == "auto"
14
17
  end
15
18
  end
16
19
  end
@@ -23,9 +23,9 @@ module ThemeCheck
23
23
  return if resource_url =~ RELATIVE_PATH
24
24
  return if url_hosted_by_shopify?(resource_url)
25
25
 
26
- # Ignore non-stylesheet rel tags
26
+ # Ignore non-stylesheet link tags
27
27
  rel = node.attributes["rel"]
28
- return if rel && rel != "stylesheet"
28
+ return if node.name == "link" && rel != "stylesheet"
29
29
 
30
30
  add_offense(
31
31
  "Asset should be served by the Shopify CDN for better performance.",
@@ -5,7 +5,7 @@ module ThemeCheck
5
5
  category :liquid
6
6
  doc docs_url(__FILE__)
7
7
 
8
- def initialize(max_length: 500, exclude_schema: true, exclude_stylesheet: true, exclude_javascript: true)
8
+ def initialize(max_length: 600, exclude_schema: true, exclude_stylesheet: true, exclude_javascript: true)
9
9
  @max_length = max_length
10
10
  @exclude_schema = exclude_schema
11
11
  @exclude_stylesheet = exclude_stylesheet
@@ -31,5 +31,10 @@ module ThemeCheck
31
31
  def create(theme, relative_path, content)
32
32
  theme.storage.write(relative_path, content)
33
33
  end
34
+
35
+ def create_default_locale_json(theme)
36
+ theme.default_locale_json = JsonFile.new("locales/#{theme.default_locale}.default.json", theme.storage)
37
+ theme.default_locale_json.update_contents('{}')
38
+ end
34
39
  end
35
40
  end
@@ -20,6 +20,17 @@ module ThemeCheck
20
20
  @parser_error
21
21
  end
22
22
 
23
+ def update_contents(new_content = '{}')
24
+ @content = new_content
25
+ end
26
+
27
+ def write
28
+ if source != @content
29
+ @storage.write(@relative_path, content)
30
+ @source = content
31
+ end
32
+ end
33
+
23
34
  def json?
24
35
  true
25
36
  end
@@ -2,21 +2,28 @@
2
2
 
3
3
  module ThemeCheck
4
4
  module LanguageServer
5
- PARTIAL_RENDER = %r{
6
- \{\%-?\s*render\s+'(?<partial>[^']*)'|
7
- \{\%-?\s*render\s+"(?<partial>[^"]*)"|
5
+ def self.partial_tag(tag)
6
+ %r{
7
+ \{\%-?\s*#{tag}\s+'(?<partial>[^']*)'|
8
+ \{\%-?\s*#{tag}\s+"(?<partial>[^"]*)"|
9
+
10
+ # in liquid tags the whole line is white space until the tag
11
+ ^\s*#{tag}\s+'(?<partial>[^']*)'|
12
+ ^\s*#{tag}\s+"(?<partial>[^"]*)"
13
+ }mix
14
+ end
15
+
16
+ PARTIAL_RENDER = partial_tag('render')
17
+ PARTIAL_INCLUDE = partial_tag('include')
18
+ PARTIAL_SECTION = partial_tag('section')
8
19
 
9
- # in liquid tags the whole line is white space until render
10
- ^\s*render\s+'(?<partial>[^']*)'|
11
- ^\s*render\s+"(?<partial>[^"]*)"
12
- }mix
13
20
  ASSET_INCLUDE = %r{
14
- \{\%-?\s*'(?<partial>[^']*)'\s*\|\s*asset_url|
15
- \{\%-?\s*"(?<partial>[^"]*)"\s*\|\s*asset_url|
21
+ \{\{-?\s*'(?<partial>[^']*)'\s*\|\s*asset_url|
22
+ \{\{-?\s*"(?<partial>[^"]*)"\s*\|\s*asset_url|
16
23
 
17
24
  # in liquid tags the whole line is white space until the asset partial
18
- ^\s*'(?<partial>[^']*)'\s*\|\s*asset_url|
19
- ^\s*"(?<partial>[^"]*)"\s*\|\s*asset_url
25
+ ^\s*(?:echo|assign[^=]*\=)\s*'(?<partial>[^']*)'\s*\|\s*asset_url|
26
+ ^\s*(?:echo|assign[^=]*\=)\s*"(?<partial>[^"]*)"\s*\|\s*asset_url
20
27
  }mix
21
28
  end
22
29
  end
@@ -3,81 +3,17 @@
3
3
  module ThemeCheck
4
4
  module LanguageServer
5
5
  class DocumentLinkEngine
6
- include PositionHelper
7
- include RegexHelpers
8
-
9
6
  def initialize(storage)
10
7
  @storage = storage
8
+ @providers = DocumentLinkProvider.all.map { |x| x.new(storage) }
11
9
  end
12
10
 
13
11
  def document_links(relative_path)
14
12
  buffer = @storage.read(relative_path)
15
13
  return [] unless buffer
16
- snippet_matches = matches(buffer, PARTIAL_RENDER).map do |match|
17
- start_line, start_character = from_index_to_row_column(
18
- buffer,
19
- match.begin(:partial),
20
- )
21
-
22
- end_line, end_character = from_index_to_row_column(
23
- buffer,
24
- match.end(:partial)
25
- )
26
-
27
- {
28
- target: snippet_link(match[:partial]),
29
- range: {
30
- start: {
31
- line: start_line,
32
- character: start_character,
33
- },
34
- end: {
35
- line: end_line,
36
- character: end_character,
37
- },
38
- },
39
- }
14
+ @providers.flat_map do |p|
15
+ p.document_links(buffer)
40
16
  end
41
- asset_matches = matches(buffer, ASSET_INCLUDE).map do |match|
42
- start_line, start_character = from_index_to_row_column(
43
- buffer,
44
- match.begin(:partial),
45
- )
46
-
47
- end_line, end_character = from_index_to_row_column(
48
- buffer,
49
- match.end(:partial)
50
- )
51
-
52
- {
53
- target: asset_link(match[:partial]),
54
- range: {
55
- start: {
56
- line: start_line,
57
- character: start_character,
58
- },
59
- end: {
60
- line: end_line,
61
- character: end_character,
62
- },
63
- },
64
- }
65
- end
66
- snippet_matches + asset_matches
67
- end
68
-
69
- def snippet_link(partial)
70
- file_link('snippets', partial, '.liquid')
71
- end
72
-
73
- def asset_link(partial)
74
- file_link('assets', partial, '')
75
- end
76
-
77
- private
78
-
79
- def file_link(directory, partial, extension)
80
- "file://#{@storage.path(directory + '/' + partial + extension)}"
81
17
  end
82
18
  end
83
19
  end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ThemeCheck
4
+ module LanguageServer
5
+ class DocumentLinkProvider
6
+ include RegexHelpers
7
+ include PositionHelper
8
+
9
+ class << self
10
+ attr_accessor :partial_regexp, :destination_directory, :destination_postfix
11
+
12
+ def all
13
+ @all ||= []
14
+ end
15
+
16
+ def inherited(subclass)
17
+ all << subclass
18
+ end
19
+ end
20
+
21
+ def initialize(storage = InMemoryStorage.new)
22
+ @storage = storage
23
+ end
24
+
25
+ def partial_regexp
26
+ self.class.partial_regexp
27
+ end
28
+
29
+ def destination_directory
30
+ self.class.destination_directory
31
+ end
32
+
33
+ def destination_postfix
34
+ self.class.destination_postfix
35
+ end
36
+
37
+ def document_links(buffer)
38
+ matches(buffer, partial_regexp).map do |match|
39
+ start_line, start_character = from_index_to_row_column(
40
+ buffer,
41
+ match.begin(:partial),
42
+ )
43
+
44
+ end_line, end_character = from_index_to_row_column(
45
+ buffer,
46
+ match.end(:partial)
47
+ )
48
+
49
+ {
50
+ target: file_link(match[:partial]),
51
+ range: {
52
+ start: {
53
+ line: start_line,
54
+ character: start_character,
55
+ },
56
+ end: {
57
+ line: end_line,
58
+ character: end_character,
59
+ },
60
+ },
61
+ }
62
+ end
63
+ end
64
+
65
+ def file_link(partial)
66
+ "file://#{@storage.path(destination_directory + '/' + partial + destination_postfix)}"
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ThemeCheck
4
+ module LanguageServer
5
+ class AssetDocumentLinkProvider < DocumentLinkProvider
6
+ @partial_regexp = ASSET_INCLUDE
7
+ @destination_directory = "assets"
8
+ @destination_postfix = ""
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ThemeCheck
4
+ module LanguageServer
5
+ class IncludeDocumentLinkProvider < DocumentLinkProvider
6
+ @partial_regexp = PARTIAL_INCLUDE
7
+ @destination_directory = "snippets"
8
+ @destination_postfix = ".liquid"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ThemeCheck
4
+ module LanguageServer
5
+ class RenderDocumentLinkProvider < DocumentLinkProvider
6
+ @partial_regexp = PARTIAL_RENDER
7
+ @destination_directory = "snippets"
8
+ @destination_postfix = ".liquid"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ThemeCheck
4
+ module LanguageServer
5
+ class SectionDocumentLinkProvider < DocumentLinkProvider
6
+ @partial_regexp = PARTIAL_SECTION
7
+ @destination_directory = "sections"
8
+ @destination_postfix = ".liquid"
9
+ end
10
+ end
11
+ end
@@ -55,10 +55,9 @@ module ThemeCheck
55
55
  end
56
56
 
57
57
  def on_text_document_did_open(_id, params)
58
- return unless @diagnostics_tracker.first_run?
59
58
  relative_path = relative_path_from_text_document_uri(params)
60
59
  @storage.write(relative_path, text_document_text(params))
61
- analyze_and_send_offenses(text_document_uri(params))
60
+ analyze_and_send_offenses(text_document_uri(params)) if @diagnostics_tracker.first_run?
62
61
  end
63
62
 
64
63
  def on_text_document_did_save(_id, params)
@@ -8,6 +8,7 @@ require_relative "language_server/variable_lookup_finder"
8
8
  require_relative "language_server/completion_helper"
9
9
  require_relative "language_server/completion_provider"
10
10
  require_relative "language_server/completion_engine"
11
+ require_relative "language_server/document_link_provider"
11
12
  require_relative "language_server/document_link_engine"
12
13
  require_relative "language_server/diagnostics_tracker"
13
14
 
@@ -15,6 +16,10 @@ Dir[__dir__ + "/language_server/completion_providers/*.rb"].each do |file|
15
16
  require file
16
17
  end
17
18
 
19
+ Dir[__dir__ + "/language_server/document_link_providers/*.rb"].each do |file|
20
+ require file
21
+ end
22
+
18
23
  module ThemeCheck
19
24
  module LanguageServer
20
25
  def self.start
@@ -7,7 +7,8 @@ module ThemeCheck
7
7
  LIQUID_REGEX = /\.liquid$/i
8
8
  JSON_REGEX = /\.json$/i
9
9
 
10
- attr_accessor :storage
10
+ attr_reader :storage
11
+ attr_writer :default_locale_json
11
12
 
12
13
  def initialize(storage)
13
14
  @storage = storage
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module ThemeCheck
3
- VERSION = "1.3.0"
3
+ VERSION = "1.4.0"
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: theme-check
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marc-André Cournoyer
@@ -194,6 +194,11 @@ files:
194
194
  - lib/theme_check/language_server/constants.rb
195
195
  - lib/theme_check/language_server/diagnostics_tracker.rb
196
196
  - lib/theme_check/language_server/document_link_engine.rb
197
+ - lib/theme_check/language_server/document_link_provider.rb
198
+ - lib/theme_check/language_server/document_link_providers/asset_document_link_provider.rb
199
+ - lib/theme_check/language_server/document_link_providers/include_document_link_provider.rb
200
+ - lib/theme_check/language_server/document_link_providers/render_document_link_provider.rb
201
+ - lib/theme_check/language_server/document_link_providers/section_document_link_provider.rb
197
202
  - lib/theme_check/language_server/handler.rb
198
203
  - lib/theme_check/language_server/protocol.rb
199
204
  - lib/theme_check/language_server/server.rb