rigortype 0.3.8 → 0.4.0
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/capability_roles/capability_roles.rbs +36 -0
- data/data/core_overlay/enumerable.rbs +51 -0
- data/data/core_overlay/enumerator.rbs +84 -0
- data/data/core_overlay/hash_rbs3.rbs +41 -0
- data/data/core_overlay/process.rbs +40 -0
- data/data/core_overlay/string_io.rbs +33 -0
- data/data/effects/core.yml +3 -3
- data/data/gem_overlay/activesupport/core_ext.rbs +236 -17
- data/docs/handbook/02-everyday-types.md +17 -14
- data/docs/handbook/03-narrowing.md +132 -14
- data/docs/handbook/04-tuples-and-shapes.md +8 -6
- data/docs/handbook/05-methods-and-blocks.md +1 -1
- data/docs/handbook/06-classes.md +2 -2
- data/docs/handbook/07-rbs-and-extended.md +19 -1
- data/docs/handbook/10-sorbet.md +9 -10
- data/docs/handbook/11-sig-gen.md +525 -13
- data/docs/handbook/README.md +1 -1
- data/docs/handbook/appendix-elixir.md +2 -2
- data/docs/handbook/appendix-go.md +2 -2
- data/docs/handbook/appendix-java-csharp.md +2 -2
- data/docs/handbook/appendix-mypy.md +2 -2
- data/docs/handbook/appendix-phpstan.md +1 -1
- data/docs/handbook/appendix-rust.md +1 -1
- data/docs/handbook/appendix-type-theory.md +4 -4
- data/docs/handbook/appendix-typescript.md +1 -1
- data/docs/llms.txt +2 -0
- data/docs/manual/02-cli-reference.md +95 -6
- data/docs/manual/03-configuration.md +18 -0
- data/docs/manual/04-diagnostics.md +15 -0
- data/docs/manual/07-plugins.md +15 -5
- data/docs/manual/08-skills.md +23 -2
- data/docs/manual/10-mcp-server.md +3 -2
- data/docs/manual/11-ci.md +9 -0
- data/docs/manual/15-type-protection-coverage.md +8 -0
- data/docs/manual/16-rbs-extended-annotations.md +46 -8
- data/docs/manual/18-removing-dead-code.md +10 -8
- data/docs/manual/19-effect-labels.md +10 -0
- data/docs/manual/plugins/README.md +7 -0
- data/docs/manual/plugins/rigor-actioncable.md +8 -1
- data/docs/manual/plugins/rigor-actionmailer.md +7 -0
- data/docs/manual/plugins/rigor-actionpack.md +261 -0
- data/docs/manual/plugins/rigor-active-model-serializers.md +153 -0
- data/docs/manual/plugins/rigor-activejob.md +7 -0
- data/docs/manual/plugins/rigor-activerecord.md +138 -4
- data/docs/manual/plugins/rigor-activestorage.md +8 -1
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +43 -7
- data/docs/manual/plugins/rigor-grape.md +106 -0
- data/docs/manual/plugins/rigor-graphql.md +23 -2
- data/docs/manual/plugins/rigor-pundit.md +8 -1
- data/docs/manual/plugins/rigor-rails-i18n.md +10 -5
- data/docs/manual/plugins/rigor-rails-routes.md +7 -0
- data/docs/manual/plugins/rigor-rbs-inline.md +229 -1
- data/docs/manual/plugins/rigor-sidekiq.md +8 -1
- data/docs/manual/plugins/rigor-sorbet.md +21 -5
- data/exe/rigor +19 -4
- data/lib/rigor/analysis/baseline.rb +3 -3
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/dead_version_guard_arms.rb +1 -5
- data/lib/rigor/analysis/check_rules/declaration_sourced_guard.rb +167 -2
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +10 -2
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +189 -0
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +6 -4
- data/lib/rigor/analysis/check_rules/published_constant_guard.rb +15 -6
- data/lib/rigor/analysis/check_rules/rule_ids.rb +21 -6
- data/lib/rigor/analysis/check_rules/rule_walk.rb +41 -5
- data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +1 -1
- data/lib/rigor/analysis/check_rules/shadowed_rescue_collector.rb +1 -1
- data/lib/rigor/analysis/check_rules/source_arity.rb +323 -0
- data/lib/rigor/analysis/check_rules/special_global_setters.rb +146 -0
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +38 -4
- data/lib/rigor/analysis/check_rules/void_value_use_collector.rb +0 -1
- data/lib/rigor/analysis/check_rules.rb +718 -79
- data/lib/rigor/analysis/crash_signature.rb +8 -24
- data/lib/rigor/analysis/dependency_recorder.rb +23 -0
- data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +1 -1
- data/lib/rigor/analysis/dependency_source_inference/builder.rb +0 -2
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +0 -2
- data/lib/rigor/analysis/dependency_source_inference/index.rb +5 -5
- data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +1 -2
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +4 -4
- data/lib/rigor/analysis/effects_cache_probe.rb +3 -4
- data/lib/rigor/analysis/erb_template_detector.rb +1 -2
- data/lib/rigor/analysis/fact_store.rb +15 -1
- data/lib/rigor/analysis/incremental.rb +42 -0
- data/lib/rigor/analysis/incremental_session.rb +117 -26
- data/lib/rigor/analysis/plugin_fact_fingerprint.rb +0 -1
- data/lib/rigor/analysis/project_scan.rb +11 -1
- data/lib/rigor/analysis/reachability/graph.rb +3 -5
- data/lib/rigor/analysis/reachability/plugin_roots.rb +5 -5
- data/lib/rigor/analysis/reachability/project_files.rb +2 -2
- data/lib/rigor/analysis/reachability/scan.rb +5 -5
- data/lib/rigor/analysis/reachability/scan_cache.rb +3 -2
- data/lib/rigor/analysis/reachability/signature_scan.rb +2 -2
- data/lib/rigor/analysis/result.rb +1 -3
- data/lib/rigor/analysis/rule_catalog.rb +131 -1
- data/lib/rigor/analysis/run_cache_key.rb +21 -12
- data/lib/rigor/analysis/run_cache_probe.rb +3 -5
- data/lib/rigor/analysis/runner/buffer_pool_dispatcher.rb +6 -8
- data/lib/rigor/analysis/runner/declaration_position.rb +1 -2
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +340 -33
- data/lib/rigor/analysis/runner/effect_annotation_residual_pass.rb +2 -3
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +18 -14
- data/lib/rigor/analysis/runner/pool_coordinator.rb +357 -97
- data/lib/rigor/analysis/runner/project_pre_passes.rb +38 -13
- data/lib/rigor/analysis/runner/run_snapshots.rb +6 -1
- data/lib/rigor/analysis/runner.rb +407 -51
- data/lib/rigor/analysis/template_unit_collector.rb +303 -0
- data/lib/rigor/analysis/template_unit_paths.rb +91 -0
- data/lib/rigor/analysis/template_unit_positions.rb +293 -0
- data/lib/rigor/analysis/template_units.rb +399 -0
- data/lib/rigor/analysis/worker_session.rb +62 -20
- data/lib/rigor/bleeding_edge.rb +10 -24
- data/lib/rigor/builtins/hkt_builtins.rb +3 -2
- data/lib/rigor/builtins/imported_refinements.rb +159 -21
- data/lib/rigor/builtins/predefined_constant_refinements.rb +5 -7
- data/lib/rigor/builtins/regex_refinement.rb +21 -13
- data/lib/rigor/builtins/static_return_refinements.rb +7 -6
- data/lib/rigor/cache/annotation_location.rb +2 -4
- data/lib/rigor/cache/descriptor.rb +63 -20
- data/lib/rigor/cache/engine_source.rb +33 -5
- data/lib/rigor/cache/file_digest.rb +9 -1
- data/lib/rigor/cache/incremental_snapshot.rb +72 -6
- data/lib/rigor/cache/rbs_cache_producer.rb +4 -0
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +0 -3
- data/lib/rigor/cache/rbs_class_type_param_names.rb +0 -3
- data/lib/rigor/cache/rbs_constant_table.rb +0 -3
- data/lib/rigor/cache/rbs_descriptor.rb +112 -14
- data/lib/rigor/cache/rbs_environment.rb +8 -4
- data/lib/rigor/cache/rbs_known_class_names.rb +0 -3
- data/lib/rigor/cache/store.rb +76 -32
- data/lib/rigor/ci_detector.rb +1 -0
- data/lib/rigor/cli/annotate_command.rb +5 -6
- data/lib/rigor/cli/check_command.rb +57 -10
- data/lib/rigor/cli/check_invocation.rb +6 -11
- data/lib/rigor/cli/check_runner_factory.rb +1 -5
- data/lib/rigor/cli/coverage_command.rb +1 -1
- data/lib/rigor/cli/coverage_mutation.rb +12 -3
- data/lib/rigor/cli/coverage_scan.rb +1 -5
- data/lib/rigor/cli/diff_command.rb +1 -1
- data/lib/rigor/cli/doc_links.rb +4 -4
- data/lib/rigor/cli/docs_command.rb +6 -6
- data/lib/rigor/cli/doctor_command.rb +85 -38
- data/lib/rigor/cli/effects_command.rb +2 -2
- data/lib/rigor/cli/effects_diff_renderer.rb +3 -3
- data/lib/rigor/cli/effects_snapshot_command.rb +1 -1
- data/lib/rigor/cli/explain_command.rb +34 -1
- data/lib/rigor/cli/fused_protection_report.rb +7 -1
- data/lib/rigor/cli/lsp_command.rb +1 -1
- data/lib/rigor/cli/mcp_command.rb +1 -1
- data/lib/rigor/cli/measurement_integrity_warning.rb +4 -5
- data/lib/rigor/cli/mutation_fork_scan.rb +6 -6
- data/lib/rigor/cli/mutation_protection_report.rb +7 -1
- data/lib/rigor/cli/plugin_command.rb +4 -4
- data/lib/rigor/cli/plugins_command.rb +2 -1
- data/lib/rigor/cli/prism_colorizer.rb +1 -2
- data/lib/rigor/cli/protection_fork_scan.rb +6 -6
- data/lib/rigor/cli/show_bleedingedge_command.rb +1 -1
- data/lib/rigor/cli/sig_gen_command.rb +212 -31
- data/lib/rigor/cli/skill_command.rb +2 -2
- data/lib/rigor/cli/skill_deep_probe.rb +4 -4
- data/lib/rigor/cli/skill_describe.rb +35 -35
- data/lib/rigor/cli/trace_command.rb +4 -4
- data/lib/rigor/cli/trace_renderer.rb +5 -6
- data/lib/rigor/cli/triage_command.rb +1 -1
- data/lib/rigor/cli/type_of_command.rb +29 -11
- data/lib/rigor/cli/type_of_renderer.rb +20 -9
- data/lib/rigor/cli/type_of_template_probe.rb +189 -0
- data/lib/rigor/cli/type_scan_command.rb +4 -4
- data/lib/rigor/cli/unused_command.rb +11 -3
- data/lib/rigor/cli/upgrade_command.rb +1 -1
- data/lib/rigor/cli.rb +89 -9
- data/lib/rigor/config_audit.rb +30 -5
- data/lib/rigor/configuration/severity_profile.rb +25 -9
- data/lib/rigor/configuration.rb +109 -7
- data/lib/rigor/effects/ancestry_recorder.rb +191 -0
- data/lib/rigor/effects/attribution.rb +12 -5
- data/lib/rigor/effects/callee_rule.rb +368 -0
- data/lib/rigor/effects/catalog.rb +7 -4
- data/lib/rigor/effects/collector.rb +11 -5
- data/lib/rigor/effects/config_envelopes.rb +15 -10
- data/lib/rigor/effects/definition_context.rb +179 -0
- data/lib/rigor/effects/definition_lines.rb +25 -6
- data/lib/rigor/effects/effect_table.rb +11 -4
- data/lib/rigor/effects/entry_points.rb +0 -2
- data/lib/rigor/effects/envelope_check.rb +9 -9
- data/lib/rigor/effects/envelope_index.rb +20 -8
- data/lib/rigor/effects/file_collection.rb +59 -5
- data/lib/rigor/effects/framework_units.rb +5 -7
- data/lib/rigor/effects/identity.rb +20 -6
- data/lib/rigor/effects/inline_anchor.rb +7 -7
- data/lib/rigor/effects/label_intent.rb +3 -4
- data/lib/rigor/effects/liskov_check.rb +8 -8
- data/lib/rigor/effects/local_ownership.rb +38 -12
- data/lib/rigor/effects/method_key.rb +22 -1
- data/lib/rigor/effects/mutation_classifier.rb +23 -12
- data/lib/rigor/effects/plugin_facts.rb +47 -37
- data/lib/rigor/effects/propagator.rb +297 -19
- data/lib/rigor/effects/registry.rb +1 -1
- data/lib/rigor/effects/scanner.rb +122 -73
- data/lib/rigor/effects/signature_sources.rb +4 -6
- data/lib/rigor/effects/snapshot.rb +12 -11
- data/lib/rigor/effects/snapshot_diff.rb +1 -1
- data/lib/rigor/effects/summary.rb +27 -4
- data/lib/rigor/effects/unit_scan.rb +393 -38
- data/lib/rigor/effects/unknown_label_check.rb +3 -8
- data/lib/rigor/effects/unknown_label_report.rb +3 -4
- data/lib/rigor/effects/visibility.rb +101 -0
- data/lib/rigor/environment/bundle_sig_discovery.rb +6 -6
- data/lib/rigor/environment/class_registry.rb +3 -1
- data/lib/rigor/environment/failure_slot.rb +2 -2
- data/lib/rigor/environment/installed_gem_set.rb +85 -0
- data/lib/rigor/environment/lockfile_resolver.rb +68 -4
- data/lib/rigor/environment/member_consistency/comparator.rb +708 -0
- data/lib/rigor/environment/member_consistency.rb +298 -0
- data/lib/rigor/environment/missing_gem_constant_index.rb +4 -4
- data/lib/rigor/environment/rbs_collection_discovery.rb +5 -5
- data/lib/rigor/environment/rbs_coverage_report.rb +5 -5
- data/lib/rigor/environment/rbs_hierarchy.rb +3 -1
- data/lib/rigor/environment/rbs_loader.rb +674 -79
- data/lib/rigor/environment.rb +174 -24
- data/lib/rigor/flow_contribution/merger.rb +0 -2
- data/lib/rigor/flow_contribution.rb +11 -13
- data/lib/rigor/hashing/xxh3.rb +264 -0
- data/lib/rigor/inference/acceptance.rb +292 -17
- data/lib/rigor/inference/block_auto_splat.rb +216 -0
- data/lib/rigor/inference/block_call_timing.rb +338 -0
- data/lib/rigor/inference/block_parameter_binder.rb +75 -30
- data/lib/rigor/inference/block_repetition.rb +71 -0
- data/lib/rigor/inference/body_fixpoint.rb +7 -6
- data/lib/rigor/inference/budget_trace.rb +3 -6
- data/lib/rigor/inference/builtins/method_catalog.rb +2 -1
- data/lib/rigor/inference/builtins/string_catalog.rb +1 -1
- data/lib/rigor/inference/captured_locals.rb +389 -18
- data/lib/rigor/inference/closure_escape_analyzer.rb +159 -17
- data/lib/rigor/inference/content_join.rb +200 -27
- data/lib/rigor/inference/coverage_scanner.rb +4 -6
- data/lib/rigor/inference/def_return_typer.rb +11 -7
- data/lib/rigor/inference/define_method_block_self.rb +64 -0
- data/lib/rigor/inference/dynamic_origin.rb +1 -1
- data/lib/rigor/inference/element_read_widening.rb +180 -0
- data/lib/rigor/inference/error_info.rb +196 -0
- data/lib/rigor/inference/expression_typer.rb +2124 -468
- data/lib/rigor/inference/external_ancestor_resolution.rb +267 -0
- data/lib/rigor/inference/fork_map.rb +5 -7
- data/lib/rigor/inference/fresh_frame_blocks.rb +127 -0
- data/lib/rigor/inference/global_write_census.rb +239 -0
- data/lib/rigor/inference/guard_rebinding.rb +447 -0
- data/lib/rigor/inference/hash_lookup_mutation.rb +88 -0
- data/lib/rigor/inference/hkt_reducer.rb +2 -3
- data/lib/rigor/inference/hkt_registry.rb +4 -7
- data/lib/rigor/inference/index_write_widening.rb +16 -7
- data/lib/rigor/inference/indexed_narrowing.rb +61 -9
- data/lib/rigor/inference/jump_targets.rb +82 -0
- data/lib/rigor/inference/last_line/implicit_self.rb +210 -0
- data/lib/rigor/inference/last_line/self_evidence.rb +329 -0
- data/lib/rigor/inference/last_line.rb +340 -0
- data/lib/rigor/inference/last_status.rb +144 -0
- data/lib/rigor/inference/macro_block_self_type.rb +168 -21
- data/lib/rigor/inference/match_rebinding/calls.rb +281 -0
- data/lib/rigor/inference/match_rebinding/frame.rb +148 -0
- data/lib/rigor/inference/match_rebinding/operands.rb +236 -0
- data/lib/rigor/inference/match_rebinding/self_calls.rb +83 -0
- data/lib/rigor/inference/match_rebinding.rb +392 -0
- data/lib/rigor/inference/method_dispatcher/alias_strict_nominals.rb +36 -0
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +87 -33
- data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +305 -19
- data/lib/rigor/inference/method_dispatcher/data_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/facet_distribution.rb +147 -0
- data/lib/rigor/inference/method_dispatcher/file_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/hash_transform_keys_folding.rb +191 -0
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +6 -2
- data/lib/rigor/inference/method_dispatcher/json_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +7 -1
- data/lib/rigor/inference/method_dispatcher/match_data_folding.rb +159 -0
- data/lib/rigor/inference/method_dispatcher/math_folding.rb +41 -3
- data/lib/rigor/inference/method_dispatcher/method_folding.rb +2 -5
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +165 -111
- data/lib/rigor/inference/method_dispatcher/process_folding.rb +56 -0
- data/lib/rigor/inference/method_dispatcher/proven_overload.rb +72 -0
- data/lib/rigor/inference/method_dispatcher/random_folding.rb +82 -0
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +1046 -69
- data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +25 -4
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +2 -8
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/self_substitute.rb +142 -0
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +129 -54
- data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/singleton_mixin_dispatch.rb +1 -2
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +5 -6
- data/lib/rigor/inference/method_dispatcher/struct_materialization.rb +85 -4
- data/lib/rigor/inference/method_dispatcher/time_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher/universal_object_dispatch.rb +1 -2
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher.rb +225 -25
- data/lib/rigor/inference/method_parameter_binder.rb +12 -9
- data/lib/rigor/inference/multi_target_binder.rb +341 -55
- data/lib/rigor/inference/mutation_rejoin.rb +171 -0
- data/lib/rigor/inference/mutation_widening.rb +156 -85
- data/lib/rigor/inference/narrowing.rb +835 -162
- data/lib/rigor/inference/operand_effects.rb +167 -0
- data/lib/rigor/inference/operand_walk.rb +88 -0
- data/lib/rigor/inference/optimistic_origin.rb +153 -16
- data/lib/rigor/inference/origin_lookup.rb +2 -3
- data/lib/rigor/inference/parameter_inference_collector.rb +7 -7
- data/lib/rigor/inference/pre_eval_constants.rb +6 -5
- data/lib/rigor/inference/precision_scanner.rb +3 -4
- data/lib/rigor/inference/project_method_ownership.rb +136 -0
- data/lib/rigor/inference/project_patched_methods.rb +9 -4
- data/lib/rigor/inference/project_patched_scanner.rb +10 -6
- data/lib/rigor/inference/protection_scanner.rb +1 -2
- data/lib/rigor/inference/range_constant.rb +57 -0
- data/lib/rigor/inference/rbs_type_translator.rb +49 -11
- data/lib/rigor/inference/receiver_alias.rb +93 -4
- data/lib/rigor/inference/receiver_blind_block.rb +219 -0
- data/lib/rigor/inference/refinement_mutation.rb +76 -0
- data/lib/rigor/inference/repeated_or_writes.rb +463 -0
- data/lib/rigor/inference/return_barrier.rb +54 -0
- data/lib/rigor/inference/rewrite_mutation.rb +120 -0
- data/lib/rigor/inference/scope_indexer.rb +5228 -627
- data/lib/rigor/inference/statement_evaluator.rb +3452 -595
- data/lib/rigor/inference/stored_block_call.rb +54 -0
- data/lib/rigor/inference/string_mutation.rb +97 -0
- data/lib/rigor/inference/struct_fold_safety.rb +6 -7
- data/lib/rigor/inference/synthetic_method_index.rb +1 -2
- data/lib/rigor/inference/synthetic_method_scanner.rb +4 -6
- data/lib/rigor/inference/unknown_store_widening.rb +200 -0
- data/lib/rigor/inference/unthreaded_rebinds.rb +282 -0
- data/lib/rigor/inference/version_guard.rb +28 -21
- data/lib/rigor/inference/void_origin.rb +3 -3
- data/lib/rigor/inference/void_tail_summary.rb +2 -4
- data/lib/rigor/language_server/buffer_table.rb +4 -4
- data/lib/rigor/language_server/completion_provider.rb +1 -1
- data/lib/rigor/language_server/debouncer.rb +0 -1
- data/lib/rigor/language_server/diagnostic_publisher.rb +7 -6
- data/lib/rigor/language_server/document_symbol_provider.rb +1 -1
- data/lib/rigor/language_server/folding_range_provider.rb +1 -1
- data/lib/rigor/language_server/hover_provider.rb +1 -1
- data/lib/rigor/language_server/hover_renderer.rb +4 -4
- data/lib/rigor/language_server/incremental_sync.rb +6 -6
- data/lib/rigor/language_server/project_context.rb +7 -8
- data/lib/rigor/language_server/publish_batcher.rb +2 -2
- data/lib/rigor/language_server/selection_range_provider.rb +2 -2
- data/lib/rigor/language_server/server.rb +9 -9
- data/lib/rigor/language_server/signature_help_provider.rb +1 -1
- data/lib/rigor/language_server/uri.rb +1 -1
- data/lib/rigor/mcp/server.rb +2 -1
- data/lib/rigor/plugin/base.rb +258 -26
- data/lib/rigor/plugin/box_probe.rb +91 -0
- data/lib/rigor/plugin/bundled_catalog.rb +167 -0
- data/lib/rigor/plugin/effect_attribution.rb +65 -11
- data/lib/rigor/plugin/effect_entry_points.rb +3 -3
- data/lib/rigor/plugin/fact_store.rb +6 -6
- data/lib/rigor/plugin/io_boundary.rb +93 -8
- data/lib/rigor/plugin/isolation.rb +29 -6
- data/lib/rigor/plugin/loader.rb +33 -13
- data/lib/rigor/plugin/macro/block_as_method.rb +45 -6
- data/lib/rigor/plugin/macro/heredoc_template.rb +1 -1
- data/lib/rigor/plugin/macro/trait_registry.rb +1 -1
- data/lib/rigor/plugin/manifest.rb +94 -11
- data/lib/rigor/plugin/registry.rb +76 -12
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +21 -4
- data/lib/rigor/plugin/template_unit.rb +196 -0
- data/lib/rigor/plugin/trust_policy.rb +2 -4
- data/lib/rigor/plugin/type_node_resolver.rb +3 -3
- data/lib/rigor/plugin.rb +1 -0
- data/lib/rigor/plugin_gap_advisory.rb +96 -0
- data/lib/rigor/project_environment.rb +138 -0
- data/lib/rigor/protection/analysis_guard.rb +93 -14
- data/lib/rigor/protection/closure_kill_oracle.rb +67 -23
- data/lib/rigor/protection/dependency_closure.rb +5 -8
- data/lib/rigor/protection/diagnostic_oracle.rb +2 -2
- data/lib/rigor/protection/discovery_seed.rb +14 -12
- data/lib/rigor/protection/kill_signature.rb +1 -4
- data/lib/rigor/protection/measurement_integrity.rb +1 -3
- data/lib/rigor/protection/mutation_cache.rb +7 -11
- data/lib/rigor/protection/mutation_scanner.rb +12 -15
- data/lib/rigor/protection/mutator.rb +2 -1
- data/lib/rigor/protection/test_suite_oracle.rb +5 -5
- data/lib/rigor/rbs_extended/conformance_checker.rb +4 -3
- data/lib/rigor/rbs_extended/envelope_scanner.rb +4 -6
- data/lib/rigor/rbs_extended/reporter.rb +36 -10
- data/lib/rigor/rbs_extended.rb +88 -21
- data/lib/rigor/reflection/constant_ancestors.rb +97 -0
- data/lib/rigor/reflection/constant_path.rb +139 -0
- data/lib/rigor/reflection.rb +93 -110
- data/lib/rigor/runtime/jit.rb +6 -8
- data/lib/rigor/scope/discovery_index.rb +165 -2
- data/lib/rigor/scope.rb +1041 -32
- data/lib/rigor/sig_gen/alias_index.rb +289 -0
- data/lib/rigor/sig_gen/classification.rb +22 -5
- data/lib/rigor/sig_gen/declaration_equivalence.rb +127 -0
- data/lib/rigor/sig_gen/effect_annotation.rb +202 -0
- data/lib/rigor/sig_gen/generator.rb +673 -53
- data/lib/rigor/sig_gen/inline_declarations.rb +184 -0
- data/lib/rigor/sig_gen/layout_index.rb +3 -4
- data/lib/rigor/sig_gen/meta_class_shape.rb +3 -5
- data/lib/rigor/sig_gen/method_candidate.rb +47 -3
- data/lib/rigor/sig_gen/observation_collector.rb +18 -16
- data/lib/rigor/sig_gen/path_mapper.rb +4 -6
- data/lib/rigor/sig_gen/rbs_validity.rb +4 -4
- data/lib/rigor/sig_gen/renderer.rb +128 -14
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +154 -0
- data/lib/rigor/sig_gen/superclass_spelling.rb +27 -0
- data/lib/rigor/sig_gen/type_elaborator.rb +1 -3
- data/lib/rigor/sig_gen/write_result.rb +19 -3
- data/lib/rigor/sig_gen/writer.rb +189 -41
- data/lib/rigor/sig_gen.rb +3 -0
- data/lib/rigor/signature_path_audit.rb +153 -6
- data/lib/rigor/source/literals.rb +0 -23
- data/lib/rigor/source/node_children.rb +0 -2
- data/lib/rigor/source/node_locator.rb +5 -11
- data/lib/rigor/source/node_walker.rb +0 -6
- data/lib/rigor/source/parameter_envelope.rb +72 -0
- data/lib/rigor/source.rb +1 -0
- data/lib/rigor/triage/catalogue.rb +1 -3
- data/lib/rigor/triage.rb +3 -5
- data/lib/rigor/type/accepts_result.rb +24 -6
- data/lib/rigor/type/combinator.rb +144 -5
- data/lib/rigor/type/data_class.rb +2 -2
- data/lib/rigor/type/data_instance.rb +4 -4
- data/lib/rigor/type/difference.rb +1 -0
- data/lib/rigor/type/float_range.rb +128 -0
- data/lib/rigor/type/hash_shape.rb +6 -6
- data/lib/rigor/type/integer_range.rb +13 -8
- data/lib/rigor/type/nominal.rb +8 -2
- data/lib/rigor/type/refined.rb +4 -3
- data/lib/rigor/type/struct_class.rb +3 -3
- data/lib/rigor/type/struct_instance.rb +4 -4
- data/lib/rigor/type.rb +1 -0
- data/lib/rigor/type_node/generic.rb +1 -1
- data/lib/rigor/type_node/range_literal.rb +25 -0
- data/lib/rigor/type_node/resolver_chain.rb +1 -1
- data/lib/rigor/type_node.rb +1 -0
- data/lib/rigor/version.rb +1 -1
- data/lib/rigor.rb +1 -0
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +0 -4
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +0 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +0 -2
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/effects.rb +1 -0
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +10 -5
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +0 -4
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +3 -5
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +1 -4
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +14 -4
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +32 -30
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +0 -1
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +1 -3
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_scan.rb +96 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/effects.rb +65 -8
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/erb_compiler.rb +270 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/render_locals.rb +402 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_assigns.rb +370 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/view_units.rb +132 -0
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +264 -3
- data/plugins/rigor-actionpack/sig/action_controller.rbs +71 -0
- data/plugins/rigor-actionpack/sig/action_view.rbs +43 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_discoverer.rb +220 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers/serializer_index.rb +56 -0
- data/plugins/rigor-active-model-serializers/lib/rigor/plugin/active_model_serializers.rb +263 -0
- data/plugins/rigor-active-model-serializers/lib/rigor-active-model-serializers.rb +7 -0
- data/plugins/rigor-active-model-serializers/sig/active_model_serializers.rbs +45 -0
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +0 -4
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/effects.rb +2 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +0 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +0 -2
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/recurring_scan.rb +1 -1
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +10 -5
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +35 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/effects.rb +72 -12
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +383 -7
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +14 -6
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +1 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/structure_sql_parser.rb +1 -2
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +322 -41
- data/plugins/rigor-activerecord/sig/active_record/framework.rbs +123 -0
- data/plugins/rigor-activerecord/sig/active_record/relation.rbs +206 -31
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +26 -14
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/effects.rb +9 -2
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +9 -2
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +290 -19
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +1 -0
- data/plugins/rigor-dry-monads/lib/rigor/plugin/dry_monads.rb +3 -0
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +9 -7
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +7 -3
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +1 -0
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +8 -6
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +11 -7
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -11
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +9 -4
- data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +2 -0
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +0 -5
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +0 -1
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +8 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/types.rb +1 -1
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +36 -4
- data/plugins/rigor-ffi-rzmq/lib/rigor/plugin/ffi_rzmq.rb +1 -0
- data/plugins/rigor-grape/lib/rigor/plugin/grape.rb +141 -0
- data/plugins/rigor-grape/lib/rigor-grape.rb +6 -0
- data/plugins/rigor-grape/sig/grape.rbs +263 -0
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +8 -6
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +78 -5
- data/plugins/rigor-graphql/sig/graphql.rbs +485 -0
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +1 -0
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +2 -1
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +2 -3
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +1 -0
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +0 -5
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/authorization_scan.rb +2 -2
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +0 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +0 -1
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +12 -7
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +0 -12
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +1 -3
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +0 -1
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +36 -37
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/acronyms.rb +5 -5
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +0 -10
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +5 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +3 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/grape_api_discoverer.rb +2 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +2 -2
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +9 -10
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +2 -3
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +10 -17
- data/plugins/rigor-railties/lib/rigor/plugin/railties.rb +1 -0
- data/plugins/rigor-rbnacl/lib/rigor/plugin/rbnacl.rb +13 -1
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline/same_line_annotations.rb +149 -0
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +324 -18
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +0 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +0 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +1 -5
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +2 -3
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +1 -0
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +0 -3
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +1 -0
- data/plugins/rigor-sassc/lib/rigor/plugin/sassc.rb +1 -0
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +1 -9
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +1 -0
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +0 -4
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/effects.rb +1 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/schedule_scan.rb +2 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +0 -1
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +0 -2
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +10 -5
- data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +1 -0
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +2 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +1 -4
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +3 -9
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +4 -4
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +1 -2
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +3 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +7 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +51 -6
- data/plugins/rigor-sorbet/sig/sorbet.rbs +277 -0
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +1 -0
- data/sig/rigor/analysis/baseline.rbs +69 -7
- data/sig/rigor/analysis/fact_store.rbs +1 -1
- data/sig/rigor/analysis/project_scan.rbs +74 -0
- data/sig/rigor/analysis/reachability/scan_cache.rbs +12 -0
- data/sig/rigor/cache.rbs +2 -3
- data/sig/rigor/effects/config_envelopes.rbs +100 -0
- data/sig/rigor/effects/effect_table.rbs +60 -0
- data/sig/rigor/effects/envelope.rbs +97 -0
- data/sig/rigor/effects/envelope_index.rbs +33 -0
- data/sig/rigor/effects/file_collection.rbs +81 -0
- data/sig/rigor/effects/label.rbs +26 -0
- data/sig/rigor/effects/label_set.rbs +46 -0
- data/sig/rigor/effects/method_key.rbs +24 -0
- data/sig/rigor/effects/origin.rbs +50 -0
- data/sig/rigor/effects/plugin_facts.rbs +141 -0
- data/sig/rigor/effects/registry.rbs +68 -0
- data/sig/rigor/effects/summary.rbs +50 -0
- data/sig/rigor/effects/taint_cause.rbs +12 -0
- data/sig/rigor/environment.rbs +17 -10
- data/sig/rigor/inference/optimistic_origin.rbs +10 -0
- data/sig/rigor/inference.rbs +9 -14
- data/sig/rigor/plugin/additional_initializer.rbs +36 -0
- data/sig/rigor/plugin/base.rbs +30 -7
- data/sig/rigor/plugin/effect_ancestry.rbs +27 -0
- data/sig/rigor/plugin/effect_attribution.rbs +66 -0
- data/sig/rigor/plugin/effect_edge.rbs +33 -0
- data/sig/rigor/plugin/effect_entry_points.rbs +25 -0
- data/sig/rigor/plugin/io_boundary.rbs +4 -0
- data/sig/rigor/plugin/loader.rbs +3 -3
- data/sig/rigor/plugin/manifest.rbs +51 -11
- data/sig/rigor/plugin/protocol_contract.rbs +68 -0
- data/sig/rigor/plugin/registry.rbs +62 -1
- data/sig/rigor/plugin.rbs +1 -1
- data/sig/rigor/rbs_extended.rbs +1 -1
- data/sig/rigor/reflection.rbs +9 -6
- data/sig/rigor/scope.rbs +148 -12
- data/sig/rigor/sig_gen/skip_reason_catalog.rbs +21 -0
- data/sig/rigor/source.rbs +4 -4
- data/sig/rigor/testing.rbs +10 -4
- data/sig/rigor/type.rbs +33 -1
- data/sig/rigor.rbs +39 -20
- data/skills/rigor-ask/SKILL.md +16 -11
- data/skills/rigor-baseline-reduce/SKILL.md +4 -6
- data/skills/rigor-ci-setup/SKILL.md +17 -21
- data/skills/rigor-doctor/SKILL.md +24 -22
- data/skills/rigor-doctor/references/01-checks.md +97 -33
- data/skills/rigor-editor-setup/SKILL.md +6 -4
- data/skills/rigor-mcp-setup/SKILL.md +5 -4
- data/skills/rigor-monkeypatch-resolve/SKILL.md +5 -3
- data/skills/rigor-next-steps/SKILL.md +4 -2
- data/skills/rigor-plugin-author/SKILL.md +19 -23
- data/skills/rigor-plugin-author/references/01-plan-and-scaffold.md +9 -8
- data/skills/rigor-plugin-author/references/02-walker-and-types.md +25 -27
- data/skills/rigor-plugin-author/references/03-test-and-ship.md +6 -8
- data/skills/rigor-plugin-review/SKILL.md +6 -4
- data/skills/rigor-plugin-review/references/01-best-practices-checklist.md +2 -1
- data/skills/rigor-plugin-tune/SKILL.md +4 -2
- data/skills/rigor-project-init/SKILL.md +15 -10
- data/skills/rigor-project-init/references/01-detect.md +13 -9
- data/skills/rigor-project-init/references/02-configure.md +43 -14
- data/skills/rigor-project-init/references/03-baseline-and-bugs.md +14 -14
- data/skills/rigor-project-init/references/04-sig-uplift.md +27 -14
- data/skills/rigor-project-init/references/06-agent-contract.md +67 -0
- data/skills/rigor-protection-uplift/SKILL.md +4 -6
- data/skills/rigor-rbs-setup/SKILL.md +4 -2
- data/skills/rigor-type-oracle/SKILL.md +226 -0
- data/skills/rigor-type-oracle/references/01-oracle-commands.md +265 -0
- data/skills/rigor-type-oracle/references/02-agents-md-fragment.md +52 -0
- data/skills/rigor-type-oracle/references/03-gap-protocol.md +125 -0
- data/skills/rigor-unused-adjudicate/SKILL.md +12 -7
- data/skills/rigor-upgrade/SKILL.md +13 -8
- metadata +133 -3
- data/lib/rigor/cli/probe_environment.rb +0 -85
- data/sig/rigor/inference/builtins/numeric_catalog.rbs +0 -3
|
@@ -46,10 +46,7 @@ module Rigor
|
|
|
46
46
|
# skipped — the controller/action scope cannot be statically determined there.
|
|
47
47
|
# - View template lazy keys (`t('.key')` inside ERB / Haml / Slim) are validated for key existence and
|
|
48
48
|
# per-locale coverage. Interpolation variable validation is skipped for view templates (the hash may
|
|
49
|
-
# come from controller instance variables not visible in the template).
|
|
50
|
-
# project-wide pass surfaced through the per-file diagnostic hook, so under `--workers` each fork-pool
|
|
51
|
-
# worker re-emits the full set (the same once-per-run limitation the `load-error` path carries);
|
|
52
|
-
# sequential `rigor check` is unaffected.
|
|
49
|
+
# come from controller instance variables not visible in the template).
|
|
53
50
|
# - Pluralization (`t('errors.messages.too_short', count: n)`) is recognised at the call site but the
|
|
54
51
|
# `count` key is not used to validate the locale's pluralization branches.
|
|
55
52
|
# - YAML aliases / merges are accepted (Psych's standard `aliases: true`) but custom Ruby classes
|
|
@@ -57,6 +54,7 @@ module Rigor
|
|
|
57
54
|
class RailsI18n < Rigor::Plugin::Base
|
|
58
55
|
manifest(
|
|
59
56
|
id: "rails-i18n",
|
|
57
|
+
target_gems: ["i18n"],
|
|
60
58
|
# Bumped 2026-06-23 — view template lazy-key scanning (`t('.key')` inside ERB / Haml / Slim under
|
|
61
59
|
# `view_search_paths`).
|
|
62
60
|
version: "0.3.0",
|
|
@@ -105,29 +103,26 @@ module Rigor
|
|
|
105
103
|
@view_search_paths = Array(config.fetch("view_search_paths")).map(&:to_s)
|
|
106
104
|
@configured_locales = Array(config.fetch("configured_locales")).map(&:to_s)
|
|
107
105
|
@load_errors = []
|
|
108
|
-
@load_errors_emitted = false
|
|
109
|
-
@view_diagnostics_emitted = false
|
|
110
106
|
end
|
|
111
107
|
|
|
112
|
-
#
|
|
113
|
-
#
|
|
114
|
-
#
|
|
115
|
-
#
|
|
108
|
+
# Returns no rows of its own: every file-level outcome here is run-scoped. The YAML load errors and the
|
|
109
|
+
# runtime (cache-load) errors are disclosures (#1051); the view-template scan is a positioned batch
|
|
110
|
+
# registered through `#emit_once` (#1060) — its rows name view files that are usually not analysed
|
|
111
|
+
# targets, so no per-file return could own them, and returning them from whichever file an instance
|
|
112
|
+
# saw first repeated the whole batch once per fork-pool worker. Per-call `t('key')` validation runs
|
|
113
|
+
# over the engine-owned walk via the node_rule below (ADR-37). The locale index and view diagnostics
|
|
114
|
+
# are lazily loaded + memoised by `producer_value`, so the repeat registrations are no-ops.
|
|
116
115
|
def diagnostics_for_file(path:, scope:, root:) # rubocop:disable Lint/UnusedMethodArgument
|
|
117
116
|
index = producer_value(:locale_index)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
else
|
|
126
|
-
diagnostics.concat(view_diags)
|
|
127
|
-
end
|
|
128
|
-
@view_diagnostics_emitted = true
|
|
117
|
+
disclose_load_errors unless @load_errors.empty?
|
|
118
|
+
disclose_locale_runtime_error if index.nil? && producer_error(:locale_index)
|
|
119
|
+
view_diags = producer_value(:view_diagnostics) || []
|
|
120
|
+
if (view_err = producer_error(:view_diagnostics))
|
|
121
|
+
disclose_view_runtime_error(view_err)
|
|
122
|
+
else
|
|
123
|
+
emit_once(:view_diagnostics, view_diags)
|
|
129
124
|
end
|
|
130
|
-
|
|
125
|
+
[]
|
|
131
126
|
end
|
|
132
127
|
|
|
133
128
|
# The lazy-key (`t('.key')`) expansion needs the enclosing method (the controller action), supplied
|
|
@@ -210,35 +205,39 @@ module Rigor
|
|
|
210
205
|
end
|
|
211
206
|
|
|
212
207
|
# The runner only invokes `diagnostics_for_file` for Ruby files (`paths:` is filtered to `.rb`). YAML
|
|
213
|
-
# parse errors therefore can't be anchored on the offending locale file directly
|
|
214
|
-
#
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
@
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
path: path, line: 1, column: 1,
|
|
208
|
+
# parse errors therefore can't be anchored on the offending locale file directly, and the row used to
|
|
209
|
+
# be pinned to the first analysed Ruby file — once per plugin INSTANCE, so once per fork-pool worker
|
|
210
|
+
# (#1051). They go through the run-scoped channel instead: keyed by the locale path that failed, so a
|
|
211
|
+
# project with two broken YAML files still discloses both, each exactly once, at `.rigor.yml:1:1`.
|
|
212
|
+
def disclose_load_errors
|
|
213
|
+
@load_errors.each do |err|
|
|
214
|
+
disclose_once(
|
|
215
|
+
"locale-parse:#{err.path}",
|
|
222
216
|
message: "rigor-rails-i18n: failed to parse `#{err.path}`: #{err.message}",
|
|
223
217
|
severity: :warning,
|
|
224
218
|
rule: "load-error"
|
|
225
219
|
)
|
|
226
220
|
end
|
|
221
|
+
nil
|
|
227
222
|
end
|
|
228
223
|
|
|
229
|
-
|
|
224
|
+
# #1051 — both of these say the plugin could not READ something the project configured, which is a
|
|
225
|
+
# run-level fact with no source position; they were repeated on every analysed file (the locale one)
|
|
226
|
+
# or on each instance's first (the view one). A key distinct from the `:view_diagnostics` batch's:
|
|
227
|
+
# the two channels share one registration table per plugin.
|
|
228
|
+
def disclose_locale_runtime_error
|
|
230
229
|
error = producer_error(:locale_index)
|
|
231
|
-
|
|
232
|
-
|
|
230
|
+
disclose_once(
|
|
231
|
+
:locale_index_failed,
|
|
233
232
|
message: "rigor-rails-i18n: failed to load locales: #{error.class}: #{error.message}",
|
|
234
233
|
severity: :warning,
|
|
235
234
|
rule: "load-error"
|
|
236
235
|
)
|
|
237
236
|
end
|
|
238
237
|
|
|
239
|
-
def
|
|
240
|
-
|
|
241
|
-
|
|
238
|
+
def disclose_view_runtime_error(error)
|
|
239
|
+
disclose_once(
|
|
240
|
+
:view_scan_failed,
|
|
242
241
|
message: "rigor-rails-i18n: failed to scan view templates: #{error.class}: #{error.message}",
|
|
243
242
|
severity: :warning,
|
|
244
243
|
rule: "load-error"
|
|
@@ -24,8 +24,8 @@ module Rigor
|
|
|
24
24
|
module Acronyms
|
|
25
25
|
module_function
|
|
26
26
|
|
|
27
|
-
# @param contents
|
|
28
|
-
# @return
|
|
27
|
+
# @param contents — the source of `config/initializers/inflections.rb`.
|
|
28
|
+
# @return declared acronyms in declaration order. Empty for a missing / unparseable
|
|
29
29
|
# file, or one that declares none — which leaves composition exactly as it was.
|
|
30
30
|
def discover(contents)
|
|
31
31
|
return [] if contents.nil? || contents.empty?
|
|
@@ -51,9 +51,9 @@ module Rigor
|
|
|
51
51
|
# camelization of the acronym appears at a camel-word boundary — `Oauth` in `OauthMetadata` and in
|
|
52
52
|
# `WellKnown::Oauth`, but never the `Oauth` inside a hypothetical `Xoauth`.
|
|
53
53
|
#
|
|
54
|
-
# @param name
|
|
55
|
-
# @param acronyms
|
|
56
|
-
# @return
|
|
54
|
+
# @param name — e.g. `"Activitypub::CollectionsController"`.
|
|
55
|
+
# @param acronyms — as returned by {.discover}.
|
|
56
|
+
# @return e.g. `"ActivityPub::CollectionsController"`.
|
|
57
57
|
def apply(name, acronyms)
|
|
58
58
|
acronyms.reduce(name) do |current, acronym|
|
|
59
59
|
plain = Rigor::Plugin::Inflector.camelize(acronym.to_s.downcase)
|
|
@@ -61,20 +61,10 @@ module Rigor
|
|
|
61
61
|
%r{(?:\A|/)config/}
|
|
62
62
|
].freeze
|
|
63
63
|
|
|
64
|
-
# @param path [String] file being analysed
|
|
65
|
-
# @param root [Prism::Node]
|
|
66
|
-
# @param helper_table [HelperTable]
|
|
67
|
-
# @return [Array<Diagnostic>]
|
|
68
64
|
# The route-helper violations for a single call node (0..2), or `[]` when the node is not an
|
|
69
65
|
# implicit `*_path` / `*_url` helper call, is shadowed by a same-file binding, or is in a
|
|
70
66
|
# suppressed directory. ADR-37: the engine owns the walk; the same-file `shadowing` set is built
|
|
71
67
|
# once as the node-rule file context.
|
|
72
|
-
#
|
|
73
|
-
# @param call_node [Prism::Node]
|
|
74
|
-
# @param helper_table [HelperTable]
|
|
75
|
-
# @param shadowing [Set<String>]
|
|
76
|
-
# @param path [String]
|
|
77
|
-
# @return [Array<Violation>]
|
|
78
68
|
def violations_for(call_node:, helper_table:, shadowing:, path:)
|
|
79
69
|
return [] unless call_node.is_a?(Prism::CallNode) && implicit_helper_call?(call_node)
|
|
80
70
|
|
|
@@ -58,6 +58,7 @@ module Rigor
|
|
|
58
58
|
[nil, "registration", :get, :show]
|
|
59
59
|
]
|
|
60
60
|
}.freeze
|
|
61
|
+
Ractor.make_shareable(CONTROLLER_HELPERS)
|
|
61
62
|
|
|
62
63
|
# Dynamic-provider helper patterns. `_omniauth_authorize_path` and `_omniauth_callback_path` are
|
|
63
64
|
# generated per configured provider (Facebook, GitHub, …) by an initializer this parser does not
|
|
@@ -70,11 +71,11 @@ module Rigor
|
|
|
70
71
|
|
|
71
72
|
module_function
|
|
72
73
|
|
|
73
|
-
# @param resource
|
|
74
|
+
# @param resource — the `devise_for` argument — typically `:users`. Used as both the
|
|
74
75
|
# helper-name segment (`new_user_session_path`) and to derive the resource path.
|
|
75
|
-
# @param skip
|
|
76
|
+
# @param skip — controllers the project disables via `devise_for :users, skip:
|
|
76
77
|
# [:registrations]`.
|
|
77
|
-
# @return
|
|
78
|
+
# @return one entry per generated `_path` helper. The caller is
|
|
78
79
|
# expected to pair `_url` variants the same way `RoutesParser` does for other entries.
|
|
79
80
|
def generate(resource:, skip: [])
|
|
80
81
|
resource_segment = singularize(resource.to_s)
|
|
@@ -135,6 +136,7 @@ module Rigor
|
|
|
135
136
|
unlocks: %w[new_unlock_path unlock_path],
|
|
136
137
|
registrations: %w[cancel_registration_path new_registration_path edit_registration_path registration_path]
|
|
137
138
|
}.freeze
|
|
139
|
+
Ractor.make_shareable(SCOPED_HELPERS)
|
|
138
140
|
private_constant :SCOPED_HELPERS
|
|
139
141
|
|
|
140
142
|
def scoped_helpers(skip_set)
|
|
@@ -63,11 +63,12 @@ module Rigor
|
|
|
63
63
|
["oauth_authorized_application_url", 1, "/oauth/authorized_applications/:id", :delete, :destroy]
|
|
64
64
|
]
|
|
65
65
|
}.freeze
|
|
66
|
+
Ractor.make_shareable(CONTROLLER_HELPERS)
|
|
66
67
|
|
|
67
68
|
module_function
|
|
68
69
|
|
|
69
|
-
# @param skip
|
|
70
|
-
# @return
|
|
70
|
+
# @param skip — controller names the project omits via `skip_controllers :name, ...`.
|
|
71
|
+
# @return flattened entries.
|
|
71
72
|
def generate(skip: [])
|
|
72
73
|
skip_set = skip.to_set(&:to_sym)
|
|
73
74
|
CONTROLLER_HELPERS.flat_map do |controller, rows|
|
|
@@ -43,9 +43,9 @@ module Rigor
|
|
|
43
43
|
|
|
44
44
|
module_function
|
|
45
45
|
|
|
46
|
-
# @param contents_per_path
|
|
46
|
+
# @param contents_per_path — file path → source text, read by the caller
|
|
47
47
|
# (through the trusted `IoBoundary`, so cache invalidation works).
|
|
48
|
-
# @return
|
|
48
|
+
# @return the recognised helper-name prefixes (`["api_v3", "api_v4"]`). Empty when
|
|
49
49
|
# the project declares no grape API — nothing changes for such a project.
|
|
50
50
|
def discover(contents_per_path)
|
|
51
51
|
declarations = {}
|
|
@@ -43,10 +43,10 @@ module Rigor
|
|
|
43
43
|
|
|
44
44
|
module_function
|
|
45
45
|
|
|
46
|
-
# @param contents_per_path
|
|
46
|
+
# @param contents_per_path — file path → source text. The caller is
|
|
47
47
|
# responsible for reading files (typically through the trusted `IoBoundary` so cache invalidation
|
|
48
48
|
# works).
|
|
49
|
-
# @return
|
|
49
|
+
# @return method names suitable for inclusion in the `HelperTable`'s custom-helper set.
|
|
50
50
|
def discover(contents_per_path)
|
|
51
51
|
names = []
|
|
52
52
|
contents_per_path.each_value do |contents|
|
|
@@ -26,21 +26,21 @@ module Rigor
|
|
|
26
26
|
|
|
27
27
|
attr_reader :entries, :custom_helpers, :devise_resources
|
|
28
28
|
|
|
29
|
-
# @param entries
|
|
30
|
-
# @param custom_helpers
|
|
29
|
+
# @param entries — freshly built; the factory below is the canonical construction path.
|
|
30
|
+
# @param custom_helpers — names of project-defined helper methods (typically
|
|
31
31
|
# pulled from `app/helpers/**/*.rb` by {HelperDiscoverer}) that the analyzer should treat as
|
|
32
32
|
# known — they do NOT correspond to a route but their presence MUST NOT fire `unknown-helper`. No
|
|
33
33
|
# arity / path metadata is recorded; the analyzer skips the route-side checks for these names.
|
|
34
|
-
# @param devise_resources
|
|
34
|
+
# @param devise_resources — resource names declared via `devise_for :resource`
|
|
35
35
|
# (already singularised, e.g. `"user"`). Used to recognise the dynamic OmniAuth helper family
|
|
36
36
|
# (`<resource>_<provider>_omniauth_(authorize|callback)_(path|url)`) whose provider segment is
|
|
37
37
|
# supplied at runtime — no per-name entry is registered for them but they MUST NOT fire
|
|
38
38
|
# `unknown-helper` either.
|
|
39
|
-
# @param grape_prefixes
|
|
39
|
+
# @param grape_prefixes — helper-name prefixes generated by `grape-path-helpers`
|
|
40
40
|
# (`"api_v4"`), composed by {GrapeApiDiscoverer} from the project's own `prefix` / `version`
|
|
41
41
|
# declarations. The names beyond the prefix come from grape's runtime route table and cannot be
|
|
42
42
|
# enumerated statically, so the namespace is open — same contract as the OmniAuth family above.
|
|
43
|
-
# @param controllers
|
|
43
|
+
# @param controllers — fully-qualified controller class names the routes file
|
|
44
44
|
# dispatches to (`"Admin::UsersController"`). Published as the plugin's `:reachability_roots` fact
|
|
45
45
|
# (ADR-102 WD3) — a controller is an entry point nothing in the project references, so without this
|
|
46
46
|
# every routed controller reads as unused. Deliberately NOT consulted by any helper-name check.
|
|
@@ -58,20 +58,19 @@ module Rigor
|
|
|
58
58
|
freeze
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
-
# @return
|
|
61
|
+
# @return the routed controller class names (see the `controllers:` parameter). Reads
|
|
62
62
|
# through a nil guard rather than `attr_reader` so a table deserialised from a cache slot written
|
|
63
63
|
# before this field existed answers `[]` instead of `nil`.
|
|
64
64
|
def controllers
|
|
65
65
|
@controllers || []
|
|
66
66
|
end
|
|
67
67
|
|
|
68
|
-
# @return
|
|
68
|
+
# @return First matching entry; for the uncountable-noun case this is the index helper
|
|
69
69
|
# (the show helper is also registered but starts second).
|
|
70
70
|
def find(helper_name)
|
|
71
71
|
@by_name[helper_name.to_s]&.first
|
|
72
72
|
end
|
|
73
73
|
|
|
74
|
-
# @return [Boolean]
|
|
75
74
|
def known?(helper_name)
|
|
76
75
|
@by_name.key?(helper_name.to_s)
|
|
77
76
|
end
|
|
@@ -118,7 +117,7 @@ module Rigor
|
|
|
118
117
|
end
|
|
119
118
|
end
|
|
120
119
|
|
|
121
|
-
# @return
|
|
120
|
+
# @return true when any entry under this helper name accepts the given positional arity.
|
|
122
121
|
#
|
|
123
122
|
# Rails helpers have the signature `helper(*segments, options = {})`, so `expected + 1` is always
|
|
124
123
|
# valid — the extra argument is treated as a query-params/options hash (e.g. `users_path(page: 2)`
|
|
@@ -127,7 +126,7 @@ module Rigor
|
|
|
127
126
|
(@by_name[helper_name.to_s] || []).any? { |entry| entry.arity == arity || entry.arity + 1 == arity }
|
|
128
127
|
end
|
|
129
128
|
|
|
130
|
-
# @return
|
|
129
|
+
# @return all accepted positional arities for a helper name. Empty when unknown.
|
|
131
130
|
def acceptable_arities(helper_name)
|
|
132
131
|
(@by_name[helper_name.to_s] || []).map(&:arity).uniq
|
|
133
132
|
end
|
|
@@ -54,11 +54,10 @@ module Rigor
|
|
|
54
54
|
|
|
55
55
|
module_function
|
|
56
56
|
|
|
57
|
-
# @param contents
|
|
58
|
-
# @param file_reader
|
|
57
|
+
# @param contents — raw `config/routes.rb` source
|
|
58
|
+
# @param file_reader — called with `"name.rb"` to load a
|
|
59
59
|
# draw partial from `config/routes/name.rb`. Returns file contents
|
|
60
60
|
# or nil when the file is absent.
|
|
61
|
-
# @return [HelperTable]
|
|
62
61
|
def parse(contents, file_reader: nil, custom_helpers: [], grape_prefixes: [], acronyms: [])
|
|
63
62
|
parse_result = Prism.parse(contents)
|
|
64
63
|
unless parse_result.errors.empty?
|
|
@@ -52,6 +52,7 @@ module Rigor
|
|
|
52
52
|
class RailsRoutes < Rigor::Plugin::Base
|
|
53
53
|
manifest(
|
|
54
54
|
id: "rails-routes",
|
|
55
|
+
target_gems: %w[actionpack railties],
|
|
55
56
|
# Bumped 2026-05-28 — GitLab FOSS sweep adds: (a) `draw_all :name` support (action_dispatch-draw_all
|
|
56
57
|
# gem; single-file load semantics matching `draw :name`); (b) keyword-style `scope(path:
|
|
57
58
|
# ':project_id', as: :project)` — path read from the `:path` keyword, not only from the positional
|
|
@@ -191,18 +192,12 @@ module Rigor
|
|
|
191
192
|
publish_reachability_roots(services, table)
|
|
192
193
|
end
|
|
193
194
|
|
|
194
|
-
# File-level only: the
|
|
195
|
-
# engine-owned walk via the node_rule below (ADR-37), with the same-file `shadowing` set built
|
|
196
|
-
# as the node-rule file context.
|
|
195
|
+
# File-level only: the run-scoped load-error disclosure (#1051). Per-call helper validation runs over
|
|
196
|
+
# the engine-owned walk via the node_rule below (ADR-37), with the same-file `shadowing` set built
|
|
197
|
+
# once as the node-rule file context.
|
|
197
198
|
def diagnostics_for_file(path:, scope:, root:) # rubocop:disable Lint/UnusedMethodArgument
|
|
198
199
|
table = helper_table_or_nil
|
|
199
|
-
if table.nil? && @load_error
|
|
200
|
-
return [] if @load_error_emitted
|
|
201
|
-
|
|
202
|
-
@load_error_emitted = true
|
|
203
|
-
return [load_error_diagnostic(path)]
|
|
204
|
-
end
|
|
205
|
-
|
|
200
|
+
disclose_load_error if table.nil? && @load_error
|
|
206
201
|
[]
|
|
207
202
|
end
|
|
208
203
|
|
|
@@ -264,13 +259,11 @@ module Rigor
|
|
|
264
259
|
nil
|
|
265
260
|
end
|
|
266
261
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
rule: "load-error"
|
|
273
|
-
)
|
|
262
|
+
# #1051 — "the routes file did not load" is a fact about the project, not about the file that
|
|
263
|
+
# happened to be analysed first by this instance, so it goes through the run-scoped channel and the
|
|
264
|
+
# engine positions it at `.rigor.yml:1:1`, once per run rather than once per fork-pool worker.
|
|
265
|
+
def disclose_load_error
|
|
266
|
+
disclose_once(:routes_load_failed, message: @load_error, severity: :warning, rule: "load-error")
|
|
274
267
|
end
|
|
275
268
|
end
|
|
276
269
|
|
|
@@ -52,6 +52,7 @@ module Rigor
|
|
|
52
52
|
class Railties < Rigor::Plugin::Base
|
|
53
53
|
manifest(
|
|
54
54
|
id: "railties",
|
|
55
|
+
target_gems: ["railties"],
|
|
55
56
|
# Bumped 2026-09-01 (#534 item 2) — the four `Rails.` singleton readers now return lenient
|
|
56
57
|
# nominals instead of `Dynamic[top]`.
|
|
57
58
|
version: "0.2.0",
|
|
@@ -8,8 +8,18 @@ module Rigor
|
|
|
8
8
|
class RbNaCl < Base
|
|
9
9
|
manifest(
|
|
10
10
|
id: "rbnacl",
|
|
11
|
+
target_gems: ["rbnacl"],
|
|
11
12
|
version: "0.1.0",
|
|
12
|
-
description: "Rigor type support for RbNaCl libsodium bindings"
|
|
13
|
+
description: "Rigor type support for RbNaCl libsodium bindings",
|
|
14
|
+
signature_paths: ["sig"],
|
|
15
|
+
# ADR-26 — `sig/rbnacl.rbs` declares three methods of a class that has many more (`nonce_bytes`,
|
|
16
|
+
# `key_bytes`, …). Contributing it without opening the receivers would close those classes and
|
|
17
|
+
# manufacture `call.undefined-method` on correct code, which is the trade the project refuses.
|
|
18
|
+
open_receivers: [
|
|
19
|
+
"RbNaCl::SecretBox",
|
|
20
|
+
"RbNaCl::Signatures::Ed25519::SigningKey",
|
|
21
|
+
"RbNaCl::Signatures::Ed25519::VerifyKey"
|
|
22
|
+
]
|
|
13
23
|
)
|
|
14
24
|
|
|
15
25
|
# Issue 2 & 5: use robust positional binding extractor and preserve module context
|
|
@@ -28,3 +38,5 @@ module Rigor
|
|
|
28
38
|
end
|
|
29
39
|
end
|
|
30
40
|
end
|
|
41
|
+
|
|
42
|
+
Rigor::Plugin.register(Rigor::Plugin::RbNaCl)
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "strscan"
|
|
4
|
+
|
|
5
|
+
module Rigor
|
|
6
|
+
module Plugin
|
|
7
|
+
class RbsInline < Base
|
|
8
|
+
# Issue #998 — the two same-line `%a{}` spellings rbs's built-in `RBS::InlineParser` and Steep's inline
|
|
9
|
+
# mode accept, repaired into the shape the `rbs-inline` gem's writer honours:
|
|
10
|
+
#
|
|
11
|
+
# - `# @rbs %a{…} () -> String` — the gem's `@rbs %a{}` rule lexes the annotations and stops, so the
|
|
12
|
+
# method type after them is discarded and the method renders `() -> untyped`;
|
|
13
|
+
# - `#: %a{…} () -> String` — the gem hands the whole payload to `RBS::Parser.parse_method_type`, which
|
|
14
|
+
# has no annotation prefix, so the line becomes a `SyntaxErrorAssertion` and nothing of it survives.
|
|
15
|
+
#
|
|
16
|
+
# Both were silent (ADR-32 WD12), and the second reached users as #997's "did not parse … DROPPED"
|
|
17
|
+
# notice on input that is valid RBS for the other two readers.
|
|
18
|
+
#
|
|
19
|
+
# This is a post-parse repair of the gem's annotation list, not a rewrite of the Ruby source. A source
|
|
20
|
+
# rewrite would have to put the annotation and the method type on two comment lines — the gem has no
|
|
21
|
+
# one-line spelling for the pair, which is the defect — and inserting a line moves every later line,
|
|
22
|
+
# including the ones a `#:` notice reports and the one a `def` uses to find its comment block.
|
|
23
|
+
#
|
|
24
|
+
# The repair is exact rather than heuristic because every step is the gem's own reading:
|
|
25
|
+
#
|
|
26
|
+
# - the leading `%a{…}` spellings are delimited by the gem's own `Tokenizer`, the lexer that already
|
|
27
|
+
# accepts them in the own-line form, so what counts as an annotation cannot drift from upstream;
|
|
28
|
+
# - each half is re-read by the gem's own `AnnotationParser` as the comment the author would have written
|
|
29
|
+
# in the own-line form (`# @rbs %a{…}`, then `# @rbs () -> String` or `#: () -> String`), on the same
|
|
30
|
+
# line and column, so the replacement annotations are indistinguishable from ones upstream built;
|
|
31
|
+
# - the split lands only when the remainder re-reads as a well-formed method type. Anything else keeps
|
|
32
|
+
# the gem's original annotation untouched, so a genuinely malformed line still reaches the WD12
|
|
33
|
+
# notices, and a split can never trade one silent loss for another.
|
|
34
|
+
module SameLineAnnotations
|
|
35
|
+
module_function
|
|
36
|
+
|
|
37
|
+
# The `@rbs` marker as the gem's `annotation_comment?` detects it, with the whitespace before it.
|
|
38
|
+
RBS_MARKER = /\A\s*@rbs\b/
|
|
39
|
+
|
|
40
|
+
# Replaces, in `parsing_result.annotations`, every same-line form that splits cleanly with the
|
|
41
|
+
# annotation and the method type it spells. Idempotent: a repaired list has no same-line form left.
|
|
42
|
+
def split!(parsing_result)
|
|
43
|
+
return parsing_result unless parsing_result.is_a?(::RBS::Inline::AnnotationParser::ParsingResult)
|
|
44
|
+
|
|
45
|
+
parsing_result.annotations.replace(parsing_result.annotations.flat_map { |annotation| expand(annotation) })
|
|
46
|
+
parsing_result
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Every `ParsingResult` a parsed declaration tree holds, which are the objects the writer reads.
|
|
50
|
+
def each_parsing_result(nodes, &)
|
|
51
|
+
nodes.each do |node|
|
|
52
|
+
comments = node.respond_to?(:comments) ? node.comments : nil
|
|
53
|
+
yield comments if comments.is_a?(::RBS::Inline::AnnotationParser::ParsingResult)
|
|
54
|
+
each_parsing_result(node.members, &) if node.respond_to?(:members)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# The text an `@rbs %a{…}` line carries after its annotations that the gem discarded — `nil` when
|
|
59
|
+
# there is none. Call it on an annotation {.split!} has already seen: a remainder that survives the
|
|
60
|
+
# split is one that did not read as a method type.
|
|
61
|
+
def dropped_remainder(annotation)
|
|
62
|
+
return nil unless annotation.is_a?(::RBS::Inline::AST::Annotations::RBSAnnotation)
|
|
63
|
+
|
|
64
|
+
parts = same_line_parts(annotation)
|
|
65
|
+
parts && parts[2].strip
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def expand(annotation)
|
|
69
|
+
parts = same_line_parts(annotation)
|
|
70
|
+
return [annotation] if parts.nil?
|
|
71
|
+
|
|
72
|
+
prefix, spellings, rest = parts
|
|
73
|
+
method_type = reparse(annotation, "##{prefix}#{rest}")
|
|
74
|
+
return [annotation] unless well_formed_method_type?(method_type)
|
|
75
|
+
|
|
76
|
+
# Re-read even when `annotation` already is the `@rbs %a{}` carrier: the original still spans the
|
|
77
|
+
# method type in its source, and {.dropped_remainder} reads exactly that to report a failed split.
|
|
78
|
+
carrier = reparse(annotation, "# @rbs #{spellings.join(' ')}")
|
|
79
|
+
return [annotation] unless carrier.is_a?(::RBS::Inline::AST::Annotations::RBSAnnotation)
|
|
80
|
+
|
|
81
|
+
[carrier, method_type]
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# `[prefix, spellings, rest]` for an annotation whose payload opens with one or more `%a{…}` and
|
|
85
|
+
# continues with something else, or `nil`. `prefix` is the marker as written (`" @rbs"` or `":"`),
|
|
86
|
+
# so the re-read keeps the gem's continuation offset for a multi-line comment block.
|
|
87
|
+
def same_line_parts(annotation)
|
|
88
|
+
# `annotations` also holds the `CommentLines` of plain prose, which has no `source` to read.
|
|
89
|
+
prefix =
|
|
90
|
+
case annotation
|
|
91
|
+
when ::RBS::Inline::AST::Annotations::RBSAnnotation
|
|
92
|
+
annotation.source.string[RBS_MARKER]
|
|
93
|
+
when ::RBS::Inline::AST::Annotations::SyntaxErrorAssertion
|
|
94
|
+
":" if annotation.source.string.start_with?(":")
|
|
95
|
+
end
|
|
96
|
+
return nil if prefix.nil?
|
|
97
|
+
|
|
98
|
+
spellings, rest = leading_annotations(annotation.source.string.delete_prefix(prefix))
|
|
99
|
+
return nil if spellings.empty? || rest.strip.empty?
|
|
100
|
+
|
|
101
|
+
[prefix, spellings, rest]
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# The `%a{…}` tokens the gem's tokenizer reads at the head of `body`, and the unread text after them.
|
|
105
|
+
def leading_annotations(body)
|
|
106
|
+
tokenizer = ::RBS::Inline::AnnotationParser::Tokenizer.new(StringScanner.new(body))
|
|
107
|
+
trivia = ::RBS::Inline::AST::Tree.new(:rigor_same_line_annotations)
|
|
108
|
+
tokenizer.advance(trivia)
|
|
109
|
+
tokenizer.advance(trivia)
|
|
110
|
+
|
|
111
|
+
spellings = []
|
|
112
|
+
while tokenizer.type?(::RBS::Inline::AnnotationParser::Tokens::T_ANNOTATION)
|
|
113
|
+
spellings << tokenizer.lookahead1[1]
|
|
114
|
+
tokenizer.advance(trivia)
|
|
115
|
+
end
|
|
116
|
+
[spellings, tokenizer.rest]
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Reads `comment_text` through the gem's `AnnotationParser` as if it stood where `annotation`'s comment
|
|
120
|
+
# block does — same first line, same column, continuation lines re-prefixed with the `#` that
|
|
121
|
+
# `CommentLines#string` strips — and returns the one annotation it yields, or `nil`.
|
|
122
|
+
def reparse(annotation, comment_text)
|
|
123
|
+
location = annotation.source.comments.first&.location
|
|
124
|
+
return nil if location.nil?
|
|
125
|
+
|
|
126
|
+
indent = " " * location.start_column
|
|
127
|
+
padding = "\n" * (location.start_line - 1)
|
|
128
|
+
source = "#{padding}#{indent}#{comment_text.gsub("\n") { "\n#{indent}#" }}\n"
|
|
129
|
+
results = ::RBS::Inline::AnnotationParser.parse(::Prism.parse(source).comments)
|
|
130
|
+
return nil unless results.size == 1
|
|
131
|
+
|
|
132
|
+
annotations = results.first.annotations
|
|
133
|
+
annotations.size == 1 && annotations.first.is_a?(::RBS::Inline::AST::Annotations::Base) ? annotations.first : nil
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def well_formed_method_type?(annotation)
|
|
137
|
+
case annotation
|
|
138
|
+
when ::RBS::Inline::AST::Annotations::MethodTypeAssertion
|
|
139
|
+
true
|
|
140
|
+
when ::RBS::Inline::AST::Annotations::Method
|
|
141
|
+
annotation.method_types.is_a?(Array) && annotation.error_source.nil?
|
|
142
|
+
else
|
|
143
|
+
false
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|