rigortype 0.4.6 → 0.4.8
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 +4 -2
- data/data/core_overlay/bigdecimal.rbs +33 -0
- data/data/core_overlay/resolv.rbs +30 -0
- data/data/gem_overlay/activesupport/core_ext.rbs +45 -13
- data/data/gem_overlay/addressable/addressable.rbs +40 -0
- data/data/vendored_gem_sigs/bundler/bundler.rbs +1 -1
- data/data/vendored_gem_sigs/rubygems/rubygems_extras.rbs +4 -3
- data/docs/handbook/01-getting-started.md +6 -3
- data/docs/handbook/11-sig-gen.md +85 -3
- data/docs/handbook/appendix-phpstan.md +4 -4
- data/docs/install.md +20 -0
- data/docs/manual/01-installation.md +67 -26
- data/docs/manual/02-cli-reference.md +455 -113
- data/docs/manual/03-configuration.md +76 -5
- data/docs/manual/04-diagnostics.md +5 -4
- data/docs/manual/06-baseline.md +6 -4
- data/docs/manual/08-skills.md +11 -0
- data/docs/manual/09-editor-integration.md +21 -2
- data/docs/manual/10-mcp-server.md +38 -2
- data/docs/manual/12-caching.md +4 -3
- data/docs/manual/14-rails-quickstart.md +1 -1
- data/docs/manual/19-effect-labels.md +3 -4
- data/docs/manual/plugins/rigor-actionpack.md +32 -15
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +23 -1
- data/docs/manual/plugins/rigor-sorbet.md +17 -3
- data/lib/rigor/analysis/baseline.rb +24 -27
- data/lib/rigor/analysis/check_rules/always_raises_shield.rb +147 -0
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +5 -6
- data/lib/rigor/analysis/check_rules/call_facts.rb +58 -0
- data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/declaration_sourced_guard.rb +12 -4
- data/lib/rigor/analysis/check_rules/duplicate_hash_key_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/inferred_param_guard.rb +85 -13
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +16 -4
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +6 -1
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +5 -8
- data/lib/rigor/analysis/check_rules/plugin_api_surface.rb +195 -0
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +41 -12
- data/lib/rigor/analysis/check_rules/rbs_receiver_surface.rb +27 -1
- data/lib/rigor/analysis/check_rules/rebinding_block_callees.rb +3 -3
- data/lib/rigor/analysis/check_rules/replaced_singleton_defs.rb +96 -0
- data/lib/rigor/analysis/check_rules/return_in_ensure_collector.rb +1 -2
- data/lib/rigor/analysis/check_rules/rule_ids.rb +9 -2
- data/lib/rigor/analysis/check_rules/rule_walk.rb +9 -7
- data/lib/rigor/analysis/check_rules/shadowed_rescue_collector.rb +3 -4
- data/lib/rigor/analysis/check_rules/special_global_setters.rb +3 -3
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules.rb +720 -141
- data/lib/rigor/analysis/crash_signature.rb +45 -3
- data/lib/rigor/analysis/dependency_recorder.rb +237 -80
- data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +14 -3
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +1 -1
- data/lib/rigor/analysis/dependency_source_inference/index.rb +6 -8
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +4 -4
- data/lib/rigor/analysis/edit_replay.rb +93 -6
- data/lib/rigor/analysis/fact_store.rb +3 -3
- data/lib/rigor/analysis/incremental.rb +11 -1
- data/lib/rigor/analysis/incremental_run_slot/write_guard.rb +4 -3
- data/lib/rigor/analysis/incremental_run_slot.rb +2 -2
- data/lib/rigor/analysis/incremental_session.rb +306 -53
- data/lib/rigor/analysis/reachability/plugin_roots.rb +6 -3
- data/lib/rigor/analysis/rule_catalog.rb +39 -3
- data/lib/rigor/analysis/run_cache_key.rb +27 -3
- data/lib/rigor/analysis/run_disclosure_credit.rb +26 -6
- data/lib/rigor/analysis/run_stats.rb +2 -2
- data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +6 -2
- data/lib/rigor/analysis/runner/declaration_position.rb +8 -8
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +264 -112
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +4 -9
- data/lib/rigor/analysis/runner/pool_coordinator.rb +173 -328
- data/lib/rigor/analysis/runner/project_pre_passes.rb +4 -37
- data/lib/rigor/analysis/runner/run_level_facts.rb +304 -0
- data/lib/rigor/analysis/runner/run_snapshots.rb +44 -54
- data/lib/rigor/analysis/runner/worker_payload.rb +36 -0
- data/lib/rigor/analysis/runner.rb +298 -109
- data/lib/rigor/analysis/self_call_resolution_recorder.rb +62 -23
- data/lib/rigor/analysis/template_unit_positions.rb +2 -3
- data/lib/rigor/analysis/template_units.rb +9 -1
- data/lib/rigor/analysis/worker_session.rb +65 -71
- data/lib/rigor/bleeding_edge.rb +22 -10
- data/lib/rigor/builtins/imported_refinements.rb +6 -8
- data/lib/rigor/builtins/predefined_constant_refinements.rb +1 -1
- data/lib/rigor/builtins/regex_refinement.rb +4 -6
- data/lib/rigor/cache/descriptor.rb +6 -5
- data/lib/rigor/cache/file_digest.rb +39 -31
- data/lib/rigor/cache/incremental_snapshot.rb +95 -17
- data/lib/rigor/cache/rbs_cache_producer.rb +2 -2
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +1 -1
- data/lib/rigor/cache/rbs_class_type_param_names.rb +2 -2
- data/lib/rigor/cache/rbs_constant_table.rb +1 -1
- data/lib/rigor/cache/rbs_descriptor.rb +90 -4
- data/lib/rigor/cache/rbs_environment.rb +8 -1
- data/lib/rigor/cache/rbs_environment_marshal_patch.rb +2 -2
- data/lib/rigor/cache/rbs_known_class_names.rb +1 -1
- data/lib/rigor/cache/store.rb +11 -10
- data/lib/rigor/ci_detector.rb +1 -1
- data/lib/rigor/cli/annotate_command.rb +24 -19
- data/lib/rigor/cli/baseline_command.rb +160 -57
- data/lib/rigor/cli/catalogue.rb +256 -0
- data/lib/rigor/cli/check_command.rb +112 -104
- data/lib/rigor/cli/check_runner_factory.rb +2 -2
- data/lib/rigor/cli/command.rb +15 -1
- data/lib/rigor/cli/coverage_command.rb +21 -8
- data/lib/rigor/cli/coverage_mutation.rb +5 -7
- data/lib/rigor/cli/coverage_renderer.rb +2 -1
- data/lib/rigor/cli/coverage_scan.rb +3 -5
- data/lib/rigor/cli/diff_command.rb +25 -20
- data/lib/rigor/cli/docs_command.rb +1 -2
- data/lib/rigor/cli/doctor_command.rb +12 -12
- data/lib/rigor/cli/effects_command.rb +50 -40
- data/lib/rigor/cli/effects_diff_renderer.rb +18 -17
- data/lib/rigor/cli/effects_explain_renderer.rb +13 -12
- data/lib/rigor/cli/effects_renderer.rb +2 -1
- data/lib/rigor/cli/effects_snapshot_command.rb +26 -18
- data/lib/rigor/cli/explain_command.rb +18 -8
- data/lib/rigor/cli/fused_protection_renderer.rb +2 -1
- data/lib/rigor/cli/json_document.rb +41 -0
- data/lib/rigor/cli/lens_command.rb +29 -10
- data/lib/rigor/cli/lsp_command.rb +250 -23
- data/lib/rigor/cli/mcp_command.rb +12 -7
- data/lib/rigor/cli/mutation_fork_scan.rb +1 -1
- data/lib/rigor/cli/mutation_protection_renderer.rb +3 -2
- data/lib/rigor/cli/options.rb +40 -1
- data/lib/rigor/cli/plugin_command.rb +93 -46
- data/lib/rigor/cli/plugins_command.rb +17 -18
- data/lib/rigor/cli/plugins_renderer.rb +10 -6
- data/lib/rigor/cli/protection_fork_scan.rb +2 -2
- data/lib/rigor/cli/protection_renderer.rb +2 -1
- data/lib/rigor/cli/show_bleedingedge_command.rb +21 -15
- data/lib/rigor/cli/sig_gen_command.rb +92 -27
- data/lib/rigor/cli/skill_command.rb +32 -3
- data/lib/rigor/cli/skill_deep_probe.rb +1 -1
- data/lib/rigor/cli/skill_describe.rb +2 -1
- data/lib/rigor/cli/trace_command.rb +14 -9
- data/lib/rigor/cli/triage_command.rb +10 -11
- data/lib/rigor/cli/triage_renderer.rb +2 -1
- data/lib/rigor/cli/type_of_command.rb +16 -11
- data/lib/rigor/cli/type_of_project_scope.rb +1 -4
- data/lib/rigor/cli/type_of_renderer.rb +4 -1
- data/lib/rigor/cli/type_scan_command.rb +14 -9
- data/lib/rigor/cli/type_scan_renderer.rb +2 -1
- data/lib/rigor/cli/unused_command.rb +27 -17
- data/lib/rigor/cli/upgrade_command.rb +5 -0
- data/lib/rigor/cli.rb +214 -56
- data/lib/rigor/config_audit.rb +33 -19
- data/lib/rigor/configuration/severity_profile.rb +14 -5
- data/lib/rigor/configuration.rb +104 -35
- data/lib/rigor/effects/collector.rb +53 -21
- data/lib/rigor/effects/definition_context.rb +0 -2
- data/lib/rigor/effects/envelope.rb +1 -1
- data/lib/rigor/effects/framework_units.rb +1 -1
- data/lib/rigor/effects/mutation_classifier.rb +4 -7
- data/lib/rigor/effects/propagator.rb +1 -1
- data/lib/rigor/effects/registry.rb +2 -2
- data/lib/rigor/effects/snapshot.rb +1 -1
- data/lib/rigor/effects/taint_cause.rb +0 -2
- data/lib/rigor/effects/unit_scan.rb +9 -13
- data/lib/rigor/environment/bundle_sig_discovery.rb +64 -33
- data/lib/rigor/environment/class_registry.rb +3 -3
- data/lib/rigor/environment/constant_type_cache_holder.rb +5 -0
- data/lib/rigor/environment/core_root.rb +77 -0
- data/lib/rigor/environment/default_libraries.rb +18 -1
- data/lib/rigor/environment/deferred_signature_plan.rb +381 -0
- data/lib/rigor/environment/gated_signature_guard.rb +1 -1
- data/lib/rigor/environment/gated_signature_plan.rb +5 -2
- data/lib/rigor/environment/hkt_registry_holder.rb +6 -0
- data/lib/rigor/environment/lockfile_resolver.rb +28 -12
- data/lib/rigor/environment/member_consistency/comparator.rb +18 -1
- data/lib/rigor/environment/member_consistency.rb +56 -7
- data/lib/rigor/environment/missing_gem_constant_index.rb +3 -2
- data/lib/rigor/environment/project_path_gems.rb +124 -0
- data/lib/rigor/environment/rbs_collection_discovery.rb +123 -8
- data/lib/rigor/environment/rbs_coverage_report.rb +12 -11
- data/lib/rigor/environment/rbs_hierarchy.rb +12 -15
- data/lib/rigor/environment/rbs_loader.rb +772 -110
- data/lib/rigor/environment/reflection.rb +7 -7
- data/lib/rigor/environment/required_features.rb +0 -3
- data/lib/rigor/environment/ruby_library_roots.rb +1 -1
- data/lib/rigor/environment/vendored_signature_plan.rb +153 -0
- data/lib/rigor/environment.rb +169 -42
- data/lib/rigor/flow_contribution/merger.rb +4 -4
- data/lib/rigor/inference/acceptance.rb +136 -40
- data/lib/rigor/inference/alias_mutation_floor/foreign_locals.rb +117 -0
- data/lib/rigor/inference/alias_mutation_floor/memos.rb +85 -0
- data/lib/rigor/inference/alias_mutation_floor/reach.rb +119 -0
- data/lib/rigor/inference/alias_mutation_floor/site_collector.rb +252 -0
- data/lib/rigor/inference/alias_mutation_floor.rb +339 -0
- data/lib/rigor/inference/anonymous_meta_class.rb +18 -0
- data/lib/rigor/inference/block_auto_splat.rb +1 -1
- data/lib/rigor/inference/block_parameter_binder.rb +2 -3
- data/lib/rigor/inference/block_run_count.rb +185 -0
- data/lib/rigor/inference/budget_trace.rb +8 -2
- data/lib/rigor/inference/builtins/array_catalog.rb +2 -2
- data/lib/rigor/inference/builtins/exception_catalog.rb +2 -2
- data/lib/rigor/inference/builtins/numeric_catalog.rb +2 -5
- data/lib/rigor/inference/builtins/random_catalog.rb +2 -2
- data/lib/rigor/inference/callee_mutation_chain.rb +88 -77
- data/lib/rigor/inference/callee_write_census.rb +815 -0
- data/lib/rigor/inference/captured_locals.rb +2 -0
- data/lib/rigor/inference/census_foreign_block.rb +354 -0
- data/lib/rigor/inference/clause_widening.rb +1 -1
- data/lib/rigor/inference/closure_escape_analyzer.rb +11 -4
- data/lib/rigor/inference/construction_escape.rb +258 -0
- data/lib/rigor/inference/declaration_walk/traversal.rb +1 -1
- data/lib/rigor/inference/declaration_walk.rb +4 -0
- data/lib/rigor/inference/deep_erasure.rb +39 -7
- data/lib/rigor/inference/def_handle.rb +1 -1
- data/lib/rigor/inference/def_node_resolver.rb +33 -15
- data/lib/rigor/inference/def_return_typer.rb +47 -5
- data/lib/rigor/inference/definer_resolution.rb +19 -9
- data/lib/rigor/inference/definers_index.rb +162 -0
- data/lib/rigor/inference/direct_ivar_writes.rb +300 -0
- data/lib/rigor/inference/element_read_widening.rb +49 -3
- data/lib/rigor/inference/error_info.rb +16 -0
- data/lib/rigor/inference/expression_typer.rb +1559 -320
- data/lib/rigor/inference/external_ancestor_resolution.rb +3 -4
- data/lib/rigor/inference/flow_tracer.rb +31 -14
- data/lib/rigor/inference/fork_map.rb +3 -0
- data/lib/rigor/inference/fresh_frame_blocks.rb +52 -1
- data/lib/rigor/inference/global_write_census.rb +81 -5
- data/lib/rigor/inference/global_writer_reach.rb +260 -0
- data/lib/rigor/inference/hkt_body.rb +1 -2
- data/lib/rigor/inference/hkt_body_parser.rb +3 -5
- data/lib/rigor/inference/hkt_reducer.rb +2 -2
- data/lib/rigor/inference/hkt_registry.rb +3 -5
- data/lib/rigor/inference/in_effect_refinements.rb +7 -0
- data/lib/rigor/inference/indexed_narrowing.rb +61 -15
- data/lib/rigor/inference/intervening_ivar_reset.rb +26 -4
- data/lib/rigor/inference/ivar_writer_census.rb +154 -8
- data/lib/rigor/inference/key_presence_guard.rb +51 -24
- data/lib/rigor/inference/last_line/self_evidence.rb +30 -0
- data/lib/rigor/inference/last_line.rb +5 -2
- data/lib/rigor/inference/loop_value_record.rb +66 -14
- data/lib/rigor/inference/match_rebinding/frame.rb +57 -0
- data/lib/rigor/inference/match_rebinding/yielding_match.rb +101 -0
- data/lib/rigor/inference/match_rebinding.rb +28 -5
- data/lib/rigor/inference/method_dispatcher/alias_strict_nominals.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/argument_distribution.rb +40 -0
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +44 -30
- data/lib/rigor/inference/method_dispatcher/class_keyed_block_params.rb +65 -0
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +3 -3
- data/lib/rigor/inference/method_dispatcher/contested_overloads.rb +89 -0
- data/lib/rigor/inference/method_dispatcher/core_enumerable_receiver.rb +44 -0
- data/lib/rigor/inference/method_dispatcher/declared_constructor.rb +151 -0
- data/lib/rigor/inference/method_dispatcher/facet_distribution.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/imprecise_argument.rb +2 -2
- data/lib/rigor/inference/method_dispatcher/interface_shape.rb +181 -0
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/no_match_fallback.rb +54 -0
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +51 -27
- data/lib/rigor/inference/method_dispatcher/random_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +606 -78
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +2 -2
- data/lib/rigor/inference/method_dispatcher/self_substitute.rb +3 -3
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +9 -7
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +467 -84
- data/lib/rigor/inference/method_dispatcher/singleton_folding.rb +0 -1
- data/lib/rigor/inference/method_dispatcher/singleton_mixin_dispatch.rb +50 -17
- data/lib/rigor/inference/method_dispatcher/singleton_type_params.rb +104 -0
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +5 -5
- data/lib/rigor/inference/method_dispatcher/struct_materialization.rb +4 -6
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher.rb +123 -25
- data/lib/rigor/inference/method_parameter_binder.rb +136 -56
- data/lib/rigor/inference/module_function_state/spellings.rb +2 -2
- data/lib/rigor/inference/module_function_state.rb +24 -3
- data/lib/rigor/inference/multi_target_binder.rb +2 -2
- data/lib/rigor/inference/mutation_rejoin.rb +240 -4
- data/lib/rigor/inference/mutation_widening.rb +199 -29
- data/lib/rigor/inference/narrowing.rb +238 -50
- data/lib/rigor/inference/operand_effects.rb +43 -2
- data/lib/rigor/inference/optimistic_origin.rb +134 -9
- data/lib/rigor/inference/origin_lookup.rb +1 -1
- data/lib/rigor/inference/out_buffer_mutation.rb +72 -0
- data/lib/rigor/inference/parameter_inference_collector.rb +5 -6
- data/lib/rigor/inference/pre_eval_constants.rb +1 -1
- data/lib/rigor/inference/precision_scanner.rb +1 -1
- data/lib/rigor/inference/project_method_ownership.rb +30 -9
- data/lib/rigor/inference/project_patched_methods.rb +65 -13
- data/lib/rigor/inference/project_patched_scanner.rb +120 -25
- data/lib/rigor/inference/project_patched_visibility.rb +39 -3
- data/lib/rigor/inference/project_yielder.rb +11 -17
- data/lib/rigor/inference/rbs_type_translator.rb +68 -15
- data/lib/rigor/inference/receiver_alias.rb +20 -0
- data/lib/rigor/inference/receiver_writer_call.rb +67 -0
- data/lib/rigor/inference/recursion_rebinding.rb +157 -0
- data/lib/rigor/inference/refined_dispatch/constructed_class.rb +57 -17
- data/lib/rigor/inference/refined_dispatch/own_method.rb +51 -16
- data/lib/rigor/inference/refined_dispatch.rb +13 -0
- data/lib/rigor/inference/reflective_ivar_write.rb +19 -11
- data/lib/rigor/inference/remover_holder_scan.rb +287 -0
- data/lib/rigor/inference/remover_narrowing.rb +224 -0
- data/lib/rigor/inference/rewrite_mutation.rb +53 -2
- data/lib/rigor/inference/scope_indexer/certainty.rb +0 -1
- data/lib/rigor/inference/scope_indexer/class_cvars_collector.rb +13 -6
- data/lib/rigor/inference/scope_indexer/constant_ivar_value.rb +93 -0
- data/lib/rigor/inference/scope_indexer/declared_param_writes.rb +70 -26
- data/lib/rigor/inference/scope_indexer/derived_param_value.rb +112 -0
- data/lib/rigor/inference/scope_indexer/empty_seed.rb +99 -0
- data/lib/rigor/inference/scope_indexer/ivar_contributions.rb +295 -0
- data/lib/rigor/inference/scope_indexer/mixin_accumulator.rb +136 -9
- data/lib/rigor/inference/scope_indexer.rb +2213 -226
- data/lib/rigor/inference/self_call_ivar_writes.rb +103 -12
- data/lib/rigor/inference/self_preserving_block.rb +87 -0
- data/lib/rigor/inference/set_mutation.rb +189 -0
- data/lib/rigor/inference/singleton_hook_decline.rb +42 -8
- data/lib/rigor/inference/singleton_object_constant.rb +32 -2
- data/lib/rigor/inference/statement_evaluator.rb +3268 -358
- data/lib/rigor/inference/string_mutation.rb +14 -0
- data/lib/rigor/inference/struct_fold_safety.rb +4 -6
- data/lib/rigor/inference/synthetic_method_scanner.rb +40 -17
- data/lib/rigor/inference/toplevel_def_census.rb +67 -0
- data/lib/rigor/inference/unknown_store_widening.rb +103 -4
- data/lib/rigor/inference/unthreaded_rebinds.rb +2 -3
- data/lib/rigor/inference/untyped_rejoin.rb +1 -1
- data/lib/rigor/inference/void_tail_summary.rb +29 -9
- data/lib/rigor/language_server/buffer_table.rb +3 -3
- data/lib/rigor/language_server/completion_provider.rb +26 -20
- data/lib/rigor/language_server/config_warning_announcer.rb +28 -0
- data/lib/rigor/language_server/diagnostic_publisher.rb +8 -3
- data/lib/rigor/language_server/document_symbol_provider.rb +1 -1
- data/lib/rigor/language_server/folding_range_provider.rb +1 -2
- data/lib/rigor/language_server/hover_provider.rb +1 -7
- data/lib/rigor/language_server/hover_renderer.rb +6 -8
- data/lib/rigor/language_server/project_context.rb +39 -1
- data/lib/rigor/language_server/publish_batcher.rb +3 -4
- data/lib/rigor/language_server/selection_range_provider.rb +2 -4
- data/lib/rigor/language_server/server.rb +7 -3
- data/lib/rigor/language_server/signature_help_provider.rb +4 -4
- data/lib/rigor/lens/claims/comparison.rb +78 -0
- data/lib/rigor/lens/claims/request.rb +131 -0
- data/lib/rigor/lens/claims/type_reader.rb +216 -0
- data/lib/rigor/lens/claims.rb +208 -0
- data/lib/rigor/lens/contract_reader.rb +5 -0
- data/lib/rigor/lens/document.rb +1 -1
- data/lib/rigor/lens/file_reader.rb +21 -8
- data/lib/rigor/lens/plugins.rb +1 -1
- data/lib/rigor/lens/run.rb +8 -0
- data/lib/rigor/lens.rb +1 -1
- data/lib/rigor/library_probe.rb +68 -0
- data/lib/rigor/mcp/server.rb +73 -2
- data/lib/rigor/mcp.rb +1 -1
- data/lib/rigor/memo_audit.rb +282 -0
- data/lib/rigor/plugin/access_denied_error.rb +1 -2
- data/lib/rigor/plugin/base.rb +15 -2
- data/lib/rigor/plugin/bundled_catalog.rb +1 -12
- data/lib/rigor/plugin/io_boundary.rb +26 -4
- data/lib/rigor/plugin/loader.rb +25 -8
- data/lib/rigor/plugin/macro/heredoc_template.rb +7 -8
- data/lib/rigor/plugin/macro/trait_registry.rb +6 -9
- data/lib/rigor/plugin/manifest.rb +16 -16
- data/lib/rigor/plugin/registry.rb +16 -5
- data/lib/rigor/plugin/services.rb +2 -3
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +11 -0
- data/lib/rigor/plugin/trust_policy.rb +48 -2
- data/lib/rigor/plugin/type_node_resolver.rb +2 -4
- data/lib/rigor/plugin.rb +6 -8
- data/lib/rigor/plugin_gap_advisory.rb +5 -1
- data/lib/rigor/project_environment.rb +16 -2
- data/lib/rigor/protection/analysis_guard.rb +1 -1
- data/lib/rigor/protection/discovery_seed.rb +44 -5
- data/lib/rigor/protection/mutation_cache.rb +4 -1
- data/lib/rigor/protection/mutator.rb +1 -1
- data/lib/rigor/rbs_extended/envelope_scanner.rb +4 -6
- data/lib/rigor/rbs_extended/hkt_directives.rb +6 -10
- data/lib/rigor/rbs_extended/reporter.rb +27 -3
- data/lib/rigor/rbs_extended.rb +2 -3
- data/lib/rigor/reflection/constant_ancestors.rb +81 -22
- data/lib/rigor/reflection/declaration_collectors.rb +55 -0
- data/lib/rigor/reflection/declarations.rb +58 -0
- data/lib/rigor/reflection/project_method.rb +177 -0
- data/lib/rigor/reflection.rb +2 -0
- data/lib/rigor/rooted_glob.rb +32 -1
- data/lib/rigor/run_scoped_slots.rb +38 -0
- data/lib/rigor/runtime/jit.rb +1 -1
- data/lib/rigor/scope/discovery_index.rb +168 -8
- data/lib/rigor/scope/resolution_chain/relevance.rb +14 -1
- data/lib/rigor/scope/resolution_chain.rb +901 -54
- data/lib/rigor/scope.rb +644 -37
- data/lib/rigor/sig_gen/bot_proposal_guard.rb +306 -0
- data/lib/rigor/sig_gen/classification.rb +18 -1
- data/lib/rigor/sig_gen/effect_annotation.rb +3 -3
- data/lib/rigor/sig_gen/generator.rb +588 -66
- data/lib/rigor/sig_gen/generic_header_scan.rb +189 -0
- data/lib/rigor/sig_gen/inline_declarations.rb +2 -2
- data/lib/rigor/sig_gen/layout_index.rb +3 -3
- data/lib/rigor/sig_gen/method_candidate.rb +37 -4
- data/lib/rigor/sig_gen/observation_collector.rb +14 -7
- data/lib/rigor/sig_gen/observed_call.rb +1 -1
- data/lib/rigor/sig_gen/path_mapper.rb +6 -0
- data/lib/rigor/sig_gen/platform_guarded_files.rb +184 -0
- data/lib/rigor/sig_gen/renderer.rb +15 -9
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +62 -2
- data/lib/rigor/sig_gen/type_name_qualification.rb +69 -0
- data/lib/rigor/sig_gen/write_reporter.rb +63 -14
- data/lib/rigor/sig_gen/write_result.rb +23 -12
- data/lib/rigor/sig_gen/writer.rb +238 -37
- data/lib/rigor/sig_gen.rb +1 -0
- data/lib/rigor/source/forwardable_delegators.rb +122 -0
- data/lib/rigor/source/node_children.rb +13 -0
- data/lib/rigor/type/acceptance_router.rb +2 -2
- data/lib/rigor/type/accepts_result.rb +1 -1
- data/lib/rigor/type/app.rb +4 -6
- data/lib/rigor/type/combinator.rb +173 -21
- data/lib/rigor/type/constant.rb +4 -5
- data/lib/rigor/type/hash_shape.rb +21 -40
- data/lib/rigor/type/interface.rb +60 -0
- data/lib/rigor/type/union.rb +1 -1
- data/lib/rigor/type.rb +1 -0
- data/lib/rigor/type_node/identifier.rb +1 -2
- data/lib/rigor/type_node/resolver_chain.rb +1 -1
- data/lib/rigor/type_node/string_literal.rb +1 -2
- data/lib/rigor/type_node/symbol_literal.rb +1 -2
- data/lib/rigor/type_node/union.rb +3 -6
- data/lib/rigor/type_of_memo/serving.rb +99 -0
- data/lib/rigor/type_of_memo/stats.rb +43 -0
- data/lib/rigor/type_of_memo.rb +337 -0
- data/lib/rigor/typing_state.rb +1094 -0
- data/lib/rigor/value_semantics.rb +1 -10
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +2 -2
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +2 -3
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +1 -1
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +38 -36
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +4 -2
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +6 -4
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +1 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +1 -5
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_scan.rb +0 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/erb_compiler.rb +2 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_assigns.rb +3 -3
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +115 -36
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers.rb +3 -6
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +25 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +16 -6
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +4 -2
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +4 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +2 -1
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/association_roots.rb +3 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/effects.rb +2 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +21 -31
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +10 -16
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +132 -33
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +20 -6
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/structure_sql_parser.rb +7 -4
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +54 -17
- data/plugins/rigor-activerecord/sig/active_record/relation.rbs +19 -5
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +3 -4
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_index.rb +1 -1
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +11 -14
- data/plugins/rigor-activestorage/lib/rigor-activestorage.rb +1 -1
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/effects.rb +1 -1
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/symbolize_keys.rb +102 -0
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +30 -9
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +55 -13
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_collector.rb +15 -21
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_discoverer.rb +1 -6
- data/plugins/rigor-alba/lib/rigor/plugin/alba/resource_index.rb +3 -3
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +1 -3
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +6 -6
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +5 -6
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +1 -1
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/params_shape.rb +2 -3
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +5 -8
- data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +1 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +10 -18
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/analyzer.rb +0 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/discoverer.rb +0 -2
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +8 -7
- data/plugins/rigor-grape/lib/rigor/plugin/grape.rb +0 -2
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +6 -7
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +12 -2
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami/action_checker.rb +2 -4
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +2 -5
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +8 -2
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +6 -6
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +2 -1
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +3 -8
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +2 -3
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +5 -8
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +200 -4
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +2 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +1 -1
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +4 -11
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +4 -3
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +2 -1
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +5 -5
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +2 -2
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +3 -4
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +6 -8
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +3 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +4 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +6 -7
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +210 -3
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +146 -7
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +2 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +52 -34
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +97 -24
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +2 -3
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_collector.rb +16 -16
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_discoverer.rb +4 -8
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_index.rb +4 -4
- data/sig/rigor/analysis/baseline.rbs +0 -3
- data/sig/rigor/analysis/check_rules/rule_walk.rbs +6 -0
- data/sig/rigor/analysis/fact_store.rbs +2 -2
- data/sig/rigor/analysis/reachability/scan_cache.rbs +1 -1
- data/sig/rigor/cache/descriptor.rbs +14 -0
- data/sig/rigor/cli/diff_command.rbs +1 -1
- data/sig/rigor/cli/explain_command.rbs +1 -1
- data/sig/rigor/effects/registry.rbs +2 -2
- data/sig/rigor/environment.rbs +4 -1
- data/sig/rigor/inference.rbs +4 -1
- data/sig/rigor/plugin/additional_initializer.rbs +0 -5
- data/sig/rigor/plugin/base.rbs +53 -18
- data/sig/rigor/plugin/effect_attribution.rbs +3 -3
- data/sig/rigor/plugin/effect_edge.rbs +1 -1
- data/sig/rigor/plugin/effect_entry_points.rbs +3 -3
- data/sig/rigor/plugin/interfaces.rbs +51 -0
- data/sig/rigor/plugin/io_boundary.rbs +3 -3
- data/sig/rigor/plugin/manifest.rbs +9 -9
- data/sig/rigor/plugin/node_context.rbs +21 -0
- data/sig/rigor/plugin/protocol_contract.rbs +3 -7
- data/sig/rigor/reflection.rbs +37 -0
- data/sig/rigor/scope.rbs +43 -4
- data/sig/rigor/trinary.rbs +1 -0
- data/sig/rigor/type.rbs +9 -3
- data/sig/rigor.rbs +3 -2
- data/skills/rigor-ask/SKILL.md +1 -0
- data/skills/rigor-plugin-author/SKILL.md +4 -4
- data/skills/rigor-plugin-author/references/02-walker-and-types.md +5 -5
- data/skills/rigor-plugin-review/SKILL.md +3 -3
- data/skills/rigor-project-init/references/01-detect.md +1 -0
- data/skills/rigor-project-init/references/03-baseline-and-bugs.md +17 -2
- data/skills/rigor-project-init/references/06-agent-contract.md +4 -4
- data/skills/rigor-rbs-contract/SKILL.md +147 -0
- data/skills/rigor-rbs-contract/references/01-finding-candidates.md +212 -0
- data/skills/rigor-rbs-contract/references/02-contract-rules.md +157 -0
- data/skills/rigor-rbs-contract/references/03-target-own-code.md +90 -0
- data/skills/rigor-rbs-contract/references/04-target-gem-rbs-collection.md +210 -0
- data/skills/rigor-rbs-contract/references/05-declaration-mutants.md +182 -0
- data/skills/rigor-rbs-setup/SKILL.md +3 -1
- data/skills/rigor-type-oracle/SKILL.md +26 -1
- data/skills/rigor-type-oracle/references/02-agents-md-fragment.md +4 -3
- metadata +82 -3
data/lib/rigor/cli.rb
CHANGED
|
@@ -10,6 +10,9 @@ require_relative "version"
|
|
|
10
10
|
require_relative "analysis/diagnostic"
|
|
11
11
|
require_relative "analysis/result"
|
|
12
12
|
require_relative "cli/options"
|
|
13
|
+
require "did_you_mean"
|
|
14
|
+
|
|
15
|
+
require_relative "cli/catalogue"
|
|
13
16
|
require_relative "cli/diagnostic_formats"
|
|
14
17
|
require_relative "ci_detector"
|
|
15
18
|
require_relative "analysis/check_rules/rule_ids"
|
|
@@ -30,8 +33,11 @@ module Rigor
|
|
|
30
33
|
# actionable": `SystemStackError` from an ancestry walk that never terminates, `NoMemoryError` from a
|
|
31
34
|
# runaway allocation. Neither is a `StandardError`, so every rescue between here and the raise site
|
|
32
35
|
# declines them by design — the whole point of those rescues is to convert a per-file or per-plugin
|
|
33
|
-
# failure into a diagnostic
|
|
34
|
-
#
|
|
36
|
+
# failure into a diagnostic. Since #2455 the per-file phases (`Runner#analyze_file_body`, the worker session,
|
|
37
|
+
# the discovery loops) do contain a `SystemStackError` raised from Ruby code, as that file's own crash row;
|
|
38
|
+
# what still reaches here is one raised from C (`Prism.parse` of a source nested near Prism's cap, which has
|
|
39
|
+
# no backtrace and leaves no stack to recover on), one outside a per-file phase, and `NoMemoryError`. Left
|
|
40
|
+
# uncaught they abort with Ruby's own ~40-frame dump, which is non-zero (so a CI gate does catch it) but says
|
|
35
41
|
# neither that Rigor is at fault nor that the report on disk is empty. `Interrupt`, `SignalException`
|
|
36
42
|
# and `SystemExit` stay out: those are the user's answer, not a failure.
|
|
37
43
|
FATAL_ERRORS = [SystemStackError, NoMemoryError].freeze
|
|
@@ -46,6 +52,17 @@ module Rigor
|
|
|
46
52
|
# 2026-07-17 and nothing noticed. See `docs/internal-spec/config.md`.
|
|
47
53
|
CONFIG_SCHEMA_URL = "https://github.com/rigortype/rigor/raw/master/schemas/rigor-config.schema.json"
|
|
48
54
|
|
|
55
|
+
# The comment `rigor init` writes under `plugins: []` when Gemfile.lock names a gem a bundled plugin models. The
|
|
56
|
+
# plugins are suggested, not enabled: ADR-96 Criterion 2 keeps a lockfile's presence from opting a project into a
|
|
57
|
+
# plugin's code, so the user uncomments the ones they want (#2536).
|
|
58
|
+
DETECTED_PLUGINS_HEADER = [
|
|
59
|
+
"# Detected from Gemfile.lock (suggested, not enabled). To load them, delete the `[]` above, uncomment the",
|
|
60
|
+
"# entries you want, then run `rigor plugins --strict`."
|
|
61
|
+
].freeze
|
|
62
|
+
|
|
63
|
+
# The file whose presence marks a Rails application for `rigor init`'s `paths:` suggestion (#2560).
|
|
64
|
+
RAILS_APPLICATION_FILE = "config/application.rb"
|
|
65
|
+
|
|
49
66
|
HANDLERS = {
|
|
50
67
|
"check" => :run_check,
|
|
51
68
|
"init" => :run_init,
|
|
@@ -79,6 +96,26 @@ module Rigor
|
|
|
79
96
|
new(argv.dup, out: out, err: err).run
|
|
80
97
|
end
|
|
81
98
|
|
|
99
|
+
# The parser `rigor init` parses with, built without parsing anything (the catalogue reads it, ADR-126 WD3).
|
|
100
|
+
def self.init_option_parser(options = {})
|
|
101
|
+
OptionParser.new do |opts|
|
|
102
|
+
opts.banner = "Usage: rigor init [options]"
|
|
103
|
+
opts.on("--force", "Overwrite an existing configuration file") { options[:force] = true }
|
|
104
|
+
opts.on("--path=PATH", "Configuration file path") { |value| options[:path] = value }
|
|
105
|
+
opts.on("--no-plugins", "Write no commented plugin suggestions from Gemfile.lock") do
|
|
106
|
+
options[:plugins] = false
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# The parser `rigor help` parses with, built without parsing anything (the catalogue reads it, ADR-126 WD3).
|
|
112
|
+
def self.help_option_parser(options = {})
|
|
113
|
+
OptionParser.new do |opts|
|
|
114
|
+
opts.banner = "Usage: rigor help [--format=text|json] [<command>]"
|
|
115
|
+
Options.add_format(opts, options, "Output format: text (default) or json")
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
82
119
|
def initialize(argv = ARGV.dup, out: $stdout, err: $stderr)
|
|
83
120
|
@argv = argv
|
|
84
121
|
@out = out
|
|
@@ -89,12 +126,14 @@ module Rigor
|
|
|
89
126
|
command = @argv.shift
|
|
90
127
|
|
|
91
128
|
case command
|
|
92
|
-
when nil, "
|
|
129
|
+
when nil, "-h", "--help"
|
|
93
130
|
@out.puts(help)
|
|
94
131
|
0
|
|
132
|
+
when "help"
|
|
133
|
+
run_help
|
|
95
134
|
when "version", "-v", "--version"
|
|
96
|
-
|
|
97
|
-
|
|
135
|
+
run_version
|
|
136
|
+
|
|
98
137
|
else
|
|
99
138
|
dispatch(command)
|
|
100
139
|
end
|
|
@@ -139,6 +178,8 @@ module Rigor
|
|
|
139
178
|
return arm_jit_deadline { send(handler) } if handler
|
|
140
179
|
|
|
141
180
|
@err.puts("Unknown command: #{command}")
|
|
181
|
+
nearest = ::DidYouMean::SpellChecker.new(dictionary: Catalogue.names).correct(command).first
|
|
182
|
+
@err.puts("Did you mean `rigor #{nearest}`?") if nearest
|
|
142
183
|
@err.puts(help)
|
|
143
184
|
EXIT_USAGE
|
|
144
185
|
end
|
|
@@ -156,6 +197,16 @@ module Rigor
|
|
|
156
197
|
yield
|
|
157
198
|
end
|
|
158
199
|
|
|
200
|
+
# `rigor version` and `-v`/`--version` print the version; `rigor version --help` prints the usage instead.
|
|
201
|
+
def run_version
|
|
202
|
+
if @argv.intersect?(%w[-h --help])
|
|
203
|
+
@out.puts("Usage: rigor version")
|
|
204
|
+
else
|
|
205
|
+
@out.puts("rigor #{Rigor::VERSION}")
|
|
206
|
+
end
|
|
207
|
+
0
|
|
208
|
+
end
|
|
209
|
+
|
|
159
210
|
def run_check
|
|
160
211
|
require_relative "cli/check_command"
|
|
161
212
|
|
|
@@ -168,15 +219,11 @@ module Rigor
|
|
|
168
219
|
# present; no implicit merge).
|
|
169
220
|
options = {
|
|
170
221
|
force: false,
|
|
171
|
-
path: ".rigor.dist.yml"
|
|
222
|
+
path: ".rigor.dist.yml",
|
|
223
|
+
plugins: true
|
|
172
224
|
}
|
|
173
225
|
|
|
174
|
-
|
|
175
|
-
opts.banner = "Usage: rigor init [options]"
|
|
176
|
-
opts.on("--force", "Overwrite an existing configuration file") { options[:force] = true }
|
|
177
|
-
opts.on("--path=PATH", "Configuration file path") { |value| options[:path] = value }
|
|
178
|
-
end
|
|
179
|
-
parser.parse!(@argv)
|
|
226
|
+
self.class.init_option_parser(options).parse!(@argv)
|
|
180
227
|
|
|
181
228
|
path = options.fetch(:path)
|
|
182
229
|
if File.exist?(path) && !options.fetch(:force)
|
|
@@ -184,24 +231,57 @@ module Rigor
|
|
|
184
231
|
return 1
|
|
185
232
|
end
|
|
186
233
|
|
|
187
|
-
|
|
234
|
+
plugins = options.fetch(:plugins) ? detected_plugins : []
|
|
235
|
+
paths_suggestion = detected_paths
|
|
236
|
+
begin
|
|
237
|
+
File.write(path, init_template(path, plugins: plugins, paths_suggestion: paths_suggestion))
|
|
238
|
+
rescue SystemCallError => e
|
|
239
|
+
# A destination whose directory is missing or not writable is a bad path argument, the same usage error
|
|
240
|
+
# `--config=PATH` gives for a file that does not exist (exit 64, docs/manual/02-cli-reference.md). The bare
|
|
241
|
+
# Errno::ENOENT backtrace read as an internal crash.
|
|
242
|
+
reason = e.message.sub(/ @ .*\z/m, "")
|
|
243
|
+
@err.puts("rigor init: cannot write #{path}: #{reason}")
|
|
244
|
+
return EXIT_USAGE
|
|
245
|
+
end
|
|
188
246
|
@out.puts("Created #{path}")
|
|
189
|
-
print_init_next_steps(path)
|
|
247
|
+
print_init_next_steps(path, plugins, paths_suggestion)
|
|
190
248
|
0
|
|
191
249
|
end
|
|
192
250
|
|
|
193
|
-
#
|
|
194
|
-
#
|
|
251
|
+
# The bundled plugins whose target gems the project's `Gemfile.lock` declares: the read `rigor doctor` makes,
|
|
252
|
+
# through {PluginGapAdvisory}, so the two cannot disagree about what the project depends on. Empty without a
|
|
253
|
+
# lockfile, which leaves the template as it was before detection existed. The advisory is required lazily:
|
|
254
|
+
# it loads every bundled plugin's entry file, a cost a plain `rigor init` in a directory with no lockfile never
|
|
255
|
+
# pays.
|
|
256
|
+
def detected_plugins
|
|
257
|
+
require_relative "plugin_gap_advisory"
|
|
258
|
+
|
|
259
|
+
PluginGapAdvisory.gaps(project_root: Dir.pwd, plugins: []).map(&:plugin_gem)
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# `rigor init`'s template lists the plugins Gemfile.lock detected, or ships empty `plugins:` so a fresh init has
|
|
263
|
+
# nothing to validate — but the moment the user adds any plugin entry, the activation-failure surfaces enumerated
|
|
264
|
+
# in `rigor plugins`'s docstring become real.
|
|
195
265
|
# Point them at the verification command + the canonical readiness flow so silent failures (the cwd / Gemfile /
|
|
196
266
|
# signature_paths mismatches that surfaced during the Mastodon trial) get caught the first time the user wires a
|
|
197
267
|
# plugin, not the first time `rigor check` reports false positives that should have been covered.
|
|
198
|
-
def print_init_next_steps(path)
|
|
268
|
+
def print_init_next_steps(path, plugins = [], paths_suggestion = nil)
|
|
199
269
|
@out.puts ""
|
|
200
270
|
@out.puts "Next steps:"
|
|
201
|
-
|
|
271
|
+
if plugins.empty?
|
|
272
|
+
@out.puts " 1. Edit #{path} — add the `plugins:` your project needs."
|
|
273
|
+
else
|
|
274
|
+
@out.puts " 1. Edit #{path} — to load a detected plugin, delete the `[]` on the `plugins:` line and"
|
|
275
|
+
@out.puts " uncomment the entries you want:"
|
|
276
|
+
plugins.each { |gem| @out.puts " #{gem}" }
|
|
277
|
+
end
|
|
202
278
|
@out.puts " 2. Run `rigor plugins` to verify every configured plugin loads."
|
|
203
279
|
@out.puts " (`--strict` exits 1 on failure; ideal CI gate.)"
|
|
204
280
|
@out.puts " 3. Run `rigor check` to analyse your code."
|
|
281
|
+
return if paths_suggestion.nil?
|
|
282
|
+
|
|
283
|
+
@out.puts " `rigor check` analyses only `lib` until you edit `paths:` in #{path}. " \
|
|
284
|
+
"The suggestion is commented beneath it."
|
|
205
285
|
end
|
|
206
286
|
|
|
207
287
|
# Word-wraps `CheckRules::ALL_RULES` into a comma-separated, `#`-commented block for `init_template`, so the
|
|
@@ -230,8 +310,9 @@ module Rigor
|
|
|
230
310
|
|
|
231
311
|
# Renders the starter `.rigor.yml` body. The template serialises `Configuration::DEFAULTS` (so the on-disk file
|
|
232
312
|
# round-trips through `Configuration.load`) and prepends a short header that points the user at the keys they are
|
|
233
|
-
# most likely to want to edit.
|
|
234
|
-
|
|
313
|
+
# most likely to want to edit. `plugins:` stays the empty list the defaults ship; detected gems appear beneath it as
|
|
314
|
+
# comments, so a project with no lockfile gets the template it always did.
|
|
315
|
+
def init_template(path = ".rigor.dist.yml", plugins: [], paths_suggestion: nil)
|
|
235
316
|
<<~YAML
|
|
236
317
|
# yaml-language-server: $schema=#{CONFIG_SCHEMA_URL}
|
|
237
318
|
# Rigor configuration. The full key reference is
|
|
@@ -287,10 +368,49 @@ module Rigor
|
|
|
287
368
|
# `target_ruby` is left commented: the default only picks the syntax Rigor parses. Set it to the lowest
|
|
288
369
|
# Ruby your project runs on, and Rigor also reports what that Ruby deprecates.
|
|
289
370
|
# target_ruby: #{Configuration::DEFAULTS.fetch('target_ruby').dump}
|
|
290
|
-
#{
|
|
371
|
+
#{settings_yaml(path, plugins, paths_suggestion)}
|
|
291
372
|
YAML
|
|
292
373
|
end
|
|
293
374
|
|
|
375
|
+
# The serialised settings. `plugins: []` stays valid YAML and schema-clean; when `Gemfile.lock` named a modelled
|
|
376
|
+
# gem, the suggestion block sits under it as comments, so nothing loads until the user uncomments a line. The
|
|
377
|
+
# `paths:` suggestion sits under the active `paths:` list the same way, and the active list stays `lib`.
|
|
378
|
+
def settings_yaml(path, plugins, paths_suggestion = nil)
|
|
379
|
+
yaml = YAML.dump(init_settings(path)).sub(/\A---\n/, "")
|
|
380
|
+
yaml = yaml.sub(/^plugins: \[\]\n/) { "plugins: []\n#{detected_plugins_block(plugins)}" } unless plugins.empty?
|
|
381
|
+
return yaml if paths_suggestion.nil?
|
|
382
|
+
|
|
383
|
+
yaml.sub(/^paths:\n(?:- .*\n)+/) { |active| active + paths_suggestion_block(paths_suggestion, path) }
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
# The commented `paths:` suggestion: one line naming what was detected and why, then the value to uncomment, written
|
|
387
|
+
# relative to the config file's directory like the active list (#1399).
|
|
388
|
+
def paths_suggestion_block(suggestion, path)
|
|
389
|
+
named = suggestion.fetch(:dirs).join(", ")
|
|
390
|
+
written = roots_relative_to(suggestion.fetch(:dirs), config_dir_of(path)).join(", ")
|
|
391
|
+
pronoun = suggestion.fetch(:dirs).one? ? "it" : "them"
|
|
392
|
+
"# #{suggestion.fetch(:reason)}: #{named}. To scan #{pronoun}, delete the `paths:` list above and " \
|
|
393
|
+
"uncomment the line below:\n# paths: [#{written}]\n"
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
# The source directories `rigor init` suggests for `paths:`, read from the project root (the cwd, like the plugin
|
|
397
|
+
# detection). A Rails application (config/application.rb) has app/ and lib/, each listed only if it exists. Any
|
|
398
|
+
# other layout gets no suggestion: the template's `lib` already covers it, and no other directory is guessed
|
|
399
|
+
# (#2560). Nil when there is nothing to add to today's `paths: [lib]`.
|
|
400
|
+
def detected_paths
|
|
401
|
+
return nil unless File.file?(RAILS_APPLICATION_FILE)
|
|
402
|
+
|
|
403
|
+
dirs = %w[app lib].select { |dir| File.directory?(dir) }
|
|
404
|
+
return nil if dirs.empty? || dirs == ["lib"]
|
|
405
|
+
|
|
406
|
+
{ dirs: dirs, reason: "Detected a Rails app (#{RAILS_APPLICATION_FILE})" }
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
def detected_plugins_block(plugins)
|
|
410
|
+
lines = DETECTED_PLUGINS_HEADER + plugins.map { |gem| "# - #{gem}" }
|
|
411
|
+
lines.map { |line| "#{line}\n" }.join
|
|
412
|
+
end
|
|
413
|
+
|
|
294
414
|
# The settings `rigor init` writes: the defaults, with `test_paths:` spelled out as the test roots found now, so
|
|
295
415
|
# the project's config says where its tests are rather than leaving it to auto-detection. The roots are written
|
|
296
416
|
# relative to the config file's directory, which is what {Configuration.load} resolves them against. `paths:`
|
|
@@ -320,7 +440,7 @@ module Rigor
|
|
|
320
440
|
|
|
321
441
|
# Each root is resolved against the physical cwd (where `rigor` reads it from), then written relative to the config
|
|
322
442
|
# dir. With the config at the project root, both sides are the same physical directory, so the roots come out as
|
|
323
|
-
# they are spelled from it (`lib`, `spec`)
|
|
443
|
+
# they are spelled from it (`lib`, `spec`).
|
|
324
444
|
def roots_relative_to(roots, config_dir)
|
|
325
445
|
roots.map { |root| Pathname(File.absolute_path(root)).relative_path_from(config_dir).to_s }
|
|
326
446
|
end
|
|
@@ -445,11 +565,18 @@ module Rigor
|
|
|
445
565
|
# Surfaced because a bare `rigor describe` is the intuitive guess (the onboarding field trial saw it tried and met
|
|
446
566
|
# "Unknown command").
|
|
447
567
|
def run_describe
|
|
568
|
+
return print_describe_usage if @argv.intersect?(%w[-h --help])
|
|
569
|
+
|
|
448
570
|
require_relative "cli/skill_command"
|
|
449
571
|
|
|
450
572
|
CLI::SkillCommand.new(argv: ["describe", *@argv], out: @out, err: @err).run
|
|
451
573
|
end
|
|
452
574
|
|
|
575
|
+
def print_describe_usage
|
|
576
|
+
@out.puts("Usage: rigor describe [--deep]")
|
|
577
|
+
0
|
|
578
|
+
end
|
|
579
|
+
|
|
453
580
|
def run_docs
|
|
454
581
|
require_relative "cli/docs_command"
|
|
455
582
|
|
|
@@ -480,41 +607,72 @@ module Rigor
|
|
|
480
607
|
CLI::UpgradeCommand.new(argv: @argv, out: @out, err: @err).run
|
|
481
608
|
end
|
|
482
609
|
|
|
610
|
+
# The text help is rendered from {Catalogue}, so the command list cannot drift from the dispatch table.
|
|
483
611
|
def help
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
612
|
+
Catalogue.help_text
|
|
613
|
+
end
|
|
614
|
+
|
|
615
|
+
# `rigor help [--format=text|json] [<command>]`. `help <command>` behaves as `rigor <command> --help`;
|
|
616
|
+
# `--format=json` prints the whole {Catalogue} document.
|
|
617
|
+
def run_help
|
|
618
|
+
return print_command_list if @argv.intersect?(%w[-h --help])
|
|
619
|
+
|
|
620
|
+
options = parse_help_options
|
|
621
|
+
topics = @argv
|
|
622
|
+
return run_help_json(topics) if options[:format] == "json"
|
|
623
|
+
|
|
624
|
+
topic = topics.first
|
|
625
|
+
return run_help_topic(topic, topics.drop(1)) if topic
|
|
626
|
+
|
|
627
|
+
print_command_list
|
|
628
|
+
end
|
|
629
|
+
|
|
630
|
+
def print_command_list
|
|
631
|
+
@out.puts(help)
|
|
632
|
+
0
|
|
633
|
+
end
|
|
634
|
+
|
|
635
|
+
def parse_help_options
|
|
636
|
+
options = Hash.new("text")
|
|
637
|
+
# `order!` stops at the first positional, so the flags of the command being asked about are never parsed here.
|
|
638
|
+
self.class.help_option_parser(options).order!(@argv)
|
|
639
|
+
options
|
|
640
|
+
end
|
|
641
|
+
|
|
642
|
+
def run_help_json(topics)
|
|
643
|
+
if topics.any?
|
|
644
|
+
@err.puts("rigor help --format=json takes no command; it prints every command")
|
|
645
|
+
return EXIT_USAGE
|
|
646
|
+
end
|
|
647
|
+
|
|
648
|
+
@out.puts(JSON.pretty_generate(Catalogue.document))
|
|
649
|
+
0
|
|
650
|
+
end
|
|
651
|
+
|
|
652
|
+
def run_help_topic(topic, rest)
|
|
653
|
+
# Flags after the command name (`help type-of --workers=2`) are not parsed; a second word is not a subcommand's
|
|
654
|
+
# help, so it is refused rather than answered with the parent's.
|
|
655
|
+
extra = rest.reject { |word| word.start_with?("-") }
|
|
656
|
+
unless extra.empty?
|
|
657
|
+
@err.puts("rigor help takes one command, got: #{[topic, *extra].join(' ')}")
|
|
658
|
+
return EXIT_USAGE
|
|
659
|
+
end
|
|
660
|
+
|
|
661
|
+
case topic
|
|
662
|
+
when "help"
|
|
663
|
+
@out.puts(self.class.help_option_parser.help)
|
|
664
|
+
0
|
|
665
|
+
when "version"
|
|
666
|
+
@out.puts("Usage: rigor version")
|
|
667
|
+
0
|
|
668
|
+
when *HANDLERS.keys
|
|
669
|
+
@argv = ["--help"]
|
|
670
|
+
dispatch(topic)
|
|
671
|
+
else
|
|
672
|
+
@err.puts("Unknown command: #{topic}")
|
|
673
|
+
@err.puts(help)
|
|
674
|
+
EXIT_USAGE
|
|
675
|
+
end
|
|
518
676
|
end
|
|
519
677
|
end
|
|
520
678
|
end
|
data/lib/rigor/config_audit.rb
CHANGED
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
require "did_you_mean"
|
|
4
4
|
|
|
5
5
|
require_relative "config_path"
|
|
6
|
+
require_relative "environment/bundle_sig_discovery"
|
|
7
|
+
require_relative "environment/rbs_collection_discovery"
|
|
6
8
|
require_relative "flow_contribution/conflict"
|
|
9
|
+
require_relative "library_probe"
|
|
7
10
|
require_relative "signature_path_audit"
|
|
8
11
|
# ADR-87 WD4 — only the pure rule-id table (`ALL_RULES` / `RULE_FAMILIES`) is needed, so require the light
|
|
9
12
|
# `rule_ids.rb` rather than the engine-pulling `check_rules.rb`; keeps `config_audit` (loaded by every check)
|
|
@@ -35,10 +38,10 @@ module Rigor
|
|
|
35
38
|
# (`rbs_extended.*`, `rbs.*`, `dynamic.*`) is left alone, since the engine emits those ids
|
|
36
39
|
# outside the catalogue.
|
|
37
40
|
module ConfigAudit
|
|
38
|
-
# One config-level finding. `kind` discriminates the source key (`:signature_path`,
|
|
41
|
+
# One config-level finding. `kind` discriminates the source key (`:unknown_key`, `:signature_path`,
|
|
39
42
|
# `:bundled_plugin_signature_path`, `:library`, `:disabled_rule`, `:severity_override`,
|
|
40
|
-
# `:bundler_bundle_path`, `:bundler_lockfile`, `:rbs_collection_lockfile`); `fields`
|
|
41
|
-
# structured data merged into {#to_h} for JSON consumers.
|
|
43
|
+
# `:bundler_bundle_path`, `:bundler_lockfile`, `:rbs_collection_lockfile`, `:rbs_collection_library`); `fields`
|
|
44
|
+
# carries the kind-specific structured data merged into {#to_h} for JSON consumers.
|
|
42
45
|
Warning = Data.define(:kind, :message, :fields) do
|
|
43
46
|
def to_h
|
|
44
47
|
{ "kind" => kind.to_s, "message" => message }.merge(fields)
|
|
@@ -51,7 +54,7 @@ module Rigor
|
|
|
51
54
|
unknown_key_warnings(configuration) +
|
|
52
55
|
signature_path_warnings(configuration) +
|
|
53
56
|
bundled_plugin_signature_path_warnings(configuration) +
|
|
54
|
-
library_warnings(configuration) +
|
|
57
|
+
library_warnings(configuration, project_root) +
|
|
55
58
|
rule_token_warnings(configuration) +
|
|
56
59
|
explicit_path_warnings(configuration, project_root)
|
|
57
60
|
end
|
|
@@ -129,21 +132,32 @@ module Rigor
|
|
|
129
132
|
end
|
|
130
133
|
end
|
|
131
134
|
|
|
132
|
-
# `libraries:` entries RBS does not recognise
|
|
133
|
-
# `
|
|
134
|
-
#
|
|
135
|
-
#
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
135
|
+
# `libraries:` entries RBS does not recognise, and — issue #2946 — `source: { type: stdlib }` entries of
|
|
136
|
+
# the run's `rbs_collection.lock.yaml`, which load as libraries too ({Environment::BaseLibraries.resolve}). Uses the
|
|
137
|
+
# same `RBS::EnvironmentLoader#has_library?` answer the loader filters through
|
|
138
|
+
# ({Environment::RbsLoader} `library_loader`), so a flagged name is one the loader skipped. A
|
|
139
|
+
# {Environment::RequiredFeatures::VENDORED_DIRS} name (`prime`) under `libraries:` is not audited: the
|
|
140
|
+
# configuration turns it into a vendored feature token the loader never asks `has_library?` about. A
|
|
141
|
+
# lockfile entry of that name is not a token, so it is still audited. The `rbs` CLI warns on the same
|
|
142
|
+
# lockfile entry (`Collection::Sources::Stdlib#manifest_of`).
|
|
143
|
+
# Fails soft: if RBS itself raises, no warning rather than a crash.
|
|
144
|
+
def self.library_warnings(configuration, project_root = Dir.pwd)
|
|
145
|
+
lock = { lockfile_path: configuration.rbs_collection_lockfile, project_root: project_root,
|
|
146
|
+
auto_detect: configuration.rbs_collection_auto_detect }
|
|
147
|
+
lockfile = Environment::RbsCollectionDiscovery.stdlib_library_names(**lock)
|
|
148
|
+
# Issue #2971 — a `libraries:` name the collection lockfile provides loads from the collection, not as an
|
|
149
|
+
# RBS library, so it is not an unknown library.
|
|
150
|
+
provided = Environment::RbsCollectionDiscovery.collection_gem_names(**lock)
|
|
151
|
+
named = (LibraryProbe.auditable(configuration.libraries) - provided).map { |lib| [:library, "libraries:", lib] } +
|
|
152
|
+
lockfile.map { |name| [:rbs_collection_library, "rbs_collection.lock.yaml: stdlib entry", name] }
|
|
153
|
+
return [] if named.empty?
|
|
154
|
+
|
|
155
|
+
unavailable = LibraryProbe.predicate.then { |has| named.reject { |_, _, lib| has.call(lib) } }
|
|
156
|
+
# Issue #2987 — nor is a name whose own `sig/` the bundle loaded; read only once a name is unavailable.
|
|
157
|
+
bundled = unavailable.empty? ? [] : Environment::BundleSigDiscovery.loaded_names(configuration, project_root)
|
|
158
|
+
unavailable.reject { |kind, _, lib| kind == :library && bundled.include?(lib) }.map do |kind, source, lib|
|
|
159
|
+
Warning.new(kind: kind, fields: { "name" => lib },
|
|
160
|
+
message: "#{source} #{lib.inspect} is not an available RBS library (no signatures loaded from it)")
|
|
147
161
|
end
|
|
148
162
|
rescue StandardError
|
|
149
163
|
[]
|
|
@@ -15,12 +15,12 @@ module Rigor
|
|
|
15
15
|
# rules `:warning`.
|
|
16
16
|
# - `strict`: Every rule is `:error`. CI-friendly.
|
|
17
17
|
#
|
|
18
|
-
# The
|
|
18
|
+
# The resolution order, first match wins:
|
|
19
19
|
#
|
|
20
|
-
# 1.
|
|
21
|
-
# 2.
|
|
22
|
-
# 3.
|
|
23
|
-
#
|
|
20
|
+
# 1. An explicit `severity_overrides:` entry for the row (`resolve`'s `overrides:`).
|
|
21
|
+
# 2. A bleeding-edge severity override.
|
|
22
|
+
# 3. The profile's entry for the canonical rule id.
|
|
23
|
+
# 4. The diagnostic's own authored severity (the rule's default); an unrecognised rule keeps it.
|
|
24
24
|
module SeverityProfile
|
|
25
25
|
VALID_PROFILES = %i[lenient balanced strict].freeze
|
|
26
26
|
VALID_SEVERITIES = %i[error warning info off].freeze
|
|
@@ -86,6 +86,7 @@ module Rigor
|
|
|
86
86
|
# a config edit the author may deliberately not want.
|
|
87
87
|
"effect.annotations-unchecked" => :info,
|
|
88
88
|
"static.value-use.void" => :off,
|
|
89
|
+
"plugin.api-surface" => :off,
|
|
89
90
|
# Opt-in author assertion: you only see it if you wrote a
|
|
90
91
|
# `conforms-to` directive, so it stays a :warning even in
|
|
91
92
|
# lenient — it is never unsolicited noise.
|
|
@@ -131,6 +132,7 @@ module Rigor
|
|
|
131
132
|
"suppression.empty" => :warning,
|
|
132
133
|
"suppression.unknown-marker" => :warning,
|
|
133
134
|
"static.value-use.void" => :off,
|
|
135
|
+
"plugin.api-surface" => :off,
|
|
134
136
|
"effect.envelope-exceeded" => :warning,
|
|
135
137
|
"effect.liskov-widened" => :warning,
|
|
136
138
|
"effect.unknown-label" => :info,
|
|
@@ -173,6 +175,7 @@ module Rigor
|
|
|
173
175
|
"suppression.unknown-marker" => :warning,
|
|
174
176
|
# `:off` even under strict: the gate is `bleeding_edge:`, not the profile (ADR-50 WD1 / ADR-100).
|
|
175
177
|
"static.value-use.void" => :off,
|
|
178
|
+
"plugin.api-surface" => :off,
|
|
176
179
|
"effect.envelope-exceeded" => :error,
|
|
177
180
|
"effect.liskov-widened" => :error,
|
|
178
181
|
"effect.unknown-label" => :warning,
|
|
@@ -234,11 +237,17 @@ module Rigor
|
|
|
234
237
|
|
|
235
238
|
private_class_method :row_override
|
|
236
239
|
|
|
240
|
+
# Rule ids a dot-free family key does not reach. `plugin.api-surface` is the one built-in id under `plugin.`,
|
|
241
|
+
# the prefix of plugin rows, so a `plugin` key must not turn the bleeding-edge rule on (#2822); `disable:
|
|
242
|
+
# [plugin]` does not reach it either. A key naming the id itself still does, in either direction.
|
|
243
|
+
FAMILY_FALLBACK_EXEMPT = ["plugin.api-surface"].freeze
|
|
244
|
+
|
|
237
245
|
# A family name has no `.` in it, so only a dot-free key can match one. `resolve` runs for every
|
|
238
246
|
# diagnostic in a run's stream, and most configurations carry no such key (usually no overrides at all),
|
|
239
247
|
# so the split below is skipped for them rather than allocating a name that nothing can match.
|
|
240
248
|
def family_override(rule, overrides)
|
|
241
249
|
return nil unless overrides.any? { |key, _| !key.to_s.include?(".") }
|
|
250
|
+
return nil if FAMILY_FALLBACK_EXEMPT.include?(rule)
|
|
242
251
|
|
|
243
252
|
family = rule.split(".").first
|
|
244
253
|
return nil if family.nil?
|