theme-check 0.8.0 → 0.8.1

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: 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