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
|
@@ -16,6 +16,7 @@ require_relative "../inference/statement_evaluator"
|
|
|
16
16
|
require_relative "prism_colorizer"
|
|
17
17
|
require_relative "command"
|
|
18
18
|
require_relative "../project_environment"
|
|
19
|
+
require_relative "json_document"
|
|
19
20
|
|
|
20
21
|
module Rigor
|
|
21
22
|
class CLI
|
|
@@ -32,10 +33,12 @@ module Rigor
|
|
|
32
33
|
class AnnotateCommand < Command
|
|
33
34
|
USAGE = "Usage: rigor annotate [options] FILE"
|
|
34
35
|
|
|
35
|
-
# Trailing `#=> …` annotation comment
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
#
|
|
36
|
+
# Trailing `#=> …` annotation comment, matched and stripped before re-annotating so re-running is idempotent.
|
|
37
|
+
# Follows xmpfilter's convention of owning the `#=>` marker, and also absorbs the older `#=> dump_type: <type>`
|
|
38
|
+
# spelling.
|
|
39
|
+
# Strips the first `#=>` that is preceded by whitespace and followed by whitespace or the end of the line,
|
|
40
|
+
# together with that preceding whitespace, through the end of the line. A string literal is not special-cased,
|
|
41
|
+
# since the pattern does not parse Ruby; `a#=>b` and `x #=>y` are left alone.
|
|
39
42
|
ANNOTATION_PATTERN = /\s+#=>(?:\s.*)?\z/
|
|
40
43
|
|
|
41
44
|
# Arguments for highlighting through `bat`: the annotated text arrives on stdin, so the language must be explicit;
|
|
@@ -59,19 +62,13 @@ module Rigor
|
|
|
59
62
|
execute(file, options)
|
|
60
63
|
end
|
|
61
64
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def
|
|
65
|
-
|
|
66
|
-
options = { config: nil, color: @out.tty? && !no_color_env?, bat: nil, format: :text }
|
|
67
|
-
|
|
68
|
-
parser = OptionParser.new do |opts|
|
|
65
|
+
# The parser this command parses with, built without parsing anything: the catalogue reads the
|
|
66
|
+
# flags and formats from it (ADR-126 WD3). `options` is only written by the switches' blocks.
|
|
67
|
+
def option_parser(options = {})
|
|
68
|
+
OptionParser.new do |opts|
|
|
69
69
|
opts.banner = USAGE
|
|
70
70
|
Options.add_config(opts, options)
|
|
71
|
-
|
|
72
|
-
"Output format: text (default) or json (a { line => type } map)") do |value|
|
|
73
|
-
options[:format] = value.to_sym
|
|
74
|
-
end
|
|
71
|
+
Options.add_format(opts, options, "Output format: text (default) or json (a { line => type } map)")
|
|
75
72
|
opts.on("--[no-]color",
|
|
76
73
|
"Force or disable ANSI colour (default: auto-detect a tty; honours NO_COLOR)") do |value|
|
|
77
74
|
options[:color] = value
|
|
@@ -81,7 +78,15 @@ module Rigor
|
|
|
81
78
|
options[:bat] = value
|
|
82
79
|
end
|
|
83
80
|
end
|
|
84
|
-
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
private
|
|
84
|
+
|
|
85
|
+
def parse_options
|
|
86
|
+
# Default: colour a tty, unless `NO_COLOR` opts out. An explicit `--color` / `--no-color` overrides both.
|
|
87
|
+
options = { config: nil, color: @out.tty? && !no_color_env?, bat: nil, format: "text" }
|
|
88
|
+
|
|
89
|
+
option_parser(options).parse!(@argv)
|
|
85
90
|
|
|
86
91
|
options
|
|
87
92
|
end
|
|
@@ -118,7 +123,7 @@ module Rigor
|
|
|
118
123
|
line_types = LineTypeCollector.new(scope_index).collect(parse_result.value)
|
|
119
124
|
|
|
120
125
|
case options.fetch(:format)
|
|
121
|
-
when
|
|
126
|
+
when "json"
|
|
122
127
|
emit_json(line_types)
|
|
123
128
|
else
|
|
124
129
|
@out.puts(render(annotate(source, line_types), color: options.fetch(:color), bat: options.fetch(:bat)))
|
|
@@ -132,7 +137,7 @@ module Rigor
|
|
|
132
137
|
# object keys).
|
|
133
138
|
def emit_json(line_types)
|
|
134
139
|
annotations = line_types.keys.sort.to_h { |line| [line.to_s, line_types[line].describe(:short)] }
|
|
135
|
-
@out.puts(JSON.generate({ "annotations" => annotations }))
|
|
140
|
+
@out.puts(JSON.generate(JsonDocument.stamp({ "annotations" => annotations })))
|
|
136
141
|
end
|
|
137
142
|
|
|
138
143
|
# The plugin-aware environment for the annotated file, so a `#=> <type>` matches what `rigor check`
|
|
@@ -225,7 +230,7 @@ module Rigor
|
|
|
225
230
|
@scope_index = scope_index
|
|
226
231
|
end
|
|
227
232
|
|
|
228
|
-
# @return 1-indexed line
|
|
233
|
+
# @return map of 1-indexed line number to type.
|
|
229
234
|
def collect(program)
|
|
230
235
|
by_line = {}
|
|
231
236
|
each_statement(program) do |statement|
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
require "optparse"
|
|
4
4
|
|
|
5
|
+
require "did_you_mean"
|
|
6
|
+
|
|
5
7
|
require_relative "../analysis/baseline"
|
|
6
8
|
require_relative "options"
|
|
7
9
|
require_relative "../analysis/runner"
|
|
@@ -24,7 +26,9 @@ module Rigor
|
|
|
24
26
|
# rigor baseline prune
|
|
25
27
|
class BaselineCommand < Command # rubocop:disable Metrics/ClassLength
|
|
26
28
|
EXIT_USAGE = 64
|
|
29
|
+
USAGE = "Usage: rigor baseline <subcommand> [options]"
|
|
27
30
|
DEFAULT_BASELINE_PATH = ".rigor-baseline.yml"
|
|
31
|
+
MAX_UNBASELINEABLE_FILES = 10
|
|
28
32
|
|
|
29
33
|
SUBCOMMANDS = %w[generate regenerate dump drift prune].freeze
|
|
30
34
|
|
|
@@ -41,6 +45,8 @@ module Rigor
|
|
|
41
45
|
when "prune" then run_prune
|
|
42
46
|
else
|
|
43
47
|
@err.puts("Unknown baseline subcommand: #{subcommand.inspect}")
|
|
48
|
+
nearest = ::DidYouMean::SpellChecker.new(dictionary: SUBCOMMANDS).correct(subcommand.to_s).first
|
|
49
|
+
@err.puts("Did you mean `rigor baseline #{nearest}`?") if nearest
|
|
44
50
|
@err.puts(help)
|
|
45
51
|
EXIT_USAGE
|
|
46
52
|
end
|
|
@@ -49,10 +55,78 @@ module Rigor
|
|
|
49
55
|
EXIT_USAGE
|
|
50
56
|
end
|
|
51
57
|
|
|
58
|
+
# The parser of `subcommand`, built without parsing anything (the catalogue reads it, ADR-126 WD3).
|
|
59
|
+
def option_parser(subcommand, options = {})
|
|
60
|
+
case subcommand
|
|
61
|
+
when "generate", "regenerate" then generate_parser(subcommand, options)
|
|
62
|
+
when "dump" then dump_parser(options)
|
|
63
|
+
when "drift" then drift_parser(options)
|
|
64
|
+
when "prune" then prune_parser(options)
|
|
65
|
+
else raise ArgumentError, "unknown baseline subcommand: #{subcommand.inspect}"
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
52
69
|
private
|
|
53
70
|
|
|
71
|
+
def generate_parser(subcommand, options)
|
|
72
|
+
OptionParser.new do |opts|
|
|
73
|
+
opts.banner = "Usage: rigor baseline #{subcommand} [options]"
|
|
74
|
+
Options.add_config(opts, options)
|
|
75
|
+
opts.on("--output=PATH", "Write baseline to PATH (default: #{DEFAULT_BASELINE_PATH})") do |v|
|
|
76
|
+
options[:output] = v
|
|
77
|
+
end
|
|
78
|
+
opts.on("--match-mode=MODE", %i[rule message],
|
|
79
|
+
"Row form: rule (default) or message") do |v|
|
|
80
|
+
options[:match_mode] = v
|
|
81
|
+
end
|
|
82
|
+
# `regenerate` always overwrites — no `--force` to offer.
|
|
83
|
+
if subcommand == "generate"
|
|
84
|
+
opts.on("--force", "Overwrite an existing baseline file") { options[:force] = true }
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def dump_parser(options)
|
|
90
|
+
OptionParser.new do |opts|
|
|
91
|
+
opts.banner = "Usage: rigor baseline dump [options]"
|
|
92
|
+
opts.on("--baseline=PATH", "Path to the baseline file (default: #{DEFAULT_BASELINE_PATH})") do |v|
|
|
93
|
+
options[:baseline] = v
|
|
94
|
+
end
|
|
95
|
+
Options.add_format(opts, options, "Output format: text (default) or json")
|
|
96
|
+
opts.on("--rule=RULE", "Filter rows by exact rule id") { |v| options[:rule] = v }
|
|
97
|
+
opts.on("--file=GLOB", "Filter rows by File.fnmatch? glob") { |v| options[:file] = v }
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def drift_parser(options)
|
|
102
|
+
OptionParser.new do |opts|
|
|
103
|
+
opts.banner = "Usage: rigor baseline drift [options]"
|
|
104
|
+
Options.add_config(opts, options)
|
|
105
|
+
opts.on("--baseline=PATH", "Path to the baseline file (default: #{DEFAULT_BASELINE_PATH})") do |v|
|
|
106
|
+
options[:baseline] = v
|
|
107
|
+
end
|
|
108
|
+
opts.on("--only=STATUS", %i[within over cleared reducible],
|
|
109
|
+
"Show only buckets with the given status (within|over|cleared|reducible)") do |v|
|
|
110
|
+
options[:only] = v
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def prune_parser(options)
|
|
116
|
+
OptionParser.new do |opts|
|
|
117
|
+
opts.banner = "Usage: rigor baseline prune [options]"
|
|
118
|
+
Options.add_config(opts, options)
|
|
119
|
+
opts.on("--baseline=PATH", "Path to the baseline file (default: #{DEFAULT_BASELINE_PATH})") do |v|
|
|
120
|
+
options[:baseline] = v
|
|
121
|
+
end
|
|
122
|
+
opts.on("--dry-run", "Show what would be dropped without writing the file") { options[:dry_run] = true }
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
54
126
|
def run_generate
|
|
55
127
|
options = parse_generate_options
|
|
128
|
+
return positional_paths_error("generate") unless @argv.empty?
|
|
129
|
+
|
|
56
130
|
path = options.fetch(:output)
|
|
57
131
|
|
|
58
132
|
if File.exist?(path) && !options.fetch(:force)
|
|
@@ -69,9 +143,32 @@ module Rigor
|
|
|
69
143
|
# so `rigor baseline regenerate` reads cleanly as "make the baseline match reality again".
|
|
70
144
|
def run_regenerate
|
|
71
145
|
options = parse_generate_options(subcommand: "regenerate")
|
|
146
|
+
return positional_paths_error("regenerate") unless @argv.empty?
|
|
147
|
+
|
|
72
148
|
write_baseline(options, verb: "regenerated baseline")
|
|
73
149
|
end
|
|
74
150
|
|
|
151
|
+
# Issues #2466 and #2577 — the baseline covers the configured `paths:`, never the positional arguments: a
|
|
152
|
+
# baseline built over a subset would silently drop the entries of every other file. `drift` and `prune`
|
|
153
|
+
# analyse the configured `paths:` and `dump` prints the whole file, so none of the five reads a path argument.
|
|
154
|
+
# Reject them, as `rigor effects update` does (`effects_snapshot_command.rb:54`), rather than honour them.
|
|
155
|
+
def positional_paths_error(subcommand)
|
|
156
|
+
@err.puts("rigor baseline #{subcommand}: unexpected argument(s) #{@argv.map(&:inspect).join(' ')}; " \
|
|
157
|
+
"#{positional_paths_hint(subcommand)}")
|
|
158
|
+
EXIT_USAGE
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def positional_paths_hint(subcommand)
|
|
162
|
+
case subcommand
|
|
163
|
+
when "dump"
|
|
164
|
+
"dump reads the baseline file, so pass none: use --file=GLOB to filter rows or --baseline=PATH to pick a file"
|
|
165
|
+
when "drift", "prune"
|
|
166
|
+
"#{subcommand} audits the configured `paths:`, so pass none"
|
|
167
|
+
else
|
|
168
|
+
"the baseline is generated from the configured `paths:`, so pass none"
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
75
172
|
def write_baseline(options, verb:)
|
|
76
173
|
path = options.fetch(:output)
|
|
77
174
|
configuration = Configuration.load(options.fetch(:config))
|
|
@@ -79,13 +176,15 @@ module Rigor
|
|
|
79
176
|
|
|
80
177
|
baseline = Analysis::Baseline.from_diagnostics(diagnostics, match_mode: options.fetch(:match_mode),
|
|
81
178
|
project_root: Dir.pwd)
|
|
82
|
-
|
|
179
|
+
return EXIT_USAGE unless write_baseline_file(path, baseline.to_yaml)
|
|
83
180
|
|
|
181
|
+
covered = baseline.buckets.sum(&:count)
|
|
84
182
|
@err.puts(
|
|
85
183
|
"rigor: #{verb} #{path} " \
|
|
86
|
-
"(#{baseline.size} bucket(s) covering #{
|
|
184
|
+
"(#{baseline.size} bucket(s) covering #{covered} diagnostic(s); " \
|
|
87
185
|
"match-mode: #{options.fetch(:match_mode)})"
|
|
88
186
|
)
|
|
187
|
+
report_unbaselineable(Analysis::Baseline.unkeyable(diagnostics))
|
|
89
188
|
if configuration.baseline_path.nil?
|
|
90
189
|
# Name the config file that actually governs this project (`.rigor.dist.yml` when no local override
|
|
91
190
|
# exists), so the hint points at the file the user must edit.
|
|
@@ -98,6 +197,38 @@ module Rigor
|
|
|
98
197
|
0
|
|
99
198
|
end
|
|
100
199
|
|
|
200
|
+
# Diagnostics the baseline cannot key never enter the file, so the next `rigor check` surfaces them. Say so,
|
|
201
|
+
# with how many, why and where; the exit status stays 0 (the file was written as asked).
|
|
202
|
+
def report_unbaselineable(unkeyable)
|
|
203
|
+
return if unkeyable.empty?
|
|
204
|
+
|
|
205
|
+
no_rule, no_path = unkeyable.partition { |d| d.qualified_rule.nil? }
|
|
206
|
+
files = unbaselineable_files(no_rule)
|
|
207
|
+
parts = []
|
|
208
|
+
unless no_rule.empty?
|
|
209
|
+
parts << "#{no_rule.size} diagnostic(s) have no rule (parse, path or internal errors) " \
|
|
210
|
+
"in #{files.size} file(s)"
|
|
211
|
+
end
|
|
212
|
+
parts << "#{no_path.size} diagnostic(s) have no path" unless no_path.empty?
|
|
213
|
+
listing = files.empty? ? "" : ":"
|
|
214
|
+
@err.puts("rigor: #{parts.join('; ')} and cannot be baselined; " \
|
|
215
|
+
"fix them, or remove or exclude the files#{listing}")
|
|
216
|
+
files.first(MAX_UNBASELINEABLE_FILES).each { |f| @err.puts(" #{f}") }
|
|
217
|
+
extra = files.size - MAX_UNBASELINEABLE_FILES
|
|
218
|
+
@err.puts(" ... and #{extra} more file(s)") if extra.positive?
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def unbaselineable_files(diagnostics)
|
|
222
|
+
root = Pathname.new(Dir.pwd)
|
|
223
|
+
diagnostics.filter_map(&:path).map { |p| relative_to(root, p) }.uniq.sort
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def relative_to(root, path)
|
|
227
|
+
Pathname.new(path).relative_path_from(root).to_s
|
|
228
|
+
rescue ArgumentError
|
|
229
|
+
path
|
|
230
|
+
end
|
|
231
|
+
|
|
101
232
|
def parse_generate_options(subcommand: "generate")
|
|
102
233
|
options = {
|
|
103
234
|
config: nil,
|
|
@@ -105,22 +236,7 @@ module Rigor
|
|
|
105
236
|
match_mode: :rule,
|
|
106
237
|
force: false
|
|
107
238
|
}
|
|
108
|
-
|
|
109
|
-
opts.banner = "Usage: rigor baseline #{subcommand} [options]"
|
|
110
|
-
Options.add_config(opts, options)
|
|
111
|
-
opts.on("--output=PATH", "Write baseline to PATH (default: #{DEFAULT_BASELINE_PATH})") do |v|
|
|
112
|
-
options[:output] = v
|
|
113
|
-
end
|
|
114
|
-
opts.on("--match-mode=MODE", %i[rule message],
|
|
115
|
-
"Row form: rule (default) or message") do |v|
|
|
116
|
-
options[:match_mode] = v
|
|
117
|
-
end
|
|
118
|
-
# `regenerate` always overwrites — no `--force` to offer.
|
|
119
|
-
if subcommand == "generate"
|
|
120
|
-
opts.on("--force", "Overwrite an existing baseline file") { options[:force] = true }
|
|
121
|
-
end
|
|
122
|
-
end
|
|
123
|
-
parser.parse!(@argv)
|
|
239
|
+
generate_parser(subcommand, options).parse!(@argv)
|
|
124
240
|
options
|
|
125
241
|
end
|
|
126
242
|
|
|
@@ -139,8 +255,6 @@ module Rigor
|
|
|
139
255
|
runner.run(configuration_for_generation.paths).diagnostics
|
|
140
256
|
end
|
|
141
257
|
|
|
142
|
-
# The loaded configuration with only `baseline` disabled (#1777): any other key can change the
|
|
143
|
-
# diagnostic set, and the baseline must record the set `rigor check` will then report.
|
|
144
258
|
def override_configuration_baseline_off(configuration)
|
|
145
259
|
configuration.without_baseline
|
|
146
260
|
end
|
|
@@ -149,31 +263,22 @@ module Rigor
|
|
|
149
263
|
|
|
150
264
|
def run_dump
|
|
151
265
|
options = parse_dump_options
|
|
266
|
+
return positional_paths_error("dump") unless @argv.empty?
|
|
267
|
+
|
|
152
268
|
baseline = load_baseline_or_exit(options.fetch(:baseline))
|
|
153
269
|
return EXIT_USAGE if baseline == :error
|
|
154
270
|
|
|
155
271
|
rows = filter_dump_rows(baseline.buckets, options)
|
|
156
272
|
case options.fetch(:format)
|
|
157
|
-
when
|
|
273
|
+
when "json" then @out.puts(JSON.pretty_generate(dump_to_json(rows)))
|
|
158
274
|
else dump_text(rows, options)
|
|
159
275
|
end
|
|
160
276
|
0
|
|
161
277
|
end
|
|
162
278
|
|
|
163
279
|
def parse_dump_options
|
|
164
|
-
options = { baseline: DEFAULT_BASELINE_PATH, format:
|
|
165
|
-
|
|
166
|
-
opts.banner = "Usage: rigor baseline dump [options]"
|
|
167
|
-
opts.on("--baseline=PATH", "Path to the baseline file (default: #{DEFAULT_BASELINE_PATH})") do |v|
|
|
168
|
-
options[:baseline] = v
|
|
169
|
-
end
|
|
170
|
-
opts.on("--format=FORMAT", %i[text json], "Output format: text (default) or json") do |v|
|
|
171
|
-
options[:format] = v
|
|
172
|
-
end
|
|
173
|
-
opts.on("--rule=RULE", "Filter rows by exact rule id") { |v| options[:rule] = v }
|
|
174
|
-
opts.on("--file=GLOB", "Filter rows by File.fnmatch? glob") { |v| options[:file] = v }
|
|
175
|
-
end
|
|
176
|
-
parser.parse!(@argv)
|
|
280
|
+
options = { baseline: DEFAULT_BASELINE_PATH, format: "text", rule: nil, file: nil }
|
|
281
|
+
dump_parser(options).parse!(@argv)
|
|
177
282
|
options
|
|
178
283
|
end
|
|
179
284
|
|
|
@@ -226,6 +331,8 @@ module Rigor
|
|
|
226
331
|
|
|
227
332
|
def run_drift
|
|
228
333
|
options = parse_drift_options
|
|
334
|
+
return positional_paths_error("drift") unless @argv.empty?
|
|
335
|
+
|
|
229
336
|
baseline = load_baseline_or_exit(options.fetch(:baseline))
|
|
230
337
|
return EXIT_USAGE if baseline == :error
|
|
231
338
|
|
|
@@ -254,18 +361,7 @@ module Rigor
|
|
|
254
361
|
baseline: DEFAULT_BASELINE_PATH,
|
|
255
362
|
only: nil
|
|
256
363
|
}
|
|
257
|
-
|
|
258
|
-
opts.banner = "Usage: rigor baseline drift [options]"
|
|
259
|
-
Options.add_config(opts, options)
|
|
260
|
-
opts.on("--baseline=PATH", "Path to the baseline file (default: #{DEFAULT_BASELINE_PATH})") do |v|
|
|
261
|
-
options[:baseline] = v
|
|
262
|
-
end
|
|
263
|
-
opts.on("--only=STATUS", %i[within over cleared reducible],
|
|
264
|
-
"Show only buckets with the given status (within|over|cleared|reducible)") do |v|
|
|
265
|
-
options[:only] = v
|
|
266
|
-
end
|
|
267
|
-
end
|
|
268
|
-
parser.parse!(@argv)
|
|
364
|
+
drift_parser(options).parse!(@argv)
|
|
269
365
|
options
|
|
270
366
|
end
|
|
271
367
|
|
|
@@ -300,6 +396,8 @@ module Rigor
|
|
|
300
396
|
|
|
301
397
|
def run_prune
|
|
302
398
|
options = parse_prune_options
|
|
399
|
+
return positional_paths_error("prune") unless @argv.empty?
|
|
400
|
+
|
|
303
401
|
baseline = load_baseline_or_exit(options.fetch(:baseline))
|
|
304
402
|
return EXIT_USAGE if baseline == :error
|
|
305
403
|
|
|
@@ -317,7 +415,8 @@ module Rigor
|
|
|
317
415
|
return 0 if options.fetch(:dry_run)
|
|
318
416
|
|
|
319
417
|
pruned = baseline.without(cleared.map(&:bucket))
|
|
320
|
-
|
|
418
|
+
return EXIT_USAGE unless write_baseline_file(options.fetch(:baseline), pruned.to_yaml)
|
|
419
|
+
|
|
321
420
|
@err.puts("rigor: pruned #{cleared.size} bucket(s); baseline now has #{pruned.size} entries.")
|
|
322
421
|
0
|
|
323
422
|
end
|
|
@@ -328,15 +427,7 @@ module Rigor
|
|
|
328
427
|
baseline: DEFAULT_BASELINE_PATH,
|
|
329
428
|
dry_run: false
|
|
330
429
|
}
|
|
331
|
-
|
|
332
|
-
opts.banner = "Usage: rigor baseline prune [options]"
|
|
333
|
-
Options.add_config(opts, options)
|
|
334
|
-
opts.on("--baseline=PATH", "Path to the baseline file (default: #{DEFAULT_BASELINE_PATH})") do |v|
|
|
335
|
-
options[:baseline] = v
|
|
336
|
-
end
|
|
337
|
-
opts.on("--dry-run", "Show what would be dropped without writing the file") { options[:dry_run] = true }
|
|
338
|
-
end
|
|
339
|
-
parser.parse!(@argv)
|
|
430
|
+
prune_parser(options).parse!(@argv)
|
|
340
431
|
options
|
|
341
432
|
end
|
|
342
433
|
|
|
@@ -349,6 +440,18 @@ module Rigor
|
|
|
349
440
|
|
|
350
441
|
# ---- shared helpers ----------------------------------------
|
|
351
442
|
|
|
443
|
+
# #2576 — an output path that cannot be written is a usage error, the same rule `rigor init
|
|
444
|
+
# --path` follows (#2562): one `rigor baseline: cannot write PATH: REASON` line on stderr and
|
|
445
|
+
# exit 64, with no backtrace and no directory created on the way. The bare Errno backtrace read
|
|
446
|
+
# as an internal crash.
|
|
447
|
+
def write_baseline_file(path, content)
|
|
448
|
+
File.write(path, content)
|
|
449
|
+
true
|
|
450
|
+
rescue SystemCallError => e
|
|
451
|
+
@err.puts("rigor baseline: cannot write #{path}: #{e.message.sub(/ @ .*\z/m, '')}")
|
|
452
|
+
false
|
|
453
|
+
end
|
|
454
|
+
|
|
352
455
|
def load_baseline_or_exit(path)
|
|
353
456
|
unless File.exist?(path)
|
|
354
457
|
@err.puts("rigor: baseline file not found: #{path}")
|
|
@@ -362,7 +465,7 @@ module Rigor
|
|
|
362
465
|
|
|
363
466
|
def help
|
|
364
467
|
<<~HELP
|
|
365
|
-
|
|
468
|
+
#{USAGE}
|
|
366
469
|
|
|
367
470
|
Subcommands:
|
|
368
471
|
generate Write a fresh baseline file from a `rigor check` run.
|