rubocop-vicenzo 0.4.0 → 0.5.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: 2caba14e7971e328ef6fc5c5fb203fe11a26cbd1f78f534f223f01f9d99c240f
4
- data.tar.gz: 2eb689487018dfa035aff365831cc219cf71dfce583885639656f314fbcffc82
3
+ metadata.gz: a18abf5413cb9807bf31adf6adeb6ac47e3fd0e7ec8cb2d47217db9b1617ed40
4
+ data.tar.gz: 871b1cb1de89c418517b67919402004ea95044aad2b1a8a0602ceb29953d1093
5
5
  SHA512:
6
- metadata.gz: e1c048efe4a3c8b7f7de35d8fcbe76908efcceb50bf053df761e59d53ea8fa9d74f779f223bb0d6e6ff1274e4ec2c83daf9a561084f970cdd5a48c8b7d4f7dce
7
- data.tar.gz: f8c2f91bd54d5845ae68928a5ff783f6b161a47ca0e2e1d0afdc177473761416487d2e0d5c984f9b6d064a98ef3cc64db98baf3454f3989be19bb146172a3620
6
+ metadata.gz: c629161e84a929d57e0ef7fdec80d17a21742adc08c7f1bafb601356815e99862d987806bfced0e88fb5d1c085af35a4f0e6039dde7cdd664c635a51e9984110
7
+ data.tar.gz: 05ddcb76888e50820eda315fa63087c12a01ace730090bd5250f363a2a01b46e8277342ff903d371a5b5d6a0d8c9abcf28023a88caca421c7bfca558acbae110
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.5.0] - 2026-06-29
4
+
5
+ - Add RuboCop::Cop::Vicenzo::Style::JsonParseSymbolizeNames #23;
6
+
3
7
  ## [0.4.0] - 2026-03-28
4
8
 
5
9
  - Add RuboCop::Cop::Vicenzo::RSpec::ConditionalInSpec #19;
data/antora-playbook.yml CHANGED
@@ -1,6 +1,7 @@
1
1
  site:
2
2
  title: RuboCop Vicenzo
3
3
  url: https://bvicenzo.github.io/rubocop-vicenzo
4
+ start_page: rubocop-vicenzo::index.adoc
4
5
 
5
6
  content:
6
7
  sources:
data/config/default.yml CHANGED
@@ -69,6 +69,12 @@ Vicenzo/RSpec/LeakyDefinition:
69
69
  - '**/spec/support/**/*'
70
70
  - '**/spec/factories/**/*'
71
71
 
72
+ Vicenzo/Style/JsonParseSymbolizeNames:
73
+ Description: 'Enforces passing `symbolize_names: true` to `JSON.parse` so keys are symbols.'
74
+ Enabled: true
75
+ Severity: convention
76
+ VersionAdded: '0.5.0'
77
+
72
78
  Vicenzo/Style/MultilineMethodCallParentheses:
73
79
  Description: 'Enforces parentheses for method calls with arguments that span multiple lines.'
74
80
  Enabled: true
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Vicenzo
6
+ module Style
7
+ # Enforces passing `symbolize_names: true` to `JSON.parse` so the
8
+ # resulting hash uses symbol keys instead of strings.
9
+ #
10
+ # An explicit `symbolize_names: false` is treated as a deliberate
11
+ # opt-out and is allowed. Calls whose options cannot be analyzed
12
+ # statically (a variable, splat, or double splat) are ignored to
13
+ # avoid false positives.
14
+ #
15
+ # @example
16
+ # # bad
17
+ # JSON.parse(payload)
18
+ #
19
+ # # bad
20
+ # JSON.parse(payload, max_nesting: 5)
21
+ #
22
+ # # good
23
+ # JSON.parse(payload, symbolize_names: true)
24
+ #
25
+ # # good (deliberate opt-out)
26
+ # JSON.parse(payload, symbolize_names: false)
27
+ class JsonParseSymbolizeNames < Base
28
+ MSG = 'Pass `symbolize_names: true` to `JSON.parse` so keys are symbols. ' \
29
+ 'Only when string keys are truly required, set `symbolize_names: false` explicitly.'
30
+
31
+ RESTRICT_ON_SEND = [:parse].freeze
32
+
33
+ # @!method json_parse?(node)
34
+ def_node_matcher :json_parse?, <<~PATTERN
35
+ (send (const {nil? cbase} :JSON) :parse ...)
36
+ PATTERN
37
+
38
+ def on_send(node)
39
+ return unless json_parse?(node)
40
+
41
+ add_offense(node) if missing_symbolize_names?(node)
42
+ end
43
+ alias on_csend on_send
44
+
45
+ private
46
+
47
+ def missing_symbolize_names?(node)
48
+ return false if node.arguments.any?(&:splat_type?)
49
+
50
+ options = options_hash(node)
51
+ return node.arguments.one? if options.nil?
52
+ return false if options.children.any?(&:kwsplat_type?)
53
+
54
+ !symbolize_names?(options)
55
+ end
56
+
57
+ # The options hash is the last argument when it is a hash literal
58
+ # (covers both `{ ... }` and trailing keyword arguments). A non-hash
59
+ # last argument (e.g. a variable) means we cannot inspect it.
60
+ def options_hash(node)
61
+ last_argument = node.last_argument
62
+ return unless last_argument&.hash_type?
63
+
64
+ last_argument
65
+ end
66
+
67
+ def symbolize_names?(options)
68
+ options.each_pair.any? { |pair| pair.key.sym_type? && pair.key.value == :symbolize_names }
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -10,4 +10,5 @@ require_relative 'vicenzo/rspec/nested_subject_redefinition'
10
10
  require_relative 'vicenzo/rspec/leaky_definition'
11
11
  require_relative 'vicenzo/rails/enum_inclusion_of_validation'
12
12
  require_relative 'vicenzo/layout/multiline_method_call_line_breaks'
13
+ require_relative 'vicenzo/style/json_parse_symbolize_names'
13
14
  require_relative 'vicenzo/style/multiline_method_call_parentheses'
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RuboCop
4
4
  module Vicenzo
5
- VERSION = '0.4.0'
5
+ VERSION = '0.5.0'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-vicenzo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bruno Vicenzo
@@ -81,6 +81,7 @@ files:
81
81
  - lib/rubocop/cop/vicenzo/rspec/nested_context_improper_start.rb
82
82
  - lib/rubocop/cop/vicenzo/rspec/nested_let_redefinition.rb
83
83
  - lib/rubocop/cop/vicenzo/rspec/nested_subject_redefinition.rb
84
+ - lib/rubocop/cop/vicenzo/style/json_parse_symbolize_names.rb
84
85
  - lib/rubocop/cop/vicenzo/style/multiline_method_call_parentheses.rb
85
86
  - lib/rubocop/cop/vicenzo_cops.rb
86
87
  - lib/rubocop/vicenzo.rb