theme-check 0.4.0 → 0.7.2
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 +4 -4
- data/.github/workflows/theme-check.yml +10 -3
- data/.rubocop.yml +12 -3
- data/CHANGELOG.md +40 -0
- data/CONTRIBUTING.md +5 -2
- data/Gemfile +5 -3
- data/LICENSE.md +2 -0
- data/README.md +12 -2
- data/RELEASING.md +10 -3
- data/Rakefile +6 -0
- data/config/default.yml +16 -0
- data/data/shopify_liquid/tags.yml +1 -0
- data/data/shopify_translation_keys.yml +850 -0
- data/docs/checks/CHECK_DOCS_TEMPLATE.md +47 -0
- data/docs/checks/asset_size_css.md +52 -0
- data/docs/checks/asset_size_javascript.md +79 -0
- data/docs/checks/convert_include_to_render.md +48 -0
- data/docs/checks/default_locale.md +46 -0
- data/docs/checks/deprecated_filter.md +46 -0
- data/docs/checks/img_width_and_height.md +79 -0
- data/docs/checks/liquid_tag.md +65 -0
- data/docs/checks/matching_schema_translations.md +93 -0
- data/docs/checks/matching_translations.md +72 -0
- data/docs/checks/missing_enable_comment.md +50 -0
- data/docs/checks/missing_required_template_files.md +26 -0
- data/docs/checks/missing_template.md +40 -0
- data/docs/checks/nested_snippet.md +69 -0
- data/docs/checks/parser_blocking_javascript.md +97 -0
- data/docs/checks/remote_asset.md +82 -0
- data/docs/checks/required_directories.md +25 -0
- data/docs/checks/required_layout_theme_object.md +28 -0
- data/docs/checks/space_inside_braces.md +63 -0
- data/docs/checks/syntax_error.md +49 -0
- data/docs/checks/template_length.md +50 -0
- data/docs/checks/translation_key_exists.md +63 -0
- data/docs/checks/undefined_object.md +53 -0
- data/docs/checks/unknown_filter.md +45 -0
- data/docs/checks/unused_assign.md +47 -0
- data/docs/checks/unused_snippet.md +32 -0
- data/docs/checks/valid_html_translation.md +53 -0
- data/docs/checks/valid_json.md +60 -0
- data/docs/checks/valid_schema.md +50 -0
- data/lib/theme_check.rb +4 -0
- data/lib/theme_check/asset_file.rb +34 -0
- data/lib/theme_check/check.rb +20 -10
- data/lib/theme_check/checks/asset_size_css.rb +89 -0
- data/lib/theme_check/checks/asset_size_javascript.rb +68 -0
- data/lib/theme_check/checks/convert_include_to_render.rb +1 -1
- data/lib/theme_check/checks/default_locale.rb +1 -0
- data/lib/theme_check/checks/deprecated_filter.rb +1 -1
- data/lib/theme_check/checks/img_width_and_height.rb +74 -0
- data/lib/theme_check/checks/liquid_tag.rb +3 -3
- data/lib/theme_check/checks/matching_schema_translations.rb +1 -0
- data/lib/theme_check/checks/matching_translations.rb +2 -1
- data/lib/theme_check/checks/missing_enable_comment.rb +1 -0
- data/lib/theme_check/checks/missing_required_template_files.rb +1 -2
- data/lib/theme_check/checks/missing_template.rb +1 -0
- data/lib/theme_check/checks/nested_snippet.rb +1 -0
- data/lib/theme_check/checks/parser_blocking_javascript.rb +8 -15
- data/lib/theme_check/checks/remote_asset.rb +99 -0
- data/lib/theme_check/checks/required_directories.rb +1 -1
- data/lib/theme_check/checks/required_layout_theme_object.rb +1 -1
- data/lib/theme_check/checks/space_inside_braces.rb +1 -0
- data/lib/theme_check/checks/syntax_error.rb +1 -0
- data/lib/theme_check/checks/template_length.rb +1 -0
- data/lib/theme_check/checks/translation_key_exists.rb +14 -1
- data/lib/theme_check/checks/undefined_object.rb +11 -5
- data/lib/theme_check/checks/unknown_filter.rb +1 -0
- data/lib/theme_check/checks/unused_assign.rb +1 -0
- data/lib/theme_check/checks/unused_snippet.rb +1 -0
- data/lib/theme_check/checks/valid_html_translation.rb +2 -1
- data/lib/theme_check/checks/valid_json.rb +1 -0
- data/lib/theme_check/checks/valid_schema.rb +1 -0
- data/lib/theme_check/cli.rb +29 -9
- data/lib/theme_check/config.rb +5 -2
- data/lib/theme_check/disabled_checks.rb +2 -2
- data/lib/theme_check/in_memory_storage.rb +13 -8
- data/lib/theme_check/language_server.rb +2 -0
- data/lib/theme_check/language_server/completion_engine.rb +3 -3
- data/lib/theme_check/language_server/completion_helper.rb +0 -10
- data/lib/theme_check/language_server/completion_provider.rb +5 -0
- data/lib/theme_check/language_server/completion_providers/filter_completion_provider.rb +6 -2
- data/lib/theme_check/language_server/completion_providers/object_completion_provider.rb +1 -1
- data/lib/theme_check/language_server/completion_providers/render_snippet_completion_provider.rb +43 -0
- data/lib/theme_check/language_server/completion_providers/tag_completion_provider.rb +2 -2
- data/lib/theme_check/language_server/constants.rb +10 -0
- data/lib/theme_check/language_server/document_link_engine.rb +48 -0
- data/lib/theme_check/language_server/handler.rb +67 -20
- data/lib/theme_check/language_server/server.rb +9 -4
- data/lib/theme_check/liquid_check.rb +11 -0
- data/lib/theme_check/node.rb +1 -2
- data/lib/theme_check/offense.rb +3 -1
- data/lib/theme_check/packager.rb +1 -1
- data/lib/theme_check/regex_helpers.rb +15 -0
- data/lib/theme_check/releaser.rb +39 -0
- data/lib/theme_check/remote_asset_file.rb +44 -0
- data/lib/theme_check/shopify_liquid/deprecated_filter.rb +10 -8
- data/lib/theme_check/shopify_liquid/filter.rb +3 -5
- data/lib/theme_check/shopify_liquid/object.rb +2 -6
- data/lib/theme_check/shopify_liquid/tag.rb +1 -3
- data/lib/theme_check/storage.rb +3 -3
- data/lib/theme_check/string_helpers.rb +47 -0
- data/lib/theme_check/tags.rb +1 -2
- data/lib/theme_check/theme.rb +7 -1
- data/lib/theme_check/version.rb +1 -1
- data/packaging/homebrew/theme_check.base.rb +1 -1
- data/theme-check.gemspec +1 -2
- metadata +46 -18
|
@@ -7,12 +7,12 @@ module ThemeCheck
|
|
|
7
7
|
return [] unless can_complete?(content, cursor)
|
|
8
8
|
partial = first_word(content) || ''
|
|
9
9
|
ShopifyLiquid::Tag.labels
|
|
10
|
-
.select { |w| w.
|
|
10
|
+
.select { |w| w.start_with?(partial) }
|
|
11
11
|
.map { |tag| tag_to_completion(tag) }
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def can_complete?(content, cursor)
|
|
15
|
-
content.
|
|
15
|
+
content.start_with?(Liquid::TagStart) && (
|
|
16
16
|
cursor_on_first_word?(content, cursor) ||
|
|
17
17
|
cursor_on_start_content?(content, cursor, Liquid::TagStart)
|
|
18
18
|
)
|
|
@@ -0,0 +1,48 @@
|
|
|
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(relative_path)
|
|
14
|
+
buffer = @storage.read(relative_path)
|
|
15
|
+
return [] unless buffer
|
|
16
|
+
matches(buffer, PARTIAL_RENDER).map do |match|
|
|
17
|
+
start_line, start_character = from_index_to_line_column(
|
|
18
|
+
buffer,
|
|
19
|
+
match.begin(:partial),
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
end_line, end_character = from_index_to_line_column(
|
|
23
|
+
buffer,
|
|
24
|
+
match.end(:partial)
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
{
|
|
28
|
+
target: 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
|
+
}
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def link(partial)
|
|
44
|
+
"file://#{@storage.path('snippets/' + partial + '.liquid')}"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
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,
|
|
@@ -40,41 +42,70 @@ module ThemeCheck
|
|
|
40
42
|
alias_method :on_shutdown, :on_exit
|
|
41
43
|
|
|
42
44
|
def on_text_document_did_change(_id, params)
|
|
43
|
-
|
|
44
|
-
@storage.write(
|
|
45
|
+
relative_path = relative_path_from_text_document_uri(params)
|
|
46
|
+
@storage.write(relative_path, content_changes_text(params))
|
|
45
47
|
end
|
|
46
48
|
|
|
47
49
|
def on_text_document_did_close(_id, params)
|
|
48
|
-
|
|
49
|
-
@storage.write(
|
|
50
|
+
relative_path = relative_path_from_text_document_uri(params)
|
|
51
|
+
@storage.write(relative_path, "")
|
|
50
52
|
end
|
|
51
53
|
|
|
52
54
|
def on_text_document_did_open(_id, params)
|
|
53
|
-
|
|
54
|
-
@storage.write(
|
|
55
|
-
analyze_and_send_offenses(
|
|
55
|
+
relative_path = relative_path_from_text_document_uri(params)
|
|
56
|
+
@storage.write(relative_path, text_document_text(params))
|
|
57
|
+
analyze_and_send_offenses(text_document_uri(params))
|
|
56
58
|
end
|
|
57
59
|
|
|
58
60
|
def on_text_document_did_save(_id, params)
|
|
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
|
+
relative_path = relative_path_from_text_document_uri(params)
|
|
66
|
+
send_response(
|
|
67
|
+
id: id,
|
|
68
|
+
result: document_links(relative_path)
|
|
69
|
+
)
|
|
70
|
+
end
|
|
71
|
+
|
|
62
72
|
def on_text_document_completion(id, params)
|
|
63
|
-
|
|
73
|
+
relative_path = relative_path_from_text_document_uri(params)
|
|
64
74
|
line = params.dig('position', 'line')
|
|
65
75
|
col = params.dig('position', 'character')
|
|
66
76
|
send_response(
|
|
67
77
|
id: id,
|
|
68
|
-
result: completions(
|
|
78
|
+
result: completions(relative_path, line, col)
|
|
69
79
|
)
|
|
70
80
|
end
|
|
71
81
|
|
|
72
82
|
private
|
|
73
83
|
|
|
84
|
+
def in_memory_storage(root)
|
|
85
|
+
config = config_for_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, config.root)
|
|
99
|
+
end
|
|
100
|
+
|
|
74
101
|
def text_document_uri(params)
|
|
75
102
|
params.dig('textDocument', 'uri').sub('file://', '')
|
|
76
103
|
end
|
|
77
104
|
|
|
105
|
+
def relative_path_from_text_document_uri(params)
|
|
106
|
+
@storage.relative_path(text_document_uri(params))
|
|
107
|
+
end
|
|
108
|
+
|
|
78
109
|
def text_document_text(params)
|
|
79
110
|
params.dig('textDocument', 'text')
|
|
80
111
|
end
|
|
@@ -83,9 +114,13 @@ module ThemeCheck
|
|
|
83
114
|
params.dig('contentChanges', 0, 'text')
|
|
84
115
|
end
|
|
85
116
|
|
|
86
|
-
def
|
|
87
|
-
root = ThemeCheck::Config.find(
|
|
88
|
-
|
|
117
|
+
def config_for_path(path)
|
|
118
|
+
root = ThemeCheck::Config.find(path) || @root_path
|
|
119
|
+
ThemeCheck::Config.from_path(root)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def analyze_and_send_offenses(absolute_path)
|
|
123
|
+
config = config_for_path(absolute_path)
|
|
89
124
|
storage = ThemeCheck::FileSystemStorage.new(
|
|
90
125
|
config.root,
|
|
91
126
|
ignored_patterns: config.ignored_patterns
|
|
@@ -104,8 +139,12 @@ module ThemeCheck
|
|
|
104
139
|
analyzer.offenses
|
|
105
140
|
end
|
|
106
141
|
|
|
107
|
-
def completions(
|
|
108
|
-
@completion_engine.completions(
|
|
142
|
+
def completions(relative_path, line, col)
|
|
143
|
+
@completion_engine.completions(relative_path, line, col)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def document_links(relative_path)
|
|
147
|
+
@document_link_engine.document_links(relative_path)
|
|
109
148
|
end
|
|
110
149
|
|
|
111
150
|
def send_diagnostics(offenses)
|
|
@@ -131,19 +170,27 @@ module ThemeCheck
|
|
|
131
170
|
send_response(
|
|
132
171
|
method: 'textDocument/publishDiagnostics',
|
|
133
172
|
params: {
|
|
134
|
-
uri: "file
|
|
173
|
+
uri: "file://#{path}",
|
|
135
174
|
diagnostics: offenses.map { |offense| offense_to_diagnostic(offense) },
|
|
136
175
|
},
|
|
137
176
|
)
|
|
138
177
|
end
|
|
139
178
|
|
|
140
179
|
def offense_to_diagnostic(offense)
|
|
141
|
-
{
|
|
180
|
+
diagnostic = {
|
|
181
|
+
code: offense.code_name,
|
|
182
|
+
message: offense.message,
|
|
142
183
|
range: range(offense),
|
|
143
184
|
severity: severity(offense),
|
|
144
|
-
code: offense.code_name,
|
|
145
185
|
source: "theme-check",
|
|
146
|
-
|
|
186
|
+
}
|
|
187
|
+
diagnostic["codeDescription"] = code_description(offense) unless offense.doc.nil?
|
|
188
|
+
diagnostic
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def code_description(offense)
|
|
192
|
+
{
|
|
193
|
+
href: offense.doc,
|
|
147
194
|
}
|
|
148
195
|
end
|
|
149
196
|
|
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
require 'json'
|
|
3
3
|
require 'stringio'
|
|
4
|
-
require 'active_support/core_ext/string/inflections'
|
|
5
4
|
|
|
6
5
|
module ThemeCheck
|
|
7
6
|
module LanguageServer
|
|
8
7
|
class DoneStreaming < StandardError; end
|
|
8
|
+
|
|
9
9
|
class IncompatibleStream < StandardError; end
|
|
10
10
|
|
|
11
11
|
class Server
|
|
12
12
|
attr_reader :handler
|
|
13
|
+
attr_reader :should_raise_errors
|
|
13
14
|
|
|
14
15
|
def initialize(
|
|
15
16
|
in_stream: STDIN,
|
|
16
17
|
out_stream: STDOUT,
|
|
17
|
-
err_stream:
|
|
18
|
+
err_stream: STDERR,
|
|
19
|
+
should_raise_errors: false
|
|
18
20
|
)
|
|
19
21
|
validate!([in_stream, out_stream, err_stream])
|
|
20
22
|
|
|
@@ -25,6 +27,8 @@ module ThemeCheck
|
|
|
25
27
|
|
|
26
28
|
@out.sync = true # do not buffer
|
|
27
29
|
@err.sync = true # do not buffer
|
|
30
|
+
|
|
31
|
+
@should_raise_errors = should_raise_errors
|
|
28
32
|
end
|
|
29
33
|
|
|
30
34
|
def listen
|
|
@@ -37,6 +41,7 @@ module ThemeCheck
|
|
|
37
41
|
return 0
|
|
38
42
|
|
|
39
43
|
rescue Exception => e # rubocop:disable Lint/RescueException
|
|
44
|
+
raise e if should_raise_errors
|
|
40
45
|
log(e)
|
|
41
46
|
log(e.backtrace)
|
|
42
47
|
return 1
|
|
@@ -45,7 +50,7 @@ module ThemeCheck
|
|
|
45
50
|
|
|
46
51
|
def send_response(response)
|
|
47
52
|
response_body = JSON.dump(response)
|
|
48
|
-
log(
|
|
53
|
+
log(JSON.pretty_generate(response)) if $DEBUG
|
|
49
54
|
|
|
50
55
|
@out.write("Content-Length: #{response_body.size}\r\n")
|
|
51
56
|
@out.write("\r\n")
|
|
@@ -93,7 +98,7 @@ module ThemeCheck
|
|
|
93
98
|
end
|
|
94
99
|
|
|
95
100
|
def to_snake_case(method_name)
|
|
96
|
-
method_name.gsub(/[^\w]/, '_')
|
|
101
|
+
StringHelpers.underscore(method_name.gsub(/[^\w]/, '_'))
|
|
97
102
|
end
|
|
98
103
|
|
|
99
104
|
def initial_line
|
|
@@ -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/node.rb
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
require 'active_support/core_ext/string/inflections'
|
|
3
2
|
|
|
4
3
|
module ThemeCheck
|
|
5
4
|
# A node from the Liquid AST, the result of parsing a template.
|
|
@@ -101,7 +100,7 @@ module ThemeCheck
|
|
|
101
100
|
# The `:under_score_name` of this type of node. Used to dispatch to the `on_<type_name>`
|
|
102
101
|
# and `after_<type_name>` check methods.
|
|
103
102
|
def type_name
|
|
104
|
-
@type_name ||= @value.class.name.
|
|
103
|
+
@type_name ||= StringHelpers.underscore(StringHelpers.demodulize(@value.class.name)).to_sym
|
|
105
104
|
end
|
|
106
105
|
|
|
107
106
|
# Is this node inside a `{% liquid ... %}` block?
|
data/lib/theme_check/offense.rb
CHANGED
|
@@ -32,6 +32,8 @@ module ThemeCheck
|
|
|
32
32
|
node&.markup
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
+
raise ArgumentError, "Offense markup cannot be an empty string" if @markup.is_a?(String) && @markup.empty?
|
|
36
|
+
|
|
35
37
|
@line_number = if line_number
|
|
36
38
|
line_number
|
|
37
39
|
elsif @node
|
|
@@ -83,7 +85,7 @@ module ThemeCheck
|
|
|
83
85
|
end
|
|
84
86
|
|
|
85
87
|
def check_name
|
|
86
|
-
check.class.name
|
|
88
|
+
StringHelpers.demodulize(check.class.name)
|
|
87
89
|
end
|
|
88
90
|
|
|
89
91
|
def doc
|
data/lib/theme_check/packager.rb
CHANGED
|
@@ -24,7 +24,7 @@ module ThemeCheck
|
|
|
24
24
|
puts "Grabbing sha256 checksum from Rubygems.org"
|
|
25
25
|
require 'digest/sha2'
|
|
26
26
|
require 'open-uri'
|
|
27
|
-
gem_checksum = open("https://rubygems.org/downloads/theme-check-#{ThemeCheck::VERSION}.gem") do |io|
|
|
27
|
+
gem_checksum = URI.open("https://rubygems.org/downloads/theme-check-#{ThemeCheck::VERSION}.gem") do |io|
|
|
28
28
|
Digest::SHA256.new.hexdigest(io.read)
|
|
29
29
|
end
|
|
30
30
|
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'theme_check/version'
|
|
3
|
+
|
|
4
|
+
module ThemeCheck
|
|
5
|
+
class Releaser
|
|
6
|
+
ROOT = File.expand_path('../../..', __FILE__)
|
|
7
|
+
LIB = File.join(ROOT, 'lib')
|
|
8
|
+
|
|
9
|
+
class VersionError < StandardError; end
|
|
10
|
+
|
|
11
|
+
def release(version)
|
|
12
|
+
raise VersionError, "Missing version argument." if version.nil?
|
|
13
|
+
raise VersionError, "Version should be a string." unless version.is_a?(String)
|
|
14
|
+
raise VersionError, "Version should be a valid semver version." unless version =~ /^\d+\.\d+.\d+$/
|
|
15
|
+
update_docs(version)
|
|
16
|
+
update_version(version)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def update_version(version)
|
|
20
|
+
version_file_path = File.join(LIB, 'theme_check/version.rb')
|
|
21
|
+
version_file = File.read(version_file_path)
|
|
22
|
+
updated_version_file = version_file.gsub(ThemeCheck::VERSION, version)
|
|
23
|
+
|
|
24
|
+
return if updated_version_file == version_file
|
|
25
|
+
puts "Updating version to #{version} in #{version_file_path}."
|
|
26
|
+
File.write(version_file_path, updated_version_file)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def update_docs(version)
|
|
30
|
+
Dir[ROOT + '/docs/checks/*.md'].each do |filename|
|
|
31
|
+
doc_content = File.read(filename)
|
|
32
|
+
updated_doc_content = doc_content.gsub('THEME_CHECK_VERSION', version)
|
|
33
|
+
next if updated_doc_content == doc_content
|
|
34
|
+
puts "Replacing `THEME_CHECK_VERSION` with #{version} in #{Pathname.new(filename).relative_path_from(ROOT)}"
|
|
35
|
+
File.write(filename, updated_doc_content)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
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
|