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
|
@@ -68,7 +68,7 @@ module Rigor
|
|
|
68
68
|
configuration = Configuration.load(options.fetch(:config))
|
|
69
69
|
paths = resolve_paths(configuration)
|
|
70
70
|
return CLI::EXIT_USAGE if paths.nil?
|
|
71
|
-
return
|
|
71
|
+
return no_ruby_files_error(configuration) if paths.empty?
|
|
72
72
|
|
|
73
73
|
return run_protection(paths, options, configuration) if options[:protection]
|
|
74
74
|
|
|
@@ -77,27 +77,31 @@ module Rigor
|
|
|
77
77
|
determine_exit(report, options)
|
|
78
78
|
end
|
|
79
79
|
|
|
80
|
+
# The parser this command parses with, built without parsing anything (the catalogue reads it, ADR-126 WD3).
|
|
81
|
+
def option_parser(options = {})
|
|
82
|
+
OptionParser.new { |opts| define_options(opts, options) }
|
|
83
|
+
end
|
|
84
|
+
|
|
80
85
|
private
|
|
81
86
|
|
|
82
|
-
# Like `rigor check`, fall back to the configured `paths:` when no path is given
|
|
83
|
-
#
|
|
84
|
-
# differ on). The mutation mode keeps its own git-changed-files default and returns before this.
|
|
87
|
+
# Like `rigor check`, fall back to the configured `paths:` when no path is given. The mutation mode keeps its own
|
|
88
|
+
# git-changed-files default and returns before this.
|
|
85
89
|
def resolve_paths(configuration)
|
|
86
90
|
args = @argv.empty? ? configuration.paths : @argv
|
|
87
|
-
|
|
91
|
+
collect_paths_reporting(args)
|
|
88
92
|
end
|
|
89
93
|
|
|
90
94
|
def parse_options
|
|
91
95
|
options = { format: "text", threshold: nil, config: nil, protection: false, mutation: false,
|
|
92
96
|
with_tests: false, test_command: DEFAULT_TEST_COMMAND, include_dynamic: false,
|
|
93
97
|
limit: nil, seed: 1, workers: nil, no_cache: false }
|
|
94
|
-
|
|
98
|
+
option_parser(options).parse!(@argv)
|
|
95
99
|
options
|
|
96
100
|
end
|
|
97
101
|
|
|
98
102
|
def define_options(opts, options)
|
|
99
103
|
opts.banner = USAGE
|
|
100
|
-
|
|
104
|
+
Options.add_format(opts, options, "Output format: text or json")
|
|
101
105
|
Options.add_config(opts, options)
|
|
102
106
|
opts.on("--protection", "Report type-protection coverage (ADR-63 Tier 1) instead of type precision") do
|
|
103
107
|
options[:protection] = true
|
|
@@ -203,7 +207,7 @@ module Rigor
|
|
|
203
207
|
# `singleton(Account)` instead of `Dynamic`. Without this, a
|
|
204
208
|
# single-file scan cannot see a class it does not itself declare,
|
|
205
209
|
# so every cross-file class-constant dispatch was miscounted as
|
|
206
|
-
# unprotected
|
|
210
|
+
# unprotected.
|
|
207
211
|
# - `param_inferred_types` (ADR-67 WD3) — an inferred-parameter
|
|
208
212
|
# receiver (`node.loc` where `node` is a `def compile(node)`
|
|
209
213
|
# parameter) counts as protected when its call sites resolve to
|
|
@@ -253,6 +257,15 @@ module Rigor
|
|
|
253
257
|
CLI::EXIT_USAGE
|
|
254
258
|
end
|
|
255
259
|
|
|
260
|
+
# #2206 — paths were named, or configured, but none holds a Ruby file. Said as such, not as "no path given".
|
|
261
|
+
def no_ruby_files_error(configuration)
|
|
262
|
+
return usage_error if @argv.empty? && Array(configuration.paths).empty?
|
|
263
|
+
|
|
264
|
+
@err.puts("coverage: no Ruby files under the given paths")
|
|
265
|
+
@err.puts(USAGE)
|
|
266
|
+
CLI::EXIT_USAGE
|
|
267
|
+
end
|
|
268
|
+
|
|
256
269
|
def scan_paths(paths, configuration)
|
|
257
270
|
CoverageScan.precision_report(files: paths, configuration: configuration)
|
|
258
271
|
end
|
|
@@ -24,7 +24,6 @@ module Rigor
|
|
|
24
24
|
DISCOVERY_SEEDED_MUTATION_SITES = "discovery-seeded-mutation-sites"
|
|
25
25
|
|
|
26
26
|
# ADR-50 § WD2 — the bleeding-edge feature id gating the Tier-2 dependent-closure kill oracle (#254).
|
|
27
|
-
# Same reason as above for naming it here rather than inlining the string.
|
|
28
27
|
DEPENDENT_CLOSURE_KILL_ORACLE = "dependent-closure-kill-oracle"
|
|
29
28
|
|
|
30
29
|
# #264 — the "loud" threshold for a rescued-harness-failure count. Below it, a rescued mutant reads as
|
|
@@ -52,8 +51,7 @@ module Rigor
|
|
|
52
51
|
MeasurementIntegrityWarning.emit(report, err: @err, floor: HARNESS_ERROR_WARN_FLOOR)
|
|
53
52
|
end
|
|
54
53
|
|
|
55
|
-
# The cross-file knowledge Tier 2 measures with
|
|
56
|
-
# knows a feature id exists.
|
|
54
|
+
# The cross-file knowledge Tier 2 measures with, gated on the #253 feature.
|
|
57
55
|
#
|
|
58
56
|
# Returns nil (today's behaviour: an unseeded per-file view on both halves of the measurement) unless the
|
|
59
57
|
# project has adopted `discovery-seeded-mutation-sites`. With it adopted, returns the table set
|
|
@@ -81,7 +79,7 @@ module Rigor
|
|
|
81
79
|
seed.empty? ? nil : seed
|
|
82
80
|
end
|
|
83
81
|
|
|
84
|
-
# The kill oracle Tier 2 measures with
|
|
82
|
+
# The kill oracle Tier 2 measures with, gated on the #254 feature.
|
|
85
83
|
#
|
|
86
84
|
# Returns nil (today's behaviour: {Protection::DiagnosticOracle}, which re-analyses the mutated file
|
|
87
85
|
# alone) unless the project has adopted `dependent-closure-kill-oracle`. With it adopted, returns the
|
|
@@ -139,7 +137,7 @@ module Rigor
|
|
|
139
137
|
# warm loop), then re-analyses each target file's mutants against its clean baseline. Defaults to the git-changed
|
|
140
138
|
# `.rb` files; explicit paths override (and enable the whole-project opt-in, which is minutes).
|
|
141
139
|
def run_mutation_protection(options)
|
|
142
|
-
explicit =
|
|
140
|
+
explicit = collect_paths_reporting(@argv)
|
|
143
141
|
return CLI::EXIT_USAGE if explicit.nil?
|
|
144
142
|
|
|
145
143
|
target_files = explicit.empty? ? changed_ruby_files : explicit
|
|
@@ -204,8 +202,8 @@ module Rigor
|
|
|
204
202
|
determine_protection_exit(report, options)
|
|
205
203
|
end
|
|
206
204
|
|
|
207
|
-
# An explicit `--workers=N` on the fused path cannot be honoured, so say so rather than
|
|
208
|
-
#
|
|
205
|
+
# An explicit `--workers=N` on the fused path cannot be honoured, so say so rather than drop it silently. Only the
|
|
206
|
+
# explicit flag warns — a project-wide
|
|
209
207
|
# `parallel.workers:` or `RIGOR_RACTOR_WORKERS` default is not a request about *this* run.
|
|
210
208
|
def warn_workers_ignored_under_tests(options)
|
|
211
209
|
return unless options[:workers].to_i > 1
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require "json"
|
|
4
4
|
require_relative "renderable"
|
|
5
|
+
require_relative "json_document"
|
|
5
6
|
|
|
6
7
|
module Rigor
|
|
7
8
|
class CLI
|
|
@@ -93,7 +94,7 @@ module Rigor
|
|
|
93
94
|
end
|
|
94
95
|
|
|
95
96
|
def render_json(report)
|
|
96
|
-
@out.puts(JSON.pretty_generate(json_payload(report)))
|
|
97
|
+
@out.puts(JSON.pretty_generate(JsonDocument.stamp(json_payload(report), mode: "precision")))
|
|
97
98
|
end
|
|
98
99
|
|
|
99
100
|
def json_payload(report)
|
|
@@ -23,11 +23,9 @@ module Rigor
|
|
|
23
23
|
|
|
24
24
|
# @param files — explicit `.rb` file paths to scan.
|
|
25
25
|
#
|
|
26
|
-
# Issue #513 — the environment is
|
|
27
|
-
# `--protection` uses)
|
|
28
|
-
#
|
|
29
|
-
# engine by ~1.2 points on a Rails target — the defect the protection path documented and fixed for
|
|
30
|
-
# itself on 2026-07-04, never applied here.
|
|
26
|
+
# Issue #513 — the environment is plugin-aware (`LanguageServer::ProjectContext`, the same builder
|
|
27
|
+
# `--protection` uses). A bare RBS environment read every plugin-typed receiver as `Dynamic` and understated
|
|
28
|
+
# the precision ratio by ~1.2 points on a Rails target.
|
|
31
29
|
def precision_report(files:, configuration:)
|
|
32
30
|
scope = discovery_seeded_scope(
|
|
33
31
|
files: files,
|
|
@@ -5,11 +5,12 @@ require_relative "options"
|
|
|
5
5
|
|
|
6
6
|
require "json"
|
|
7
7
|
require "optionparser"
|
|
8
|
+
require_relative "json_document"
|
|
8
9
|
|
|
9
10
|
module Rigor
|
|
10
11
|
class CLI
|
|
11
|
-
# Executes `rigor diff <
|
|
12
|
-
#
|
|
12
|
+
# Executes `rigor diff <rigor-check.json> [paths...]`. Compares the current `rigor check` diagnostics against a
|
|
13
|
+
# saved `rigor check --format=json` result and prints the delta:
|
|
13
14
|
#
|
|
14
15
|
# - **new** — diagnostics in the current run that were not
|
|
15
16
|
# in the baseline (typically a regression introduced in
|
|
@@ -21,11 +22,11 @@ module Rigor
|
|
|
21
22
|
# diagnostic to a new line surfaces as one fixed + one new pair, which lines up with the user's mental model of "you
|
|
22
23
|
# changed the line, the analyzer's position changed too."
|
|
23
24
|
#
|
|
24
|
-
# CI usage: commit a `rigor.
|
|
25
|
-
#
|
|
25
|
+
# CI usage: commit a `rigor-check.json` produced once with `rigor check --format=json > rigor-check.json`, then
|
|
26
|
+
# run `rigor diff rigor-check.json` in CI. Exit code is `1` when any new diagnostic appears, `0` otherwise —
|
|
26
27
|
# so adding new errors fails CI but legacy errors recorded in the baseline don't.
|
|
27
28
|
class DiffCommand < Command
|
|
28
|
-
USAGE = "Usage: rigor diff [options] <
|
|
29
|
+
USAGE = "Usage: rigor diff [options] <rigor-check.json> [paths...]"
|
|
29
30
|
|
|
30
31
|
# @return CLI exit status.
|
|
31
32
|
def run
|
|
@@ -51,22 +52,26 @@ module Rigor
|
|
|
51
52
|
diff[:new].any? ? 1 : 0
|
|
52
53
|
end
|
|
53
54
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def
|
|
57
|
-
options = { format: "text", current_path: nil, config: nil }
|
|
55
|
+
# The parser this command parses with, built without parsing anything: the catalogue reads the
|
|
56
|
+
# flags and formats from it (ADR-126 WD3). `options` is only written by the switches' blocks.
|
|
57
|
+
def option_parser(options = {})
|
|
58
58
|
OptionParser.new do |opt|
|
|
59
59
|
opt.banner = USAGE
|
|
60
|
-
|
|
61
|
-
options[:format] = fmt
|
|
62
|
-
end
|
|
60
|
+
Options.add_format(opt, options, "Output format (text | json). Default: text.")
|
|
63
61
|
opt.on("--current=PATH", "Compare to the saved current JSON instead of running `rigor check`.") do |path|
|
|
64
62
|
options[:current_path] = path
|
|
65
63
|
end
|
|
66
64
|
opt.on("--config=PATH", "Path to .rigor.yml. Forwarded to the implicit `rigor check` run.") do |path|
|
|
67
65
|
options[:config] = Options.config_path(path)
|
|
68
66
|
end
|
|
69
|
-
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def parse_options
|
|
73
|
+
options = { format: "text", current_path: nil, config: nil }
|
|
74
|
+
option_parser(options).parse!(@argv)
|
|
70
75
|
options
|
|
71
76
|
end
|
|
72
77
|
|
|
@@ -121,13 +126,13 @@ module Rigor
|
|
|
121
126
|
end
|
|
122
127
|
|
|
123
128
|
def write_diff_json(diff, baseline_path, baseline_count, current_count)
|
|
124
|
-
@out.puts(JSON.pretty_generate(
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
129
|
+
@out.puts(JSON.pretty_generate(JsonDocument.stamp({
|
|
130
|
+
"baseline" => baseline_path,
|
|
131
|
+
"baseline_count" => baseline_count,
|
|
132
|
+
"current_count" => current_count,
|
|
133
|
+
"new" => diff[:new],
|
|
134
|
+
"fixed" => diff[:fixed]
|
|
135
|
+
})))
|
|
131
136
|
end
|
|
132
137
|
|
|
133
138
|
def write_diff_text(diff, baseline_path, baseline_count, current_count)
|
|
@@ -203,8 +203,7 @@ module Rigor
|
|
|
203
203
|
relative: relative,
|
|
204
204
|
path: path,
|
|
205
205
|
category: category,
|
|
206
|
-
# Always-unique addresses: the `docs/`-relative path and the prefixed basename.
|
|
207
|
-
# `03-narrowing`.
|
|
206
|
+
# Always-unique addresses: the `docs/`-relative path and the prefixed basename.
|
|
208
207
|
exact_aliases: [relative, base].uniq,
|
|
209
208
|
# The prefix-stripped short name (`narrowing`); ambiguous when two categories carry the same chapter slug
|
|
210
209
|
# (`plugins`).
|
|
@@ -17,6 +17,7 @@ require_relative "../type/combinator"
|
|
|
17
17
|
require_relative "check_invocation"
|
|
18
18
|
require_relative "command"
|
|
19
19
|
require_relative "options"
|
|
20
|
+
require_relative "json_document"
|
|
20
21
|
|
|
21
22
|
module Rigor
|
|
22
23
|
class CLI
|
|
@@ -86,23 +87,22 @@ module Rigor
|
|
|
86
87
|
CLI::EXIT_USAGE
|
|
87
88
|
end
|
|
88
89
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
def
|
|
92
|
-
options = { config: nil, format: "text" }
|
|
90
|
+
# The parser this command parses with, built without parsing anything: the catalogue reads the
|
|
91
|
+
# flags and formats from it (ADR-126 WD3). `options` is only written by the switches' blocks.
|
|
92
|
+
def option_parser(options = {})
|
|
93
93
|
OptionParser.new do |opts|
|
|
94
94
|
opts.banner = USAGE
|
|
95
95
|
Options.add_config(opts, options)
|
|
96
|
-
|
|
97
|
-
end
|
|
98
|
-
validate!(options)
|
|
99
|
-
options
|
|
96
|
+
Options.add_format(opts, options, "Output format: text (default) or json")
|
|
97
|
+
end
|
|
100
98
|
end
|
|
101
99
|
|
|
102
|
-
|
|
103
|
-
return if %w[text json].include?(options.fetch(:format))
|
|
100
|
+
private
|
|
104
101
|
|
|
105
|
-
|
|
102
|
+
def parse_options
|
|
103
|
+
options = { config: nil, format: "text" }
|
|
104
|
+
option_parser(options).parse!(@argv)
|
|
105
|
+
options
|
|
106
106
|
end
|
|
107
107
|
|
|
108
108
|
# ------------------------------------------------------------------
|
|
@@ -437,7 +437,7 @@ module Rigor
|
|
|
437
437
|
}
|
|
438
438
|
end
|
|
439
439
|
}
|
|
440
|
-
@out.puts(JSON.pretty_generate(payload))
|
|
440
|
+
@out.puts(JSON.pretty_generate(JsonDocument.stamp(payload)))
|
|
441
441
|
end
|
|
442
442
|
|
|
443
443
|
def report_text(findings)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "did_you_mean"
|
|
3
4
|
require "optionparser"
|
|
4
5
|
|
|
5
6
|
require_relative "../configuration"
|
|
@@ -50,6 +51,38 @@ module Rigor
|
|
|
50
51
|
run_report
|
|
51
52
|
end
|
|
52
53
|
|
|
54
|
+
# The parser this command parses with, built without parsing anything: the catalogue reads the
|
|
55
|
+
# flags and formats from it (ADR-126 WD3). `options` is only written by the switches' blocks.
|
|
56
|
+
def option_parser(options = {})
|
|
57
|
+
OptionParser.new do |opts|
|
|
58
|
+
opts.banner = USAGE
|
|
59
|
+
Options.add_config(opts, options)
|
|
60
|
+
Options.add_format(opts, options, "Output format: text (default) or json")
|
|
61
|
+
opts.on("--full", "List every method, including the ones with nothing to say") do
|
|
62
|
+
options[:full] = true
|
|
63
|
+
end
|
|
64
|
+
opts.on("--label=LABEL", "Only methods carrying LABEL (or a label under it), in either lane") do |value|
|
|
65
|
+
options[:label].concat(value.split(",").map(&:strip).reject(&:empty?))
|
|
66
|
+
end
|
|
67
|
+
opts.on("--pure", "Only methods proven to do nothing beyond mutate.local — the %a{pure} set") do
|
|
68
|
+
options[:pure] = true
|
|
69
|
+
end
|
|
70
|
+
opts.on("--limit=N", Integer, "Print at most N methods") { |value| options[:limit] = value }
|
|
71
|
+
opts.on("--why", "Expand each method's unresolved reasons and declared-lane sources") do
|
|
72
|
+
options[:why] = true
|
|
73
|
+
end
|
|
74
|
+
opts.on("--list-labels", "Print the effect vocabulary this project can name, and exit") do
|
|
75
|
+
options[:list_labels] = true
|
|
76
|
+
end
|
|
77
|
+
# Accepted here and deliberately inert, exactly as it is on `update`: the report is an
|
|
78
|
+
# observation, and observations are undischarged. Only a JUDGMENT reads `effects.tolerated:` —
|
|
79
|
+
# `rigor effects check` / `diff`, and `rigor check`'s envelope contract.
|
|
80
|
+
opts.on("--no-tolerated-effects", "Judge as if effects.tolerated: were empty (inert on the report)") do
|
|
81
|
+
options[:no_tolerated] = true
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
53
86
|
private
|
|
54
87
|
|
|
55
88
|
def run_verb(verb)
|
|
@@ -91,7 +124,7 @@ module Rigor
|
|
|
91
124
|
|
|
92
125
|
def run_report
|
|
93
126
|
options = parse_options
|
|
94
|
-
return
|
|
127
|
+
return CLI::EXIT_USAGE if misspelled_verb?
|
|
95
128
|
|
|
96
129
|
configuration = Configuration.load(options.fetch(:config)).with_effects_enabled
|
|
97
130
|
return list_labels(configuration) if options.fetch(:list_labels)
|
|
@@ -107,6 +140,20 @@ module Rigor
|
|
|
107
140
|
0
|
|
108
141
|
end
|
|
109
142
|
|
|
143
|
+
# A first word that is no path but is one edit from a snapshot verb (`rigor effects updat`) is a misspelled verb,
|
|
144
|
+
# not a scope: the report would otherwise run to completion and say only that no unit lives in `updat`.
|
|
145
|
+
def misspelled_verb?
|
|
146
|
+
word = @argv.first
|
|
147
|
+
return false if word.nil? || word.match?(%r{[/.]}) || File.exist?(word)
|
|
148
|
+
|
|
149
|
+
nearest = ::DidYouMean::SpellChecker.new(dictionary: EffectsSnapshotCommand::VERBS).correct(word).first
|
|
150
|
+
return false unless nearest
|
|
151
|
+
|
|
152
|
+
@err.puts("rigor: unknown effects subcommand: #{word}")
|
|
153
|
+
@err.puts("Did you mean `rigor effects #{nearest}`?")
|
|
154
|
+
true
|
|
155
|
+
end
|
|
156
|
+
|
|
110
157
|
# A path argument is a **view**, and the note says so (#439).
|
|
111
158
|
#
|
|
112
159
|
# It used to narrow the analysed set, and effect labels are transitive over whatever was analysed —
|
|
@@ -131,48 +178,13 @@ module Rigor
|
|
|
131
178
|
"label is the one the whole-project run reports")
|
|
132
179
|
end
|
|
133
180
|
|
|
134
|
-
FORMATS = %w[text json].freeze
|
|
135
|
-
private_constant :FORMATS
|
|
136
|
-
|
|
137
181
|
def parse_options
|
|
138
182
|
options = { config: nil, format: "text", full: false, no_tolerated: false, label: [], pure: false,
|
|
139
183
|
limit: nil, why: false, list_labels: false }
|
|
140
|
-
|
|
141
|
-
opts.banner = USAGE
|
|
142
|
-
Options.add_config(opts, options)
|
|
143
|
-
opts.on("--format=FORMAT", "Output format: text (default) or json") { |value| options[:format] = value }
|
|
144
|
-
opts.on("--full", "List every method, including the ones with nothing to say") do
|
|
145
|
-
options[:full] = true
|
|
146
|
-
end
|
|
147
|
-
opts.on("--label=LABEL", "Only methods carrying LABEL (or a label under it), in either lane") do |value|
|
|
148
|
-
options[:label].concat(value.split(",").map(&:strip).reject(&:empty?))
|
|
149
|
-
end
|
|
150
|
-
opts.on("--pure", "Only methods proven to do nothing beyond mutate.local — the %a{pure} set") do
|
|
151
|
-
options[:pure] = true
|
|
152
|
-
end
|
|
153
|
-
opts.on("--limit=N", Integer, "Print at most N methods") { |value| options[:limit] = value }
|
|
154
|
-
opts.on("--why", "Expand each method's unresolved reasons and declared-lane sources") do
|
|
155
|
-
options[:why] = true
|
|
156
|
-
end
|
|
157
|
-
opts.on("--list-labels", "Print the effect vocabulary this project can name, and exit") do
|
|
158
|
-
options[:list_labels] = true
|
|
159
|
-
end
|
|
160
|
-
# Accepted here and deliberately inert, exactly as it is on `update`: the report is an
|
|
161
|
-
# observation, and observations are undischarged. Only a JUDGMENT reads `effects.tolerated:` —
|
|
162
|
-
# `rigor effects check` / `diff`, and `rigor check`'s envelope contract.
|
|
163
|
-
opts.on("--no-tolerated-effects", "Judge as if effects.tolerated: were empty (inert on the report)") do
|
|
164
|
-
options[:no_tolerated] = true
|
|
165
|
-
end
|
|
166
|
-
end.parse!(@argv)
|
|
184
|
+
option_parser(options).parse!(@argv)
|
|
167
185
|
options
|
|
168
186
|
end
|
|
169
187
|
|
|
170
|
-
def usage_error(message)
|
|
171
|
-
@err.puts(message)
|
|
172
|
-
@err.puts(USAGE)
|
|
173
|
-
CLI::EXIT_USAGE
|
|
174
|
-
end
|
|
175
|
-
|
|
176
188
|
# Sequential and cache-backed, through the same ADR-45 whole-run result cache `rigor check` uses:
|
|
177
189
|
# the diagnostics entry serves the run and the #382 effects sidecar serves the collections, leaving
|
|
178
190
|
# only the fixpoint. Sequential is not a cache decision — the run-result cache declines pool mode —
|
|
@@ -222,9 +234,7 @@ module Rigor
|
|
|
222
234
|
|
|
223
235
|
# The analysed set is the configured `paths:` **plus** whatever the arguments name — never the
|
|
224
236
|
# arguments alone (#439). An effect summary is transitive over whatever was analysed, so analysing
|
|
225
|
-
# less does not filter the report, it lowers every answer in it
|
|
226
|
-
# app/controllers/issues_controller.rb` used to report `IssuesController#create: [] …?` where the
|
|
227
|
-
# whole-project run reported four labels and a declared lane, with nothing marking the difference.
|
|
237
|
+
# less does not filter the report, it lowers every answer in it.
|
|
228
238
|
#
|
|
229
239
|
# The union rather than the configured paths alone, so that pointing the command at a tree the
|
|
230
240
|
# configuration does not cover — which is what every `rigor effects PATH` invocation from outside a
|
|
@@ -6,6 +6,7 @@ require_relative "../effects/definition_lines"
|
|
|
6
6
|
require_relative "../effects/snapshot"
|
|
7
7
|
require_relative "../effects/snapshot_diff"
|
|
8
8
|
require_relative "renderable"
|
|
9
|
+
require_relative "json_document"
|
|
9
10
|
|
|
10
11
|
module Rigor
|
|
11
12
|
class CLI
|
|
@@ -121,7 +122,7 @@ module Rigor
|
|
|
121
122
|
# method that no longer exists was not defined by it. Such a row renders exactly as it did before
|
|
122
123
|
# this suffix existed.
|
|
123
124
|
#
|
|
124
|
-
# @return
|
|
125
|
+
# @return a relative path and line per file, the line nil when that
|
|
125
126
|
# file spells the key with no `def` — an accessor, or a definition the nesting cannot name.
|
|
126
127
|
def sources_of(symbol)
|
|
127
128
|
Array(@sources[symbol]).map do |path|
|
|
@@ -175,22 +176,22 @@ module Rigor
|
|
|
175
176
|
end
|
|
176
177
|
|
|
177
178
|
def render_json(diff)
|
|
178
|
-
@out.puts(JSON.pretty_generate(
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
179
|
+
@out.puts(JSON.pretty_generate(JsonDocument.stamp({
|
|
180
|
+
"fresh" => diff.fresh?,
|
|
181
|
+
"events" => diff.events.map { |event| event_json(event) },
|
|
182
|
+
"footer" => {
|
|
183
|
+
"added_symbols" => diff.footer[:added_symbols],
|
|
184
|
+
"removed_symbols" => diff.footer[:removed_symbols],
|
|
185
|
+
"suppressed" => diff.footer[:suppressed]
|
|
186
|
+
},
|
|
187
|
+
"regeneration" => diff.regeneration?,
|
|
188
|
+
"header" => {
|
|
189
|
+
"snapshot" => @path,
|
|
190
|
+
"gate" => diff.gate.to_s,
|
|
191
|
+
"recorded" => diff.recorded&.header,
|
|
192
|
+
"current" => diff.current.header
|
|
193
|
+
}
|
|
194
|
+
})))
|
|
194
195
|
end
|
|
195
196
|
end
|
|
196
197
|
end
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "json"
|
|
4
4
|
|
|
5
5
|
require_relative "renderable"
|
|
6
|
+
require_relative "json_document"
|
|
6
7
|
|
|
7
8
|
module Rigor
|
|
8
9
|
class CLI
|
|
@@ -53,18 +54,18 @@ module Rigor
|
|
|
53
54
|
end
|
|
54
55
|
|
|
55
56
|
def render_json(rows)
|
|
56
|
-
@out.puts(JSON.pretty_generate(
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
57
|
+
@out.puts(JSON.pretty_generate(JsonDocument.stamp({
|
|
58
|
+
"paths" => rows.map do |row|
|
|
59
|
+
{
|
|
60
|
+
"table" => row.table,
|
|
61
|
+
"symbol" => row.symbol,
|
|
62
|
+
"label" => row.label,
|
|
63
|
+
"path" => row.path,
|
|
64
|
+
"origin" => row.origin,
|
|
65
|
+
"causes" => row.causes
|
|
66
|
+
}
|
|
67
|
+
end
|
|
68
|
+
})))
|
|
68
69
|
end
|
|
69
70
|
end
|
|
70
71
|
end
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "json"
|
|
4
4
|
|
|
5
5
|
require_relative "renderable"
|
|
6
|
+
require_relative "json_document"
|
|
6
7
|
|
|
7
8
|
module Rigor
|
|
8
9
|
class CLI
|
|
@@ -85,7 +86,7 @@ module Rigor
|
|
|
85
86
|
end
|
|
86
87
|
}
|
|
87
88
|
payload["totals"] = report.totals.to_h.transform_keys(&:to_s) if report.totals
|
|
88
|
-
@out.puts(JSON.pretty_generate(payload))
|
|
89
|
+
@out.puts(JSON.pretty_generate(JsonDocument.stamp(payload)))
|
|
89
90
|
end
|
|
90
91
|
end
|
|
91
92
|
end
|
|
@@ -38,9 +38,6 @@ module Rigor
|
|
|
38
38
|
class EffectsSnapshotCommand < Command
|
|
39
39
|
VERBS = %w[update check diff explain].freeze
|
|
40
40
|
|
|
41
|
-
FORMATS = %w[text json].freeze
|
|
42
|
-
private_constant :FORMATS
|
|
43
|
-
|
|
44
41
|
# The verbs that read a committed record, and so accept `--baseline PATH` —
|
|
45
42
|
# `--baseline <(git show origin/main:.rigor-effects.yml)` is the bot form.
|
|
46
43
|
COMPARING_VERBS = %w[check diff explain].freeze
|
|
@@ -54,8 +51,6 @@ module Rigor
|
|
|
54
51
|
# @return 0 fresh / written, 1 on drift under `check`, 64 on a usage error.
|
|
55
52
|
def run
|
|
56
53
|
options = parse_options
|
|
57
|
-
return usage_error("unsupported format: #{options.fetch(:format)}") unless
|
|
58
|
-
FORMATS.include?(options[:format])
|
|
59
54
|
return usage_error("rigor effects #{@verb} takes no paths; it records the configured paths:") unless
|
|
60
55
|
@argv.empty?
|
|
61
56
|
|
|
@@ -64,6 +59,22 @@ module Rigor
|
|
|
64
59
|
usage_error(e.message)
|
|
65
60
|
end
|
|
66
61
|
|
|
62
|
+
# The parser this command parses with, built without parsing anything: the catalogue reads the
|
|
63
|
+
# flags and formats from it (ADR-126 WD3). `options` is only written by the switches' blocks.
|
|
64
|
+
def option_parser(options = {})
|
|
65
|
+
OptionParser.new do |opts|
|
|
66
|
+
opts.banner = "Usage: rigor effects #{@verb} [options]"
|
|
67
|
+
Options.add_config(opts, options)
|
|
68
|
+
add_common_options(opts, options)
|
|
69
|
+
add_comparison_options(opts, options) if COMPARING_VERBS.include?(@verb)
|
|
70
|
+
if @verb == "explain"
|
|
71
|
+
opts.on("--symbol=KEY", "Explain this unit instead of the changed ones") do |value|
|
|
72
|
+
options[:symbol] = value
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
67
78
|
private
|
|
68
79
|
|
|
69
80
|
def execute(options)
|
|
@@ -80,7 +91,14 @@ module Rigor
|
|
|
80
91
|
# exists" hazard: it records observations, so overwriting it is the whole point of running it.
|
|
81
92
|
def write(configuration, snapshot)
|
|
82
93
|
path = configuration.effects_snapshot_path
|
|
83
|
-
|
|
94
|
+
begin
|
|
95
|
+
File.write(path, snapshot.to_yaml)
|
|
96
|
+
rescue SystemCallError => e
|
|
97
|
+
# #2576 — an `effects.snapshot.path:` that cannot be written is a usage error, the same rule
|
|
98
|
+
# `rigor init --path` follows (#2562): one line on stderr and exit 64, no backtrace.
|
|
99
|
+
@err.puts("rigor effects: cannot write #{path}: #{e.message.sub(/ @ .*\z/m, '')}")
|
|
100
|
+
return CLI::EXIT_USAGE
|
|
101
|
+
end
|
|
84
102
|
@err.puts("rigor: wrote #{path} (#{snapshot.methods.size} method(s), #{snapshot.reach.size} reach entr" \
|
|
85
103
|
"#{snapshot.reach.size == 1 ? 'y' : 'ies'})")
|
|
86
104
|
# #436 — the note names what to write, not only what is missing: the same per-project preset
|
|
@@ -273,17 +291,7 @@ module Rigor
|
|
|
273
291
|
def parse_options
|
|
274
292
|
options = { config: nil, format: "text", full: false, baseline: nil, symbol: nil,
|
|
275
293
|
strict_tolerated: false, no_tolerated: false }
|
|
276
|
-
|
|
277
|
-
opts.banner = "Usage: rigor effects #{@verb} [options]"
|
|
278
|
-
Options.add_config(opts, options)
|
|
279
|
-
add_common_options(opts, options)
|
|
280
|
-
add_comparison_options(opts, options) if COMPARING_VERBS.include?(@verb)
|
|
281
|
-
if @verb == "explain"
|
|
282
|
-
opts.on("--symbol=KEY", "Explain this unit instead of the changed ones") do |value|
|
|
283
|
-
options[:symbol] = value
|
|
284
|
-
end
|
|
285
|
-
end
|
|
286
|
-
end.parse!(@argv)
|
|
294
|
+
option_parser(options).parse!(@argv)
|
|
287
295
|
options
|
|
288
296
|
end
|
|
289
297
|
|
|
@@ -292,7 +300,7 @@ module Rigor
|
|
|
292
300
|
# byte-identical files. A flag that changed the record would make the file a function of policy and
|
|
293
301
|
# a policy change indistinguishable from a code change.
|
|
294
302
|
def add_common_options(opts, options)
|
|
295
|
-
|
|
303
|
+
Options.add_format(opts, options, "Output format: text (default) or json")
|
|
296
304
|
opts.on("--full", "Record every method, including the omitted trivial and synthesised ones") do
|
|
297
305
|
options[:full] = true
|
|
298
306
|
end
|