theme-check 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +6 -3
- data/CHANGELOG.md +11 -0
- data/Gemfile +5 -3
- data/README.md +2 -0
- data/config/default.yml +8 -1
- data/data/shopify_translation_keys.yml +850 -0
- data/docs/checks/asset_size_css.md +52 -0
- data/docs/checks/img_width_and_height.md +79 -0
- data/docs/checks/parser_blocking_javascript.md +3 -3
- data/lib/theme_check/checks/asset_size_css.rb +89 -0
- data/lib/theme_check/checks/asset_size_javascript.rb +1 -7
- data/lib/theme_check/checks/img_width_and_height.rb +74 -0
- data/lib/theme_check/checks/parser_blocking_javascript.rb +5 -13
- data/lib/theme_check/checks/translation_key_exists.rb +16 -1
- data/lib/theme_check/cli.rb +19 -8
- data/lib/theme_check/config.rb +3 -0
- data/lib/theme_check/in_memory_storage.rb +11 -3
- data/lib/theme_check/language_server.rb +2 -0
- data/lib/theme_check/language_server/completion_engine.rb +1 -1
- data/lib/theme_check/language_server/completion_provider.rb +4 -0
- data/lib/theme_check/language_server/completion_providers/filter_completion_provider.rb +5 -1
- data/lib/theme_check/language_server/completion_providers/render_snippet_completion_provider.rb +43 -0
- data/lib/theme_check/language_server/constants.rb +10 -0
- data/lib/theme_check/language_server/document_link_engine.rb +47 -0
- data/lib/theme_check/language_server/handler.rb +33 -2
- data/lib/theme_check/language_server/server.rb +3 -2
- data/lib/theme_check/liquid_check.rb +11 -0
- data/lib/theme_check/remote_asset_file.rb +1 -1
- data/lib/theme_check/shopify_liquid/deprecated_filter.rb +4 -0
- data/lib/theme_check/version.rb +1 -1
- metadata +10 -2
data/lib/theme_check/config.rb
CHANGED
@@ -10,6 +10,8 @@ module ThemeCheck
|
|
10
10
|
attr_accessor :only_categories, :exclude_categories, :auto_correct
|
11
11
|
|
12
12
|
class << self
|
13
|
+
attr_reader :last_loaded_config
|
14
|
+
|
13
15
|
def from_path(path)
|
14
16
|
if (filename = find(path))
|
15
17
|
new(root: filename.dirname, configuration: load_file(filename))
|
@@ -36,6 +38,7 @@ module ThemeCheck
|
|
36
38
|
end
|
37
39
|
|
38
40
|
def load_file(absolute_path)
|
41
|
+
@last_loaded_config = absolute_path
|
39
42
|
YAML.load_file(absolute_path)
|
40
43
|
end
|
41
44
|
|
@@ -6,20 +6,28 @@
|
|
6
6
|
# as a big hash already, leave it like that and save yourself some IO.
|
7
7
|
module ThemeCheck
|
8
8
|
class InMemoryStorage < Storage
|
9
|
-
def initialize(files = {})
|
9
|
+
def initialize(files = {}, root = nil)
|
10
10
|
@files = files
|
11
|
+
@root = root
|
11
12
|
end
|
12
13
|
|
13
14
|
def path(name)
|
15
|
+
return File.join(@root, name) unless @root.nil?
|
16
|
+
name
|
17
|
+
end
|
18
|
+
|
19
|
+
def relative_path(name)
|
20
|
+
path = Pathname.new(name)
|
21
|
+
return path.relative_path_from(@root).to_s unless path.relative? || @root.nil?
|
14
22
|
name
|
15
23
|
end
|
16
24
|
|
17
25
|
def read(name)
|
18
|
-
@files[name]
|
26
|
+
@files[relative_path(name)]
|
19
27
|
end
|
20
28
|
|
21
29
|
def write(name, content)
|
22
|
-
@files[name] = content
|
30
|
+
@files[relative_path(name)] = content
|
23
31
|
end
|
24
32
|
|
25
33
|
def files
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require_relative "language_server/protocol"
|
3
|
+
require_relative "language_server/constants"
|
3
4
|
require_relative "language_server/handler"
|
4
5
|
require_relative "language_server/server"
|
5
6
|
require_relative "language_server/tokens"
|
@@ -7,6 +8,7 @@ require_relative "language_server/position_helper"
|
|
7
8
|
require_relative "language_server/completion_helper"
|
8
9
|
require_relative "language_server/completion_provider"
|
9
10
|
require_relative "language_server/completion_engine"
|
11
|
+
require_relative "language_server/document_link_engine"
|
10
12
|
|
11
13
|
Dir[__dir__ + "/language_server/completion_providers/*.rb"].each do |file|
|
12
14
|
require file
|
@@ -7,7 +7,7 @@ module ThemeCheck
|
|
7
7
|
|
8
8
|
def completions(content, cursor)
|
9
9
|
return [] unless can_complete?(content, cursor)
|
10
|
-
|
10
|
+
available_labels
|
11
11
|
.select { |w| w.starts_with?(partial(content, cursor)) }
|
12
12
|
.map { |filter| filter_to_completion(filter) }
|
13
13
|
end
|
@@ -21,6 +21,10 @@ module ThemeCheck
|
|
21
21
|
|
22
22
|
private
|
23
23
|
|
24
|
+
def available_labels
|
25
|
+
@labels ||= ShopifyLiquid::Filter.labels - ShopifyLiquid::DeprecatedFilter.labels
|
26
|
+
end
|
27
|
+
|
24
28
|
def cursor_on_filter?(content, cursor)
|
25
29
|
return false unless content.match?(NAMED_FILTER)
|
26
30
|
matches(content, NAMED_FILTER).any? do |match|
|
data/lib/theme_check/language_server/completion_providers/render_snippet_completion_provider.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ThemeCheck
|
4
|
+
module LanguageServer
|
5
|
+
class RenderSnippetCompletionProvider < CompletionProvider
|
6
|
+
def completions(content, cursor)
|
7
|
+
return [] unless cursor_on_quoted_argument?(content, cursor)
|
8
|
+
partial = snippet(content) || ''
|
9
|
+
snippets
|
10
|
+
.select { |x| x.starts_with?(partial) }
|
11
|
+
.map { |x| snippet_to_completion(x) }
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def cursor_on_quoted_argument?(content, cursor)
|
17
|
+
match = content.match(PARTIAL_RENDER)
|
18
|
+
return false if match.nil?
|
19
|
+
match.begin(:partial) <= cursor && cursor <= match.end(:partial)
|
20
|
+
end
|
21
|
+
|
22
|
+
def snippet(content)
|
23
|
+
match = content.match(PARTIAL_RENDER)
|
24
|
+
return if match.nil?
|
25
|
+
match[:partial]
|
26
|
+
end
|
27
|
+
|
28
|
+
def snippets
|
29
|
+
@storage
|
30
|
+
.files
|
31
|
+
.select { |x| x.include?('snippets/') }
|
32
|
+
end
|
33
|
+
|
34
|
+
def snippet_to_completion(file)
|
35
|
+
{
|
36
|
+
label: File.basename(file, '.liquid'),
|
37
|
+
kind: CompletionItemKinds::SNIPPET,
|
38
|
+
detail: file,
|
39
|
+
}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ThemeCheck
|
4
|
+
module LanguageServer
|
5
|
+
class DocumentLinkEngine
|
6
|
+
include PositionHelper
|
7
|
+
include RegexHelpers
|
8
|
+
|
9
|
+
def initialize(storage)
|
10
|
+
@storage = storage
|
11
|
+
end
|
12
|
+
|
13
|
+
def document_links(uri)
|
14
|
+
buffer = @storage.read(uri)
|
15
|
+
matches(buffer, PARTIAL_RENDER).map do |match|
|
16
|
+
start_line, start_character = from_index_to_line_column(
|
17
|
+
buffer,
|
18
|
+
match.begin(:partial),
|
19
|
+
)
|
20
|
+
|
21
|
+
end_line, end_character = from_index_to_line_column(
|
22
|
+
buffer,
|
23
|
+
match.end(:partial)
|
24
|
+
)
|
25
|
+
|
26
|
+
{
|
27
|
+
target: link(match[:partial]),
|
28
|
+
range: {
|
29
|
+
start: {
|
30
|
+
line: start_line,
|
31
|
+
character: start_character,
|
32
|
+
},
|
33
|
+
end: {
|
34
|
+
line: end_line,
|
35
|
+
character: end_character,
|
36
|
+
},
|
37
|
+
},
|
38
|
+
}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def link(partial)
|
43
|
+
'file://' + @storage.path('snippets/' + partial + '.liquid')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -8,6 +8,7 @@ module ThemeCheck
|
|
8
8
|
triggerCharacters: ['.', '{{ ', '{% '],
|
9
9
|
context: true,
|
10
10
|
},
|
11
|
+
documentLinkProvider: true,
|
11
12
|
textDocumentSync: {
|
12
13
|
openClose: true,
|
13
14
|
change: TextDocumentSyncKind::FULL,
|
@@ -19,12 +20,13 @@ module ThemeCheck
|
|
19
20
|
def initialize(server)
|
20
21
|
@server = server
|
21
22
|
@previously_reported_files = Set.new
|
22
|
-
@storage = InMemoryStorage.new
|
23
|
-
@completion_engine = CompletionEngine.new(@storage)
|
24
23
|
end
|
25
24
|
|
26
25
|
def on_initialize(id, params)
|
27
26
|
@root_path = params["rootPath"]
|
27
|
+
@storage = in_memory_storage(@root_path)
|
28
|
+
@completion_engine = CompletionEngine.new(@storage)
|
29
|
+
@document_link_engine = DocumentLinkEngine.new(@storage)
|
28
30
|
# https://microsoft.github.io/language-server-protocol/specifications/specification-current/#responseMessage
|
29
31
|
send_response(
|
30
32
|
id: id,
|
@@ -59,6 +61,14 @@ module ThemeCheck
|
|
59
61
|
analyze_and_send_offenses(text_document_uri(params))
|
60
62
|
end
|
61
63
|
|
64
|
+
def on_text_document_document_link(id, params)
|
65
|
+
uri = text_document_uri(params)
|
66
|
+
send_response(
|
67
|
+
id: id,
|
68
|
+
result: document_links(uri)
|
69
|
+
)
|
70
|
+
end
|
71
|
+
|
62
72
|
def on_text_document_completion(id, params)
|
63
73
|
uri = text_document_uri(params)
|
64
74
|
line = params.dig('position', 'line')
|
@@ -71,6 +81,23 @@ module ThemeCheck
|
|
71
81
|
|
72
82
|
private
|
73
83
|
|
84
|
+
def in_memory_storage(root)
|
85
|
+
config = ThemeCheck::Config.from_path(root)
|
86
|
+
|
87
|
+
# Make a real FS to get the files from the snippets folder
|
88
|
+
fs = ThemeCheck::FileSystemStorage.new(
|
89
|
+
config.root,
|
90
|
+
ignored_patterns: config.ignored_patterns
|
91
|
+
)
|
92
|
+
|
93
|
+
# Turn that into a hash of empty buffers
|
94
|
+
files = fs.files
|
95
|
+
.map { |fn| [fn, ""] }
|
96
|
+
.to_h
|
97
|
+
|
98
|
+
InMemoryStorage.new(files, root)
|
99
|
+
end
|
100
|
+
|
74
101
|
def text_document_uri(params)
|
75
102
|
params.dig('textDocument', 'uri').sub('file://', '')
|
76
103
|
end
|
@@ -108,6 +135,10 @@ module ThemeCheck
|
|
108
135
|
@completion_engine.completions(uri, line, col)
|
109
136
|
end
|
110
137
|
|
138
|
+
def document_links(uri)
|
139
|
+
@document_link_engine.document_links(uri)
|
140
|
+
end
|
141
|
+
|
111
142
|
def send_diagnostics(offenses)
|
112
143
|
reported_files = Set.new
|
113
144
|
|
@@ -6,6 +6,7 @@ require 'active_support/core_ext/string/inflections'
|
|
6
6
|
module ThemeCheck
|
7
7
|
module LanguageServer
|
8
8
|
class DoneStreaming < StandardError; end
|
9
|
+
|
9
10
|
class IncompatibleStream < StandardError; end
|
10
11
|
|
11
12
|
class Server
|
@@ -15,7 +16,7 @@ module ThemeCheck
|
|
15
16
|
def initialize(
|
16
17
|
in_stream: STDIN,
|
17
18
|
out_stream: STDOUT,
|
18
|
-
err_stream:
|
19
|
+
err_stream: STDERR,
|
19
20
|
should_raise_errors: false
|
20
21
|
)
|
21
22
|
validate!([in_stream, out_stream, err_stream])
|
@@ -50,7 +51,7 @@ module ThemeCheck
|
|
50
51
|
|
51
52
|
def send_response(response)
|
52
53
|
response_body = JSON.dump(response)
|
53
|
-
log(
|
54
|
+
log(JSON.pretty_generate(response)) if $DEBUG
|
54
55
|
|
55
56
|
@out.write("Content-Length: #{response_body.size}\r\n")
|
56
57
|
@out.write("\r\n")
|
@@ -6,6 +6,17 @@ module ThemeCheck
|
|
6
6
|
extend ChecksTracking
|
7
7
|
include ParsingHelpers
|
8
8
|
|
9
|
+
TAG = /#{Liquid::TagStart}.*?#{Liquid::TagEnd}/om
|
10
|
+
VARIABLE = /#{Liquid::VariableStart}.*?#{Liquid::VariableEnd}/om
|
11
|
+
START_OR_END_QUOTE = /(^['"])|(['"]$)/
|
12
|
+
QUOTED_LIQUID_ATTRIBUTE = %r{
|
13
|
+
'(?:#{TAG}|#{VARIABLE}|[^'])*'| # any combination of tag/variable or non straight quote inside straight quotes
|
14
|
+
"(?:#{TAG}|#{VARIABLE}|[^"])*" # any combination of tag/variable or non double quotes inside double quotes
|
15
|
+
}omix
|
16
|
+
ATTR = /[a-z0-9-]+/i
|
17
|
+
HTML_ATTRIBUTE = /#{ATTR}(?:=#{QUOTED_LIQUID_ATTRIBUTE})?/omix
|
18
|
+
HTML_ATTRIBUTES = /(?:#{HTML_ATTRIBUTE}|\s)*/omix
|
19
|
+
|
9
20
|
def add_offense(message, node: nil, template: node&.template, markup: nil, line_number: nil, &block)
|
10
21
|
offenses << Offense.new(check: self, message: message, template: template, node: node, markup: markup, line_number: line_number, correction: block)
|
11
22
|
end
|
data/lib/theme_check/version.rb
CHANGED
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.
|
4
|
+
version: 0.6.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-03-
|
11
|
+
date: 2021-03-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: liquid
|
@@ -81,12 +81,15 @@ files:
|
|
81
81
|
- data/shopify_liquid/objects.yml
|
82
82
|
- data/shopify_liquid/plus_objects.yml
|
83
83
|
- data/shopify_liquid/tags.yml
|
84
|
+
- data/shopify_translation_keys.yml
|
84
85
|
- dev.yml
|
85
86
|
- docs/checks/CHECK_DOCS_TEMPLATE.md
|
87
|
+
- docs/checks/asset_size_css.md
|
86
88
|
- docs/checks/asset_size_javascript.md
|
87
89
|
- docs/checks/convert_include_to_render.md
|
88
90
|
- docs/checks/default_locale.md
|
89
91
|
- docs/checks/deprecated_filter.md
|
92
|
+
- docs/checks/img_width_and_height.md
|
90
93
|
- docs/checks/liquid_tag.md
|
91
94
|
- docs/checks/matching_schema_translations.md
|
92
95
|
- docs/checks/matching_translations.md
|
@@ -116,10 +119,12 @@ files:
|
|
116
119
|
- lib/theme_check/asset_file.rb
|
117
120
|
- lib/theme_check/check.rb
|
118
121
|
- lib/theme_check/checks.rb
|
122
|
+
- lib/theme_check/checks/asset_size_css.rb
|
119
123
|
- lib/theme_check/checks/asset_size_javascript.rb
|
120
124
|
- lib/theme_check/checks/convert_include_to_render.rb
|
121
125
|
- lib/theme_check/checks/default_locale.rb
|
122
126
|
- lib/theme_check/checks/deprecated_filter.rb
|
127
|
+
- lib/theme_check/checks/img_width_and_height.rb
|
123
128
|
- lib/theme_check/checks/liquid_tag.rb
|
124
129
|
- lib/theme_check/checks/matching_schema_translations.rb
|
125
130
|
- lib/theme_check/checks/matching_translations.rb
|
@@ -157,7 +162,10 @@ files:
|
|
157
162
|
- lib/theme_check/language_server/completion_provider.rb
|
158
163
|
- lib/theme_check/language_server/completion_providers/filter_completion_provider.rb
|
159
164
|
- lib/theme_check/language_server/completion_providers/object_completion_provider.rb
|
165
|
+
- lib/theme_check/language_server/completion_providers/render_snippet_completion_provider.rb
|
160
166
|
- lib/theme_check/language_server/completion_providers/tag_completion_provider.rb
|
167
|
+
- lib/theme_check/language_server/constants.rb
|
168
|
+
- lib/theme_check/language_server/document_link_engine.rb
|
161
169
|
- lib/theme_check/language_server/handler.rb
|
162
170
|
- lib/theme_check/language_server/position_helper.rb
|
163
171
|
- lib/theme_check/language_server/protocol.rb
|