rigortype 0.4.6 → 0.4.7
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 +2 -2
- data/data/gem_overlay/activesupport/core_ext.rbs +16 -13
- 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 +5 -2
- data/docs/handbook/11-sig-gen.md +50 -3
- data/docs/handbook/appendix-phpstan.md +4 -4
- data/docs/manual/02-cli-reference.md +152 -26
- data/docs/manual/03-configuration.md +36 -3
- data/docs/manual/06-baseline.md +6 -4
- data/docs/manual/09-editor-integration.md +13 -2
- data/docs/manual/10-mcp-server.md +38 -2
- data/docs/manual/12-caching.md +4 -3
- data/docs/manual/plugins/rigor-actionpack.md +19 -11
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +20 -1
- data/lib/rigor/analysis/baseline.rb +24 -27
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +5 -6
- data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +2 -2
- data/lib/rigor/analysis/check_rules/declaration_sourced_guard.rb +4 -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 +3 -2
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +0 -1
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +5 -8
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +1 -1
- data/lib/rigor/analysis/check_rules/rebinding_block_callees.rb +3 -3
- data/lib/rigor/analysis/check_rules/return_in_ensure_collector.rb +1 -2
- data/lib/rigor/analysis/check_rules/rule_ids.rb +1 -1
- 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 +1 -1
- data/lib/rigor/analysis/check_rules.rb +124 -44
- data/lib/rigor/analysis/crash_signature.rb +2 -2
- data/lib/rigor/analysis/dependency_recorder.rb +4 -4
- 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_run_slot/write_guard.rb +2 -2
- data/lib/rigor/analysis/incremental_run_slot.rb +2 -2
- data/lib/rigor/analysis/incremental_session.rb +27 -16
- data/lib/rigor/analysis/rule_catalog.rb +2 -2
- data/lib/rigor/analysis/run_stats.rb +2 -2
- data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +2 -2
- data/lib/rigor/analysis/runner/declaration_position.rb +1 -1
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +193 -93
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +1 -1
- data/lib/rigor/analysis/runner/pool_coordinator.rb +147 -323
- data/lib/rigor/analysis/runner/project_pre_passes.rb +3 -3
- 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 +77 -71
- data/lib/rigor/analysis/self_call_resolution_recorder.rb +1 -1
- 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 +24 -31
- data/lib/rigor/bleeding_edge.rb +3 -6
- 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/incremental_snapshot.rb +31 -12
- 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 +54 -3
- data/lib/rigor/cache/rbs_environment.rb +4 -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 +145 -55
- data/lib/rigor/cli/catalogue.rb +256 -0
- data/lib/rigor/cli/check_command.rb +108 -102
- 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 +18 -17
- 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 +12 -8
- 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 +84 -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 +1 -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 +209 -54
- data/lib/rigor/config_audit.rb +1 -1
- data/lib/rigor/configuration/severity_profile.rb +5 -5
- data/lib/rigor/configuration.rb +72 -30
- 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 +5 -9
- data/lib/rigor/environment/class_registry.rb +3 -3
- data/lib/rigor/environment/core_root.rb +77 -0
- data/lib/rigor/environment/default_libraries.rb +1 -1
- data/lib/rigor/environment/deferred_signature_plan.rb +283 -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/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_hierarchy.rb +6 -15
- data/lib/rigor/environment/rbs_loader.rb +480 -67
- 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 +41 -10
- data/lib/rigor/flow_contribution/merger.rb +4 -4
- data/lib/rigor/inference/acceptance.rb +93 -32
- data/lib/rigor/inference/block_parameter_binder.rb +2 -3
- data/lib/rigor/inference/block_run_count.rb +178 -0
- data/lib/rigor/inference/budget_trace.rb +8 -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/construction_escape.rb +217 -0
- data/lib/rigor/inference/declaration_walk/traversal.rb +1 -1
- 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 +1 -1
- data/lib/rigor/inference/def_return_typer.rb +46 -4
- data/lib/rigor/inference/definer_resolution.rb +4 -2
- data/lib/rigor/inference/definers_index.rb +106 -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/expression_typer.rb +116 -49
- data/lib/rigor/inference/external_ancestor_resolution.rb +3 -4
- data/lib/rigor/inference/global_write_census.rb +76 -2
- 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/indexed_narrowing.rb +4 -7
- data/lib/rigor/inference/intervening_ivar_reset.rb +26 -4
- data/lib/rigor/inference/ivar_writer_census.rb +51 -0
- data/lib/rigor/inference/key_presence_guard.rb +2 -1
- data/lib/rigor/inference/loop_value_record.rb +8 -4
- data/lib/rigor/inference/match_rebinding/frame.rb +46 -0
- data/lib/rigor/inference/match_rebinding/yielding_match.rb +45 -0
- data/lib/rigor/inference/match_rebinding.rb +11 -1
- data/lib/rigor/inference/memo_audit.rb +55 -0
- 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 +1 -1
- 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/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 +39 -27
- data/lib/rigor/inference/method_dispatcher/random_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +203 -17
- 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 +2 -2
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +9 -7
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +83 -20
- 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/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 +64 -14
- data/lib/rigor/inference/module_function_state.rb +11 -1
- data/lib/rigor/inference/multi_target_binder.rb +1 -1
- data/lib/rigor/inference/mutation_rejoin.rb +240 -4
- data/lib/rigor/inference/mutation_widening.rb +157 -27
- data/lib/rigor/inference/narrowing.rb +47 -33
- data/lib/rigor/inference/optimistic_origin.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/project_method_ownership.rb +6 -3
- data/lib/rigor/inference/project_yielder.rb +11 -17
- data/lib/rigor/inference/receiver_alias.rb +20 -0
- data/lib/rigor/inference/refined_dispatch/constructed_class.rb +3 -1
- data/lib/rigor/inference/refined_dispatch/own_method.rb +2 -1
- data/lib/rigor/inference/remover_holder_scan.rb +233 -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/constant_ivar_value.rb +93 -0
- data/lib/rigor/inference/scope_indexer/declared_param_writes.rb +58 -15
- 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 +135 -0
- data/lib/rigor/inference/scope_indexer.rb +137 -46
- data/lib/rigor/inference/self_call_ivar_writes.rb +84 -12
- data/lib/rigor/inference/set_mutation.rb +189 -0
- data/lib/rigor/inference/singleton_hook_decline.rb +1 -2
- data/lib/rigor/inference/statement_evaluator.rb +2328 -138
- data/lib/rigor/inference/struct_fold_safety.rb +4 -6
- data/lib/rigor/inference/synthetic_method_scanner.rb +5 -6
- data/lib/rigor/inference/toplevel_def_census.rb +59 -0
- data/lib/rigor/inference/unknown_store_widening.rb +103 -4
- data/lib/rigor/inference/unthreaded_rebinds.rb +2 -3
- data/lib/rigor/inference/void_tail_summary.rb +2 -1
- 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/plugins.rb +1 -1
- data/lib/rigor/mcp/server.rb +73 -2
- data/lib/rigor/mcp.rb +1 -1
- data/lib/rigor/plugin/access_denied_error.rb +1 -2
- data/lib/rigor/plugin/bundled_catalog.rb +1 -12
- data/lib/rigor/plugin/io_boundary.rb +1 -1
- 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 +9 -13
- data/lib/rigor/plugin/registry.rb +3 -3
- 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 +2 -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/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 +5 -3
- data/lib/rigor/rooted_glob.rb +15 -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 +19 -6
- data/lib/rigor/scope/resolution_chain.rb +3 -1
- data/lib/rigor/scope.rb +365 -31
- data/lib/rigor/sig_gen/classification.rb +4 -0
- data/lib/rigor/sig_gen/effect_annotation.rb +3 -3
- data/lib/rigor/sig_gen/generator.rb +371 -58
- 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 +23 -4
- data/lib/rigor/sig_gen/observation_collector.rb +3 -5
- 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/renderer.rb +15 -9
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +15 -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 +217 -37
- 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 +9 -13
- data/lib/rigor/type/constant.rb +4 -5
- data/lib/rigor/type/hash_shape.rb +21 -40
- data/lib/rigor/type/union.rb +1 -1
- 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/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 +1 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +66 -19
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +4 -3
- 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 +2 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +0 -1
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +5 -4
- 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 +7 -12
- 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 +19 -6
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +26 -13
- 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 +4 -5
- 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-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 +2 -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 +1 -3
- 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 +1 -1
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +2 -1
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +1 -1
- 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 +1 -1
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +2 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +17 -21
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +2 -3
- data/plugins/rigor-typelizer/lib/rigor/plugin/typelizer/serializer_discoverer.rb +3 -2
- 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/fact_store.rbs +1 -0
- data/sig/rigor/analysis/reachability/scan_cache.rbs +1 -1
- 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/inference.rbs +4 -1
- data/sig/rigor/plugin/additional_initializer.rbs +0 -5
- data/sig/rigor/plugin/base.rbs +1 -0
- 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/io_boundary.rbs +2 -1
- data/sig/rigor/plugin/manifest.rbs +9 -9
- data/sig/rigor/plugin/protocol_contract.rbs +3 -7
- data/sig/rigor/scope.rbs +23 -3
- 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/03-baseline-and-bugs.md +12 -1
- metadata +36 -3
|
@@ -16,7 +16,7 @@ module Rigor
|
|
|
16
16
|
#
|
|
17
17
|
# Scope:
|
|
18
18
|
#
|
|
19
|
-
# - Recognises the standard
|
|
19
|
+
# - Recognises the standard controllers (`:sessions`, `:passwords`, `:confirmations`, `:unlocks`,
|
|
20
20
|
# `:registrations`, `:omniauth_callbacks`).
|
|
21
21
|
# - Honours `skip: [...]` to suppress controllers the project disables.
|
|
22
22
|
# - Honours `path: "..."` to remap the URL path (does NOT remap the helper-name prefix — Devise uses
|
|
@@ -162,8 +162,7 @@ module Rigor
|
|
|
162
162
|
OMNIAUTH_SUFFIXES
|
|
163
163
|
end
|
|
164
164
|
|
|
165
|
-
# ADR-39 — delegates to the shared inflector (real `ActiveSupport::Inflector` when available)
|
|
166
|
-
# replacing the tiny AS-replica this module used to duplicate from `RoutesParser`.
|
|
165
|
+
# ADR-39 — delegates to the shared inflector (real `ActiveSupport::Inflector` when available).
|
|
167
166
|
def singularize(word)
|
|
168
167
|
Rigor::Plugin::Inflector.singularize(word)
|
|
169
168
|
end
|
|
@@ -7,7 +7,7 @@ require "prism"
|
|
|
7
7
|
module Rigor
|
|
8
8
|
module Plugin
|
|
9
9
|
class RailsRoutes < Rigor::Plugin::Base
|
|
10
|
-
# Walks
|
|
10
|
+
# Walks the configured `helper_paths:` directories (default `app/`) and extracts every public
|
|
11
11
|
# module-level method name so the analyzer's `unknown-helper` rule does not false-fire on calls to
|
|
12
12
|
# project-defined `*_path` / `*_url` helpers (the canonical Rails pattern: a `UrlHelper` module
|
|
13
13
|
# exposing `full_asset_url`, `host_to_url`, `frontend_asset_url`, and so on).
|
|
@@ -409,14 +409,9 @@ module Rigor
|
|
|
409
409
|
end
|
|
410
410
|
end
|
|
411
411
|
|
|
412
|
-
# ADR-39: inflection delegates to the shared `Rigor::Plugin::Inflector`, which
|
|
413
|
-
# `ActiveSupport::Inflector` (the authority Rails
|
|
414
|
-
#
|
|
415
|
-
# AS-replica these methods used to carry — every special case they accreted (`news` uncountable,
|
|
416
|
-
# `media`→`medium`, `databases`→`database`, `custom_css` ss-preservation,
|
|
417
|
-
# `async_refresh`→`async_refreshes`) was reverse-engineered `ActiveSupport::Inflector` behaviour,
|
|
418
|
-
# so the real inflector produces the same result for those and the correct one for the words the
|
|
419
|
-
# replica never covered.
|
|
412
|
+
# ADR-39: inflection delegates to the shared `Rigor::Plugin::Inflector`, which uses the real
|
|
413
|
+
# `ActiveSupport::Inflector` (the authority Rails uses to generate helper names) when available,
|
|
414
|
+
# and a built-in approximation otherwise.
|
|
420
415
|
def singularize(word)
|
|
421
416
|
Rigor::Plugin::Inflector.singularize(word)
|
|
422
417
|
end
|
|
@@ -1286,7 +1281,7 @@ module Rigor
|
|
|
1286
1281
|
return nil unless plural
|
|
1287
1282
|
|
|
1288
1283
|
# Rails appends `_index_path` to the index helper name when the singular form of the resource
|
|
1289
|
-
# matches the plural form
|
|
1284
|
+
# matches the plural form (uncountable nouns included). The collision
|
|
1290
1285
|
# would otherwise put both the index (`:id`-less) and show (`:id`-bearing) helpers under the same
|
|
1291
1286
|
# name, and Rails disambiguates by suffixing the index form. Mastodon's `resources
|
|
1292
1287
|
# :reblogged_by, controller: :reblogged_by_accounts, only: :index` and similar rely on this —
|
|
@@ -1432,8 +1427,6 @@ module Rigor
|
|
|
1432
1427
|
end
|
|
1433
1428
|
|
|
1434
1429
|
# ADR-39 — delegates to the shared inflector (real `ActiveSupport::Inflector` when available).
|
|
1435
|
-
# Previously a hand-tuned AS-replica kept in sync with `Context#singularize`; both now share the
|
|
1436
|
-
# one authoritative implementation.
|
|
1437
1430
|
def singularize_word(word)
|
|
1438
1431
|
Rigor::Plugin::Inflector.singularize(word)
|
|
1439
1432
|
end
|
|
@@ -14,7 +14,7 @@ module Rigor
|
|
|
14
14
|
# rigor-rails-routes — validates Rails route-helper calls (`users_path`, `edit_user_path(@user)`, …)
|
|
15
15
|
# against the project's `config/routes.rb`.
|
|
16
16
|
#
|
|
17
|
-
# Tier 1A of the [Rails plugins roadmap](
|
|
17
|
+
# Tier 1A of the [Rails plugins roadmap](../../../../../docs/design/20260508-rails-plugins-roadmap.md).
|
|
18
18
|
# Statically interprets the routes DSL via Prism — no `rails` runtime dependency. Recognised v0.1.0
|
|
19
19
|
# surface:
|
|
20
20
|
#
|
|
@@ -35,7 +35,8 @@ module Rigor
|
|
|
35
35
|
class RbsInline < Rigor::Plugin::Base
|
|
36
36
|
# Synthesizer callable invoked once per project Ruby source file by `Environment.for_project` at
|
|
37
37
|
# env-build time. Returns the synthesised RBS source as a String, or `nil` when the file contributes
|
|
38
|
-
# nothing (no
|
|
38
|
+
# nothing (no annotation in the default mode, no magic comment under `require_magic_comment: true`,
|
|
39
|
+
# or a parse error per WD6).
|
|
39
40
|
class Synthesizer
|
|
40
41
|
# An RDoc directive comment: `#:` followed by a bare word (RDoc allows a hyphen, as in `:call-seq:`)
|
|
41
42
|
# and a closing colon. RDoc predates rbs-inline by about two decades and `#:<name>:` is
|
|
@@ -358,7 +358,7 @@ module Rigor
|
|
|
358
358
|
# signature, a core ancestor, or the project's source) is kept whole. `Object`, `BasicObject` and a module
|
|
359
359
|
# String or Symbol includes otherwise read `String | Symbol`, as the String they most often are, so a String
|
|
360
360
|
# method called after the matcher reports nothing. Any other module is UNDECIDED: a passing value may include
|
|
361
|
-
# it without being a String. (
|
|
361
|
+
# it without being a String. (Decision shared with #2256.)
|
|
362
362
|
def module_match_member(member, scope)
|
|
363
363
|
return nil unless member.is_a?(Rigor::Type::Nominal) && member.type_args.empty?
|
|
364
364
|
|
|
@@ -14,7 +14,7 @@ module Rigor
|
|
|
14
14
|
# narrows `expect(x).to MATCHER` assertions downstream, and binds `let`/`subject` locals to their
|
|
15
15
|
# inferred return types inside `it` bodies.
|
|
16
16
|
#
|
|
17
|
-
# Tier 3A of the [Rails plugins roadmap](
|
|
17
|
+
# Tier 3A of the [Rails plugins roadmap](../../../../../docs/design/20260508-rails-plugins-roadmap.md).
|
|
18
18
|
# Ships four checks:
|
|
19
19
|
#
|
|
20
20
|
# 1. **Duplicate `let` / `subject` declarations** in the same scope (`warning`). RSpec's runtime lets
|
|
@@ -44,7 +44,7 @@ module Rigor
|
|
|
44
44
|
# - **No shared-context resolution.** `include_context`, `shared_context`, and `it_behaves_like` are
|
|
45
45
|
# recognised as scope-opening calls but their declarations are not pulled into the host scope.
|
|
46
46
|
# - **Constant validation is not done here.** `RSpec.describe SomeClass do` does not validate
|
|
47
|
-
# `SomeClass`; the engine's
|
|
47
|
+
# `SomeClass`; the engine's constant-resolution diagnostics already catch that.
|
|
48
48
|
class Rspec < Rigor::Plugin::Base
|
|
49
49
|
manifest(
|
|
50
50
|
id: "rspec",
|
|
@@ -30,7 +30,7 @@ module Rigor
|
|
|
30
30
|
# - `route_to(...)` / `redirect_to(...)` — needs the routes table from `rigor-rails-routes`
|
|
31
31
|
# (`:helper_table` cross-plugin fact). Future slice.
|
|
32
32
|
# - `have_enqueued_job(JobClass)` / `have_enqueued_mail(MailerClass)` — class-existence check overlaps
|
|
33
|
-
# with engine's
|
|
33
|
+
# with the engine's constant-resolution diagnostics; queued behind a decision on which surface owns the
|
|
34
34
|
# diagnostic.
|
|
35
35
|
# - `have_received(:method)` — overlaps with engine's `call.undefined-method`; same coordination
|
|
36
36
|
# question.
|
|
@@ -44,9 +44,8 @@ module Rigor
|
|
|
44
44
|
description: "Validates rspec-rails behavioral matchers (have_http_status floor)."
|
|
45
45
|
)
|
|
46
46
|
|
|
47
|
-
# ADR-37 — the engine walks each file and hands us every CallNode; the analyzer is
|
|
48
|
-
# logic. The diagnostic points at the matcher name (`message_loc`)
|
|
49
|
-
# `message_loc || location` positioning.
|
|
47
|
+
# ADR-37 — the engine walks each file and hands us every CallNode; the analyzer is pure per-node
|
|
48
|
+
# logic. The diagnostic points at the matcher name (`message_loc`).
|
|
50
49
|
node_rule Prism::CallNode do |node, _scope, path|
|
|
51
50
|
violation = HaveHttpStatusAnalyzer.violation_for(node)
|
|
52
51
|
next [] unless violation
|
|
@@ -31,7 +31,7 @@ module Rigor
|
|
|
31
31
|
# have_db_index(:col)
|
|
32
32
|
#
|
|
33
33
|
# All look up `:col` against the model's `columns:` (the published `:model_index` fact's flat
|
|
34
|
-
#
|
|
34
|
+
# name list per model — see `Analyzer#column_names`). Unknown columns fire `unknown-column`.
|
|
35
35
|
#
|
|
36
36
|
# ### Association matchers
|
|
37
37
|
#
|
|
@@ -107,8 +107,7 @@ module Rigor
|
|
|
107
107
|
|
|
108
108
|
# A direct matcher invocation is a `CallNode` whose `name` is in `MATCHER_TABLE` and whose first
|
|
109
109
|
# argument is a `SymbolNode`. The chain shape (`should`, `expect(...).to`, `is_expected.to`) is
|
|
110
|
-
# irrelevant
|
|
111
|
-
# regardless of the surrounding chain.
|
|
110
|
+
# irrelevant: the engine visits the inner matcher call, so the diagnostic fires on it regardless.
|
|
112
111
|
def matcher_invocation?(node)
|
|
113
112
|
node.is_a?(Prism::CallNode) && MATCHER_TABLE.key?(node.name) && symbol_first_arg?(node)
|
|
114
113
|
end
|
|
@@ -172,11 +171,10 @@ module Rigor
|
|
|
172
171
|
end
|
|
173
172
|
|
|
174
173
|
# `entry` is the published fact's per-model Hash: `{ table:, columns:, associations:, ... }`.
|
|
175
|
-
# `columns:` is a flat
|
|
176
|
-
#
|
|
177
|
-
#
|
|
178
|
-
#
|
|
179
|
-
# read here.
|
|
174
|
+
# `columns:` is a flat list of column names (`Activerecord#index_to_published_hash`); `associations:`
|
|
175
|
+
# is a list of rows with `:name`, `:kind` (`:singular` | `:collection`), `:nullable`, `:polymorphic`,
|
|
176
|
+
# and a `:target` that is nil on polymorphic rows — the row shape `ModelDiscoverer#build_association_row`
|
|
177
|
+
# publishes. Only `:name` and `:kind` are read here.
|
|
180
178
|
def column_names(entry) = entry[:columns] || []
|
|
181
179
|
def association_rows(entry) = entry[:associations] || []
|
|
182
180
|
def find_association(entry, name) = association_rows(entry).find { |a| a[:name] == name.to_s }
|
|
@@ -98,9 +98,10 @@ module Rigor
|
|
|
98
98
|
# Cached separately from `:worker_index` because the two invalidate on different files: editing a
|
|
99
99
|
# schedule changes which workers are reached without touching `app/workers` at all. The `watch:` roots
|
|
100
100
|
# the glob at the working directory so that CREATING a schedule file — not just editing one — is seen. Each
|
|
101
|
-
# configured path is escaped to a literal name, so `sidekiq[1].yml` is watched as that file
|
|
101
|
+
# configured path is escaped to a literal name, so `sidekiq[1].yml` is watched as that file, and an
|
|
102
|
+
# absolute path is watched under its own directory (`RootedGlob.split_file`, #2222).
|
|
102
103
|
producer :scheduled_workers,
|
|
103
|
-
watch: -> {
|
|
104
|
+
watch: -> { @schedule_paths.map { |path| Rigor::RootedGlob.split_file(path) } } do |_params|
|
|
104
105
|
ScheduleScan.new(
|
|
105
106
|
io_boundary: io_boundary,
|
|
106
107
|
schedule_paths: @schedule_paths
|
|
@@ -31,11 +31,10 @@ module Rigor
|
|
|
31
31
|
# behaviour: it always raises). This lets the engine's existing flow analysis treat code after
|
|
32
32
|
# `T.absurd` as unreachable, matching what users of Sorbet expect.
|
|
33
33
|
# - When the branch is REACHABLE (the discriminant's type isn't `bot`), the recogniser also records
|
|
34
|
-
# the call node in a per-plugin set. The plugin's
|
|
35
|
-
# `
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
# `diagnostics_for_file`.
|
|
34
|
+
# the call node in a per-plugin set. The plugin's node rule later emits a
|
|
35
|
+
# `plugin.sorbet.absurd-reachable` warning for each recorded call node, matched by object identity.
|
|
36
|
+
# We rely on the runner only parsing each file once per run, so the same Prism node object is seen
|
|
37
|
+
# in both the `dynamic_return` rule and the node rule.
|
|
39
38
|
module AbsurdRecognizer
|
|
40
39
|
# @return true when `call_node` is `T.absurd(x)`.
|
|
41
40
|
def self.absurd_call?(call_node)
|
|
@@ -21,7 +21,7 @@ module Rigor
|
|
|
21
21
|
# | `T.unsafe(x)` | return type ← `Dynamic[top]` |
|
|
22
22
|
# | `T.reveal_type(expr)` | return type ← `inferred(expr)` (passes through) |
|
|
23
23
|
# | `T.assert_type!(expr, T)` | return type ← translated `T` + static subtype check |
|
|
24
|
-
# | `T.bind(self, T)` | return type ← `Constant[nil]` +
|
|
24
|
+
# | `T.bind(self, T)` | return type ← `Constant[nil]` + `self` narrowing fact |
|
|
25
25
|
#
|
|
26
26
|
# The Sorbet runtime's `T.let` / `T.cast` actually return the inner expression unchanged at runtime;
|
|
27
27
|
# their job is purely to *assert* a static type. From Rigor's static perspective the simplest
|
|
@@ -36,7 +36,7 @@ module Rigor
|
|
|
36
36
|
# `T.reveal_type` is "diagnostic-only" in Sorbet: it passes the value through unchanged at runtime
|
|
37
37
|
# AND surfaces the inferred static type as a build-time message. The recogniser contributes the
|
|
38
38
|
# inferred type (so chained call sites still resolve as if the `T.reveal_type` wrapper weren't
|
|
39
|
-
# there); the plugin's
|
|
39
|
+
# there); the plugin's node rule surfaces the `plugin.sorbet.reveal-type` `:info`
|
|
40
40
|
# message for human consumption.
|
|
41
41
|
#
|
|
42
42
|
# `T.bind(self, T)` is recognised as block-scope self narrowing. The recogniser returns a
|
|
@@ -113,9 +113,9 @@ module Rigor
|
|
|
113
113
|
|
|
114
114
|
# `T.assert_type!(expr, T)` shares the typed-assertion contribution shape with `T.cast` (return is
|
|
115
115
|
# the asserted type), so the recogniser delegates the return-type half through
|
|
116
|
-
# `resolve_typed_assertion`. The static subtype check that distinguishes `assert_type!` from
|
|
117
|
-
#
|
|
118
|
-
#
|
|
116
|
+
# `resolve_typed_assertion`. The static subtype check that distinguishes `assert_type!` from `cast`
|
|
117
|
+
# is run by the plugin's `record_assert_type_check`, which records a mismatch for the node rule to
|
|
118
|
+
# emit (the absurd-recognizer pattern).
|
|
119
119
|
def assert_type_check(call_node, scope)
|
|
120
120
|
return nil if scope.nil?
|
|
121
121
|
|
|
@@ -135,8 +135,7 @@ module Rigor
|
|
|
135
135
|
# `T.reveal_type(expr)` returns `expr` unchanged at runtime; the Sorbet-side semantics is "make
|
|
136
136
|
# the inferred static type visible to the user." The contribution mirrors `T.must` minus the
|
|
137
137
|
# nil-stripping: the call's return type is the inner expression's inferred type. The companion
|
|
138
|
-
# diagnostic is emitted by
|
|
139
|
-
# contribution only.
|
|
138
|
+
# diagnostic is emitted by a node rule; this method handles the contribution only.
|
|
140
139
|
def resolve_reveal_type(call_node, scope)
|
|
141
140
|
inner = nth_argument(call_node, 0)
|
|
142
141
|
return Rigor::Type::Combinator.untyped if inner.nil? || scope.nil?
|
|
@@ -57,7 +57,7 @@ module Rigor
|
|
|
57
57
|
@entries[key_for(class_name, method_name, kind)]
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
-
# @return frozen
|
|
60
|
+
# @return frozen `:include` / `:extend` buckets of mixed-in module names.
|
|
61
61
|
# Returns {EMPTY_MIXINS} when no mixins were recorded.
|
|
62
62
|
def mixins_for(class_name)
|
|
63
63
|
@mixins[class_name] || EMPTY_MIXINS
|
|
@@ -22,8 +22,8 @@ module Rigor
|
|
|
22
22
|
#
|
|
23
23
|
# The parser walks the chain right-to-left, gathering whatever it recognises (`params` / `returns` /
|
|
24
24
|
# `void` / `abstract` / `override` / `overridable` / `final` / `type_parameters` / `checked` /
|
|
25
|
-
# `on_failure`) into a frozen result hash stored in {MethodSignature}. Modifiers
|
|
26
|
-
# `type_parameters`
|
|
25
|
+
# `on_failure`) into a frozen result hash stored in {MethodSignature}. Modifiers are recorded but not
|
|
26
|
+
# yet acted on; `type_parameters` is recognised and its payload discarded.
|
|
27
27
|
#
|
|
28
28
|
# The parser is intentionally tolerant — unknown chain nodes degrade to "the rest of the chain is
|
|
29
29
|
# opaque" rather than raising. The plugin emits a diagnostic (`plugin.sorbet.parse-error`) only when
|
|
@@ -42,8 +42,8 @@ module Rigor
|
|
|
42
42
|
# `IoBoundary`. The catalog is frozen after the first build and consulted by the `dynamic_return` rule
|
|
43
43
|
# at every gated call site. RBI files share the catalog with project-source sigs — both produce
|
|
44
44
|
# `MethodSignature` entries keyed by `(class_name, method_name, kind)`. When a key collides across
|
|
45
|
-
# files, the last-walked sig wins (
|
|
46
|
-
#
|
|
45
|
+
# files, the last-walked sig wins (`Dir.glob` results are sorted, so the walk order is stable).
|
|
46
|
+
# Sorbet's full shim-override semantics — `sorbet/rbi/shims/` overriding
|
|
47
47
|
# `sorbet/rbi/gems/` — lands in a later slice once the catalog gains per-source provenance.
|
|
48
48
|
#
|
|
49
49
|
# The plugin emits `plugin.sorbet.parse-error` warnings for malformed sig blocks (no block / empty
|
|
@@ -79,12 +79,10 @@ module Rigor
|
|
|
79
79
|
"rbi_paths" => { kind: :array, default: ["sorbet/rbi"] },
|
|
80
80
|
"enforce_sigil" => { kind: :boolean, default: true }
|
|
81
81
|
},
|
|
82
|
-
# #1097 — bundled sorbet-runtime DSL surface (`sig/sorbet.rbs`). `sig`
|
|
83
|
-
#
|
|
84
|
-
#
|
|
85
|
-
#
|
|
86
|
-
# `T::Helpers` / `T::Generic`, and `rbs_complete_ancestors:` carries the Struct/Enum family
|
|
87
|
-
# for the subclass bridge.
|
|
82
|
+
# #1097 — bundled sorbet-runtime DSL surface (`sig/sorbet.rbs`). `sig` reaches the class object
|
|
83
|
+
# through `extend T::Sig` (or the `T::Struct` / `T::Enum` family, which carry the edge themselves):
|
|
84
|
+
# `rbs_complete_extends:` is that extend-edge allow-list, and `rbs_complete_ancestors:` carries the
|
|
85
|
+
# Struct/Enum family for the subclass bridge.
|
|
88
86
|
signature_paths: ["sig"],
|
|
89
87
|
rbs_complete_extends: %w[T::Sig T::Helpers T::Generic],
|
|
90
88
|
rbs_complete_ancestors: %w[T::Struct T::InexactStruct T::ImmutableStruct T::Enum],
|
|
@@ -122,8 +120,7 @@ module Rigor
|
|
|
122
120
|
@configured_paths = Array(config.fetch("paths", services.configuration.paths)).map(&:to_s)
|
|
123
121
|
@rbi_paths = Array(config.fetch("rbi_paths")).map(&:to_s)
|
|
124
122
|
# Schema default `true` — only files marked `# typed: true` / `:strict` / `:strong` contribute
|
|
125
|
-
# their sigs. Set to `false` to record every file's sigs regardless of sigil
|
|
126
|
-
# pre-this-config).
|
|
123
|
+
# their sigs. Set to `false` to record every file's sigs regardless of sigil.
|
|
127
124
|
@enforce_sigil = config.fetch("enforce_sigil")
|
|
128
125
|
# Per-call-site assertion gating: `@sigil_by_path` (built during catalog harvest) is consulted so
|
|
129
126
|
# `T.let` / `T.cast` / `T.must` / `T.bind` / `T.assert_type!` only fire in files Sorbet itself
|
|
@@ -135,20 +132,20 @@ module Rigor
|
|
|
135
132
|
@parse_errors_by_path = {}
|
|
136
133
|
@catalog_built = false
|
|
137
134
|
# ADR-11 slice 6 — Prism nodes for `T.absurd` calls we observed in the `dynamic_return` rule to be
|
|
138
|
-
# *reachable* (i.e., their discriminant didn't narrow to `bot`).
|
|
139
|
-
#
|
|
140
|
-
#
|
|
141
|
-
#
|
|
135
|
+
# *reachable* (i.e., their discriminant didn't narrow to `bot`). The node rule below surfaces these
|
|
136
|
+
# as `plugin.sorbet.absurd-reachable` warnings. The Hash is keyed by node identity
|
|
137
|
+
# (`compare_by_identity`) because the runner only parses each file once per run, so identity is
|
|
138
|
+
# stable across the two plugin hooks.
|
|
142
139
|
@reachable_absurd_nodes = {}.compare_by_identity
|
|
143
140
|
# ADR-11 light follow-up — `T.reveal_type` calls observed in the `dynamic_return` rule, paired
|
|
144
141
|
# with the display string for the inferred type at the call site. Mirrors the absurd-node
|
|
145
|
-
# compare-by-identity hash;
|
|
142
|
+
# compare-by-identity hash; the node rule below surfaces each entry as a
|
|
146
143
|
# `plugin.sorbet.reveal-type` `:info` diagnostic.
|
|
147
144
|
@reveal_type_calls = {}.compare_by_identity
|
|
148
145
|
# T.bind / T.assert_type! priority slice 1 — `T.assert_type!` calls observed in the
|
|
149
146
|
# `dynamic_return` rule whose static subtype check FAILED, paired with the inferred + asserted
|
|
150
|
-
# type display strings. Same compare-by-identity discipline.
|
|
151
|
-
#
|
|
147
|
+
# type display strings. Same compare-by-identity discipline. The node rule below surfaces matching
|
|
148
|
+
# entries as
|
|
152
149
|
# `plugin.sorbet.assert-type-mismatch` `:error` diagnostics.
|
|
153
150
|
@assert_type_mismatches = {}.compare_by_identity
|
|
154
151
|
end
|
|
@@ -245,7 +242,7 @@ module Rigor
|
|
|
245
242
|
# analysis treats code after it as unreachable; the legacy contribution's `exceptional: :raises`
|
|
246
243
|
# slot was never consumed on the dispatcher path — only `return_type` survives the merge). When
|
|
247
244
|
# the discriminant *isn't* narrowed to `bot` at this scope, also records the call node so
|
|
248
|
-
#
|
|
245
|
+
# the node rule can surface a `plugin.sorbet.absurd-reachable` warning.
|
|
249
246
|
if AbsurdRecognizer.absurd_call?(call_node)
|
|
250
247
|
@reachable_absurd_nodes[call_node] = true unless AbsurdRecognizer.exhaustive?(call_node, scope)
|
|
251
248
|
return Rigor::Type::Combinator.bot
|
|
@@ -255,7 +252,7 @@ module Rigor
|
|
|
255
252
|
# cheaper to recognise (no catalog walk required) and they win over any cataloged signature: the
|
|
256
253
|
# user explicitly asserted the type at the call site. The light follow-up extends the recogniser
|
|
257
254
|
# to `T.must_because` (alias of `T.must`) and `T.reveal_type` (passes the type through; the
|
|
258
|
-
# human-facing diagnostic is recorded here for
|
|
255
|
+
# human-facing diagnostic is recorded here for the node rule to emit).
|
|
259
256
|
#
|
|
260
257
|
# Per-call-site sigil gating: with `enforce_sigil: true` (default), assertions only fire in files
|
|
261
258
|
# Sorbet itself would enforce. Files at `# typed: false` (or sigil-less, which Sorbet treats as
|
|
@@ -502,8 +499,7 @@ module Rigor
|
|
|
502
499
|
# ADR-88 WD2 — deterministic fold order matters now that the catalog VALUE is digested into the
|
|
503
500
|
# incremental fact-surface fingerprint: a duplicate `(class, method, kind)` sig's last-wins winner
|
|
504
501
|
# must not vary by machine / run. `Dir.glob` sorts its results by default on Ruby 3.0+, so the fold
|
|
505
|
-
# order is already stable
|
|
506
|
-
# this walk relies on it rather than re-sorting.
|
|
502
|
+
# order is already stable; this walk relies on it rather than re-sorting.
|
|
507
503
|
Dir.glob("**/*#{ext}", base: absolute).each do |relative|
|
|
508
504
|
harvest_file(canonicalize(File.join(absolute, relative)), catalog, sigil_by_path, parse_errors_by_path)
|
|
509
505
|
end
|
|
@@ -11,9 +11,8 @@ module Rigor
|
|
|
11
11
|
#
|
|
12
12
|
# 1. **Collect pass.** Walk the file once to gather every state name declared inside a
|
|
13
13
|
# `state_machine do ... end` block (`state :draft`, `state :submitted`, ...).
|
|
14
|
-
# 2. **Validate pass.** Walk the file again, validating each `transition_to(:sym)`
|
|
15
|
-
#
|
|
16
|
-
# suggestions.
|
|
14
|
+
# 2. **Validate pass.** Walk the file again, validating each `transition_to(:sym)` reference against
|
|
15
|
+
# the collected state set. `DidYouMean::SpellChecker` drives the did-you-mean suggestions.
|
|
17
16
|
#
|
|
18
17
|
# Useful for `aasm` / `statesman` / hand-rolled DSLs and any framework where declarations and uses
|
|
19
18
|
# live in the same file. The same skeleton lifts to GraphQL types, ActiveModel validations, route
|
|
@@ -10,8 +10,9 @@ require_relative "serializer_index"
|
|
|
10
10
|
module Rigor
|
|
11
11
|
module Plugin
|
|
12
12
|
class Typelizer < Rigor::Plugin::Base
|
|
13
|
-
# Reads every `.rb` file under the configured typelizer dirs and the project's `paths:` through the
|
|
14
|
-
# {SerializerCollector} over each and merges the results into one
|
|
13
|
+
# Reads every `.rb` file under the configured typelizer dirs and the project's `paths:` through the
|
|
14
|
+
# plugin's `IoBoundary`, runs a {SerializerCollector} over each and merges the results into one
|
|
15
|
+
# {SerializerIndex}.
|
|
15
16
|
class SerializerDiscoverer
|
|
16
17
|
def initialize(io_boundary:, dirs:, project_paths: [])
|
|
17
18
|
@io_boundary = io_boundary
|
|
@@ -3,16 +3,16 @@
|
|
|
3
3
|
module Rigor
|
|
4
4
|
module Plugin
|
|
5
5
|
class Typelizer < Rigor::Plugin::Base
|
|
6
|
-
# The project's classes (every file of the project's `paths:` and the typelizer `dirs`), as the
|
|
7
|
-
# object the `:serializer_index` producer caches.
|
|
6
|
+
# The project's classes (every file of the project's `paths:` and the typelizer `dirs`), as the
|
|
7
|
+
# {SerializerCollector} found them. A frozen value object the `:serializer_index` producer caches.
|
|
8
8
|
#
|
|
9
9
|
# {#roots} answers the one question, conservatively — a wrong "no" costs a missing root, a wrong "yes"
|
|
10
10
|
# hides a dead class.
|
|
11
11
|
class SerializerIndex
|
|
12
12
|
# A class the project declares. `superclass` is the constant as written (`nil` when absent) and
|
|
13
13
|
# `nesting` the `Module.nesting` chain (innermost first) its header was written under, which is where
|
|
14
|
-
# Ruby resolves that constant. `dsl` is true when its body includes or extends `Typelizer::DSL`;
|
|
15
|
-
# typelizer `dirs` declares it (only such a class is published as a root).
|
|
14
|
+
# Ruby resolves that constant. `dsl` is true when its body includes or extends `Typelizer::DSL`;
|
|
15
|
+
# `in_dirs` when a file under the typelizer `dirs` declares it (only such a class is published as a root).
|
|
16
16
|
ClassEntry = Data.define(:name, :superclass, :nesting, :dsl, :in_dirs)
|
|
17
17
|
|
|
18
18
|
def initialize(classes:)
|
|
@@ -66,9 +66,6 @@ module Rigor
|
|
|
66
66
|
|
|
67
67
|
# Always an Array of Bucket — `initialize` freezes what it is given and every caller hands it
|
|
68
68
|
# Bucket instances (parse_row rows, from_diagnostics groups, `without`'s reject, or `[]`).
|
|
69
|
-
# sig-gen gap: #2321 — `initialize` assigns `buckets.freeze`, an expression derived from the
|
|
70
|
-
# parameter rather than a bare read of it, so the reader is skipped (untyped return) and the element type
|
|
71
|
-
# is hand-written.
|
|
72
69
|
attr_reader buckets: Array[Bucket]
|
|
73
70
|
|
|
74
71
|
# `project_root` is `Pathname.new`'d, so a `Pathname` is accepted as well as a `String`
|
|
@@ -3,6 +3,7 @@ module Rigor
|
|
|
3
3
|
module CheckRules
|
|
4
4
|
def self?.diagnose: (path: String, root: untyped, scope_index: Hash[untyped, Scope]) -> Array[Diagnostic]
|
|
5
5
|
def self?.build_node_collectors: (String path, untyped scope_index, ?untyped root) -> Hash[Symbol, untyped]
|
|
6
|
+
# authored: returns Rigor::Analysis::CheckRules::RuleWalk::CollectorDriver, which has no RBS declaration yet (#2404); stays `untyped` until it is declared
|
|
6
7
|
def self?.node_collector_driver: (Hash[Symbol, untyped] collectors) -> untyped
|
|
7
8
|
def self?.shadow_verify_converged_collectors: (String path, untyped root, untyped scope_index, Hash[Symbol, untyped]? collectors) -> void
|
|
8
9
|
def self?.filter_suppressed: (Array[Diagnostic] diagnostics, comments: untyped, disabled_rules: Array[String]) -> Array[Diagnostic]
|
|
@@ -3,7 +3,7 @@ module Rigor
|
|
|
3
3
|
module Reachability
|
|
4
4
|
class ScanCache
|
|
5
5
|
def self.open: (untyped, ?target_ruby: untyped) -> Rigor::Analysis::Reachability::ScanCache
|
|
6
|
-
def self.source_digest: () -> String
|
|
6
|
+
def self.source_digest: () -> ("unreadable" | String)
|
|
7
7
|
def initialize: (path: untyped, header: untyped) -> void
|
|
8
8
|
def save: () -> nil
|
|
9
9
|
end
|
|
@@ -33,7 +33,7 @@ module Rigor
|
|
|
33
33
|
def self.load_file: (untyped path) -> Registry
|
|
34
34
|
|
|
35
35
|
attr_reader vocabulary_version: Integer
|
|
36
|
-
# sig-gen gap: #
|
|
36
|
+
# sig-gen gap: #2325 — `labels:` is declared `Array[untyped]` (input `untyped`, looks deliberate; a declared
|
|
37
37
|
# type is authoring intent tracked by #2325, and only then does this row generate; coercion-facing:
|
|
38
38
|
# `map(&:to_s)`); every declared label, sorted. Implied ancestors are recognised by {#known?} but not listed
|
|
39
39
|
# here.
|
|
@@ -42,7 +42,7 @@ module Rigor
|
|
|
42
42
|
# Unmarked residue: `@roots` is computed from `@known` in `initialize`, not assigned from a
|
|
43
43
|
# parameter, so no parameter credit applies.
|
|
44
44
|
attr_reader roots: Array[String]
|
|
45
|
-
# sig-gen gap: #
|
|
45
|
+
# sig-gen gap: #2325 — `descriptions:` is declared `Hash[untyped, untyped]` (input `untyped`, looks deliberate;
|
|
46
46
|
# a declared type is authoring intent tracked by #2325, and only then does this row generate; coercion-facing:
|
|
47
47
|
# keys and texts `to_s`'d); one line per root, from the data file's `descriptions:`.
|
|
48
48
|
attr_reader descriptions: Hash[String, String]
|
data/sig/rigor/inference.rbs
CHANGED
|
@@ -3,7 +3,8 @@ module Rigor
|
|
|
3
3
|
type closure_classification = :non_escaping | :escaping | :unknown
|
|
4
4
|
|
|
5
5
|
class ExpressionTyper
|
|
6
|
-
def self.harvest_return_memo: () -> Hash[untyped, Array[untyped]]
|
|
6
|
+
def self.harvest_return_memo: (?Hash[untyped, Hash[untyped, untyped]]? bucket) -> Hash[untyped, Array[untyped]]
|
|
7
|
+
def self.current_return_memo: () -> Hash[untyped, Hash[untyped, untyped]]?
|
|
7
8
|
def initialize: (scope: Scope, ?tracer: FallbackTracer?) -> void
|
|
8
9
|
def type_of: (untyped node) -> Type::t
|
|
9
10
|
def return_type_for: (untyped def_node, Type::t receiver, Array[Type::t] arg_types) -> Type::t?
|
|
@@ -172,6 +173,8 @@ module Rigor
|
|
|
172
173
|
def self?.collect_class_decls: (untyped node, Array[String] qualified_prefix, Hash[String, Type::t] accumulator) -> void
|
|
173
174
|
def self?.constant_writes_for_file: (untyped root) -> Hash[String, untyped]
|
|
174
175
|
def self?.constant_literal_value: (untyped rvalue) -> Array[untyped]?
|
|
176
|
+
# authored: the `Set[String]` values are source paths by contract; a Set's element type stays `untyped` in sig-gen (#2177, #2317), so the generator
|
|
177
|
+
# would never propose it.
|
|
175
178
|
def self?.finalize_constant_writes: (Hash[String, Hash[String, untyped]] writes) -> [Hash[String, Type::Constant], Hash[String, Set[String]]]
|
|
176
179
|
def self?.propagate: (untyped node, Hash[untyped, Scope] table, Scope parent_scope) -> void
|
|
177
180
|
|
|
@@ -4,15 +4,10 @@ module Rigor
|
|
|
4
4
|
# the read-before-write nil soundness gate does not widen their ivars. See
|
|
5
5
|
# lib/rigor/plugin/additional_initializer.rb for the full contract.
|
|
6
6
|
class AdditionalInitializer
|
|
7
|
-
# sig-gen gap: #2321 — `attr_reader` rows over ivars `initialize` assigns from expressions derived from its
|
|
8
|
-
# parameters are skipped (untyped return); the constructor validates `receiver_constraint` is a non-empty String
|
|
9
|
-
# and normalizes both lists with `map(&:to_sym)`, so the stored types are hand-written.
|
|
10
7
|
attr_reader receiver_constraint: String
|
|
11
8
|
|
|
12
|
-
# sig-gen gap: #2321 — as above.
|
|
13
9
|
attr_reader methods: Array[Symbol]
|
|
14
10
|
|
|
15
|
-
# sig-gen gap: #2321 — as above.
|
|
16
11
|
attr_reader block_methods: Array[Symbol]
|
|
17
12
|
|
|
18
13
|
# The validators accept Symbol or non-empty String elements; `initialize` normalizes to
|
data/sig/rigor/plugin/base.rbs
CHANGED
|
@@ -84,5 +84,6 @@ class Rigor::Plugin::Base
|
|
|
84
84
|
def effect_ancestry: () -> Array[Rigor::Plugin::EffectAncestry]
|
|
85
85
|
def io_boundary: () -> Rigor::Plugin::IoBoundary
|
|
86
86
|
def cache_for: (untyped producer_id, ?params: untyped, ?descriptor: untyped) -> Proc
|
|
87
|
+
# authored: returns Rigor::Cache::Descriptor::PluginEntry, which has no RBS declaration yet (#2404); stays `untyped` until it is declared
|
|
87
88
|
def plugin_entry: () -> untyped
|
|
88
89
|
end
|
|
@@ -19,7 +19,7 @@ module Rigor
|
|
|
19
19
|
# intent tracked by #2325, and only then does this row generate; coercion-facing: `to_s`), and `initialize`
|
|
20
20
|
# stores the private `validate_receiver!` helper's result (#2312).
|
|
21
21
|
attr_reader receiver: String
|
|
22
|
-
# sig-gen gap: #
|
|
22
|
+
# sig-gen gap: #2325 — `method:` is `untyped` (input `untyped`, looks deliberate; a declared type is authoring
|
|
23
23
|
# intent tracked by #2325, and only then does this row generate; coercion-facing: `String | Symbol`), stored as
|
|
24
24
|
# `method.to_sym`.
|
|
25
25
|
attr_reader method: Symbol
|
|
@@ -28,7 +28,7 @@ module Rigor
|
|
|
28
28
|
# intent tracked by #2325, and only then does this row generate; coercion-facing: `Array()` of anything
|
|
29
29
|
# answering `to_s`), stored from the private `normalize_labels` helper (#2312).
|
|
30
30
|
attr_reader labels: Array[String]
|
|
31
|
-
# sig-gen gap: #
|
|
31
|
+
# sig-gen gap: #2325 — `narrow:` is `untyped` (input `untyped`, looks deliberate; a declared type is authoring
|
|
32
32
|
# intent tracked by #2325, and only then does this row generate; coercion-facing: `to_s`, nil kept).
|
|
33
33
|
attr_reader narrow: String?
|
|
34
34
|
attr_reader discharge: bool
|
|
@@ -41,7 +41,7 @@ module Rigor
|
|
|
41
41
|
# intent tracked by #2325, and only then does this row generate; coercion-facing: `to_s`), stored from the
|
|
42
42
|
# private `validate_taint!` helper (#2312).
|
|
43
43
|
attr_reader taint: String?
|
|
44
|
-
# sig-gen gap: #
|
|
44
|
+
# sig-gen gap: #2325 — `callee:` is `untyped` (input `untyped`, looks deliberate; a declared type is authoring
|
|
45
45
|
# intent tracked by #2325, and only then does this row generate; coercion-facing: `to_s`, nil kept).
|
|
46
46
|
attr_reader callee: String?
|
|
47
47
|
# sig-gen gap: #2312 — `callee_fallbacks:` is `untyped` (input `untyped`, looks deliberate; a declared type is
|
|
@@ -11,7 +11,7 @@ module Rigor
|
|
|
11
11
|
# intent tracked by #2325, and only then does this row generate; coercion-facing: `to_s`), and `initialize`
|
|
12
12
|
# stores the result of the private `validate_receiver!` helper (#2312).
|
|
13
13
|
attr_reader receiver: String
|
|
14
|
-
# sig-gen gap: #
|
|
14
|
+
# sig-gen gap: #2325 — `method:` is `untyped` (input `untyped`, looks deliberate; a declared type is authoring
|
|
15
15
|
# intent tracked by #2325, and only then does this row generate; coercion-facing: `String | Symbol | nil`),
|
|
16
16
|
# stored as `method&.to_sym`.
|
|
17
17
|
attr_reader method: Symbol?
|
|
@@ -4,15 +4,15 @@ module Rigor
|
|
|
4
4
|
# framework entry points (ADR-103 WD6). Frozen value object; {#globs} are deduplicated and
|
|
5
5
|
# sorted in `initialize`.
|
|
6
6
|
class EffectEntryPoints
|
|
7
|
-
# sig-gen gap: #
|
|
7
|
+
# sig-gen gap: #2325 — `initialize` declares `name:` `untyped` (input `untyped`, looks deliberate; a declared
|
|
8
8
|
# type is authoring intent tracked by #2325, and only then does this row generate; coercion-facing: it takes
|
|
9
9
|
# anything that answers `to_s`), so no input type reaches the reader.
|
|
10
10
|
attr_reader name: String
|
|
11
|
-
# sig-gen gap: #
|
|
11
|
+
# sig-gen gap: #2325 — `globs:` is `untyped` (input `untyped`, looks deliberate; a declared type is authoring
|
|
12
12
|
# intent tracked by #2325, and only then does this row generate; coercion-facing: `Array(globs)`, each `to_s`),
|
|
13
13
|
# deduplicated and sorted in `initialize`.
|
|
14
14
|
attr_reader globs: Array[String]
|
|
15
|
-
# sig-gen gap: #
|
|
15
|
+
# sig-gen gap: #2325 — `why:` is `untyped` (input `untyped`, looks deliberate; a declared type is authoring
|
|
16
16
|
# intent tracked by #2325, and only then does this row generate; coercion-facing: `to_s`).
|
|
17
17
|
attr_reader why: String
|
|
18
18
|
|
|
@@ -4,7 +4,7 @@ class Rigor::Plugin::IoBoundary
|
|
|
4
4
|
def file?: (untyped) -> bool
|
|
5
5
|
def directory?: (untyped) -> bool
|
|
6
6
|
def list_directory: (untyped) -> Array[String]
|
|
7
|
-
def list_directory_kinds: (untyped) -> Hash[String,
|
|
7
|
+
def list_directory_kinds: (untyped) -> Hash[String, Symbol]
|
|
8
8
|
# Records a `:names` glob row (membership only); a caller needing a match's content `read_file`s it. A `..`
|
|
9
9
|
# segment, a brace or a backslash in `pattern` raises `AccessDeniedError`.
|
|
10
10
|
def glob: (untyped root, untyped pattern) -> Array[String]
|
|
@@ -15,6 +15,7 @@ class Rigor::Plugin::IoBoundary
|
|
|
15
15
|
def refusal_summary: () -> { count: Integer, first_path: String?, nearest_root: String? }?
|
|
16
16
|
def open_url: (untyped url) -> String
|
|
17
17
|
# Returns a frozen `Rigor::Cache::Descriptor` (no RBS yet -> untyped).
|
|
18
|
+
# authored: returns Rigor::Cache::Descriptor, which has no RBS declaration yet (#2404); stays `untyped` until it is declared
|
|
18
19
|
def cache_descriptor: () -> untyped
|
|
19
20
|
def replay: (untyped descriptor) -> nil
|
|
20
21
|
end
|