rubocop 1.81.7 → 1.92.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/LICENSE.txt +1 -1
- data/README.md +2 -2
- data/config/default.yml +626 -111
- data/config/obsoletion.yml +39 -1
- data/exe/rubocop +1 -1
- data/lib/rubocop/cache_config.rb +29 -0
- data/lib/rubocop/cached_data.rb +50 -5
- data/lib/rubocop/changed_files.rb +134 -0
- data/lib/rubocop/cli/command/auto_generate_config.rb +34 -2
- data/lib/rubocop/cli/command/cop_names.rb +57 -0
- data/lib/rubocop/cli/command/execute_runner.rb +54 -3
- data/lib/rubocop/cli/command/explain.rb +34 -0
- data/lib/rubocop/cli/command/list_enabled_cops_for.rb +40 -0
- data/lib/rubocop/cli/command/lsp.rb +1 -1
- data/lib/rubocop/cli/command/mcp.rb +19 -0
- data/lib/rubocop/cli/command/show_cops.rb +8 -2
- data/lib/rubocop/cli/command/show_docs_url.rb +8 -10
- data/lib/rubocop/cli/command/suggest_extensions.rb +1 -1
- data/lib/rubocop/cli.rb +41 -14
- data/lib/rubocop/comment_config/directive_range.rb +34 -0
- data/lib/rubocop/comment_config/disable_next.rb +143 -0
- data/lib/rubocop/comment_config/push_pop.rb +55 -0
- data/lib/rubocop/comment_config.rb +97 -44
- data/lib/rubocop/config.rb +100 -15
- data/lib/rubocop/config_finder.rb +1 -1
- data/lib/rubocop/config_loader.rb +49 -27
- data/lib/rubocop/config_loader_resolver.rb +95 -20
- data/lib/rubocop/config_obsoletion/cop_rule.rb +2 -1
- data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -2
- data/lib/rubocop/config_obsoletion/removed_cop.rb +9 -1
- data/lib/rubocop/config_obsoletion.rb +1 -1
- data/lib/rubocop/config_store.rb +2 -2
- data/lib/rubocop/config_validator.rb +69 -7
- data/lib/rubocop/cop/autocorrect_logic.rb +24 -6
- data/lib/rubocop/cop/badge.rb +10 -2
- data/lib/rubocop/cop/base.rb +128 -35
- data/lib/rubocop/cop/bundler/gem_comment.rb +5 -4
- data/lib/rubocop/cop/bundler/gem_version.rb +28 -28
- data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -10
- data/lib/rubocop/cop/bundler.rb +19 -0
- data/lib/rubocop/cop/commissioner.rb +13 -11
- data/lib/rubocop/cop/cop_documentation.rb +81 -0
- data/lib/rubocop/cop/cop_explanation.rb +140 -0
- data/lib/rubocop/cop/corrector.rb +4 -4
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +87 -9
- data/lib/rubocop/cop/correctors/condition_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +37 -7
- data/lib/rubocop/cop/correctors/empty_line_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +31 -4
- data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +35 -5
- data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +8 -1
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +70 -2
- data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
- data/lib/rubocop/cop/correctors.rb +28 -0
- data/lib/rubocop/cop/documentation.rb +3 -4
- data/lib/rubocop/cop/exclude_limit.rb +31 -5
- data/lib/rubocop/cop/gemspec/dependency_version.rb +0 -6
- data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
- data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +14 -4
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -8
- data/lib/rubocop/cop/gemspec/require_mfa.rb +9 -6
- data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +12 -7
- data/lib/rubocop/cop/gemspec.rb +22 -0
- data/lib/rubocop/cop/generator/registration_injector.rb +188 -0
- data/lib/rubocop/cop/generator.rb +5 -1
- data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +8 -8
- data/lib/rubocop/cop/internal_affairs/itblock_handler.rb +69 -0
- data/lib/rubocop/cop/internal_affairs/location_exists.rb +28 -2
- data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +1 -0
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +12 -16
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +1 -2
- data/lib/rubocop/cop/internal_affairs/node_type_group.rb +0 -7
- data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/redundant_context_config_parameter.rb +1 -7
- data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +5 -3
- data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +1 -7
- data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +4 -4
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/argument_alignment.rb +9 -3
- data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/begin_end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/block_alignment.rb +84 -4
- data/lib/rubocop/cop/layout/case_indentation.rb +28 -10
- data/lib/rubocop/cop/layout/class_structure.rb +156 -41
- data/lib/rubocop/cop/layout/comment_indentation.rb +17 -7
- data/lib/rubocop/cop/layout/condition_position.rb +13 -3
- data/lib/rubocop/cop/layout/def_end_alignment.rb +4 -0
- data/lib/rubocop/cop/layout/dot_position.rb +26 -16
- data/lib/rubocop/cop/layout/else_alignment.rb +2 -14
- data/lib/rubocop/cop/layout/empty_comment.rb +8 -10
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +25 -7
- data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +63 -5
- data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +21 -8
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +15 -2
- data/lib/rubocop/cop/layout/empty_lines.rb +5 -2
- data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +2 -2
- data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +2 -0
- data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +21 -5
- data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +16 -2
- data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +23 -1
- data/lib/rubocop/cop/layout/empty_lines_around_module_body.rb +16 -2
- data/lib/rubocop/cop/layout/end_alignment.rb +23 -15
- data/lib/rubocop/cop/layout/extra_spacing.rb +109 -3
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +81 -2
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +18 -5
- data/lib/rubocop/cop/layout/first_array_element_line_break.rb +41 -0
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +36 -23
- data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +25 -25
- data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +6 -0
- data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +4 -0
- data/lib/rubocop/cop/layout/first_parameter_indentation.rb +11 -0
- data/lib/rubocop/cop/layout/hash_alignment.rb +16 -11
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +8 -4
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +48 -3
- data/lib/rubocop/cop/layout/indentation_consistency.rb +22 -5
- data/lib/rubocop/cop/layout/indentation_style.rb +5 -2
- data/lib/rubocop/cop/layout/indentation_width.rb +158 -12
- data/lib/rubocop/cop/layout/leading_comment_space.rb +27 -0
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +10 -4
- data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +25 -9
- data/lib/rubocop/cop/layout/line_length.rb +265 -29
- data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +69 -57
- data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +8 -2
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +10 -1
- data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +65 -56
- data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +7 -1
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +268 -38
- data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +4 -0
- data/lib/rubocop/cop/layout/parameter_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/redundant_line_break.rb +102 -2
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +19 -5
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +10 -2
- data/lib/rubocop/cop/layout/space_after_comma.rb +2 -10
- data/lib/rubocop/cop/layout/space_after_not.rb +5 -0
- data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +10 -4
- data/lib/rubocop/cop/layout/space_around_keyword.rb +14 -2
- data/lib/rubocop/cop/layout/space_around_operators.rb +18 -3
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +4 -1
- data/lib/rubocop/cop/layout/space_before_brackets.rb +1 -1
- data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +9 -8
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +44 -34
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +31 -8
- data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +2 -12
- data/lib/rubocop/cop/layout.rb +114 -0
- data/lib/rubocop/cop/lazy_loader.rb +41 -0
- data/lib/rubocop/cop/lint/ambiguous_assignment.rb +9 -17
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +72 -1
- data/lib/rubocop/cop/lint/ambiguous_operator.rb +1 -1
- data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +3 -11
- data/lib/rubocop/cop/lint/ambiguous_range.rb +1 -2
- data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +6 -1
- data/lib/rubocop/cop/lint/argument_mismatch.rb +99 -0
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +15 -1
- data/lib/rubocop/cop/lint/circular_argument_reference.rb +45 -3
- data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
- data/lib/rubocop/cop/lint/constant_reassignment.rb +94 -15
- data/lib/rubocop/cop/lint/constant_resolution.rb +31 -6
- data/lib/rubocop/cop/lint/cop_directive_syntax.rb +165 -15
- data/lib/rubocop/cop/lint/data_define_override.rb +63 -0
- data/lib/rubocop/cop/lint/debugger.rb +13 -2
- data/lib/rubocop/cop/lint/deprecated_constants.rb +2 -8
- data/lib/rubocop/cop/lint/deprecated_reference.rb +194 -0
- data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +4 -4
- data/lib/rubocop/cop/lint/duplicate_methods.rb +405 -28
- data/lib/rubocop/cop/lint/else_layout.rb +19 -0
- data/lib/rubocop/cop/lint/empty_block.rb +4 -4
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +9 -2
- data/lib/rubocop/cop/lint/empty_in_pattern.rb +8 -1
- data/lib/rubocop/cop/lint/empty_when.rb +8 -1
- data/lib/rubocop/cop/lint/ensure_return.rb +19 -1
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +4 -2
- data/lib/rubocop/cop/lint/float_comparison.rb +2 -1
- data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +4 -0
- data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -2
- data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -1
- data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +1 -2
- data/lib/rubocop/cop/lint/inherit_exception.rb +53 -7
- data/lib/rubocop/cop/lint/interpolation_check.rb +25 -6
- data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
- data/lib/rubocop/cop/lint/literal_as_condition.rb +36 -9
- data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +11 -1
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +75 -37
- data/lib/rubocop/cop/lint/loop.rb +24 -2
- data/lib/rubocop/cop/lint/misplaced_magic_comment.rb +245 -0
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +46 -18
- data/lib/rubocop/cop/lint/missing_super.rb +31 -1
- data/lib/rubocop/cop/lint/multiple_comparison.rb +2 -2
- data/lib/rubocop/cop/lint/name_typo.rb +270 -0
- data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
- data/lib/rubocop/cop/lint/next_without_accumulator.rb +2 -0
- data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +20 -0
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +4 -2
- data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +1 -1
- data/lib/rubocop/cop/lint/number_conversion.rb +22 -11
- data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
- data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +10 -0
- data/lib/rubocop/cop/lint/ordered_magic_comments.rb +7 -7
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +15 -4
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +20 -14
- data/lib/rubocop/cop/lint/raise_exception.rb +1 -1
- data/lib/rubocop/cop/lint/rand_one.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +160 -39
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +53 -19
- data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +28 -6
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +5 -4
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +37 -14
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +13 -4
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +11 -5
- data/lib/rubocop/cop/lint/redundant_with_index.rb +2 -3
- data/lib/rubocop/cop/lint/redundant_with_object.rb +5 -0
- data/lib/rubocop/cop/lint/refinement_import_methods.rb +8 -1
- data/lib/rubocop/cop/lint/regexp_as_condition.rb +9 -1
- data/lib/rubocop/cop/lint/require_parentheses.rb +13 -4
- data/lib/rubocop/cop/lint/require_range_parentheses.rb +2 -1
- data/lib/rubocop/cop/lint/require_relative_self_path.rb +7 -5
- data/lib/rubocop/cop/lint/rescue_type.rb +1 -1
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +24 -0
- data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +56 -6
- data/lib/rubocop/cop/lint/safe_navigation_with_empty.rb +1 -1
- data/lib/rubocop/cop/lint/script_permission.rb +5 -1
- data/lib/rubocop/cop/lint/self_assignment.rb +33 -2
- data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -1
- data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +14 -0
- data/lib/rubocop/cop/lint/shared_mutable_default.rb +3 -1
- data/lib/rubocop/cop/lint/struct_new_override.rb +17 -1
- data/lib/rubocop/cop/lint/super_argument_mismatch.rb +179 -0
- data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +13 -2
- data/lib/rubocop/cop/lint/symbol_conversion.rb +22 -4
- data/lib/rubocop/cop/lint/syntax.rb +25 -1
- data/lib/rubocop/cop/lint/to_enum_arguments.rb +72 -4
- data/lib/rubocop/cop/lint/to_json.rb +20 -17
- data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +1 -1
- data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +5 -1
- data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +54 -11
- data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -0
- data/lib/rubocop/cop/lint/unreachable_code.rb +15 -9
- data/lib/rubocop/cop/lint/unreachable_pattern_branch.rb +113 -0
- data/lib/rubocop/cop/lint/unused_method_argument.rb +10 -0
- data/lib/rubocop/cop/lint/unused_private_method.rb +234 -0
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +1 -2
- data/lib/rubocop/cop/lint/useless_assignment.rb +61 -27
- data/lib/rubocop/cop/lint/useless_constant_scoping.rb +40 -4
- data/lib/rubocop/cop/lint/useless_default_value_argument.rb +2 -0
- data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
- data/lib/rubocop/cop/lint/useless_numeric_operation.rb +10 -10
- data/lib/rubocop/cop/lint/useless_or.rb +15 -2
- data/lib/rubocop/cop/lint/useless_rescue.rb +1 -2
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +10 -4
- data/lib/rubocop/cop/lint/useless_setter_call.rb +11 -5
- data/lib/rubocop/cop/lint/useless_times.rb +22 -1
- data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +94 -14
- data/lib/rubocop/cop/lint/void.rb +59 -22
- data/lib/rubocop/cop/lint.rb +179 -0
- data/lib/rubocop/cop/metrics/block_length.rb +1 -1
- data/lib/rubocop/cop/metrics/block_nesting.rb +23 -0
- data/lib/rubocop/cop/metrics/class_length.rb +4 -2
- data/lib/rubocop/cop/metrics/collection_literal_length.rb +1 -1
- data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +0 -4
- data/lib/rubocop/cop/metrics/method_length.rb +2 -2
- data/lib/rubocop/cop/metrics/module_length.rb +4 -2
- data/lib/rubocop/cop/metrics/perceived_complexity.rb +37 -7
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -3
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/iterating_block.rb +1 -1
- data/lib/rubocop/cop/metrics.rb +31 -0
- data/lib/rubocop/cop/migration/department_name.rb +11 -5
- data/lib/rubocop/cop/migration.rb +13 -0
- data/lib/rubocop/cop/mixin/alignment.rb +5 -1
- data/lib/rubocop/cop/mixin/allowed_methods.rb +5 -5
- data/lib/rubocop/cop/mixin/allowed_pattern.rb +5 -1
- data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +47 -25
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +12 -8
- data/lib/rubocop/cop/mixin/code_length.rb +10 -2
- data/lib/rubocop/cop/mixin/comments_help.rb +1 -2
- data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +1 -2
- data/lib/rubocop/cop/mixin/configurable_max.rb +6 -5
- data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +12 -1
- data/lib/rubocop/cop/mixin/endless_method_body_help.rb +105 -0
- data/lib/rubocop/cop/mixin/endless_method_rewriter.rb +13 -5
- data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +2 -2
- data/lib/rubocop/cop/mixin/forbidden_pattern.rb +5 -1
- data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +58 -12
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +37 -10
- data/lib/rubocop/cop/mixin/hash_subset.rb +9 -2
- data/lib/rubocop/cop/mixin/hash_transform_method/autocorrection.rb +63 -0
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +14 -60
- data/lib/rubocop/cop/mixin/indexed_method_arity.rb +94 -0
- data/lib/rubocop/cop/mixin/line_length_help.rb +28 -3
- data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
- data/lib/rubocop/cop/mixin/min_branches_count.rb +3 -1
- data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +11 -1
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
- data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +10 -1
- data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
- data/lib/rubocop/cop/mixin/pattern_matching_help.rb +35 -0
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +79 -8
- data/lib/rubocop/cop/mixin/project_index_help.rb +203 -0
- data/lib/rubocop/cop/mixin/range_help.rb +1 -2
- data/lib/rubocop/cop/mixin/reparsed_equivalence.rb +181 -0
- data/lib/rubocop/cop/mixin/space_after_punctuation.rb +5 -4
- data/lib/rubocop/cop/mixin/statement_modifier.rb +69 -12
- data/lib/rubocop/cop/mixin/trailing_comma.rb +7 -6
- data/lib/rubocop/cop/mixin/visibility_help.rb +2 -1
- data/lib/rubocop/cop/mixin.rb +93 -0
- data/lib/rubocop/cop/naming/accessor_method_name.rb +8 -0
- data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +17 -1
- data/lib/rubocop/cop/naming/block_forwarding.rb +4 -1
- data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
- data/lib/rubocop/cop/naming/file_name.rb +4 -3
- data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +9 -2
- data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +5 -3
- data/lib/rubocop/cop/naming/inclusive_language.rb +8 -2
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +12 -5
- data/lib/rubocop/cop/naming/method_name.rb +6 -3
- data/lib/rubocop/cop/naming/predicate_method.rb +13 -2
- data/lib/rubocop/cop/naming/predicate_prefix.rb +30 -17
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +12 -7
- data/lib/rubocop/cop/naming/variable_number.rb +3 -1
- data/lib/rubocop/cop/naming.rb +31 -0
- data/lib/rubocop/cop/offense.rb +108 -9
- data/lib/rubocop/cop/registry.rb +232 -66
- data/lib/rubocop/cop/security/eval.rb +15 -2
- data/lib/rubocop/cop/security/io_methods.rb +2 -2
- data/lib/rubocop/cop/security/json_load.rb +16 -4
- data/lib/rubocop/cop/security/marshal_load.rb +1 -1
- data/lib/rubocop/cop/security.rb +19 -0
- data/lib/rubocop/cop/severity.rb +12 -0
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +55 -8
- data/lib/rubocop/cop/style/accessor_grouping.rb +16 -5
- data/lib/rubocop/cop/style/alias.rb +33 -8
- data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +4 -3
- data/lib/rubocop/cop/style/and_or.rb +8 -3
- data/lib/rubocop/cop/style/arguments_forwarding.rb +61 -17
- data/lib/rubocop/cop/style/array_first_last.rb +13 -3
- data/lib/rubocop/cop/style/array_intersect.rb +28 -5
- data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +3 -0
- data/lib/rubocop/cop/style/array_join.rb +4 -2
- data/lib/rubocop/cop/style/ascii_comments.rb +6 -3
- data/lib/rubocop/cop/style/attr.rb +8 -6
- data/lib/rubocop/cop/style/bare_percent_literals.rb +4 -3
- data/lib/rubocop/cop/style/begin_block.rb +3 -1
- data/lib/rubocop/cop/style/bitwise_predicate.rb +7 -6
- data/lib/rubocop/cop/style/block_delimiters.rb +74 -38
- data/lib/rubocop/cop/style/case_equality.rb +29 -15
- data/lib/rubocop/cop/style/case_like_if.rb +11 -10
- data/lib/rubocop/cop/style/character_literal.rb +2 -2
- data/lib/rubocop/cop/style/class_and_module_children.rb +151 -35
- data/lib/rubocop/cop/style/class_equality_comparison.rb +21 -13
- data/lib/rubocop/cop/style/class_methods_definitions.rb +26 -5
- data/lib/rubocop/cop/style/collection_compact.rb +37 -17
- data/lib/rubocop/cop/style/collection_querying.rb +79 -46
- data/lib/rubocop/cop/style/colon_method_call.rb +16 -7
- data/lib/rubocop/cop/style/combinable_loops.rb +91 -9
- data/lib/rubocop/cop/style/comparable_clamp.rb +12 -1
- data/lib/rubocop/cop/style/concat_array_literals.rb +65 -9
- data/lib/rubocop/cop/style/conditional_assignment.rb +34 -18
- data/lib/rubocop/cop/style/constant_visibility.rb +13 -7
- data/lib/rubocop/cop/style/copyright.rb +27 -12
- data/lib/rubocop/cop/style/data_inheritance.rb +18 -0
- data/lib/rubocop/cop/style/date_time.rb +4 -4
- data/lib/rubocop/cop/style/def_with_parentheses.rb +6 -2
- data/lib/rubocop/cop/style/dig_chain.rb +5 -0
- data/lib/rubocop/cop/style/dir_empty.rb +4 -0
- data/lib/rubocop/cop/style/directive_scope.rb +304 -0
- data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +184 -20
- data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +6 -1
- data/lib/rubocop/cop/style/documentation.rb +53 -6
- data/lib/rubocop/cop/style/documentation_method.rb +8 -12
- data/lib/rubocop/cop/style/double_negation.rb +11 -0
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
- data/lib/rubocop/cop/style/each_with_object.rb +2 -0
- data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
- data/lib/rubocop/cop/style/empty_case_condition.rb +13 -4
- data/lib/rubocop/cop/style/empty_class_definition.rb +126 -0
- data/lib/rubocop/cop/style/empty_heredoc.rb +4 -0
- data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
- data/lib/rubocop/cop/style/empty_literal.rb +8 -3
- data/lib/rubocop/cop/style/empty_method.rb +15 -9
- data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +74 -22
- data/lib/rubocop/cop/style/encoding.rb +7 -1
- data/lib/rubocop/cop/style/end_block.rb +3 -1
- data/lib/rubocop/cop/style/endless_method.rb +100 -21
- data/lib/rubocop/cop/style/env_home.rb +4 -0
- data/lib/rubocop/cop/style/even_odd.rb +11 -1
- data/lib/rubocop/cop/style/exact_regexp_match.rb +52 -8
- data/lib/rubocop/cop/style/explicit_block_argument.rb +50 -10
- data/lib/rubocop/cop/style/fetch_env_var.rb +1 -1
- data/lib/rubocop/cop/style/file_null.rb +6 -4
- data/lib/rubocop/cop/style/file_open.rb +84 -0
- data/lib/rubocop/cop/style/file_write.rb +21 -16
- data/lib/rubocop/cop/style/float_division.rb +28 -14
- data/lib/rubocop/cop/style/for.rb +60 -1
- data/lib/rubocop/cop/style/format_string.rb +44 -9
- data/lib/rubocop/cop/style/format_string_token.rb +50 -7
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +2 -1
- data/lib/rubocop/cop/style/global_vars.rb +5 -2
- data/lib/rubocop/cop/style/guard_clause.rb +57 -40
- data/lib/rubocop/cop/style/hash_as_last_array_item.rb +31 -9
- data/lib/rubocop/cop/style/hash_conversion.rb +39 -11
- data/lib/rubocop/cop/style/hash_each_methods.rb +1 -2
- data/lib/rubocop/cop/style/hash_lookup_method.rb +128 -0
- data/lib/rubocop/cop/style/hash_slice.rb +16 -0
- data/lib/rubocop/cop/style/hash_syntax.rb +19 -5
- data/lib/rubocop/cop/style/hash_transform_keys.rb +17 -7
- data/lib/rubocop/cop/style/hash_transform_values.rb +17 -7
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +38 -10
- data/lib/rubocop/cop/style/if_inside_else.rb +36 -8
- data/lib/rubocop/cop/style/if_unless_modifier.rb +80 -76
- data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +17 -14
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +4 -1
- data/lib/rubocop/cop/style/if_with_semicolon.rb +61 -8
- data/lib/rubocop/cop/style/inline_comment.rb +5 -2
- data/lib/rubocop/cop/style/inverse_methods.rb +24 -2
- data/lib/rubocop/cop/style/invertible_unless_condition.rb +25 -5
- data/lib/rubocop/cop/style/ip_addresses.rb +1 -2
- data/lib/rubocop/cop/style/it_block_parameter.rb +94 -4
- data/lib/rubocop/cop/style/keyword_arguments_merging.rb +4 -0
- data/lib/rubocop/cop/style/keyword_parameters_order.rb +10 -4
- data/lib/rubocop/cop/style/lambda.rb +45 -2
- data/lib/rubocop/cop/style/lambda_call.rb +24 -8
- data/lib/rubocop/cop/style/magic_comment_format.rb +4 -4
- data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +11 -0
- data/lib/rubocop/cop/style/map_into_array.rb +2 -3
- data/lib/rubocop/cop/style/map_join.rb +123 -0
- data/lib/rubocop/cop/style/map_to_hash.rb +1 -2
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +102 -20
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +15 -2
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +42 -6
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +36 -8
- data/lib/rubocop/cop/style/method_def_parentheses.rb +36 -8
- data/lib/rubocop/cop/style/min_max_comparison.rb +4 -1
- data/lib/rubocop/cop/style/missing_else.rb +7 -1
- data/lib/rubocop/cop/style/missing_respond_to_missing.rb +40 -7
- data/lib/rubocop/cop/style/mixin_grouping.rb +12 -3
- data/lib/rubocop/cop/style/mixin_usage.rb +1 -1
- data/lib/rubocop/cop/style/module_function.rb +4 -2
- data/lib/rubocop/cop/style/module_member_existence_check.rb +110 -0
- data/lib/rubocop/cop/style/multiline_if_modifier.rb +45 -5
- data/lib/rubocop/cop/style/multiline_if_then.rb +10 -4
- data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +7 -0
- data/lib/rubocop/cop/style/multiline_memoization.rb +7 -1
- data/lib/rubocop/cop/style/multiline_method_signature.rb +14 -13
- data/lib/rubocop/cop/style/multiline_ternary_operator.rb +7 -3
- data/lib/rubocop/cop/style/multiline_when_then.rb +7 -0
- data/lib/rubocop/cop/style/multiple_comparison.rb +33 -22
- data/lib/rubocop/cop/style/mutable_constant.rb +158 -14
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +3 -3
- data/lib/rubocop/cop/style/negative_array_index.rb +228 -0
- data/lib/rubocop/cop/style/nested_modifier.rb +36 -12
- data/lib/rubocop/cop/style/nested_ternary_operator.rb +26 -8
- data/lib/rubocop/cop/style/next.rb +24 -10
- data/lib/rubocop/cop/style/nil_comparison.rb +50 -12
- data/lib/rubocop/cop/style/nil_lambda.rb +9 -1
- data/lib/rubocop/cop/style/non_nil_check.rb +21 -11
- data/lib/rubocop/cop/style/not.rb +12 -3
- data/lib/rubocop/cop/style/numeric_literal_prefix.rb +11 -1
- data/lib/rubocop/cop/style/numeric_literals.rb +3 -2
- data/lib/rubocop/cop/style/numeric_predicate.rb +22 -6
- data/lib/rubocop/cop/style/one_class_per_file.rb +115 -0
- data/lib/rubocop/cop/style/one_line_conditional.rb +18 -6
- data/lib/rubocop/cop/style/open_struct_use.rb +1 -1
- data/lib/rubocop/cop/style/operator_method_call.rb +10 -2
- data/lib/rubocop/cop/style/option_hash.rb +1 -1
- data/lib/rubocop/cop/style/optional_arguments.rb +1 -0
- data/lib/rubocop/cop/style/parallel_assignment.rb +26 -7
- data/lib/rubocop/cop/style/parentheses_around_condition.rb +7 -2
- data/lib/rubocop/cop/style/partition_instead_of_double_select.rb +270 -0
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +18 -3
- data/lib/rubocop/cop/style/perl_backrefs.rb +5 -3
- data/lib/rubocop/cop/style/predicate_with_kind.rb +84 -0
- data/lib/rubocop/cop/style/preferred_hash_methods.rb +12 -12
- data/lib/rubocop/cop/style/proc.rb +3 -2
- data/lib/rubocop/cop/style/raise_args.rb +20 -10
- data/lib/rubocop/cop/style/reduce_to_hash.rb +216 -0
- data/lib/rubocop/cop/style/redundant_argument.rb +2 -0
- data/lib/rubocop/cop/style/redundant_array_constructor.rb +2 -2
- data/lib/rubocop/cop/style/redundant_assignment.rb +12 -2
- data/lib/rubocop/cop/style/redundant_begin.rb +25 -7
- data/lib/rubocop/cop/style/redundant_condition.rb +41 -23
- data/lib/rubocop/cop/style/redundant_constant_base.rb +42 -6
- data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +13 -1
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +17 -3
- data/lib/rubocop/cop/style/redundant_each.rb +4 -5
- data/lib/rubocop/cop/style/redundant_exception.rb +21 -3
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +10 -2
- data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +9 -0
- data/lib/rubocop/cop/style/redundant_filter_chain.rb +1 -1
- data/lib/rubocop/cop/style/redundant_format.rb +43 -7
- data/lib/rubocop/cop/style/redundant_freeze.rb +11 -3
- data/lib/rubocop/cop/style/redundant_heredoc_delimiter_quotes.rb +6 -1
- data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +49 -10
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +82 -115
- data/lib/rubocop/cop/style/redundant_min_max_by.rb +93 -0
- data/lib/rubocop/cop/style/redundant_parentheses.rb +105 -83
- data/lib/rubocop/cop/style/redundant_percent_q.rb +5 -3
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +13 -2
- data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +6 -5
- data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +27 -7
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +12 -4
- data/lib/rubocop/cop/style/redundant_return.rb +4 -3
- data/lib/rubocop/cop/style/redundant_self.rb +11 -2
- data/lib/rubocop/cop/style/redundant_self_assignment.rb +1 -2
- data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +27 -4
- data/lib/rubocop/cop/style/redundant_sort.rb +45 -11
- data/lib/rubocop/cop/style/redundant_string_escape.rb +1 -2
- data/lib/rubocop/cop/style/redundant_struct_keyword_init.rb +133 -0
- data/lib/rubocop/cop/style/regexp_literal.rb +106 -28
- data/lib/rubocop/cop/style/require_order.rb +25 -8
- data/lib/rubocop/cop/style/rescue_modifier.rb +15 -14
- data/lib/rubocop/cop/style/return_nil.rb +17 -2
- data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +11 -1
- data/lib/rubocop/cop/style/reverse_find.rb +51 -0
- data/lib/rubocop/cop/style/safe_navigation.rb +18 -9
- data/lib/rubocop/cop/style/sample.rb +19 -13
- data/lib/rubocop/cop/style/select_by_kind.rb +158 -0
- data/lib/rubocop/cop/style/select_by_range.rb +197 -0
- data/lib/rubocop/cop/style/select_by_regexp.rb +52 -23
- data/lib/rubocop/cop/style/self_assignment.rb +13 -16
- data/lib/rubocop/cop/style/semicolon.rb +39 -13
- data/lib/rubocop/cop/style/send_with_literal_method_name.rb +4 -0
- data/lib/rubocop/cop/style/single_line_block_params.rb +2 -2
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +19 -7
- data/lib/rubocop/cop/style/single_line_methods.rb +24 -5
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +25 -7
- data/lib/rubocop/cop/style/special_global_vars.rb +7 -2
- data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +31 -5
- data/lib/rubocop/cop/style/static_class.rb +21 -0
- data/lib/rubocop/cop/style/string_concatenation.rb +25 -6
- data/lib/rubocop/cop/style/string_hash_keys.rb +1 -0
- data/lib/rubocop/cop/style/struct_inheritance.rb +36 -1
- data/lib/rubocop/cop/style/super_arguments.rb +6 -4
- data/lib/rubocop/cop/style/symbol_proc.rb +32 -14
- data/lib/rubocop/cop/style/tally_method.rb +181 -0
- data/lib/rubocop/cop/style/ternary_parentheses.rb +34 -1
- data/lib/rubocop/cop/style/time_now.rb +41 -0
- data/lib/rubocop/cop/style/top_level_method_definition.rb +2 -2
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
- data/lib/rubocop/cop/style/trailing_method_end_statement.rb +1 -0
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +35 -32
- data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
- data/lib/rubocop/cop/style/unless_logical_operators.rb +3 -3
- data/lib/rubocop/cop/style/while_until_do.rb +7 -0
- data/lib/rubocop/cop/style/while_until_modifier.rb +16 -0
- data/lib/rubocop/cop/style/word_array.rb +1 -0
- data/lib/rubocop/cop/style/yoda_condition.rb +26 -12
- data/lib/rubocop/cop/style/yoda_expression.rb +11 -2
- data/lib/rubocop/cop/style/zero_length_predicate.rb +6 -3
- data/lib/rubocop/cop/style.rb +311 -0
- data/lib/rubocop/cop/team.rb +171 -48
- data/lib/rubocop/cop/util.rb +5 -8
- data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
- data/lib/rubocop/cop/variable_force/branch.rb +30 -6
- data/lib/rubocop/cop/variable_force/variable.rb +33 -9
- data/lib/rubocop/cops_documentation_generator.rb +27 -9
- data/lib/rubocop/directive_comment.rb +116 -7
- data/lib/rubocop/feature_loader.rb +0 -6
- data/lib/rubocop/file_patterns.rb +9 -1
- data/lib/rubocop/formatter/base_formatter.rb +22 -0
- data/lib/rubocop/formatter/clang_style_formatter.rb +5 -2
- data/lib/rubocop/formatter/disabled_config_formatter.rb +39 -10
- data/lib/rubocop/formatter/emacs_style_formatter.rb +3 -1
- data/lib/rubocop/formatter/formatter_set.rb +7 -2
- data/lib/rubocop/formatter/github_actions_formatter.rb +6 -5
- data/lib/rubocop/formatter/html_formatter.rb +2 -4
- data/lib/rubocop/formatter/json_formatter.rb +82 -7
- data/lib/rubocop/formatter/junit_formatter.rb +27 -10
- data/lib/rubocop/formatter/offense_count_formatter.rb +4 -3
- data/lib/rubocop/formatter/pacman_formatter.rb +3 -1
- data/lib/rubocop/formatter/sarif_formatter.rb +186 -0
- data/lib/rubocop/formatter/simple_text_formatter.rb +4 -5
- data/lib/rubocop/formatter/tap_formatter.rb +8 -3
- data/lib/rubocop/formatter/worst_offenders_formatter.rb +5 -4
- data/lib/rubocop/formatter.rb +23 -21
- data/lib/rubocop/lockfile.rb +18 -0
- data/lib/rubocop/lsp/diagnostic.rb +22 -42
- data/lib/rubocop/lsp/disable_comment_edits.rb +135 -0
- data/lib/rubocop/lsp/routes.rb +130 -83
- data/lib/rubocop/lsp/runtime.rb +64 -15
- data/lib/rubocop/lsp/server.rb +6 -2
- data/lib/rubocop/lsp/stdin_runner.rb +35 -2
- data/lib/rubocop/lsp.rb +5 -2
- data/lib/rubocop/magic_comment.rb +47 -0
- data/lib/rubocop/mcp/autocorrection_request.rb +52 -0
- data/lib/rubocop/mcp/explain_tool.rb +68 -0
- data/lib/rubocop/mcp/scope.rb +65 -0
- data/lib/rubocop/mcp/server.rb +307 -0
- data/lib/rubocop/mcp/source_files.rb +35 -0
- data/lib/rubocop/offense_limit.rb +30 -0
- data/lib/rubocop/options.rb +141 -13
- data/lib/rubocop/path_util.rb +16 -5
- data/lib/rubocop/pending_cops_reporter.rb +1 -6
- data/lib/rubocop/plugin/configuration_integrator.rb +13 -3
- data/lib/rubocop/plugin/loader.rb +2 -2
- data/lib/rubocop/project_index_loader.rb +82 -0
- data/lib/rubocop/rake_task.rb +2 -3
- data/lib/rubocop/remote_config.rb +18 -13
- data/lib/rubocop/result_cache.rb +102 -59
- data/lib/rubocop/rspec/cop_helper.rb +8 -0
- data/lib/rubocop/rspec/expect_offense.rb +2 -4
- data/lib/rubocop/rspec/shared_contexts.rb +53 -5
- data/lib/rubocop/rspec/support.rb +2 -1
- data/lib/rubocop/runner.rb +362 -106
- data/lib/rubocop/server/cache.rb +21 -40
- data/lib/rubocop/server/cli.rb +2 -4
- data/lib/rubocop/server/core.rb +8 -0
- data/lib/rubocop/server.rb +14 -0
- data/lib/rubocop/target_finder.rb +18 -8
- data/lib/rubocop/target_ruby.rb +42 -22
- data/lib/rubocop/todo_audit.rb +111 -0
- data/lib/rubocop/unified_diff.rb +257 -0
- data/lib/rubocop/util.rb +69 -0
- data/lib/rubocop/version.rb +23 -7
- data/lib/rubocop.rb +34 -701
- data/lib/ruby_lsp/rubocop/addon.rb +1 -2
- metadata +80 -14
- data/lib/rubocop/cop/style/double_cop_disable_directive.rb +0 -46
|
@@ -11,6 +11,8 @@ module RuboCop
|
|
|
11
11
|
KEYWORDS = {
|
|
12
12
|
encoding: '(?:en)?coding',
|
|
13
13
|
frozen_string_literal: 'frozen[_-]string[_-]literal',
|
|
14
|
+
rbs_inline: 'rbs_inline',
|
|
15
|
+
warn_indent: 'warn[_-]indent',
|
|
14
16
|
shareable_constant_value: 'shareable[_-]constant[_-]value',
|
|
15
17
|
typed: 'typed'
|
|
16
18
|
}.freeze
|
|
@@ -36,6 +38,8 @@ module RuboCop
|
|
|
36
38
|
def any?
|
|
37
39
|
frozen_string_literal_specified? ||
|
|
38
40
|
encoding_specified? ||
|
|
41
|
+
rbs_inline_specified? ||
|
|
42
|
+
warn_indent_specified? ||
|
|
39
43
|
shareable_constant_value_specified? ||
|
|
40
44
|
typed_specified?
|
|
41
45
|
end
|
|
@@ -60,6 +64,10 @@ module RuboCop
|
|
|
60
64
|
[true, false].include?(frozen_string_literal)
|
|
61
65
|
end
|
|
62
66
|
|
|
67
|
+
def valid_rbs_inline_value?
|
|
68
|
+
%w[enabled disabled].include?(extract_rbs_inline_value)
|
|
69
|
+
end
|
|
70
|
+
|
|
63
71
|
def valid_shareable_constant_value?
|
|
64
72
|
%w[none literal experimental_everything experimental_copy].include?(shareable_constant_value)
|
|
65
73
|
end
|
|
@@ -71,6 +79,13 @@ module RuboCop
|
|
|
71
79
|
specified?(frozen_string_literal)
|
|
72
80
|
end
|
|
73
81
|
|
|
82
|
+
# Was a warn_indent specified?
|
|
83
|
+
#
|
|
84
|
+
# @return [Boolean]
|
|
85
|
+
def warn_indent_specified?
|
|
86
|
+
specified?(warn_indent)
|
|
87
|
+
end
|
|
88
|
+
|
|
74
89
|
# Was a shareable_constant_value specified?
|
|
75
90
|
#
|
|
76
91
|
# @return [Boolean]
|
|
@@ -94,6 +109,13 @@ module RuboCop
|
|
|
94
109
|
end
|
|
95
110
|
end
|
|
96
111
|
|
|
112
|
+
# Expose the `warn_indent` value.
|
|
113
|
+
#
|
|
114
|
+
# @return [String] for warn_indent config
|
|
115
|
+
def warn_indent
|
|
116
|
+
extract_warn_indent
|
|
117
|
+
end
|
|
118
|
+
|
|
97
119
|
# Expose the `shareable_constant_value` value coerced to a boolean if possible.
|
|
98
120
|
#
|
|
99
121
|
# @return [String] for shareable_constant_value config
|
|
@@ -105,6 +127,10 @@ module RuboCop
|
|
|
105
127
|
specified?(encoding)
|
|
106
128
|
end
|
|
107
129
|
|
|
130
|
+
def rbs_inline_specified?
|
|
131
|
+
valid_rbs_inline_value?
|
|
132
|
+
end
|
|
133
|
+
|
|
108
134
|
# Was the Sorbet `typed` sigil specified?
|
|
109
135
|
#
|
|
110
136
|
# @return [Boolean]
|
|
@@ -203,6 +229,13 @@ module RuboCop
|
|
|
203
229
|
match(KEYWORDS[:frozen_string_literal])
|
|
204
230
|
end
|
|
205
231
|
|
|
232
|
+
# Emacs comments cannot specify RBS::inline behavior.
|
|
233
|
+
def extract_rbs_inline_value; end
|
|
234
|
+
|
|
235
|
+
def extract_warn_indent
|
|
236
|
+
match(KEYWORDS[:warn_indent])
|
|
237
|
+
end
|
|
238
|
+
|
|
206
239
|
def extract_shareable_constant_value
|
|
207
240
|
match(KEYWORDS[:shareable_constant_value])
|
|
208
241
|
end
|
|
@@ -242,6 +275,12 @@ module RuboCop
|
|
|
242
275
|
# Vim comments cannot specify frozen string literal behavior.
|
|
243
276
|
def frozen_string_literal; end
|
|
244
277
|
|
|
278
|
+
# Vim comments cannot specify RBS::inline behavior.
|
|
279
|
+
def extract_rbs_inline_value; end
|
|
280
|
+
|
|
281
|
+
# Vim comments cannot specify indentation warning behavior.
|
|
282
|
+
def warn_indent; end
|
|
283
|
+
|
|
245
284
|
# Vim comments cannot specify shareable constant values behavior.
|
|
246
285
|
def shareable_constant_value; end
|
|
247
286
|
|
|
@@ -296,6 +335,14 @@ module RuboCop
|
|
|
296
335
|
extract(/\A\s*#\s*#{KEYWORDS[:frozen_string_literal]}:\s*#{TOKEN}\s*\z/io)
|
|
297
336
|
end
|
|
298
337
|
|
|
338
|
+
def extract_rbs_inline_value
|
|
339
|
+
extract(/\A\s*#\s*#{KEYWORDS[:rbs_inline]}:\s*#{TOKEN}\s*\z/io)
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
def extract_warn_indent
|
|
343
|
+
extract(/\A\s*#\s*#{KEYWORDS[:warn_indent]}:\s*#{TOKEN}\s*\z/io)
|
|
344
|
+
end
|
|
345
|
+
|
|
299
346
|
def extract_shareable_constant_value
|
|
300
347
|
extract(/\A\s*#\s*#{KEYWORDS[:shareable_constant_value]}:\s*#{TOKEN}\s*\z/io)
|
|
301
348
|
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module MCP
|
|
5
|
+
# What an autocorrection request asks for, shared by every file it corrects.
|
|
6
|
+
# The keywords are the tool's arguments, so an unknown one is refused.
|
|
7
|
+
# @api private
|
|
8
|
+
class AutocorrectionRequest
|
|
9
|
+
PROPERTIES = {
|
|
10
|
+
safety: { type: 'boolean' },
|
|
11
|
+
contextual: { type: 'boolean' },
|
|
12
|
+
dry_run: { type: 'boolean' },
|
|
13
|
+
max_offenses_per_cop: { type: 'integer', minimum: 1 }
|
|
14
|
+
}.freeze
|
|
15
|
+
|
|
16
|
+
# The offenses left over come back after the files are written, so they're
|
|
17
|
+
# capped unless the agent asks otherwise: a result too big for the client
|
|
18
|
+
# would hide what was done.
|
|
19
|
+
DEFAULT_MAX_OFFENSES_PER_COP = 5
|
|
20
|
+
|
|
21
|
+
attr_reader :scope, :limit
|
|
22
|
+
|
|
23
|
+
def initialize(scope, safety: true, contextual: false, dry_run: false,
|
|
24
|
+
max_offenses_per_cop: DEFAULT_MAX_OFFENSES_PER_COP)
|
|
25
|
+
@scope = scope
|
|
26
|
+
@safety = safety
|
|
27
|
+
@contextual = contextual
|
|
28
|
+
@dry_run = dry_run
|
|
29
|
+
@limit = OffenseLimit.new(max_offenses_per_cop)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def dry_run?
|
|
33
|
+
@dry_run
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# The options `LSP::Runtime#format` takes to apply the corrections
|
|
37
|
+
# `safety` and `contextual` allow, from the cops the scope selects.
|
|
38
|
+
def format_options
|
|
39
|
+
command = @safety ? 'rubocop.formatAutocorrects' : 'rubocop.formatAutocorrectsAll'
|
|
40
|
+
{ command: command, options: runtime_options }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# The options the LSP runtime takes for each call the request makes.
|
|
44
|
+
# Cops with `AutoCorrect: contextual` hold back corrections that get in
|
|
45
|
+
# the way of code still being written, such as removing a variable that
|
|
46
|
+
# is about to be used, so an agent that is done editing has to ask for them.
|
|
47
|
+
def runtime_options
|
|
48
|
+
{ **@scope.cop_options, editing: !@contextual }
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module MCP
|
|
5
|
+
# The `rubocop_explain` tool: what cops do, as `--explain` prints it.
|
|
6
|
+
# @api private
|
|
7
|
+
class ExplainTool
|
|
8
|
+
include RuboCop::CLI::Command::CopNames
|
|
9
|
+
|
|
10
|
+
DESCRIPTION =
|
|
11
|
+
'Explain what cops do: the problem each one targets, bad and good examples, ' \
|
|
12
|
+
'its configuration as this project resolves it, and whether it autocorrects. ' \
|
|
13
|
+
'Takes cop names as offenses report them, such as `Style/StringLiterals`. ' \
|
|
14
|
+
'Pass the `path` of a file to see the configuration that applies to it.'
|
|
15
|
+
INPUT_SCHEMA = {
|
|
16
|
+
properties: {
|
|
17
|
+
cop_names: { type: 'array', items: { type: 'string' }, minItems: 1 },
|
|
18
|
+
path: { type: 'string' }
|
|
19
|
+
},
|
|
20
|
+
required: ['cop_names'],
|
|
21
|
+
additionalProperties: false
|
|
22
|
+
}.freeze
|
|
23
|
+
ANNOTATIONS = {
|
|
24
|
+
title: "RuboCop's cop explanation", destructive_hint: false, idempotent_hint: true,
|
|
25
|
+
open_world_hint: false, read_only_hint: true
|
|
26
|
+
}.freeze
|
|
27
|
+
|
|
28
|
+
def initialize(config_store)
|
|
29
|
+
@config_store = config_store
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# The tool's block does not run in this instance, so it reaches
|
|
33
|
+
# `explain` through a method object it closes over.
|
|
34
|
+
def to_tool
|
|
35
|
+
explain = method(:explain)
|
|
36
|
+
|
|
37
|
+
::MCP::Tool.define(
|
|
38
|
+
name: 'rubocop_explain',
|
|
39
|
+
description: DESCRIPTION,
|
|
40
|
+
input_schema: INPUT_SCHEMA,
|
|
41
|
+
annotations: ANNOTATIONS
|
|
42
|
+
) do |cop_names:, path: nil|
|
|
43
|
+
::MCP::Tool::Response.new([{ type: 'text', text: explain.call(cop_names, path) }])
|
|
44
|
+
rescue RuboCop::Error => e
|
|
45
|
+
::MCP::Tool::Response.new([{ type: 'text', text: e.message }], error: true)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
# Explains the cops it recognizes and then names the ones it does not, as
|
|
52
|
+
# `--explain` does, so a typo does not cost the explanations asked for
|
|
53
|
+
# alongside it. The configuration is loaded first, since that is what
|
|
54
|
+
# registers the cops of any plugins it names.
|
|
55
|
+
def explain(cop_names, path)
|
|
56
|
+
config = path ? @config_store.for_file(path) : @config_store.for_pwd
|
|
57
|
+
explanations = known_cop_classes(cop_names).map do |cop_class|
|
|
58
|
+
Cop::CopExplanation.new(cop_class, config).to_s
|
|
59
|
+
end
|
|
60
|
+
validate_cop_names!(cop_names)
|
|
61
|
+
|
|
62
|
+
explanations.join("\n\n")
|
|
63
|
+
rescue IncorrectCopNameError => e
|
|
64
|
+
raise RuboCop::Error, [*explanations, e.message].join("\n\n")
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module MCP
|
|
5
|
+
# What a request asks RuboCop to look at: which cops run, as `--only` and
|
|
6
|
+
# `--except` choose them, and, when checking files, whether to stick to the
|
|
7
|
+
# ones git says changed, as `--changed` does.
|
|
8
|
+
# @api private
|
|
9
|
+
class Scope
|
|
10
|
+
PROPERTIES = {
|
|
11
|
+
only: {
|
|
12
|
+
type: 'array', items: { type: 'string' },
|
|
13
|
+
description: 'Run only these cops or departments, ' \
|
|
14
|
+
'such as `Style/StringLiterals` or `Lint`.'
|
|
15
|
+
},
|
|
16
|
+
except: {
|
|
17
|
+
type: 'array', items: { type: 'string' },
|
|
18
|
+
description: 'Run every cop except these cops or departments.'
|
|
19
|
+
},
|
|
20
|
+
changed: {
|
|
21
|
+
type: %w[boolean string],
|
|
22
|
+
description: 'Check only the files git says changed: `true` for changes since the ' \
|
|
23
|
+
'last commit, or a revision to compare against, such as `main`.'
|
|
24
|
+
}
|
|
25
|
+
}.freeze
|
|
26
|
+
|
|
27
|
+
# An empty list would select no cops at all rather than leave the choice
|
|
28
|
+
# alone, so it counts as no list.
|
|
29
|
+
#
|
|
30
|
+
# @raise [RuboCop::Error] for a scope the command line would refuse
|
|
31
|
+
def initialize(inline:, only: nil, except: nil, changed: nil)
|
|
32
|
+
@only = only if only&.any?
|
|
33
|
+
@except = except if except&.any?
|
|
34
|
+
@changed = changed == true ? ChangedFiles::DEFAULT_REVISION : changed
|
|
35
|
+
validate(inline)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @return [Hash] the cop selection, among the options the LSP runtime takes
|
|
39
|
+
def cop_options
|
|
40
|
+
{ only: @only, except: @except }.compact
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def select_files(files)
|
|
44
|
+
@changed ? ChangedFiles.new(@changed).filter(files) : files
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
# Refuses what the command line refuses for the same options. Cop names
|
|
50
|
+
# are left to the runner, which checks them the way `--only` does: short
|
|
51
|
+
# names allowed, and only once the configuration naming a plugin's cops
|
|
52
|
+
# has been loaded.
|
|
53
|
+
def validate(inline)
|
|
54
|
+
raise Error, '`changed` only applies when checking files.' if inline && @changed
|
|
55
|
+
raise Error, '`changed` takes `true` or a git revision.' if @changed == ''
|
|
56
|
+
|
|
57
|
+
validator = OptionsValidator.new(cop_options)
|
|
58
|
+
if validator.only_includes_redundant_disable?
|
|
59
|
+
raise Error, 'Lint/RedundantCopDisableDirective cannot be used with `only`.'
|
|
60
|
+
end
|
|
61
|
+
raise Error, 'Syntax checking cannot be turned off.' if validator.except_syntax?
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
begin
|
|
4
|
+
require 'mcp'
|
|
5
|
+
|
|
6
|
+
required_mcp_version = '0.6.0'
|
|
7
|
+
|
|
8
|
+
if Gem::Version.new(required_mcp_version) > Gem::Version.new(MCP::VERSION)
|
|
9
|
+
# While `mcp` is not a runtime dependency, users may have an outdated version installed.
|
|
10
|
+
warn <<~MESSAGE
|
|
11
|
+
Error: `mcp` gem version #{MCP::VERSION} was loaded, but `rubocop --mcp` requires #{required_mcp_version}.
|
|
12
|
+
- If you're using Bundler and don't yet have `gem 'mcp'` as a dependency, add it now.
|
|
13
|
+
- If you're using Bundler and already have `gem 'mcp'` as a dependency, update it to the most recent version.
|
|
14
|
+
- If you don't use Bundler, run `gem update mcp`.
|
|
15
|
+
MESSAGE
|
|
16
|
+
exit!
|
|
17
|
+
end
|
|
18
|
+
rescue LoadError => e
|
|
19
|
+
raise unless e.path == 'mcp'
|
|
20
|
+
|
|
21
|
+
warn <<~MESSAGE
|
|
22
|
+
Error: Unable to load `mcp` gem. Add `gem 'mcp'` to your Gemfile, or run `gem install mcp`.
|
|
23
|
+
MESSAGE
|
|
24
|
+
|
|
25
|
+
exit!
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
require_relative '../lsp'
|
|
29
|
+
require_relative '../lsp/runtime'
|
|
30
|
+
require_relative 'autocorrection_request'
|
|
31
|
+
require_relative 'explain_tool'
|
|
32
|
+
require_relative 'scope'
|
|
33
|
+
require_relative 'source_files'
|
|
34
|
+
|
|
35
|
+
module RuboCop
|
|
36
|
+
module MCP
|
|
37
|
+
# RuboCop MCP Server.
|
|
38
|
+
# @api private
|
|
39
|
+
class Server
|
|
40
|
+
INSPECTION_DESCRIPTION =
|
|
41
|
+
'Inspect Ruby code for offenses. ' \
|
|
42
|
+
'Provide `source_code` to check inline code or `path` to check files. ' \
|
|
43
|
+
'Either way the result lists offenses per file, with a summary, and the ' \
|
|
44
|
+
'offenses use the `rubocop --format json` format, with 1-based lines. ' \
|
|
45
|
+
'`correctable` says whether `rubocop_autocorrection` fixes an offense, ' \
|
|
46
|
+
'and one whose `correction` is not `safe` needs `safety` set to false. ' \
|
|
47
|
+
'One with a `correction` that is not `correctable` is held back while code is ' \
|
|
48
|
+
'being written, and only fixed with `contextual` set to true. ' \
|
|
49
|
+
'`max_offenses_per_cop` caps what each cop reports, and the ' \
|
|
50
|
+
'summary\'s `unreported_offenses` counts what was left out. ' \
|
|
51
|
+
'A cop that crashes is listed in its file\'s `errors`; the rest still report.'
|
|
52
|
+
|
|
53
|
+
AUTOCORRECTION_DESCRIPTION =
|
|
54
|
+
'Autocorrect RuboCop offenses in Ruby code. ' \
|
|
55
|
+
'Provide `source_code` to correct inline code, which comes back corrected as ' \
|
|
56
|
+
'plain text, or `path` to correct files. ' \
|
|
57
|
+
'Set `safety` to false to include unsafe corrections, and `contextual` to true ' \
|
|
58
|
+
'to include the ones held back while code is being written, such as removing ' \
|
|
59
|
+
'an unused variable. ' \
|
|
60
|
+
'Set `dry_run` to true to preview: nothing is written, and each corrected file ' \
|
|
61
|
+
'comes with its `diff`. ' \
|
|
62
|
+
'For files, the result lists each file that was corrected or still has offenses, ' \
|
|
63
|
+
'with the offenses left in the `rubocop_inspection` format, located in the ' \
|
|
64
|
+
'corrected file. One whose `correction` is not `safe` needs `safety` set to false, ' \
|
|
65
|
+
'and one with a `correction` that is not `correctable` needs `contextual` set to ' \
|
|
66
|
+
'true. Each cop lists at most `max_offenses_per_cop` of them, 5 unless ' \
|
|
67
|
+
'set, and the summary\'s `unreported_offenses` counts the rest. ' \
|
|
68
|
+
'A cop that crashes is listed in its file\'s `errors`, and a file whose ' \
|
|
69
|
+
'corrections loop is left unchanged.'
|
|
70
|
+
|
|
71
|
+
def initialize(config_store)
|
|
72
|
+
@config_store = config_store
|
|
73
|
+
# An agent isn't an editor, so offenses are located and worded the way
|
|
74
|
+
# the command line does it. Only contextual corrections are held back.
|
|
75
|
+
@runtime = RuboCop::LSP::Runtime.new(@config_store, lsp_mode: false)
|
|
76
|
+
# One cop crashing on one file should not cost an agent everything else
|
|
77
|
+
# in the request, so cop errors are collected and reported per file.
|
|
78
|
+
@runtime.raise_cop_error = false
|
|
79
|
+
@options = {}
|
|
80
|
+
# Offenses are reported the way `--format json` reports them, so an agent
|
|
81
|
+
# sees the same 1-based locations and correction data either way.
|
|
82
|
+
@json_formatter = RuboCop::Formatter::JSONFormatter.new(nil)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def start
|
|
86
|
+
# No `protocol_version` is specified because draft feature by default can be used.
|
|
87
|
+
server = ::MCP::Server.new(
|
|
88
|
+
name: 'rubocop_mcp_server',
|
|
89
|
+
version: RuboCop::Version::STRING,
|
|
90
|
+
tools: [inspection_tool, autocorrection_tool, ExplainTool.new(@config_store).to_tool]
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
::MCP::Server::Transports::StdioTransport.new(server).open
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
private
|
|
97
|
+
|
|
98
|
+
def inspection_tool
|
|
99
|
+
build_tool(
|
|
100
|
+
name: 'rubocop_inspection',
|
|
101
|
+
description: INSPECTION_DESCRIPTION,
|
|
102
|
+
title: "RuboCop's inspection",
|
|
103
|
+
destructive_hint: false,
|
|
104
|
+
idempotent_hint: true,
|
|
105
|
+
read_only_hint: true,
|
|
106
|
+
properties: { max_offenses_per_cop: { type: 'integer', minimum: 1 } }
|
|
107
|
+
) do |scope:, path: nil, source_code: nil, max_offenses_per_cop: nil|
|
|
108
|
+
run_inspection(path, source_code, max_offenses_per_cop, scope)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def autocorrection_tool
|
|
113
|
+
build_tool(
|
|
114
|
+
name: 'rubocop_autocorrection',
|
|
115
|
+
description: AUTOCORRECTION_DESCRIPTION,
|
|
116
|
+
title: "RuboCop's autocorrection",
|
|
117
|
+
destructive_hint: true,
|
|
118
|
+
idempotent_hint: false,
|
|
119
|
+
read_only_hint: false,
|
|
120
|
+
properties: AutocorrectionRequest::PROPERTIES,
|
|
121
|
+
required: ['safety']
|
|
122
|
+
) do |scope:, path: nil, source_code: nil, **arguments|
|
|
123
|
+
run_autocorrection(path, source_code, AutocorrectionRequest.new(scope, **arguments))
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# A limit counts across the files of one request, so every request starts
|
|
128
|
+
# from zero.
|
|
129
|
+
def run_inspection(path, source_code, max_offenses_per_cop, scope)
|
|
130
|
+
limit = OffenseLimit.new(max_offenses_per_cop) if max_offenses_per_cop
|
|
131
|
+
result =
|
|
132
|
+
if source_code
|
|
133
|
+
file = path || 'example.rb'
|
|
134
|
+
build_result([file], [inspect_source(file, source_code, limit, scope)])
|
|
135
|
+
else
|
|
136
|
+
process_files(path, scope) { |file, src| inspect_source(file, src, limit, scope) }
|
|
137
|
+
end
|
|
138
|
+
result_json(result, limit)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def inspect_source(file, source, limit, scope)
|
|
142
|
+
options = { **scope.cop_options, editing: true }
|
|
143
|
+
offenses = @runtime.raw_offenses(file, source, options: options)
|
|
144
|
+
offense_entry(file, offenses, limit).merge(problems_of_last_run(file))
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# The offenses of a file the way `--format json` lists them, capped across
|
|
148
|
+
# the files of a request.
|
|
149
|
+
def offense_entry(file, offenses, limit)
|
|
150
|
+
offenses = limit.filter(offenses) if limit
|
|
151
|
+
@json_formatter.hash_for_file(file, offenses)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def run_autocorrection(path, source_code, request)
|
|
155
|
+
return correct_inline(path, source_code, request) if source_code
|
|
156
|
+
|
|
157
|
+
result = process_files(path, request.scope) do |file, source|
|
|
158
|
+
correct_file(file, source, request)
|
|
159
|
+
end
|
|
160
|
+
result[:summary][:corrected_file_count] = result[:files].count { |file| file[:corrected] }
|
|
161
|
+
result_json(result, request.limit)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# The agent never sees stderr, so the summary says what the limit left out.
|
|
165
|
+
def result_json(result, limit)
|
|
166
|
+
unreported = limit&.elided_per_cop
|
|
167
|
+
result[:summary][:unreported_offenses] = unreported if unreported&.any?
|
|
168
|
+
result.to_json
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Cops that keep undoing each other's corrections leave the file half
|
|
172
|
+
# corrected, so it is left alone and the loop is reported instead. A file
|
|
173
|
+
# with nothing to correct is left alone too, so its modification time
|
|
174
|
+
# doesn't tell editors and agents it changed. The offenses left over are
|
|
175
|
+
# the ones an agent has to fix itself, which saves it inspecting again.
|
|
176
|
+
def correct_file(file, source, request)
|
|
177
|
+
corrected = @runtime.format(file, source, **request.format_options)
|
|
178
|
+
problems = problems_of_last_run(file)
|
|
179
|
+
looped = @runtime.errors.any?(Runner::InfiniteCorrectionLoop)
|
|
180
|
+
changed = !looped && source != corrected
|
|
181
|
+
leftovers = leftover_offenses(file, source, corrected, changed, request)
|
|
182
|
+
entry = offense_entry(file, leftovers, request.limit)
|
|
183
|
+
diff = write_or_diff(file, entry[:path], source, corrected, request) if changed
|
|
184
|
+
|
|
185
|
+
{ path: entry[:path], corrected: changed, diff: diff, **entry, **problems }.compact
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# A dry run writes nothing and returns the diff a real run would have
|
|
189
|
+
# applied, line endings included.
|
|
190
|
+
def write_or_diff(file, path, source, corrected, request)
|
|
191
|
+
if request.dry_run?
|
|
192
|
+
UnifiedDiff.new(path, source, Util.emulate_write_read_cycle(corrected)).to_s
|
|
193
|
+
else
|
|
194
|
+
SourceFiles.write(file, corrected)
|
|
195
|
+
nil
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# What's left is in the file as written, or as a dry run would have
|
|
200
|
+
# written it, or as it was when its corrections loop. The runner checks
|
|
201
|
+
# corrected code with LF line endings, which writing turns into CRLF on
|
|
202
|
+
# Windows, so there the file is checked again as written.
|
|
203
|
+
def leftover_offenses(file, source, corrected, changed, request)
|
|
204
|
+
on_disk = changed ? Util.emulate_write_read_cycle(corrected) : source
|
|
205
|
+
return @runtime.uncorrected_offenses if on_disk == corrected
|
|
206
|
+
|
|
207
|
+
@runtime.raw_offenses(file, on_disk, options: request.runtime_options)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# Corrected inline code comes back as plain text with nowhere to mention
|
|
211
|
+
# a cop that crashed, so a crash fails the call instead of going unseen.
|
|
212
|
+
def correct_inline(path, source_code, request)
|
|
213
|
+
file = path || 'example.rb'
|
|
214
|
+
corrected = @runtime.format(file, source_code, **request.format_options)
|
|
215
|
+
errors = problems_of_last_run(file)[:errors]
|
|
216
|
+
raise RuboCop::Error, errors.join("\n") if errors
|
|
217
|
+
|
|
218
|
+
SourceFiles.write(path, corrected) if path && !request.dry_run?
|
|
219
|
+
corrected
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# Collapsed the way `--format json` collapses them, which also folds the
|
|
223
|
+
# repeats from each autocorrection pass a crashing cop fails on.
|
|
224
|
+
def problems_of_last_run(file)
|
|
225
|
+
errors, warnings = [@runtime.errors, @runtime.warnings].map do |problems|
|
|
226
|
+
problems.map { |problem| Rainbow::StringUtils.uncolor(problem.to_s) }
|
|
227
|
+
end
|
|
228
|
+
@json_formatter.hash_for_problems(file, errors, warnings)
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def process_files(path, scope)
|
|
232
|
+
target_finder = RuboCop::TargetFinder.new(@config_store, @options)
|
|
233
|
+
target_files = scope.select_files(
|
|
234
|
+
target_finder.find(path ? [path] : [], :only_recognized_file_types)
|
|
235
|
+
)
|
|
236
|
+
all_files = target_files.map do |file|
|
|
237
|
+
yield(file, SourceFiles.read(file, @config_store.for_file(file)))
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
build_result(target_files, all_files)
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# Inline code is reported as a single file, so an agent reads one shape
|
|
244
|
+
# whichever way it asked. Files with nothing to report are only counted.
|
|
245
|
+
def build_result(target_files, all_files)
|
|
246
|
+
files = all_files.reject { |f| nothing_to_report?(f) }
|
|
247
|
+
|
|
248
|
+
{ files: files, summary: build_summary(target_files, all_files) }
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
def nothing_to_report?(file)
|
|
252
|
+
file[:offenses].empty? && !file[:corrected] && !file[:errors] && !file[:warnings]
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# NOTE: It is useful for RuboCop's result summary to be shown in the LLM's responses
|
|
256
|
+
# during interactions, so the summary is returned in a form that is easy for the LLM
|
|
257
|
+
# to reason about. Since LLM execution is non-deterministic, it is also sensible to
|
|
258
|
+
# compute the summary deterministically at this stage.
|
|
259
|
+
def build_summary(target_files, files)
|
|
260
|
+
offense_count = files.sum { |f| f[:offenses].size }
|
|
261
|
+
{ target_file_count: target_files.count, offense_count: offense_count }
|
|
262
|
+
.merge(@json_formatter.problem_counts(files))
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# rubocop:disable-next Metrics/MethodLength, Metrics/ParameterLists
|
|
266
|
+
def build_tool(
|
|
267
|
+
name:, description:,
|
|
268
|
+
title:, destructive_hint:, idempotent_hint:, read_only_hint:, properties:, required: nil
|
|
269
|
+
)
|
|
270
|
+
::MCP::Tool.define(
|
|
271
|
+
name: name,
|
|
272
|
+
description: description,
|
|
273
|
+
input_schema: {
|
|
274
|
+
properties: {
|
|
275
|
+
path: { type: 'string' },
|
|
276
|
+
source_code: { type: 'string' }
|
|
277
|
+
}.merge(properties, Scope::PROPERTIES),
|
|
278
|
+
required: required,
|
|
279
|
+
# The gem checks arguments against the schema, so one the tool
|
|
280
|
+
# doesn't take is refused by name rather than failing the call.
|
|
281
|
+
additionalProperties: false
|
|
282
|
+
}.compact,
|
|
283
|
+
annotations: {
|
|
284
|
+
title: title,
|
|
285
|
+
destructive_hint: destructive_hint,
|
|
286
|
+
idempotent_hint: idempotent_hint,
|
|
287
|
+
open_world_hint: false,
|
|
288
|
+
read_only_hint: read_only_hint
|
|
289
|
+
}
|
|
290
|
+
) do |**arguments|
|
|
291
|
+
# Taking any keywords makes the gem pass a `server_context` as well.
|
|
292
|
+
# Each tool's own block names the arguments it accepts.
|
|
293
|
+
arguments.delete(:server_context)
|
|
294
|
+
selection = Scope::PROPERTIES.keys.to_h { |key| [key, arguments.delete(key)] }
|
|
295
|
+
scope = Scope.new(inline: !arguments[:source_code].nil?, **selection)
|
|
296
|
+
result = yield(**arguments, scope: scope)
|
|
297
|
+
|
|
298
|
+
::MCP::Tool::Response.new([{ type: 'text', text: result }])
|
|
299
|
+
rescue RuboCop::Error, IncorrectCopNameError => e
|
|
300
|
+
# The runner raises `IncorrectCopNameError` for a name in `only` or
|
|
301
|
+
# `except` that it does not know, with suggestions.
|
|
302
|
+
::MCP::Tool::Response.new([{ type: 'text', text: e.message }], error: true)
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module MCP
|
|
5
|
+
# Reads and writes the files the tools work on. A file that can't be read
|
|
6
|
+
# or written fails the request with an error the agent can act on.
|
|
7
|
+
# @api private
|
|
8
|
+
module SourceFiles
|
|
9
|
+
module_function
|
|
10
|
+
|
|
11
|
+
def read(file, config)
|
|
12
|
+
RuboCop::ProcessedSource.from_file(
|
|
13
|
+
file, config.target_ruby_version, parser_engine: config.parser_engine
|
|
14
|
+
).raw_source
|
|
15
|
+
rescue Errno::ENOENT
|
|
16
|
+
raise RuboCop::Error, "No such file or directory: #{file}"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Writing what a file already holds would only bump its modification time.
|
|
20
|
+
def write(file, content)
|
|
21
|
+
return if File.file?(file) && File.binread(file) == content.b
|
|
22
|
+
|
|
23
|
+
Util.replace_file_contents(file, content)
|
|
24
|
+
rescue Errno::EACCES
|
|
25
|
+
raise RuboCop::Error, "Permission denied: #{file}"
|
|
26
|
+
rescue Errno::EPERM
|
|
27
|
+
raise RuboCop::Error, "Operation not permitted: #{file}"
|
|
28
|
+
rescue Errno::ENOSPC
|
|
29
|
+
raise RuboCop::Error, "No space left on device: #{file}"
|
|
30
|
+
rescue Errno::EROFS
|
|
31
|
+
raise RuboCop::Error, "Read-only file system: #{file}"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
# Caps how many offenses each cop gets to report.
|
|
5
|
+
#
|
|
6
|
+
# Counted across a whole run rather than per file, since a cop that fires a
|
|
7
|
+
# handful of times in every file is exactly the one worth capping. Offenses
|
|
8
|
+
# have to be offered in a stable order (files in the order they are
|
|
9
|
+
# reported) for the same ones to survive every time.
|
|
10
|
+
# @api private
|
|
11
|
+
class OffenseLimit
|
|
12
|
+
attr_reader :max
|
|
13
|
+
|
|
14
|
+
def initialize(max)
|
|
15
|
+
@max = max
|
|
16
|
+
@offered = Hash.new(0)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# @return [Array<Cop::Offense>] the offenses still within their cop's limit
|
|
20
|
+
def filter(offenses)
|
|
21
|
+
offenses.select { |offense| (@offered[offense.cop_name] += 1) <= @max }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# @return [Hash{String => Integer}] how many offenses each cop had left out,
|
|
25
|
+
# sorted by cop name
|
|
26
|
+
def elided_per_cop
|
|
27
|
+
@offered.filter_map { |cop, count| [cop, count - @max] if count > @max }.sort.to_h
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|