rubocop 1.71.1 → 1.73.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 +4 -4
- data/README.md +3 -3
- data/config/default.yml +54 -11
- data/config/internal_affairs.yml +16 -0
- data/lib/rubocop/cli/command/suggest_extensions.rb +7 -1
- data/lib/rubocop/comment_config.rb +1 -1
- data/lib/rubocop/config.rb +4 -0
- data/lib/rubocop/config_loader.rb +44 -8
- data/lib/rubocop/config_loader_resolver.rb +23 -9
- data/lib/rubocop/config_validator.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/example_description.rb +4 -2
- data/lib/rubocop/cop/internal_affairs/location_exists.rb +116 -0
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/plugin.rb +33 -0
- data/lib/rubocop/cop/internal_affairs/undefined_config.rb +7 -1
- data/lib/rubocop/cop/internal_affairs.rb +1 -16
- data/lib/rubocop/cop/layout/block_alignment.rb +2 -0
- data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +4 -4
- data/lib/rubocop/cop/layout/else_alignment.rb +2 -2
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +0 -6
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +26 -1
- data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +22 -2
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -1
- data/lib/rubocop/cop/layout/line_length.rb +3 -3
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +2 -2
- data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
- data/lib/rubocop/cop/lint/cop_directive_syntax.rb +84 -0
- data/lib/rubocop/cop/lint/duplicate_methods.rb +0 -14
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +10 -5
- data/lib/rubocop/cop/lint/empty_expression.rb +0 -2
- data/lib/rubocop/cop/lint/float_comparison.rb +1 -6
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
- data/lib/rubocop/cop/lint/literal_as_condition.rb +99 -9
- data/lib/rubocop/cop/lint/mixed_case_range.rb +2 -2
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +0 -21
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +252 -0
- data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +111 -0
- data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -1
- data/lib/rubocop/cop/lint/useless_constant_scoping.rb +80 -0
- data/lib/rubocop/cop/lint/void.rb +7 -6
- data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +7 -7
- data/lib/rubocop/cop/mixin/alignment.rb +2 -2
- data/lib/rubocop/cop/mixin/allowed_pattern.rb +4 -4
- data/lib/rubocop/cop/mixin/comments_help.rb +1 -1
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +18 -18
- data/lib/rubocop/cop/mixin/hash_subset.rb +19 -4
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +74 -74
- data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
- data/lib/rubocop/cop/mixin/range_help.rb +3 -3
- data/lib/rubocop/cop/mixin/string_help.rb +1 -1
- data/lib/rubocop/cop/mixin/trailing_comma.rb +12 -0
- data/lib/rubocop/cop/naming/block_forwarding.rb +3 -3
- data/lib/rubocop/cop/naming/predicate_name.rb +44 -0
- data/lib/rubocop/cop/naming/variable_name.rb +64 -6
- data/lib/rubocop/cop/style/accessor_grouping.rb +19 -5
- data/lib/rubocop/cop/style/arguments_forwarding.rb +3 -3
- data/lib/rubocop/cop/style/commented_keyword.rb +1 -1
- data/lib/rubocop/cop/style/each_with_object.rb +2 -3
- data/lib/rubocop/cop/style/endless_method.rb +163 -18
- data/lib/rubocop/cop/style/explicit_block_argument.rb +14 -1
- data/lib/rubocop/cop/style/line_end_concatenation.rb +10 -4
- data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +1 -1
- data/lib/rubocop/cop/style/redundant_condition.rb +46 -0
- data/lib/rubocop/cop/style/redundant_format.rb +250 -0
- data/lib/rubocop/cop/style/redundant_parentheses.rb +18 -4
- data/lib/rubocop/cop/style/redundant_self_assignment.rb +1 -1
- data/lib/rubocop/cop/style/single_line_methods.rb +3 -3
- data/lib/rubocop/cop/style/string_concatenation.rb +1 -1
- data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +47 -6
- data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +48 -6
- data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
- data/lib/rubocop/cop/style/while_until_modifier.rb +0 -1
- data/lib/rubocop/cop/util.rb +1 -1
- data/lib/rubocop/cop/utils/format_string.rb +7 -5
- data/lib/rubocop/cop/variable_force/variable.rb +13 -1
- data/lib/rubocop/cops_documentation_generator.rb +12 -1
- data/lib/rubocop/directive_comment.rb +35 -2
- data/lib/rubocop/lsp/runtime.rb +2 -0
- data/lib/rubocop/lsp/server.rb +0 -2
- data/lib/rubocop/options.rb +26 -11
- data/lib/rubocop/path_util.rb +4 -0
- data/lib/rubocop/plugin/configuration_integrator.rb +143 -0
- data/lib/rubocop/plugin/load_error.rb +26 -0
- data/lib/rubocop/plugin/loader.rb +100 -0
- data/lib/rubocop/plugin/not_supported_error.rb +29 -0
- data/lib/rubocop/plugin.rb +46 -0
- data/lib/rubocop/rake_task.rb +4 -1
- data/lib/rubocop/rspec/cop_helper.rb +9 -0
- data/lib/rubocop/rspec/shared_contexts.rb +15 -0
- data/lib/rubocop/rspec/support.rb +1 -0
- data/lib/rubocop/server/cache.rb +35 -2
- data/lib/rubocop/server/cli.rb +2 -2
- data/lib/rubocop/version.rb +17 -2
- data/lib/rubocop.rb +5 -1
- data/lib/ruby_lsp/rubocop/addon.rb +7 -10
- data/lib/ruby_lsp/rubocop/{wraps_built_in_lsp_runtime.rb → runtime_adapter.rb} +5 -8
- metadata +35 -10
- data/lib/rubocop/cop/utils/regexp_ranges.rb +0 -113
@@ -8,9 +8,9 @@ module RuboCop
|
|
8
8
|
#
|
9
9
|
# Endless methods added in Ruby 3.0 are also accepted by this cop.
|
10
10
|
#
|
11
|
-
# If `Style/EndlessMethod` is enabled with `EnforcedStyle: allow_single_line`
|
12
|
-
# `
|
13
|
-
# methods if there is only one statement in the body.
|
11
|
+
# If `Style/EndlessMethod` is enabled with `EnforcedStyle: allow_single_line`, `allow_always`,
|
12
|
+
# `require_single_line`, or `require_always`, single-line methods will be autocorrected
|
13
|
+
# to endless methods if there is only one statement in the body.
|
14
14
|
#
|
15
15
|
# @example
|
16
16
|
# # bad
|
@@ -6,12 +6,13 @@ module RuboCop
|
|
6
6
|
# Checks for trailing comma in array literals.
|
7
7
|
# The configuration options are:
|
8
8
|
#
|
9
|
-
# * `consistent_comma`: Requires a comma after the
|
10
|
-
#
|
11
|
-
# * `comma`: Requires a comma after last item in an array,
|
12
|
-
#
|
13
|
-
# * `
|
14
|
-
#
|
9
|
+
# * `consistent_comma`: Requires a comma after the last item of all non-empty, multiline array
|
10
|
+
# literals.
|
11
|
+
# * `comma`: Requires a comma after the last item in an array, but only when each item is on
|
12
|
+
# its own line.
|
13
|
+
# * `diff_comma`: Requires a comma after the last item in an array, but only when that item is
|
14
|
+
# followed by an immediate newline.
|
15
|
+
# * `no_comma`: Does not require a comma after the last item in an array
|
15
16
|
#
|
16
17
|
# @example EnforcedStyleForMultiline: consistent_comma
|
17
18
|
# # bad
|
@@ -37,6 +38,14 @@ module RuboCop
|
|
37
38
|
# 2,
|
38
39
|
# ]
|
39
40
|
#
|
41
|
+
# # bad
|
42
|
+
# a = [1, 2,
|
43
|
+
# 3, 4]
|
44
|
+
#
|
45
|
+
# # good
|
46
|
+
# a = [1, 2,
|
47
|
+
# 3, 4,]
|
48
|
+
#
|
40
49
|
# @example EnforcedStyleForMultiline: comma
|
41
50
|
# # bad
|
42
51
|
# a = [1, 2,]
|
@@ -72,6 +81,38 @@ module RuboCop
|
|
72
81
|
# 2,
|
73
82
|
# ]
|
74
83
|
#
|
84
|
+
# @example EnforcedStyleForMultiline: diff_comma
|
85
|
+
# # bad
|
86
|
+
# a = [1, 2,]
|
87
|
+
#
|
88
|
+
# # good
|
89
|
+
# a = [1, 2]
|
90
|
+
#
|
91
|
+
# # good
|
92
|
+
# a = [
|
93
|
+
# 1, 2,
|
94
|
+
# 3,
|
95
|
+
# ]
|
96
|
+
#
|
97
|
+
# # good
|
98
|
+
# a = [
|
99
|
+
# 1, 2, 3,
|
100
|
+
# ]
|
101
|
+
#
|
102
|
+
# # good
|
103
|
+
# a = [
|
104
|
+
# 1,
|
105
|
+
# 2,
|
106
|
+
# ]
|
107
|
+
#
|
108
|
+
# # bad
|
109
|
+
# a = [1, 2,
|
110
|
+
# 3, 4,]
|
111
|
+
#
|
112
|
+
# # good
|
113
|
+
# a = [1, 2,
|
114
|
+
# 3, 4]
|
115
|
+
#
|
75
116
|
# @example EnforcedStyleForMultiline: no_comma (default)
|
76
117
|
# # bad
|
77
118
|
# a = [1, 2,]
|
@@ -6,12 +6,13 @@ module RuboCop
|
|
6
6
|
# Checks for trailing comma in hash literals.
|
7
7
|
# The configuration options are:
|
8
8
|
#
|
9
|
-
# * `consistent_comma`: Requires a comma after the
|
10
|
-
#
|
11
|
-
# * `comma`: Requires a comma after the last item in a hash,
|
12
|
-
#
|
13
|
-
# * `
|
14
|
-
#
|
9
|
+
# * `consistent_comma`: Requires a comma after the last item of all non-empty, multiline hash
|
10
|
+
# literals.
|
11
|
+
# * `comma`: Requires a comma after the last item in a hash, but only when each item is on its
|
12
|
+
# own line.
|
13
|
+
# * `diff_comma`: Requires a comma after the last item in a hash, but only when that item is
|
14
|
+
# followed by an immediate newline.
|
15
|
+
# * `no_comma`: Does not require a comma after the last item in a hash
|
15
16
|
#
|
16
17
|
# @example EnforcedStyleForMultiline: consistent_comma
|
17
18
|
#
|
@@ -38,6 +39,14 @@ module RuboCop
|
|
38
39
|
# bar: 2,
|
39
40
|
# }
|
40
41
|
#
|
42
|
+
# # bad
|
43
|
+
# a = { foo: 1, bar: 2,
|
44
|
+
# baz: 3, qux: 4 }
|
45
|
+
#
|
46
|
+
# # good
|
47
|
+
# a = { foo: 1, bar: 2,
|
48
|
+
# baz: 3, qux: 4, }
|
49
|
+
#
|
41
50
|
# @example EnforcedStyleForMultiline: comma
|
42
51
|
#
|
43
52
|
# # bad
|
@@ -74,6 +83,39 @@ module RuboCop
|
|
74
83
|
# bar: 2,
|
75
84
|
# }
|
76
85
|
#
|
86
|
+
# @example EnforcedStyleForMultiline: diff_comma
|
87
|
+
#
|
88
|
+
# # bad
|
89
|
+
# a = { foo: 1, bar: 2, }
|
90
|
+
#
|
91
|
+
# # good
|
92
|
+
# a = { foo: 1, bar: 2 }
|
93
|
+
#
|
94
|
+
# # good
|
95
|
+
# a = {
|
96
|
+
# foo: 1, bar: 2,
|
97
|
+
# qux: 3,
|
98
|
+
# }
|
99
|
+
#
|
100
|
+
# # good
|
101
|
+
# a = {
|
102
|
+
# foo: 1, bar: 2, qux: 3,
|
103
|
+
# }
|
104
|
+
#
|
105
|
+
# # good
|
106
|
+
# a = {
|
107
|
+
# foo: 1,
|
108
|
+
# bar: 2,
|
109
|
+
# }
|
110
|
+
#
|
111
|
+
# # bad
|
112
|
+
# a = { foo: 1, bar: 2,
|
113
|
+
# baz: 3, qux: 4, }
|
114
|
+
#
|
115
|
+
# # good
|
116
|
+
# a = { foo: 1, bar: 2,
|
117
|
+
# baz: 3, qux: 4 }
|
118
|
+
#
|
77
119
|
# @example EnforcedStyleForMultiline: no_comma (default)
|
78
120
|
#
|
79
121
|
# # bad
|
@@ -113,7 +113,7 @@ module RuboCop
|
|
113
113
|
private
|
114
114
|
|
115
115
|
def in_module_or_instance_eval?(node)
|
116
|
-
node.each_ancestor(:
|
116
|
+
node.each_ancestor(:any_block, :class, :sclass, :module).each do |pnode|
|
117
117
|
case pnode.type
|
118
118
|
when :class, :sclass
|
119
119
|
return false
|
data/lib/rubocop/cop/util.rb
CHANGED
@@ -5,15 +5,16 @@ module RuboCop
|
|
5
5
|
module Utils
|
6
6
|
# Parses {Kernel#sprintf} format strings.
|
7
7
|
class FormatString
|
8
|
-
DIGIT_DOLLAR = /(
|
8
|
+
DIGIT_DOLLAR = /(?<arg_number>\d+)\$/.freeze
|
9
|
+
INTERPOLATION = /#\{.*?\}/.freeze
|
9
10
|
FLAG = /[ #0+-]|#{DIGIT_DOLLAR}/.freeze
|
10
11
|
NUMBER_ARG = /\*#{DIGIT_DOLLAR}?/.freeze
|
11
|
-
NUMBER = /\d+|#{NUMBER_ARG}/.freeze
|
12
|
+
NUMBER = /\d+|#{NUMBER_ARG}|#{INTERPOLATION}/.freeze
|
12
13
|
WIDTH = /(?<width>#{NUMBER})/.freeze
|
13
|
-
PRECISION = /\.(?<precision>#{NUMBER})/.freeze
|
14
|
+
PRECISION = /\.(?<precision>#{NUMBER}?)/.freeze
|
14
15
|
TYPE = /(?<type>[bBdiouxXeEfgGaAcps])/.freeze
|
15
16
|
NAME = /<(?<name>\w+)>/.freeze
|
16
|
-
TEMPLATE_NAME =
|
17
|
+
TEMPLATE_NAME = /(?<!#)\{(?<name>\w+)\}/.freeze
|
17
18
|
|
18
19
|
SEQUENCE = /
|
19
20
|
% (?<type>%)
|
@@ -41,7 +42,7 @@ module RuboCop
|
|
41
42
|
#
|
42
43
|
# @see https://ruby-doc.org/core-2.6.3/Kernel.html#method-i-format
|
43
44
|
class FormatSequence
|
44
|
-
attr_reader :begin_pos, :end_pos, :flags, :width, :precision, :name, :type
|
45
|
+
attr_reader :begin_pos, :end_pos, :flags, :width, :precision, :name, :type, :arg_number
|
45
46
|
|
46
47
|
def initialize(match)
|
47
48
|
@source = match[0]
|
@@ -52,6 +53,7 @@ module RuboCop
|
|
52
53
|
@precision = match[:precision]
|
53
54
|
@name = match[:name]
|
54
55
|
@type = match[:type]
|
56
|
+
@arg_number = match[:arg_number]
|
55
57
|
end
|
56
58
|
|
57
59
|
def percent?
|
@@ -6,6 +6,8 @@ module RuboCop
|
|
6
6
|
# A Variable represents existence of a local variable.
|
7
7
|
# This holds a variable declaration node and some states of the variable.
|
8
8
|
class Variable
|
9
|
+
extend NodePattern::Macros
|
10
|
+
|
9
11
|
VARIABLE_DECLARATION_TYPES = (VARIABLE_ASSIGNMENT_TYPES + ARGUMENT_DECLARATION_TYPES).freeze
|
10
12
|
|
11
13
|
attr_reader :name, :declaration_node, :scope, :assignments, :references, :captured_by_block
|
@@ -31,11 +33,21 @@ module RuboCop
|
|
31
33
|
def assign(node)
|
32
34
|
assignment = Assignment.new(node, self)
|
33
35
|
|
34
|
-
|
36
|
+
mark_last_as_reassigned!(assignment)
|
35
37
|
|
36
38
|
@assignments << assignment
|
37
39
|
end
|
38
40
|
|
41
|
+
def mark_last_as_reassigned!(assignment)
|
42
|
+
return if captured_by_block?
|
43
|
+
return if candidate_condition?(assignment.node.parent)
|
44
|
+
|
45
|
+
@assignments.last&.reassigned!
|
46
|
+
end
|
47
|
+
|
48
|
+
# @!method candidate_condition?(node)
|
49
|
+
def_node_matcher :candidate_condition?, '[{if case case_match when}]'
|
50
|
+
|
39
51
|
def referenced?
|
40
52
|
!@references.empty?
|
41
53
|
end
|
@@ -28,6 +28,12 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
|
|
28
28
|
#
|
29
29
|
# CopsDocumentationGenerator.new(departments: ['Lint']).call
|
30
30
|
#
|
31
|
+
# For plugin extensions, specify `:plugin_name` keyword as follows:
|
32
|
+
#
|
33
|
+
# CopsDocumentationGenerator.new(
|
34
|
+
# departments: ['Performance'], plugin_name: 'rubocop-performance'
|
35
|
+
# ).call
|
36
|
+
#
|
31
37
|
# You can append additional information:
|
32
38
|
#
|
33
39
|
# callback = ->(data) { required_rails_version(data.cop) }
|
@@ -36,11 +42,16 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
|
|
36
42
|
# This will insert the string returned from the lambda _after_ the section from RuboCop itself.
|
37
43
|
# See `CopsDocumentationGenerator::STRUCTURE` for available sections.
|
38
44
|
#
|
39
|
-
def initialize(departments: [], extra_info: {}, base_dir: Dir.pwd)
|
45
|
+
def initialize(departments: [], extra_info: {}, base_dir: Dir.pwd, plugin_name: nil)
|
40
46
|
@departments = departments.map(&:to_sym).sort!
|
41
47
|
@extra_info = extra_info
|
42
48
|
@cops = RuboCop::Cop::Registry.global
|
43
49
|
@config = RuboCop::ConfigLoader.default_configuration
|
50
|
+
# NOTE: For example, this prevents excessive plugin loading before another task executes,
|
51
|
+
# in cases where plugins are already loaded by `internal_investigation`.
|
52
|
+
if plugin_name && @config.loaded_plugins.none? { |plugin| plugin.about.name == plugin_name }
|
53
|
+
RuboCop::Plugin.integrate_plugins(RuboCop::Config.new, [plugin_name])
|
54
|
+
end
|
44
55
|
@base_dir = base_dir
|
45
56
|
@docs_path = "#{base_dir}/docs/modules/ROOT"
|
46
57
|
FileUtils.mkdir_p("#{@docs_path}/pages")
|
@@ -18,10 +18,24 @@ module RuboCop
|
|
18
18
|
# @api private
|
19
19
|
COPS_PATTERN = "(all|#{COP_NAMES_PATTERN})"
|
20
20
|
# @api private
|
21
|
+
AVAILABLE_MODES = %w[disable enable todo].freeze
|
22
|
+
# @api private
|
23
|
+
DIRECTIVE_MARKER_PATTERN = '# rubocop : '
|
24
|
+
# @api private
|
25
|
+
DIRECTIVE_MARKER_REGEXP = Regexp.new(DIRECTIVE_MARKER_PATTERN.gsub(' ', '\s*'))
|
26
|
+
# @api private
|
27
|
+
DIRECTIVE_HEADER_PATTERN = "#{DIRECTIVE_MARKER_PATTERN}((?:#{AVAILABLE_MODES.join('|')}))\\b"
|
28
|
+
# @api private
|
21
29
|
DIRECTIVE_COMMENT_REGEXP = Regexp.new(
|
22
|
-
"#
|
30
|
+
"#{DIRECTIVE_HEADER_PATTERN} #{COPS_PATTERN}"
|
23
31
|
.gsub(' ', '\s*')
|
24
32
|
)
|
33
|
+
# @api private
|
34
|
+
TRAILING_COMMENT_MARKER = '--'
|
35
|
+
# @api private
|
36
|
+
MALFORMED_DIRECTIVE_WITHOUT_COP_NAME_REGEXP = Regexp.new(
|
37
|
+
"\\A#{DIRECTIVE_HEADER_PATTERN}\\s*\\z".gsub(' ', '\s*')
|
38
|
+
)
|
25
39
|
|
26
40
|
def self.before_comment(line)
|
27
41
|
line.split(DIRECTIVE_COMMENT_REGEXP).first
|
@@ -32,9 +46,28 @@ module RuboCop
|
|
32
46
|
def initialize(comment, cop_registry = Cop::Registry.global)
|
33
47
|
@comment = comment
|
34
48
|
@cop_registry = cop_registry
|
49
|
+
@match_data = comment.text.match(DIRECTIVE_COMMENT_REGEXP)
|
35
50
|
@mode, @cops = match_captures
|
36
51
|
end
|
37
52
|
|
53
|
+
# Checks if the comment starts with `# rubocop:` marker
|
54
|
+
def start_with_marker?
|
55
|
+
comment.text.start_with?(DIRECTIVE_MARKER_REGEXP)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Checks if the comment is malformed as a `# rubocop:` directive
|
59
|
+
def malformed?
|
60
|
+
return true if !start_with_marker? || @match_data.nil?
|
61
|
+
|
62
|
+
tail = @match_data.post_match.lstrip
|
63
|
+
!(tail.empty? || tail.start_with?(TRAILING_COMMENT_MARKER))
|
64
|
+
end
|
65
|
+
|
66
|
+
# Checks if the directive comment is missing a cop name
|
67
|
+
def missing_cop_name?
|
68
|
+
MALFORMED_DIRECTIVE_WITHOUT_COP_NAME_REGEXP.match?(comment.text)
|
69
|
+
end
|
70
|
+
|
38
71
|
# Checks if this directive relates to single line
|
39
72
|
def single_line?
|
40
73
|
!comment.text.start_with?(DIRECTIVE_COMMENT_REGEXP)
|
@@ -55,7 +88,7 @@ module RuboCop
|
|
55
88
|
|
56
89
|
# Returns match captures to directive comment pattern
|
57
90
|
def match_captures
|
58
|
-
@match_captures ||=
|
91
|
+
@match_captures ||= @match_data&.captures
|
59
92
|
end
|
60
93
|
|
61
94
|
# Checks if this directive disables cops
|
data/lib/rubocop/lsp/runtime.rb
CHANGED
data/lib/rubocop/lsp/server.rb
CHANGED
@@ -22,8 +22,6 @@ module RuboCop
|
|
22
22
|
def initialize(config_store)
|
23
23
|
$PROGRAM_NAME = "rubocop --lsp #{ConfigFinder.project_root}"
|
24
24
|
|
25
|
-
RuboCop::LSP.enable
|
26
|
-
|
27
25
|
@reader = LanguageServer::Protocol::Transport::Io::Reader.new($stdin)
|
28
26
|
@writer = LanguageServer::Protocol::Transport::Io::Writer.new($stdout)
|
29
27
|
@runtime = RuboCop::LSP::Runtime.new(config_store)
|
data/lib/rubocop/options.rb
CHANGED
@@ -243,6 +243,7 @@ module RuboCop
|
|
243
243
|
option(opts, '--init')
|
244
244
|
option(opts, '-c', '--config FILE')
|
245
245
|
option(opts, '-d', '--debug')
|
246
|
+
option(opts, '--plugin FILE') { |f| plugin_feature(f) }
|
246
247
|
option(opts, '-r', '--require FILE') { |f| require_feature(f) }
|
247
248
|
option(opts, '--[no-]color')
|
248
249
|
option(opts, '-v', '--version')
|
@@ -299,11 +300,25 @@ module RuboCop
|
|
299
300
|
long_opt[2..].sub('[no-]', '').sub(/ .*/, '').tr('-', '_').gsub(/[\[\]]/, '').to_sym
|
300
301
|
end
|
301
302
|
|
302
|
-
def
|
303
|
-
# If any features were added on the CLI from `--
|
303
|
+
def plugin_feature(file)
|
304
|
+
# If any features were added on the CLI from `--plugin`,
|
304
305
|
# add them to the config.
|
305
|
-
|
306
|
-
|
306
|
+
ConfigLoaderResolver.new.resolve_plugins(Config.new, file)
|
307
|
+
end
|
308
|
+
|
309
|
+
def require_feature(file)
|
310
|
+
if Plugin.plugin_capable?(file)
|
311
|
+
# NOTE: Compatibility for before plugins style.
|
312
|
+
warn Rainbow(<<~MESSAGE).yellow
|
313
|
+
#{file} gem supports plugin, use `--plugin` instead of `--require`.
|
314
|
+
MESSAGE
|
315
|
+
plugin_feature(file)
|
316
|
+
else
|
317
|
+
# If any features were added on the CLI from `--require`,
|
318
|
+
# add them to the config.
|
319
|
+
require file
|
320
|
+
ConfigLoader.add_loaded_features(file)
|
321
|
+
end
|
307
322
|
end
|
308
323
|
end
|
309
324
|
|
@@ -397,7 +412,7 @@ module RuboCop
|
|
397
412
|
return if @options[:format] == 'junit'
|
398
413
|
|
399
414
|
raise OptionArgumentError,
|
400
|
-
|
415
|
+
'--display-only-failed can only be used together with --format junit.'
|
401
416
|
end
|
402
417
|
|
403
418
|
def validate_display_only_correctable_and_autocorrect
|
@@ -415,14 +430,13 @@ module RuboCop
|
|
415
430
|
!@options.key?(:display_only_safe_correctable)
|
416
431
|
|
417
432
|
raise OptionArgumentError,
|
418
|
-
|
433
|
+
'--display-only-failed cannot be used together with other display options.'
|
419
434
|
end
|
420
435
|
|
421
436
|
def validate_lsp_and_editor_mode
|
422
437
|
return if !@options.key?(:lsp) || !@options.key?(:editor_mode)
|
423
438
|
|
424
|
-
raise OptionArgumentError,
|
425
|
-
format('Do not specify `--editor-mode` as it is redundant in `--lsp`.')
|
439
|
+
raise OptionArgumentError, 'Do not specify `--editor-mode` as it is redundant in `--lsp`.'
|
426
440
|
end
|
427
441
|
|
428
442
|
def validate_autocorrect
|
@@ -436,7 +450,7 @@ module RuboCop
|
|
436
450
|
return unless @options.key?(:disable_uncorrectable)
|
437
451
|
|
438
452
|
raise OptionArgumentError,
|
439
|
-
|
453
|
+
'--disable-uncorrectable can only be used together with --autocorrect.'
|
440
454
|
end
|
441
455
|
|
442
456
|
def disable_parallel_when_invalid_option_combo
|
@@ -504,6 +518,7 @@ module RuboCop
|
|
504
518
|
only_guide_cops: ['Run only cops for rules that link to a',
|
505
519
|
'style guide.'],
|
506
520
|
except: 'Exclude the given cop(s).',
|
521
|
+
plugin: 'Load a RuboCop plugin.',
|
507
522
|
require: 'Require Ruby file.',
|
508
523
|
config: 'Specify configuration file.',
|
509
524
|
auto_gen_config: ['Generate a configuration file acting as a',
|
@@ -542,8 +557,8 @@ module RuboCop
|
|
542
557
|
only_recognized_file_types: ['Inspect files given on the command line only if',
|
543
558
|
'they are listed in `AllCops/Include` parameters',
|
544
559
|
'of user configuration or default configuration.'],
|
545
|
-
ignore_disable_comments: ['
|
546
|
-
'
|
560
|
+
ignore_disable_comments: ['Report offenses even if they have been manually disabled',
|
561
|
+
'with a `rubocop:disable` or `rubocop:todo` directive.'],
|
547
562
|
ignore_parent_exclusion: ['Prevent from inheriting `AllCops/Exclude` from',
|
548
563
|
'parent folders.'],
|
549
564
|
ignore_unrecognized_cops: ['Ignore unrecognized cops or departments in the config.'],
|
data/lib/rubocop/path_util.rb
CHANGED
@@ -0,0 +1,143 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'lint_roller/context'
|
4
|
+
require_relative 'not_supported_error'
|
5
|
+
|
6
|
+
module RuboCop
|
7
|
+
module Plugin
|
8
|
+
# A class for integrating plugin configurations into RuboCop.
|
9
|
+
# Handles configuration merging, validation, and compatibility for plugins.
|
10
|
+
# @api private
|
11
|
+
class ConfigurationIntegrator
|
12
|
+
class << self
|
13
|
+
def integrate_plugins_into_rubocop_config(rubocop_config, plugins)
|
14
|
+
default_config = ConfigLoader.default_configuration
|
15
|
+
runner_context = create_context(rubocop_config)
|
16
|
+
|
17
|
+
validate_plugins!(plugins, runner_context)
|
18
|
+
|
19
|
+
plugin_config = combine_rubocop_configs(default_config, runner_context, plugins).to_h
|
20
|
+
|
21
|
+
merge_plugin_config_into_all_cops!(default_config, plugin_config)
|
22
|
+
merge_plugin_config_into_default_config!(default_config, plugin_config)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def create_context(rubocop_config)
|
28
|
+
LintRoller::Context.new(
|
29
|
+
runner: :rubocop,
|
30
|
+
runner_version: Version.version,
|
31
|
+
engine: :rubocop,
|
32
|
+
engine_version: Version.version,
|
33
|
+
target_ruby_version: rubocop_config.target_ruby_version
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
def validate_plugins!(plugins, runner_context)
|
38
|
+
unsupported_plugins = plugins.reject { |plugin| plugin.supported?(runner_context) }
|
39
|
+
return if unsupported_plugins.none?
|
40
|
+
|
41
|
+
raise Plugin::NotSupportedError, unsupported_plugins
|
42
|
+
end
|
43
|
+
|
44
|
+
def combine_rubocop_configs(default_config, runner_context, plugins)
|
45
|
+
fake_out_rubocop_default_configuration(default_config) do |fake_config|
|
46
|
+
all_cop_keys_configured_by_plugins = []
|
47
|
+
|
48
|
+
plugins.reduce(fake_config) do |combined_config, plugin|
|
49
|
+
RuboCop::ConfigLoader.instance_variable_set(:@default_configuration, combined_config)
|
50
|
+
|
51
|
+
print 'Plugin ' if ConfigLoader.debug
|
52
|
+
|
53
|
+
plugin_config, plugin_config_path = load_plugin_rubocop_config(plugin, runner_context)
|
54
|
+
|
55
|
+
plugin_config['AllCops'], all_cop_keys_configured_by_plugins = merge_all_cop_settings(
|
56
|
+
combined_config['AllCops'], plugin_config['AllCops'],
|
57
|
+
all_cop_keys_configured_by_plugins
|
58
|
+
)
|
59
|
+
|
60
|
+
plugin_config.make_excludes_absolute
|
61
|
+
|
62
|
+
ConfigLoader.merge_with_default(plugin_config, plugin_config_path)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def merge_plugin_config_into_all_cops!(rubocop_config, plugin_config)
|
68
|
+
rubocop_config['AllCops'].merge!(plugin_config['AllCops'])
|
69
|
+
end
|
70
|
+
|
71
|
+
def merge_plugin_config_into_default_config!(default_config, plugin_config)
|
72
|
+
plugin_config.each do |key, value|
|
73
|
+
default_config[key] = if default_config[key].is_a?(Hash)
|
74
|
+
resolver.merge(default_config[key], value)
|
75
|
+
else
|
76
|
+
value
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def fake_out_rubocop_default_configuration(default_config)
|
82
|
+
orig_default_config = ConfigLoader.instance_variable_get(:@default_configuration)
|
83
|
+
|
84
|
+
result = yield default_config
|
85
|
+
|
86
|
+
ConfigLoader.instance_variable_set(:@default_configuration, orig_default_config)
|
87
|
+
|
88
|
+
result
|
89
|
+
end
|
90
|
+
|
91
|
+
# rubocop:disable Metrics/AbcSize
|
92
|
+
def load_plugin_rubocop_config(plugin, runner_context)
|
93
|
+
rules = plugin.rules(runner_context)
|
94
|
+
|
95
|
+
case rules.type
|
96
|
+
when :path
|
97
|
+
[ConfigLoader.load_file(rules.value, check: false), rules.value]
|
98
|
+
when :object
|
99
|
+
path = plugin.method(:rules).source_location[0]
|
100
|
+
[Config.create(rules.value, path, check: true), path]
|
101
|
+
when :error
|
102
|
+
plugin_name = plugin.about&.name || plugin.inspect
|
103
|
+
error_message = rules.value.respond_to?(:message) ? rules.value.message : rules.value
|
104
|
+
|
105
|
+
raise "Plugin `#{plugin_name}' failed to load with error: #{error_message}"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
# rubocop:enable Metrics/AbcSize
|
109
|
+
|
110
|
+
# This is how we ensure "first-in wins": plugins can override AllCops settings that are
|
111
|
+
# set by RuboCop's default configuration, but once a plugin sets an AllCop setting, they
|
112
|
+
# have exclusive first-in-wins rights to that setting.
|
113
|
+
#
|
114
|
+
# The one exception to this are array fields, because we don't want to
|
115
|
+
# overwrite the AllCops defaults but rather munge the arrays (`existing |
|
116
|
+
# new`) to allow plugins to add to the array, for example Include and
|
117
|
+
# Exclude paths and patterns.
|
118
|
+
def merge_all_cop_settings(existing_all_cops, new_all_cops, already_configured_keys)
|
119
|
+
return [existing_all_cops, already_configured_keys] unless new_all_cops.is_a?(Hash)
|
120
|
+
|
121
|
+
combined_all_cops = existing_all_cops.dup
|
122
|
+
combined_configured_keys = already_configured_keys.dup
|
123
|
+
|
124
|
+
new_all_cops.each do |key, value|
|
125
|
+
if combined_all_cops[key].is_a?(Array) && value.is_a?(Array)
|
126
|
+
combined_all_cops[key] |= value
|
127
|
+
combined_configured_keys |= [key]
|
128
|
+
elsif !combined_configured_keys.include?(key)
|
129
|
+
combined_all_cops[key] = value
|
130
|
+
combined_configured_keys << key
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
[combined_all_cops, combined_configured_keys]
|
135
|
+
end
|
136
|
+
|
137
|
+
def resolver
|
138
|
+
@resolver ||= ConfigLoaderResolver.new
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Plugin
|
5
|
+
# An exception raised when a plugin fails to load.
|
6
|
+
# @api private
|
7
|
+
class LoadError < Error
|
8
|
+
def initialize(plugin_name)
|
9
|
+
super
|
10
|
+
|
11
|
+
@plugin_name = plugin_name
|
12
|
+
end
|
13
|
+
|
14
|
+
def message
|
15
|
+
<<~MESSAGE
|
16
|
+
Failed to load plugin `#{@plugin_name}` because the corresponding plugin class could not be determined for instantiation.
|
17
|
+
Try upgrading it first (e.g., `bundle update #{@plugin_name}`).
|
18
|
+
If `#{@plugin_name}` is not yet a plugin, use `require: #{@plugin_name}` instead of `plugins: #{@plugin_name}` in your configuration.
|
19
|
+
|
20
|
+
For further assistance, check with the developer regarding the following points:
|
21
|
+
https://docs.rubocop.org/rubocop/plugin_migration_guide.html
|
22
|
+
MESSAGE
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|