theme-check 0.8.0 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 299afef3e63667dca21495d3a3e6246d378b4be98c6b26a7a5f46405e6db80b8
4
- data.tar.gz: b4d57dd51b0bd8960fcd42314fea731c1ae0aaac1ca29bbd2c591b3a6a9f4781
3
+ metadata.gz: b841f4d2f809e07dec57140fd76f373e216f721903baa7ac1dce747b5ce77c82
4
+ data.tar.gz: b513333c296966cedb4d00345cb7ab1a3d4dcbb305b92b3eb96edc598867bba5
5
5
  SHA512:
6
- metadata.gz: ea83f67457a564676ca6e32f7b6f601f54c2d6c259cc1a8af705d673640bb9a3e11881f54ca9cc571faf75cb36af93b51c5f03c96547d2cb24eb19ff69d59795
7
- data.tar.gz: 2694a73abcb292ebcc6d1f142a9255f9b5126d4748c64ece82c0081acb65d12c194acbd6232f24b50d0ddf982d076f49b342ef833883a09ab9a287712b631af5
6
+ metadata.gz: 1d75dc49ae97db15d4622d6a59b7a12a0eab0de6a6bcf19e6e8bca3b7f6eb6f94c40c11cfcdb3ac911bbc4d93e6d08cfbb83e85de763d00cb60b6fab10bfc7bb
7
+ data.tar.gz: eb7c5fdb74551461de7fd643071734dc8b2442db4a5a80492b982bc392c67a100614e4a9fa3b4580e28c5f1b8321564adc8f9580618f3bcdbc36dfd4e4ab13e3
data/CHANGELOG.md CHANGED
@@ -1,4 +1,14 @@
1
1
 
