gl_rubocop 0.2.19 → 0.3.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: bd4eb564bfaea4ae8ab15506ff2196070f55223989f1ac9504f281913a55dd6c
4
- data.tar.gz: 931bb25c4f11632bacfada61d5cf99306dbfddf1d4ba056f9ee773f86a876e6c
3
+ metadata.gz: cfa3a041b813576c82945878a3a5b712cddc171ee7e490a562c8186c8a078122
4
+ data.tar.gz: 59c4a3a19c71605f920bb21ca0b76ef965385e94836d8965b9735164cf227b7c
5
5
  SHA512:
6
- metadata.gz: 1db06adef9f18338c30d02177c993ef7c7978f4563683ac821c933f824170476f0088b90cc29ce87629d6b0d5bf76e335cacb8662d25a6583de074e5f92de18b
7
- data.tar.gz: d2631001ed66f5f91ede31f60387f07edf95bb297cd999e2b2528b29b79c215c75bfa0c79771804505b25b3ccfc457c54b8a42f35cc615f5af9d621e8769b86e
6
+ metadata.gz: 240a0d83e8b317ef314783c0ff96c3f56cc1af17f144dda86d9048d791ecadb41d3408776831a5130ea8396467def9d65d524c778846539f32828565a742d2cc
7
+ data.tar.gz: d4870f2db16c75c7843df195c9a4f0a3b96e412ffedd20489368e7ad634a46933253ee56bd0f61f649edd35465b997d561d2f20618e8b1bcabae2977e7a1bcfe
data/default.yml CHANGED
@@ -3,6 +3,7 @@ require:
3
3
  - rubocop-rails
4
4
  - rubocop-rspec
5
5
  - rubocop-magic_numbers
6
+ - rubocop-erb
6
7
  - rubocop-haml
7
8
  - rubocop-i18n
8
9
  - rubocop-rake
@@ -11,10 +12,11 @@ require:
11
12
  - ./lib/gl_rubocop/gl_cops/interactor_inherits_from_interactor_base.rb
12
13
  - ./lib/gl_rubocop/gl_cops/limit_flash_options.rb
13
14
  - ./lib/gl_rubocop/gl_cops/no_stubbing_perform_async.rb
14
- - ./lib/gl_rubocop/gl_cops/prevent_erb_files.rb
15
+ - ./lib/gl_rubocop/gl_cops/prevent_haml_files.rb
15
16
  - ./lib/gl_rubocop/gl_cops/rails_cache.rb
16
17
  - ./lib/gl_rubocop/gl_cops/sidekiq_inherits_from_sidekiq_job.rb
17
18
  - ./lib/gl_rubocop/gl_cops/unique_identifier.rb
19
+ - ./lib/gl_rubocop/gl_cops/tailwind_no_contradicting_class_name.rb
18
20
 
19
21
  AllCops:
20
22
  SuggestExtensions: false
@@ -53,7 +55,7 @@ GLCops/NoStubbingPerformAsync:
53
55
  Include:
54
56
  - "**/*spec.rb"
55
57
 
56
- GLCops/PreventErbFiles:
58
+ GLCops/PreventHamlFiles:
57
59
  Enabled: true
58
60
 
59
61
  GLCops/RailsCache:
@@ -67,7 +69,7 @@ GLCops/SidekiqInheritsFromSidekiqJob:
67
69
  GLCops/UniqueIdentifier:
68
70
  Enabled: true
69
71
  Include:
70
- - "app/components/**/*.haml"
72
+ - "app/components/**/*.erb"
71
73
 
72
74
  I18n/GetText:
73
75
  Enabled: false
data/gl_rubocop.gemspec CHANGED
@@ -2,8 +2,6 @@
2
2
 
3
3
  require_relative 'lib/gl_rubocop/version'
4
4
 
5
- NON_GEM_FILES = ['Gemfile', 'Gemfile.lock', 'Guardfile', 'bin/lint'].freeze
6
-
7
5
  Gem::Specification.new do |spec|
8
6
  spec.name = 'gl_rubocop'
9
7
  spec.version = GLRubocop::VERSION
@@ -26,7 +24,8 @@ Gem::Specification.new do |spec|
26
24
  spec.require_paths = ['lib']
27
25
 
28
26
  spec.add_dependency 'rubocop', '~> 1.62.1'
29
- spec.add_dependency 'rubocop-haml', '~> 0.2.4'
27
+ spec.add_dependency 'rubocop-erb'
28
+ spec.add_dependency 'rubocop-haml'
30
29
  spec.add_dependency 'rubocop-i18n'