2
+ 0.8.1 / 2021-04-22
3
+ ==================
4
+
5
+ * Add consistent spacing around the pipe character (`|`) in variable expressions to the `SpaceInsideBrace` check ([#73](https://github.com/shopify/theme-check/issues/73))
6
+ * Add ReCaptcha system translation ([#265](https://github.com/shopify/theme-check/issues/265))
7
+ * Fix document links in `{% liquid %}` tags ([#263](https://github.com/shopify/theme-check/issues/263))
8
+ * Fix theme-check-disable for checks based on regular expressions ([#242](https://github.com/shopify/theme-check/issues/242))
9
+ * Fix VS Code crash on new window ([#264](https://github.com/shopify/theme-check/issues/264))
10
+ * Rescue errors thrown by remote_asset_file
11
+
2
12
  0.8.0 / 2021-04-13
3
13
  ==================
4
14
 
@@ -848,3 +848,4 @@
848
848
  - shopify.store_availability.pick_up_time.two_to_four_hours
849
849
  - shopify.store_availability.pick_up_time.immediately
850
850
  - shopify.store_availability.pick_up_time.next_day
851
+ - shopify.online_store.spam_detection.disclaimer_html
@@ -17,6 +17,10 @@ This check is aimed at eliminating ugly Liquid:
17
17
  <!-- After commas and semicolons -->
18
18
  {% form 'type', object, key:value %}
19
19
  {% endform %}
20
+
21
+ <!-- Arround filter pipelines -->
22
+ {{ url | asset_url | img_tag }}
23
+ {% assign my_upcase_string = "Hello world"| upcase %}
20
24
  ```
21
25
 
22
26
  :+1: Examples of **correct** code for this check:
@@ -33,6 +37,8 @@ This check is aimed at eliminating ugly Liquid:
33
37
  media_size: section.settings.product_recommendations_image_ratio,
34
38
  center_align_text: section.settings.center_align_text
35
39
  %}
40
+ {{ url | asset_url | img_tag }}
41
+ {% assign my_upcase_string = "Hello world" | upcase %}
36
42
  ```
37
43
 
38
44
  ## Check Options
data/lib/theme_check.rb CHANGED
@@ -1,10 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
  require "liquid"
3
3
 
4
+ require_relative "theme_check/exceptions"
4
5
  require_relative "theme_check/analyzer"
5
6
  require_relative "theme_check/check"
6
7
  require_relative "theme_check/checks_tracking"
7
8
  require_relative "theme_check/cli"
9
+ require_relative "theme_check/disabled_check"
8
10
  require_relative "theme_check/disabled_checks"
9
11
  require_relative "theme_check/liquid_check"
10
12
  require_relative "theme_check/locale_diff"
@@ -14,6 +16,8 @@ require_relative "theme_check/regex_helpers"
14
16
  require_relative "theme_check/json_check"
15
17
  require_relative "theme_check/json_file"
16
18
  require_relative "theme_check/json_helpers"
19
+ require_relative "theme_check/position_helper"
20
+ require_relative "theme_check/position"
17
21
  require_relative "theme_check/language_server"
18
22
  require_relative "theme_check/checks"
19
23
  require_relative "theme_check/config"
@@ -1,11 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
  module ThemeCheck
3
3
  class Analyzer
4
- attr_reader :offenses
5
-
6
4
  def initialize(theme, checks = Check.all.map(&:new), auto_correct = false)
7
5
  @theme = theme
8
- @offenses = []
9
6
  @auto_correct = auto_correct
10
7
 
11
8
  @liquid_checks = Checks.new
@@ -13,7 +10,6 @@ module ThemeCheck
13
10
 
14
11
  checks.each do |check|
15
12
  check.theme = @theme
16
- check.offenses = @offenses
17
13
 
18
14
  case check
19
15
  when LiquidCheck
@@ -26,26 +22,40 @@ module ThemeCheck
26
22
  @visitor = Visitor.new(@liquid_checks)
27
23
  end
28
24
 
25
+ def offenses
26
+ @liquid_checks.flat_map(&:offenses) + @json_checks.flat_map(&:offenses)
27
+ end
28
+
29
+ def offenses_clear!
30
+ @liquid_checks.each do |check|
31
+ check.offenses.clear
32
+ end
33
+
34
+ @json_checks.each do |check|
35
+ check.offenses.clear
36
+ end
37
+ end
38
+
29
39
  def analyze_theme
30
- @offenses.clear
40
+ offenses_clear!
31
41
  @theme.liquid.each { |template| @visitor.visit_template(template) }
32
42
  @theme.json.each { |json_file| @json_checks.call(:on_file, json_file) }
33
43
  @liquid_checks.call(:on_end)
34
44
  @json_checks.call(:on_end)
35
- @offenses
45
+ offenses
36
46
  end
37
47
 
38
48
  def uncorrectable_offenses
39
49
  unless @auto_correct
40
- return @offenses
50
+ return offenses
41
51
  end
42
52
 
43
- @offenses.select { |offense| !offense.correctable? }
53
+ offenses.select { |offense| !offense.correctable? }
44
54
  end
45
55
 
46
56
  def correct_offenses
47
57
  if @auto_correct
48
- @offenses.each(&:correct)
58
+ offenses.each(&:correct)
49
59
  @theme.liquid.each(&:write)
50
60
  end
51
61
  end
@@ -6,8 +6,8 @@ module ThemeCheck
6
6
  include JsonHelpers
7
7
 
8
8
  attr_accessor :theme
9
- attr_accessor :offenses
10
9
  attr_accessor :options
10
+ attr_writer :offenses
11
11
 
12
12
  SEVERITIES = [
13
13
  :error,
@@ -69,6 +69,10 @@ module ThemeCheck
69
69
  end
70
70
  end
71
71
 
72
+ def offenses
73
+ @offenses ||= []
74
+ end
75
+
72
76
  def severity
73
77
  self.class.severity
74
78
  end
@@ -9,14 +9,8 @@ module ThemeCheck
9
9
  end
10
10
  end
11
11
 
12
- def always_enabled
13
- self.class.new(reject(&:can_disable?))
14
- end
15
-
16
- def except_for(disabled_checks)
17
- still_enabled = reject { |check| disabled_checks.all.include?(check.code_name) }
18
-
19
- self.class.new((always_enabled + still_enabled).uniq)
12
+ def disableable
13
+ self.class.new(select(&:can_disable?))
20
14
  end
21
15
  end
22
16
  end
@@ -17,13 +17,13 @@ module ThemeCheck
17
17
  end
18
18
 
19
19
  def after_document(node)
20
- return if @disabled_checks.full_document_disabled?
21
- return unless @disabled_checks.any?
20
+ checks_missing_end_index = @disabled_checks.checks_missing_end_index
21
+ return if checks_missing_end_index.empty?
22
22
 
23
- message = if @disabled_checks.all_disabled?
23
+ message = if checks_missing_end_index.any? { |name| name == :all }
24
24
  "All checks were"
25
25
  else
26
- @disabled_checks.all.join(', ') + " " + (@disabled_checks.all.size == 1 ? "was" : "were")
26
+ checks_missing_end_index.join(', ') + " " + (checks_missing_end_index.size == 1 ? "was" : "were")
27
27
  end
28
28
 
29
29
  add_offense("#{message} disabled but not re-enabled with theme-check-enable", node: node)
@@ -15,12 +15,18 @@ module ThemeCheck
15
15
  return if :assign == node.type_name
16
16
 
17
17
  outside_of_strings(node.markup) do |chunk|
18
- chunk.scan(/([,:]) +/) do |_match|
18
+ chunk.scan(/([,:|]) +/) do |_match|
19
19
  add_offense("Too many spaces after '#{Regexp.last_match(1)}'", node: node, markup: Regexp.last_match(0))
20
20
  end
21
- chunk.scan(/([,:])\S/) do |_match|
21
+ chunk.scan(/([,:|])\S/) do |_match|
22
22
  add_offense("Space missing after '#{Regexp.last_match(1)}'", node: node, markup: Regexp.last_match(0))
23
23
  end
24
+ chunk.scan(/ ([|])+/) do |_match|
25
+ add_offense("Too many spaces before '#{Regexp.last_match(1)}'", node: node, markup: Regexp.last_match(0))
26
+ end
27
+ chunk.scan(/\A(?<pipe>\|)|\S(?<pipe>\|)/) do |_match|
28
+ add_offense("Space missing before '#{Regexp.last_match(:pipe)}'", node: node, markup: Regexp.last_match(:pipe))
29
+ end
24
30
  end
25
31
  end
26
32
 
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This class keeps track of checks being turned on and off in ranges.
4
+ # We'll use the node position to figure out if the test is disabled or not.
5
+ module ThemeCheck
6
+ class DisabledCheck
7
+ attr_reader :name, :ranges
8
+ attr_accessor :first_line
9
+
10
+ def initialize(name)
11
+ @name = name
12
+ @ranges = []
13
+ @first_line = false
14
+ end
15
+
16
+ def start_index=(index)
17
+ return unless ranges.empty? || !last.end.nil?
18
+ @ranges << (index..)
19
+ end
20
+
21
+ def end_index=(index)
22
+ return if ranges.empty? || !last.end.nil?
23
+ @ranges << (@ranges.pop.begin..index)
24
+ end
25
+
26
+ def disabled?(index)
27
+ ranges.any? { |range| range.cover?(index) }
28
+ end
29
+
30
+ def last
31
+ ranges.last
32
+ end
33
+
34
+ def missing_end_index?
35
+ return false if first_line && ranges.size == 1
36
+ last.end.nil?
37
+ end
38
+ end
39
+ end
@@ -8,50 +8,36 @@ module ThemeCheck
8
8
 
9
9
  ACTION_DISABLE_CHECKS = :disable
10
10
  ACTION_ENABLE_CHECKS = :enable
11
- ACTION_UNRELATED_COMMENT = :unrelated
12
11
 
13
12
  def initialize
14
- @disabled = []
15
- @all_disabled = false
16
- @full_document_disabled = false
13
+ @disabled_checks = {}
17
14
  end
18
15
 
19
16
  def update(node)
20
17
  text = comment_text(node)
21
-
22
18
  if start_disabling?(text)
23
- @disabled = checks_from_text(text)
24
- @all_disabled = @disabled.empty?
25
-
26
- if node&.line_number == 1
27
- @full_document_disabled = true
19
+ checks_from_text(text).each do |check_name|
20
+ @disabled_checks[check_name] ||= DisabledCheck.new(check_name)
21
+ @disabled_checks[check_name].start_index = node.start_index
22
+ @disabled_checks[check_name].first_line = true if node.line_number == 1
28
23
  end
29
24
  elsif stop_disabling?(text)
30
- checks = checks_from_text(text)
31
- @disabled = checks.empty? ? [] : @disabled - checks
32
-
33
- @all_disabled = false
25
+ checks_from_text(text).each do |check_name|
26
+ next unless @disabled_checks.key?(check_name)
27
+ @disabled_checks[check_name].end_index = node.end_index
28
+ end
34
29
  end
35
30
  end
36
31
 
37
- # Whether any checks are currently disabled
38
- def any?
39
- !@disabled.empty? || @all_disabled
40
- end
41
-
42
- # Whether all checks should be disabled
43
- def all_disabled?
44
- @all_disabled
45
- end
46
-
47
- # Get a list of all the individual disabled checks
48
- def all
49
- @disabled
32
+ def disabled?(key, index)
33
+ @disabled_checks[:all]&.disabled?(index) ||
34
+ @disabled_checks[key]&.disabled?(index)
50
35
  end
51
36
 
52
- # If the first line of the document is a theme-check-disable comment
53
- def full_document_disabled?
54
- @full_document_disabled
37
+ def checks_missing_end_index
38
+ @disabled_checks.values
39
+ .select(&:missing_end_index?)
40
+ .map(&:name)
55
41
  end
56
42
 
57
43
  private
@@ -69,9 +55,11 @@ module ThemeCheck
69
55
  end
70
56
 
71
57
  # Return a list of checks from a theme-check-disable comment
72
- # Returns [] if all checks are meant to be disabled
58
+ # Returns [:all] if all checks are meant to be disabled
73
59
  def checks_from_text(text)
74
- text.gsub(DISABLE_PREFIX_PATTERN, '').strip.split(',').map(&:strip)
60
+ checks = text.gsub(DISABLE_PREFIX_PATTERN, '').strip.split(',').map(&:strip)
61
+ return [:all] if checks.empty?
62
+ checks
75
63
  end
76
64
  end
77
65
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+ require "net/http"
3
+
4
+ TIMEOUT_EXCEPTIONS = [
5
+ Net::ReadTimeout,
6
+ Net::OpenTimeout,
7
+ Net::WriteTimeout,
8
+ Errno::ETIMEDOUT,
9
+ Timeout::Error,
10
+ ]
11
+
12
+ CONNECTION_EXCEPTIONS = [
13
+ IOError,
14
+ EOFError,
15
+ SocketError,
16
+ Errno::EINVAL,
17
+ Errno::ECONNRESET,
18
+ Errno::ECONNABORTED,
19
+ Errno::EPIPE,
20
+ Errno::ECONNREFUSED,
21
+ Errno::EAGAIN,
22
+ Errno::EHOSTUNREACH,
23
+ Errno::ENETUNREACH,
24
+ ]
25
+
26
+ NET_HTTP_EXCEPTIONS = [
27
+ Net::HTTPBadResponse,
28
+ Net::HTTPHeaderSyntaxError,
29
+ Net::ProtocolError,
30
+ *TIMEOUT_EXCEPTIONS,
31
+ *CONNECTION_EXCEPTIONS,
32
+ ]
@@ -20,6 +20,10 @@ module ThemeCheck
20
20
  @relative_pathname ||= Pathname.new(@relative_path)
21
21
  end
22
22
 
23
+ def source
24
+ @source ||= @storage.read(@relative_path)
25
+ end
26
+
23
27
  def content
24
28
  load!
25
29
  @content
@@ -39,7 +43,7 @@ module ThemeCheck
39
43
  def load!
40
44
  return if @loaded
41
45
 
42
- @content = JSON.parse(@storage.read(@relative_path))
46
+ @content = JSON.parse(source)
43
47
  rescue JSON::ParserError => e
44
48
  @parser_error = e
45
49
  ensure
@@ -4,7 +4,6 @@ require_relative "language_server/constants"
4
4
  require_relative "language_server/handler"
5
5
  require_relative "language_server/server"
6
6
  require_relative "language_server/tokens"
7
- require_relative "language_server/position_helper"
8
7
  require_relative "language_server/completion_helper"
9
8
  require_relative "language_server/completion_provider"
10
9
  require_relative "language_server/completion_engine"
@@ -12,7 +12,7 @@ module ThemeCheck
12
12
 
13
13
  def completions(relative_path, line, col)
14
14
  buffer = @storage.read(relative_path)
15
- cursor = from_line_column_to_index(buffer, line, col)
15
+ cursor = from_row_column_to_index(buffer, line, col)
16
16
  token = find_token(buffer, cursor)
17
17
  return [] if token.nil?
18
18
 
@@ -4,7 +4,11 @@ module ThemeCheck
4
4
  module LanguageServer
5
5
  PARTIAL_RENDER = %r{
6
6
  \{\%-?\s*render\s+'(?<partial>[^']*)'|
7
- \{\%-?\s*render\s+"(?<partial>[^"]*)"
7
+ \{\%-?\s*render\s+"(?<partial>[^"]*)"|
8
+
9
+ # in liquid tags the whole line is white space until render
10
+ ^\s*render\s+'(?<partial>[^']*)'|
11
+ ^\s*render\s+"(?<partial>[^"]*)"
8
12
  }mix
9
13
  end
10
14
  end
@@ -14,12 +14,12 @@ module ThemeCheck
14
14
  buffer = @storage.read(relative_path)
15
15
  return [] unless buffer
16
16
  matches(buffer, PARTIAL_RENDER).map do |match|
17
- start_line, start_character = from_index_to_line_column(
17
+ start_line, start_character = from_index_to_row_column(
18
18
  buffer,
19
19
  match.begin(:partial),
20
20
  )
21
21
 
22
- end_line, end_character = from_index_to_line_column(
22
+ end_line, end_character = from_index_to_row_column(
23
23
  buffer,
24
24
  match.end(:partial)
25
25
  )
@@ -23,17 +23,17 @@ module ThemeCheck
23
23
  end
24
24
 
25
25
  def on_initialize(id, params)
26
- @root_path = params["rootPath"]
26
+ @root_path = path_from_uri(params["rootUri"]) || params["rootPath"]
27
+
28
+ # Tell the client we don't support anything if there's no rootPath
29
+ return send_response(id, { capabilities: {} }) if @root_path.nil?
27
30
  @storage = in_memory_storage(@root_path)
28
31
  @completion_engine = CompletionEngine.new(@storage)
29
32
  @document_link_engine = DocumentLinkEngine.new(@storage)
30
33
  # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#responseMessage
31
- send_response(
32
- id: id,
33
- result: {
34
- capabilities: CAPABILITIES,
35
- }
36
- )
34
+ send_response(id, {
35
+ capabilities: CAPABILITIES,
36
+ })
37
37
  end
38
38
 
39
39
  def on_exit(_id, _params)
@@ -63,20 +63,14 @@ module ThemeCheck
63
63
 
64
64
  def on_text_document_document_link(id, params)
65
65
  relative_path = relative_path_from_text_document_uri(params)
66
- send_response(
67
- id: id,
68
- result: document_links(relative_path)
69
- )
66
+ send_response(id, document_links(relative_path))
70
67
  end
71
68
 
72
69
  def on_text_document_completion(id, params)
73
70
  relative_path = relative_path_from_text_document_uri(params)
74
71
  line = params.dig('position', 'line')
75
72
  col = params.dig('position', 'character')
76
- send_response(
77
- id: id,
78
- result: completions(relative_path, line, col)
79
- )
73
+ send_response(id, completions(relative_path, line, col))
80
74
  end
81
75
 
82
76
  private
@@ -99,7 +93,11 @@ module ThemeCheck
99
93
  end
100
94
 
101
95
  def text_document_uri(params)
102
- params.dig('textDocument', 'uri').sub('file://', '')
96
+ path_from_uri(params.dig('textDocument', 'uri'))
97
+ end
98
+
99
+ def path_from_uri(uri)
100
+ uri&.sub('file://', '')
103
101
  end
104
102
 
105
103
  def relative_path_from_text_document_uri(params)
@@ -167,13 +165,10 @@ module ThemeCheck
167
165
 
168
166
  def send_diagnostic(path, offenses)
169
167
  # https://microsoft.github.io/language-server-protocol/specifications/specification-current/#notificationMessage
170
- send_response(
171
- method: 'textDocument/publishDiagnostics',
172
- params: {
173
- uri: "file://#{path}",
174
- diagnostics: offenses.map { |offense| offense_to_diagnostic(offense) },
175
- },
176
- )
168
+ send_notification('textDocument/publishDiagnostics', {
169
+ uri: "file://#{path}",
170
+ diagnostics: offenses.map { |offense| offense_to_diagnostic(offense) },
171
+ })
177
172
  end
178
173
 
179
174
  def offense_to_diagnostic(offense)
@@ -220,11 +215,24 @@ module ThemeCheck
220
215
  }
221
216
  end
222
217
 
223
- def send_response(message)
218
+ def send_message(message)
224
219
  message[:jsonrpc] = '2.0'
225
220
  @server.send_response(message)
226
221
  end
227
222
 
223
+ def send_response(id, result = nil, error = nil)
224
+ message = { id: id }
225
+ message[:result] = result if result
226
+ message[:error] = error if error
227
+ send_message(message)
228
+ end
229
+
230
+ def send_notification(method, params)
231
+ message = { method: method }
232
+ message[:params] = params
233
+ send_message(message)
234
+ end
235
+
228
236
  def log(message)
229
237
  @server.log(message)
230
238
  end
@@ -125,5 +125,17 @@ module ThemeCheck
125
125
  start = template.full_line(line_number).index(markup)
126
126
  [start, start + markup.length - 1]
127
127
  end
128
+
129
+ def position
130
+ @position ||= Position.new(markup, template&.source, line_number)
131
+ end
132
+
133
+ def start_index
134
+ position.start_index
135
+ end
136
+
137
+ def end_index
138
+ position.end_index
139
+ end
128
140
  end
129
141
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  module ThemeCheck
3
- Position = Struct.new(:line, :column)
4
-
5
3
  class Offense
6
4
  MAX_SOURCE_EXCERPT_SIZE = 120
7
5
 
@@ -20,6 +18,7 @@ module ThemeCheck
20
18
  end
21
19
 
22
20
  @node = node
21
+ @template = nil
23
22
  if node
24
23
  @template = node.template
25
24
  elsif template
@@ -40,8 +39,7 @@ module ThemeCheck
40
39
  @node.line_number
41
40
  end
42
41
 
43
- @start_position = nil
44
- @end_position = nil
42
+ @position = Position.new(@markup, @template&.source, @line_number)
45
43
  end
46
44
 
47
45
  def source_excerpt
@@ -56,20 +54,28 @@ module ThemeCheck
56
54
  end
57
55
  end
58
56
 
57
+ def start_index
58
+ @position.start_index
59
+ end
60
+
59
61
  def start_line
60
- start_position.line
62
+ @position.start_row
61
63
  end
62
64
 
63
65
  def start_column
64
- start_position.column
66
+ @position.start_column
67
+ end
68
+
69
+ def end_index
70
+ @position.end_index
65
71
  end
66
72
 
67
73
  def end_line
68
- end_position.line
74
+ @position.end_row
69
75
  end
70
76
 
71
77
  def end_column
72
- end_position.column
78
+ @position.end_column
73
79
  end
74
80
 
75
81
  def code_name
@@ -115,45 +121,5 @@ module ThemeCheck
115
121
  message
116
122
  end
117
123
  end
118
-
119
- private
120
-
121
- def full_line(line)
122
- # Liquid::Template is 1-indexed.
123
- template.full_line(line + 1)
124
- end
125
-
126
- def lines_of_content
127
- @lines ||= markup.lines.map { |x| x.sub(/\n$/, '') }
128
- end
129
-
130
- # 0-indexed, inclusive
131
- def start_position
132
- return @start_position if @start_position
133
- return @start_position = Position.new(0, 0) unless line_number && markup
134
-
135
- position = Position.new
136
- position.line = line_number - 1
137
- position.column = full_line(position.line).index(lines_of_content.first) || 0
138
-
139
- @start_position = position
140
- end
141
-
142
- # 0-indexed, exclusive. It's the line + col that are exclusive.
143
- # This is why it doesn't make sense to calculate them separately.
144
- def end_position
145
- return @end_position if @end_position
146
- return @end_position = Position.new(0, 0) unless line_number && markup
147
-
148
- position = Position.new
149
- position.line = start_line + lines_of_content.size - 1
150
- position.column = if start_line == position.line
151
- start_column + markup.size
152
- else
153
- lines_of_content.last.size
154
- end
155
-
156
- @end_position = position
157
- end
158
124
  end
159
125
  end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ThemeCheck
4
+ class Position
5
+ include PositionHelper
6
+
7
+ def initialize(needle, contents, line_number_1_indexed)
8
+ @needle = needle
9
+ @contents = contents
10
+ @line_number_1_indexed = line_number_1_indexed
11
+ @start_row_column = nil
12
+ @end_row_column = nil
13
+ end
14
+
15
+ def start_line_index
16
+ from_row_column_to_index(contents, line_number, 0)
17
+ end
18
+
19
+ # 0-indexed, inclusive
20
+ def start_index
21
+ contents.index(needle, start_line_index) || start_line_index
22
+ end
23
+
24
+ # 0-indexed, exclusive
25
+ def end_index
26
+ start_index + needle.size
27
+ end
28
+
29
+ def start_row
30
+ start_row_column[0]
31
+ end
32
+
33
+ def start_column
34
+ start_row_column[1]
35
+ end
36
+
37
+ def end_row
38
+ end_row_column[0]
39
+ end
40
+
41
+ def end_column
42
+ end_row_column[1]
43
+ end
44
+
45
+ private
46
+
47
+ def contents
48
+ return '' unless @contents.is_a?(String) && !@contents.empty?
49
+ @contents
50
+ end
51
+
52
+ def line_number
53
+ return 0 if @line_number_1_indexed.nil?
54
+ bounded(0, @line_number_1_indexed - 1, contents.lines.size - 1)
55
+ end
56
+
57
+ def needle
58
+ if @needle.nil? && !contents.empty? && !@line_number_1_indexed.nil?
59
+ contents.lines(chomp: true)[line_number] || ''
60
+ elsif contents.empty? || @needle.nil?
61
+ ''
62
+ else
63
+ @needle
64
+ end
65
+ end
66
+
67
+ def start_row_column
68
+ return @start_row_column unless @start_row_column.nil?
69
+ @start_row_column = from_index_to_row_column(contents, start_index)
70
+ end
71
+
72
+ def end_row_column
73
+ return @end_row_column unless @end_row_column.nil?
74
+ @end_row_column = from_index_to_row_column(contents, end_index)
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+ # Note: Everything is 0-indexed here.
3
+
4
+ module ThemeCheck
5
+ module PositionHelper
6
+ def from_row_column_to_index(content, row, col)
7
+ return 0 unless content.is_a?(String) && !content.empty?
8
+ return 0 unless row.is_a?(Integer) && col.is_a?(Integer)
9
+ i = 0
10
+ result = 0
11
+ safe_row = bounded(0, row, content.lines.size - 1)
12
+ lines = content.lines
13
+ line_size = lines[i].size
14
+ while i < safe_row
15
+ result += line_size
16
+ i += 1
17
+ line_size = lines[i].size
18
+ end
19
+ result += bounded(0, col, line_size - 1)
20
+ result
21
+ end
22
+
23
+ def from_index_to_row_column(content, index)
24
+ return [0, 0] unless content.is_a?(String) && !content.empty?
25
+ return [0, 0] unless index.is_a?(Integer)
26
+ safe_index = bounded(0, index, content.size - 1)
27
+ lines = content[0..safe_index].lines
28
+ row = lines.size - 1
29
+ col = lines.last.size - 1
30
+ [row, col]
31
+ end
32
+
33
+ def bounded(a, x, b)
34
+ [a, [x, b].min].max
35
+ end
36
+ end
37
+ end
@@ -35,6 +35,9 @@ module ThemeCheck
35
35
  end
36
36
 
37
37
  @content = res.body
38
+
39
+ rescue OpenSSL::SSL::SSLError, Zlib::StreamError, *NET_HTTP_EXCEPTIONS
40
+ @contents = ''
38
41
  end
39
42
 
40
43
  def gzipped_size
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module ThemeCheck
3
- VERSION = "0.8.0"
3
+ VERSION = "0.8.1"
4
4
  end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
  module ThemeCheck
3
3
  class Visitor
4
+ attr_reader :checks
5
+
4
6
  def initialize(checks)
5
7
  @checks = checks
6
8
  end
@@ -8,6 +10,7 @@ module ThemeCheck
8
10
  def visit_template(template)
9
11
  @disabled_checks = DisabledChecks.new
10
12
  visit(Node.new(template.root, nil, template))
13
+ remove_disabled_offenses
11
14
  rescue Liquid::Error => exception
12
15
  exception.template_name = template.name
13
16
  call_checks(:on_error, exception)
@@ -29,20 +32,16 @@ module ThemeCheck
29
32
  @disabled_checks.update(node) if node.comment?
30
33
  end
31
34
 
32
- def visit_children(node)
33
- node.children.each { |child| visit(child) }
34
- end
35
-
36
35
  def call_checks(method, *args)
37
36
  checks.call(method, *args)
38
37
  end
39
38
 
40
- def checks
41
- return @checks unless @disabled_checks.any?
42
-
43
- return @checks.always_enabled if @disabled_checks.all_disabled?
44
-
45
- @checks.except_for(@disabled_checks)
39
+ def remove_disabled_offenses
40
+ checks.disableable.each do |check|
41
+ check.offenses.reject! do |offense|
42
+ @disabled_checks.disabled?(offense.code_name, offense.start_index)
43
+ end
44
+ end
46
45
  end
47
46
  end
48
47
  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.8.0
4
+ version: 0.8.1
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-04-13 00:00:00.000000000 Z
11
+ date: 2021-04-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: liquid
@@ -138,7 +138,9 @@ files:
138
138
  - lib/theme_check/cli.rb
139
139
  - lib/theme_check/config.rb
140
140
  - lib/theme_check/corrector.rb
141
+ - lib/theme_check/disabled_check.rb
141
142
  - lib/theme_check/disabled_checks.rb
143
+ - lib/theme_check/exceptions.rb
142
144
  - lib/theme_check/file_system_storage.rb
143
145
  - lib/theme_check/in_memory_storage.rb
144
146
  - lib/theme_check/json_check.rb
@@ -155,7 +157,6 @@ files:
155
157
  - lib/theme_check/language_server/constants.rb
156
158
  - lib/theme_check/language_server/document_link_engine.rb
157
159
  - lib/theme_check/language_server/handler.rb
158
- - lib/theme_check/language_server/position_helper.rb
159
160
  - lib/theme_check/language_server/protocol.rb
160
161
  - lib/theme_check/language_server/server.rb
161
162
  - lib/theme_check/language_server/tokens.rb
@@ -165,6 +166,8 @@ files:
165
166
  - lib/theme_check/offense.rb
166
167
  - lib/theme_check/packager.rb
167
168
  - lib/theme_check/parsing_helpers.rb
169
+ - lib/theme_check/position.rb
170
+ - lib/theme_check/position_helper.rb
168
171
  - lib/theme_check/printer.rb
169
172
  - lib/theme_check/regex_helpers.rb
170
173
  - lib/theme_check/releaser.rb
@@ -1,27 +0,0 @@
1
- # frozen_string_literal: true
2
- # Note: Everything is 0-indexed here.
3
-
4
- module ThemeCheck
5
- module LanguageServer
6
- module PositionHelper
7
- def from_line_column_to_index(content, row, col)
8
- i = 0
9
- result = 0
10
- lines = content.lines
11
- while i < row
12
- result += lines[i].size
13
- i += 1
14
- end
15
- result += col
16
- result
17
- end
18
-
19
- def from_index_to_line_column(content, index)
20
- lines = content[0..index].lines
21
- row = lines.size - 1
22
- col = lines.last.size - 1
23
- [row, col]
24
- end
25
- end
26
- end
27
- end