31
30
  spec.add_dependency 'rubocop-magic_numbers'
32
31
  spec.add_dependency 'rubocop-performance'
@@ -1,11 +1,11 @@
1
1
  module GLRubocop
2
2
  module GLCops
3
- class PreventErbFiles < RuboCop::Cop::Cop
4
- MSG = 'File name should not end with .erb'.freeze
3
+ class PreventHamlFiles < RuboCop::Cop::Cop
4
+ MSG = 'File name should not end with .haml'.freeze
5
5
 
6
6
  def investigate(processed_source)
7
7
  file_path = processed_source.buffer.name
8
- return unless File.extname(file_path) == '.erb'
8
+ return unless File.extname(file_path) == '.haml'
9
9
 
10
10
  range = processed_source.buffer.source_range
11
11
  add_offense(nil, location: range, message: MSG)
@@ -0,0 +1,423 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../helpers/haml_content_helper'
4
+ require_relative '../helpers/erb_content_helper'
5
+
6
+ module GLRubocop
7
+ module GLCops
8
+ # Cop to detect contradicting Tailwind CSS class names
9
+ #
10
+ # @example
11
+ # # bad
12
+ # %div{ class: "tw:w-1 tw:w-2" }
13
+ # .tw:h-5.tw:h-6
14
+ # %button.tw:w-1.tw:w-2
15
+ #
16
+ #
17
+ # # good
18
+ # %div{ class: "tw:w-1 tw:h-2" }
19
+ # tw:h-5
20
+ # %button.tw:m-4.tw:p-8
21
+
22
+ # rubocop:disable Metrics/ClassLength
23
+ class TailwindNoContradictingClassName < RuboCop::Cop::Cop
24
+ include GLRubocop::HamlContentHelper
25
+ include GLRubocop::ErbContentHelper
26
+
27
+ MSG =
28
+ 'Contradicting Tailwind CSS classes found: %<classes>s both affect the same CSS property'
29
+ GIVELIVELY_TAILWIND_CLASS_PREFIX = 'tw:'
30
+
31
+ # Tailwind CSS property groups that should not contradict
32
+ CONTRADICTION_GROUPS = {
33
+ width: %w[w],
34
+ height: %w[h],
35
+ max_width: %w[max-w],
36
+ max_height: %w[max-h],
37
+ min_width: %w[min-w],
38
+ min_height: %w[min-h],
39
+ margin_top: %w[m my mt],
40
+ margin_right: %w[m mx mr],
41
+ margin_bottom: %w[m my mb],
42
+ margin_left: %w[m mx ml],
43
+ padding_top: %w[p py pt],
44
+ padding_right: %w[p px pr],
45
+ padding_bottom: %w[p py pb],
46
+ padding_left: %w[p px pl],
47
+ display: %w[block hidden flex inline inline-block inline-flex grid inline-grid table],
48
+ position: %w[static relative absolute fixed sticky],
49
+ text_align: %w[text-left text-center text-right text-justify],
50
+ flex_direction: %w[flex-row flex-row-reverse flex-col flex-col-reverse],
51
+ flex_wrap: %w[flex-nowrap flex-wrap flex-wrap-reverse],
52
+ justify_content: %w[
53
+ justify-start justify-end justify-center justify-between justify-around justify-evenly
54
+ ],
55
+ align_items: %w[items-start items-end items-center items-baseline items-stretch],
56
+ place_content: %w[
57
+ place-content-center place-content-start place-content-end place-content-between
58
+ place-content-around place-content-evenly
59
+ ],
60
+ place_items: %w[
61
+ place-items-start place-items-end place-items-center place-items-baseline
62
+ place-items-stretch
63
+ ],
64
+ place_self: %w[
65
+ place-self-auto place-self-start place-self-end place-self-center place-self-stretch
66
+ ],
67
+ align_content: %w[
68
+ content-center content-start content-end content-between content-around content-evenly
69
+ ],
70
+ align_self: %w[
71
+ self-auto self-start self-end self-center self-stretch self-baseline
72
+ ],
73
+ justify_items: %w[
74
+ justify-items-start justify-items-end justify-items-center justify-items-stretch
75
+ ],
76
+ justify_self: %w[
77
+ justify-self-auto justify-self-start justify-self-end justify-self-center
78
+ justify-self-stretch
79
+ ],
80
+ font_size: %w[
81
+ text-xs text-sm text-base text-lg text-xl text-2xl text-3xl text-4xl text-5xl text-6xl
82
+ ],
83
+ font_weight: %w[
84
+ font-thin font-extralight font-light font-normal font-medium font-semibold font-bold
85
+ font-extrabold font-black
86
+ ],
87
+ font_style: %w[italic not-italic],
88
+ letter_spacing: %w[
89
+ tracking-tighter tracking-tight tracking-normal tracking-wide tracking-wider
90
+ tracking-widest
91
+ ],
92
+ line_height: %w[
93
+ leading-none leading-tight leading-snug leading-normal leading-relaxed leading-loose
94
+ ],
95
+ text_decoration_line: %w[underline line-through no-underline],
96
+ text_transform: %w[uppercase lowercase capitalize normal-case],
97
+ text_decoration_style: %w[
98
+ decoration-solid decoration-dashed decoration-dotted decoration-double decoration-wavy
99
+ ],
100
+ text_wrap: %w[break-normal break-words break-all],
101
+ vertical_align: %w[
102
+ align-baseline align-top align-middle align-bottom align-text-top align-text-bottom
103
+ ],
104
+ text_overflow: %w[truncate overflow-ellipsis overflow-clip],
105
+ overflow: %w[
106
+ overflow-auto overflow-hidden overflow-visible overflow-scroll
107
+ ],
108
+ visibility: %w[visible invisible collapse],
109
+ border_style: %w[
110
+ border-solid border-dashed border-dotted border-double border-none
111
+ ],
112
+ box_shadow: %w[
113
+ shadow-sm shadow shadow-md shadow-lg shadow-xl shadow-2xl shadow-inner shadow-none
114
+ ]
115
+ # Add more property groups as needed, currently we have chosen to omit color-related properties and border-radius classes
116
+ # to reduce false positives in common use cases.
117
+ }.freeze
118
+
119
+ BREAKPOINT_ORDER = %w[sm md lg xl 2xl].freeze
120
+
121
+ def on_send(node)
122
+ return unless render_method?(node)
123
+
124
+ if haml_file?
125
+ haml_content = read_haml_file
126
+ return unless haml_content
127
+
128
+ check_haml_content(haml_content, node)
129
+ elsif erb_file?
130
+ erb_content = read_erb_file
131
+ return unless erb_content
132
+
133
+ check_erb_content(erb_content, node)
134
+ end
135
+ end
136
+
137
+ def on_str(node)
138
+ # Check string literals for Tailwind classes
139
+ check_string_for_tailwind_classes(node)
140
+ end
141
+
142
+ private
143
+
144
+ def render_method?(node)
145
+ node.method_name == :render && node.arguments.any?
146
+ end
147
+
148
+ def check_erb_content(content, node)
149
+ classes = extract_all_erb_classes(content)
150
+ contradicting_classes = find_contradicting_classes(classes)
151
+
152
+ return if contradicting_classes.empty?
153
+
154
+ contradicting_classes.each do |group|
155
+ add_offense(
156
+ node,
157
+ message: format(MSG, classes: group.join(', '))
158
+ )
159
+ end
160
+ end
161
+
162
+ def extract_all_erb_classes(content)
163
+ classes = []
164
+ classes.concat(extract_classes_from_html_attributes(content))
165
+ classes.concat(extract_classes_from_rails_hash(content))
166
+ classes.concat(extract_classes_from_rails_symbol_hash(content))
167
+ classes.select { |class_name| tailwind_class?(class_name) }
168
+ end
169
+
170
+ def extract_classes_from_html_attributes(content)
171
+ # Example: <div class="tw:w-1 tw:w-2"></div>
172
+ content.scan(/class\s*=\s*['"]([^'"]+)['"]/).flat_map { |match| match.first.split(/\s+/) }
173
+ end
174
+
175
+ def extract_classes_from_rails_hash(content)
176
+ # Example: <%= radio_button_tag { class: 'tw:w-1 tw:w-2' } %>
177
+ content.scan(/class:\s*['"]([^'"]+)['"]/).flat_map { |match| match.first.split(/\s+/) }
178
+ end
179
+
180
+ def extract_classes_from_rails_symbol_hash(content)
181
+ # Example: <%= text_field_tag( ..., :class => 'tw:w-1 tw:w-2' ) %>
182
+ content.scan(/:class\s*=>\s*['"]([^'"]+)['"]/).flat_map { |match| match.first.split(/\s+/) }
183
+ end
184
+
185
+ def check_haml_content(content, node)
186
+ classes = extract_all_haml_classes(content)
187
+ contradicting_classes = find_contradicting_classes(classes)
188
+
189
+ return if contradicting_classes.empty?
190
+
191
+ contradicting_classes.each do |group|
192
+ add_offense(
193
+ node,
194
+ message: format(MSG, classes: group.join(', '))
195
+ )
196
+ end
197
+ end
198
+
199
+ def check_string_for_tailwind_classes(node)
200
+ return unless node.str_type?
201
+
202
+ content = node.value
203
+ classes = extract_classes_from_string(content)
204
+ contradicting_classes = find_contradicting_classes(classes)
205
+
206
+ return if contradicting_classes.empty?
207
+
208
+ contradicting_classes.each do |group|
209
+ add_offense(
210
+ node,
211
+ message: format(MSG, classes: group.join(', '))
212
+ )
213
+ end
214
+ end
215
+
216
+ def extract_classes_from_string(content)
217
+ # Split by whitespace and filter for Tailwind classes
218
+ content.split(/\s+/).select { |cls| tailwind_class?(cls) }
219
+ end
220
+
221
+ def extract_all_haml_classes(content)
222
+ classes = []
223
+
224
+ # Extract from HAML class shortcuts (e.g., %div.tw:w-1.tw:w-2)
225
+ content.scan(/^[^#]*%\w+(?:\.[^{\s#]+)+/m) do |match|
226
+ class_shortcuts = match.scan(/\.([^.{\s#]+)/).flatten
227
+ classes.concat(class_shortcuts)
228
+ end
229
+
230
+ # Extract from HAML hash syntax (e.g., %div{ class: 'tw:m-4 tw:m-8' })
231
+ content.scan(/class:\s*['"]([^'"]+)['"]/) do |match|
232
+ class_list = match.first.split(/\s+/)
233
+ classes.concat(class_list)
234
+ end
235
+
236
+ classes.select { |class_name| tailwind_class?(class_name) }
237
+ end
238
+
239
+ def tailwind_class?(class_name)
240
+ class_name.start_with?(GIVELIVELY_TAILWIND_CLASS_PREFIX)
241
+ end
242
+
243
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
244
+ def find_contradicting_classes(classes)
245
+ # Remove the 'tw:' prefix for property matching
246
+ normalized_classes = classes.map { |class_name| class_name.sub(matcher, '') }
247
+
248
+ contradictions = []
249
+
250
+ normalized_classes.each_with_index do |first_class, index|
251
+ first_class_data = extract_class_data(first_class)
252
+ next unless valid_property?(first_class_data[:css_property])
253
+
254
+ classes_to_compare = normalized_classes[(index + 1)..]
255
+
256
+ classes_to_compare.each_with_index do |second_class, j|
257
+ second_class_data = extract_class_data(second_class)
258
+ next unless valid_property?(second_class_data[:css_property])
259
+
260
+ next unless contradiction_found?(first_class_data, second_class_data)
261
+
262
+ original_class = classes[index]
263
+ contradicting_class = classes[index + j + 1]
264
+ contradictions << [original_class, contradicting_class]
265
+ end
266
+ end
267
+
268
+ contradictions
269
+ end
270
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
271
+
272
+ def contradiction_found?(first_class_data, second_class_data)
273
+ breakpoint_ranges_overlap?(first_class_data[:breakpoint_range],
274
+ second_class_data[:breakpoint_range]) &&
275
+ container_queries_overlap?(first_class_data[:container_query],
276
+ second_class_data[:container_query]) &&
277
+ properties_contradict?(first_class_data[:css_property], second_class_data[:css_property])
278
+ end
279
+
280
+ def extract_class_data(class_name)
281
+ {
282
+ css_property: extract_css_property(class_name),
283
+ breakpoint_range: extract_breakpoint_range(class_name),
284
+ container_query: extract_container_query(class_name)
285
+ }
286
+ end
287
+
288
+ # Extracts container query (e.g., @md:) from class name
289
+ def extract_container_query(class_name)
290
+ match = class_name.match(/^@([a-zA-Z0-9_-]+):/)
291
+ match ? match[1] : nil
292
+ end
293
+
294
+ def container_queries_overlap?(first_container, second_container)
295
+ # If both have a container query, they overlap
296
+ return true if first_container && second_container
297
+
298
+ # If neither has a container query, they overlap (global)
299
+ return true if first_container.nil? && second_container.nil?
300
+
301
+ # If only one has a container query, treat as non-overlapping
302
+ false
303
+ end
304
+
305
+ def matcher
306
+ /^#{GIVELIVELY_TAILWIND_CLASS_PREFIX}/o
307
+ end
308
+
309
+ def valid_property?(property)
310
+ property && CONTRADICTION_GROUPS.any? { |_, group| group.include?(property) }
311
+ end
312
+
313
+ # rubocop:disable Metrics/MethodLength
314
+ def extract_css_property(class_name)
315
+ # Remove container query prefix (e.g., @md:)
316
+ class_without_container = class_name.sub(/^@([a-zA-Z0-9_-]+):/, '')
317
+ # Remove breakpoint prefixes (including v4 range syntax and max-only syntax)
318
+ class_without_breakpoint = class_without_container.sub(
319
+ /^(?:(?:sm|md|lg|xl|2xl)(?::max-(?:sm|md|lg|xl|2xl))?:|max-(?:sm|md|lg|xl|2xl):)+/,
320
+ ''
321
+ )
322
+
323
+ patterns = [
324
+ /^(w|h)-/,
325
+ /^(max-w|max-h)-/,
326
+ /^(min-w|min-h)-/,
327
+ /^(m[trblxy]?)-/,
328
+ /^(p[trblxy]?)-/,
329
+ /^(block|hidden|flex|inline|inline-block|inline-flex|grid|inline-grid|table)$/,
330
+ /^(static|relative|absolute|fixed|sticky)$/,
331
+ /^(text-(?:left|center|right|justify))$/,
332
+ /^(flex-(?:row|row-reverse|col|col-reverse))$/,
333
+ /^(justify-(?:start|end|center|between|around|evenly))$/,
334
+ /^(items-(?:start|end|center|baseline|stretch))$/,
335
+ /^(place-content-(?:center|start|end|between|around|evenly))$/,
336
+ /^(place-items-(?:start|end|center|baseline|stretch))$/,
337
+ /^(place-self-(?:auto|start|end|center|stretch))$/,
338
+ /^(content-(?:center|start|end|between|around|evenly))$/,
339
+ /^(self-(?:auto|start|end|center|stretch|baseline))$/,
340
+ /^(justify-items-(?:start|end|center|stretch))$/,
341
+ /^(justify-self-(?:auto|start|end|center|stretch))$/,
342
+ /^(text-(?:xs|sm|base|lg|xl|2xl|3xl|4xl|5xl|6xl))$/,
343
+ /^(font-(?:thin|extralight|light|normal|medium|semibold|bold|extrabold|black))$/,
344
+ /^(italic|not-italic)$/,
345
+ /^(tracking-(?:tighter|tight|normal|wide|wider|widest))$/,
346
+ /^(leading-(?:none|tight|snug|normal|relaxed|loose))$/,
347
+ /^(underline|line-through|no-underline)$/,
348
+ /^(uppercase|lowercase|capitalize|normal-case)$/,
349
+ /^(decoration-(?:solid|dashed|dotted|double|wavy))$/,
350
+ /^(break-(?:normal|words|all))$/,
351
+ /^(align-(?:baseline|top|middle|bottom|text-top|text-bottom))$/,
352
+ /^(truncate|overflow-(?:ellipsis|clip))$/,
353
+ /^(overflow-(?:auto|hidden|visible|scroll))$/,
354
+ /^(visible|invisible|collapse)$/,
355
+ /^(border-(?:solid|dashed|dotted|double|none))$/,
356
+ /^(shadow(?:-(?:sm|md|lg|xl|2xl|inner|none))?)$/
357
+ ]
358
+
359
+ patterns.each do |pattern|
360
+ match = class_without_breakpoint.match(pattern)
361
+ return match[1] if match
362
+ end
363
+
364
+ nil
365
+ end
366
+ # rubocop:enable Metrics/MethodLength
367
+
368
+ def extract_breakpoint_range(class_name)
369
+ # Extract breakpoint range (e.g., 'md', 'lg:max-xl', 'sm:max-md')
370
+ # Returns a hash with :min and :max keys, or nil if no breakpoint
371
+
372
+ # Match Tailwind v4 range syntax: breakpoint:max-breakpoint: or just breakpoint:
373
+ range_match = class_name.match(/^(sm|md|lg|xl|2xl)(?::max-(sm|md|lg|xl|2xl))?:/)
374
+ return nil unless range_match
375
+
376
+ min_breakpoint = range_match[1]
377
+ max_breakpoint = range_match[2]
378
+
379
+ {
380
+ min: min_breakpoint,
381
+ max: max_breakpoint
382
+ }
383
+ end
384
+
385
+ def breakpoint_ranges_overlap?(first_range, second_range)
386
+ # If either range is nil (no breakpoint), they're considered the same (base styles)
387
+ return true if first_range.nil? && second_range.nil?
388
+ return false if first_range.nil? || second_range.nil?
389
+
390
+ # Get numeric indices for comparison
391
+ first_min_index = BREAKPOINT_ORDER.index(first_range[:min])
392
+ first_max_index = max_index(first_range)
393
+
394
+ second_min_index = BREAKPOINT_ORDER.index(second_range[:min])
395
+ second_max_index = max_index(second_range)
396
+
397
+ # Check for overlap: ranges overlap if one starts before the other ends
398
+ !(first_max_index < second_min_index || second_max_index < first_min_index)
399
+ end
400
+
401
+ def max_index(range)
402
+ return BREAKPOINT_ORDER.index(range[:max]) if range[:max]
403
+
404
+ BREAKPOINT_ORDER.length - 1
405
+ end
406
+
407
+ def properties_contradict?(first_prop, second_prop)
408
+ first_prop_group = CONTRADICTION_GROUPS.select do |_, group|
409
+ group.include?(first_prop)
410
+ end.keys
411
+ second_prop_group = CONTRADICTION_GROUPS.select do |_, group|
412
+ group.include?(second_prop)
413
+ end.keys
414
+
415
+ return false unless first_prop_group && second_prop_group
416
+
417
+ # Check if both properties belong to the same contradicting group
418
+ first_prop_group.intersect?(second_prop_group)
419
+ end
420
+ end
421
+ # rubocop:enable Metrics/ClassLength
422
+ end
423
+ end
@@ -0,0 +1,15 @@
1
+ module GLRubocop
2
+ module ErbContentHelper
3
+ def erb_file?
4
+ processed_source.file_path&.end_with?('.erb', '.html.erb')
5
+ end
6
+
7
+ def read_erb_file
8
+ return unless processed_source.file_path
9
+
10
+ File.read(processed_source.file_path)
11
+ rescue StandardError
12
+ nil
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ module GLRubocop
2
+ module HamlContentHelper
3
+ def haml_file?
4
+ file_path = processed_source.file_path
5
+ file_path&.end_with?('.html.haml') && File.exist?(file_path)
6
+ end
7
+
8
+ def read_haml_file
9
+ File.read(processed_source.file_path)
10
+ rescue StandardError
11
+ nil
12
+ end
13
+ end
14
+ end
@@ -1,3 +1,3 @@
1
1
  module GLRubocop
2
- VERSION = '0.2.19'.freeze
2
+ VERSION = '0.3.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gl_rubocop
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.19
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Give Lively
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-10-30 00:00:00.000000000 Z
11
+ date: 2025-10-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop
@@ -24,20 +24,34 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: 1.62.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: rubocop-erb
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rubocop-haml
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
- - - "~>"
45
+ - - ">="
32
46
  - !ruby/object:Gem::Version
33
- version: 0.2.4
47
+ version: '0'
34
48
  type: :runtime
35
49
  prerelease: false
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
- - - "~>"
52
+ - - ">="
39
53
  - !ruby/object:Gem::Version
40
- version: 0.2.4
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rubocop-i18n
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -152,10 +166,13 @@ files:
152
166
  - lib/gl_rubocop/gl_cops/interactor_inherits_from_interactor_base.rb
153
167
  - lib/gl_rubocop/gl_cops/limit_flash_options.rb
154
168
  - lib/gl_rubocop/gl_cops/no_stubbing_perform_async.rb
155
- - lib/gl_rubocop/gl_cops/prevent_erb_files.rb
169
+ - lib/gl_rubocop/gl_cops/prevent_haml_files.rb
156
170
  - lib/gl_rubocop/gl_cops/rails_cache.rb
157
171
  - lib/gl_rubocop/gl_cops/sidekiq_inherits_from_sidekiq_job.rb
172
+ - lib/gl_rubocop/gl_cops/tailwind_no_contradicting_class_name.rb
158
173
  - lib/gl_rubocop/gl_cops/unique_identifier.rb
174
+ - lib/gl_rubocop/helpers/erb_content_helper.rb
175
+ - lib/gl_rubocop/helpers/haml_content_helper.rb
159
176
  - lib/gl_rubocop/version.rb
160
177
  homepage: https://github.com/givelively/gl_rubocop
161
178
  licenses: