rigortype 0.3.9 → 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/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 +127 -4
- data/docs/handbook/03-narrowing.md +95 -10
- data/docs/handbook/04-tuples-and-shapes.md +8 -6
- data/docs/handbook/07-rbs-and-extended.md +16 -11
- data/docs/handbook/10-sorbet.md +9 -10
- data/docs/handbook/11-sig-gen.md +454 -13
- data/docs/manual/02-cli-reference.md +63 -2
- data/docs/manual/03-configuration.md +7 -0
- data/docs/manual/04-diagnostics.md +4 -0
- data/docs/manual/07-plugins.md +1 -1
- data/docs/manual/10-mcp-server.md +3 -2
- data/docs/manual/16-rbs-extended-annotations.md +40 -7
- 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 +243 -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 +110 -4
- data/docs/manual/plugins/rigor-activestorage.md +8 -1
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +11 -5
- 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 +212 -25
- 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 +1 -1
- data/lib/rigor/analysis/check_rules/declaration_sourced_guard.rb +167 -2
- data/lib/rigor/analysis/check_rules/lexical_method_sites.rb +189 -0
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +5 -3
- data/lib/rigor/analysis/check_rules/rule_ids.rb +20 -5
- data/lib/rigor/analysis/check_rules/rule_walk.rb +2 -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 +36 -2
- data/lib/rigor/analysis/check_rules.rb +520 -49
- data/lib/rigor/analysis/dependency_recorder.rb +23 -0
- data/lib/rigor/analysis/fact_store.rb +9 -0
- data/lib/rigor/analysis/incremental.rb +26 -0
- data/lib/rigor/analysis/incremental_session.rb +36 -4
- data/lib/rigor/analysis/project_scan.rb +11 -1
- data/lib/rigor/analysis/reachability/plugin_roots.rb +0 -1
- data/lib/rigor/analysis/reachability/scan_cache.rb +1 -0
- data/lib/rigor/analysis/rule_catalog.rb +127 -0
- data/lib/rigor/analysis/run_cache_key.rb +20 -11
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +167 -11
- data/lib/rigor/analysis/runner/effect_envelope_pass.rb +9 -4
- data/lib/rigor/analysis/runner/pool_coordinator.rb +107 -15
- data/lib/rigor/analysis/runner/project_pre_passes.rb +26 -7
- data/lib/rigor/analysis/runner.rb +278 -20
- 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 +53 -10
- data/lib/rigor/bleeding_edge.rb +0 -2
- data/lib/rigor/builtins/hkt_builtins.rb +1 -0
- data/lib/rigor/builtins/imported_refinements.rb +4 -0
- data/lib/rigor/builtins/regex_refinement.rb +17 -9
- data/lib/rigor/builtins/static_return_refinements.rb +2 -0
- data/lib/rigor/cache/descriptor.rb +6 -1
- data/lib/rigor/cache/engine_source.rb +29 -1
- data/lib/rigor/cache/incremental_snapshot.rb +33 -1
- data/lib/rigor/cache/rbs_cache_producer.rb +4 -0
- data/lib/rigor/cache/rbs_descriptor.rb +37 -7
- data/lib/rigor/cache/store.rb +0 -1
- data/lib/rigor/ci_detector.rb +1 -0
- data/lib/rigor/cli/doc_links.rb +1 -1
- data/lib/rigor/cli/docs_command.rb +4 -4
- data/lib/rigor/cli/plugin_command.rb +3 -3
- data/lib/rigor/cli/prism_colorizer.rb +0 -1
- data/lib/rigor/cli/sig_gen_command.rb +210 -29
- data/lib/rigor/cli/skill_command.rb +1 -1
- data/lib/rigor/cli/skill_describe.rb +0 -1
- data/lib/rigor/cli/type_of_command.rb +19 -5
- 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.rb +21 -3
- data/lib/rigor/configuration/severity_profile.rb +19 -3
- data/lib/rigor/configuration.rb +66 -3
- data/lib/rigor/effects/ancestry_recorder.rb +191 -0
- data/lib/rigor/effects/attribution.rb +11 -2
- 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 +9 -2
- data/lib/rigor/effects/definition_context.rb +179 -0
- data/lib/rigor/effects/effect_table.rb +11 -3
- data/lib/rigor/effects/envelope_check.rb +1 -1
- data/lib/rigor/effects/envelope_index.rb +15 -0
- data/lib/rigor/effects/file_collection.rb +59 -5
- data/lib/rigor/effects/framework_units.rb +1 -1
- data/lib/rigor/effects/identity.rb +16 -0
- data/lib/rigor/effects/local_ownership.rb +38 -12
- data/lib/rigor/effects/method_key.rb +21 -0
- data/lib/rigor/effects/mutation_classifier.rb +23 -12
- data/lib/rigor/effects/plugin_facts.rb +43 -31
- data/lib/rigor/effects/propagator.rb +295 -16
- data/lib/rigor/effects/registry.rb +1 -1
- data/lib/rigor/effects/scanner.rb +121 -72
- data/lib/rigor/effects/signature_sources.rb +1 -1
- data/lib/rigor/effects/snapshot.rb +2 -1
- data/lib/rigor/effects/summary.rb +27 -4
- data/lib/rigor/effects/unit_scan.rb +385 -30
- data/lib/rigor/effects/visibility.rb +101 -0
- data/lib/rigor/environment/lockfile_resolver.rb +17 -0
- data/lib/rigor/environment/member_consistency/comparator.rb +708 -0
- data/lib/rigor/environment/member_consistency.rb +298 -0
- data/lib/rigor/environment/rbs_loader.rb +399 -133
- data/lib/rigor/environment.rb +103 -38
- data/lib/rigor/hashing/xxh3.rb +264 -0
- data/lib/rigor/inference/acceptance.rb +139 -9
- 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 +73 -27
- data/lib/rigor/inference/block_repetition.rb +71 -0
- data/lib/rigor/inference/body_fixpoint.rb +2 -1
- data/lib/rigor/inference/budget_trace.rb +2 -1
- 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 +387 -15
- data/lib/rigor/inference/closure_escape_analyzer.rb +157 -13
- data/lib/rigor/inference/content_join.rb +200 -27
- 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/element_read_widening.rb +22 -10
- data/lib/rigor/inference/error_info.rb +196 -0
- data/lib/rigor/inference/expression_typer.rb +1532 -496
- data/lib/rigor/inference/external_ancestor_resolution.rb +267 -0
- 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/index_write_widening.rb +16 -3
- 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 +167 -17
- 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 +85 -24
- data/lib/rigor/inference/method_dispatcher/facet_distribution.rb +147 -0
- data/lib/rigor/inference/method_dispatcher/hash_transform_keys_folding.rb +191 -0
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +4 -0
- data/lib/rigor/inference/method_dispatcher/match_data_folding.rb +159 -0
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +113 -73
- 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/rbs_dispatch.rb +881 -38
- data/lib/rigor/inference/method_dispatcher/self_substitute.rb +142 -0
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +128 -53
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +1 -1
- data/lib/rigor/inference/method_dispatcher.rb +214 -13
- data/lib/rigor/inference/method_parameter_binder.rb +8 -3
- data/lib/rigor/inference/multi_target_binder.rb +340 -52
- data/lib/rigor/inference/mutation_rejoin.rb +4 -1
- data/lib/rigor/inference/mutation_widening.rb +70 -48
- data/lib/rigor/inference/narrowing.rb +540 -120
- 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 +152 -9
- data/lib/rigor/inference/parameter_inference_collector.rb +3 -2
- data/lib/rigor/inference/project_method_ownership.rb +136 -0
- data/lib/rigor/inference/project_patched_methods.rb +7 -2
- data/lib/rigor/inference/project_patched_scanner.rb +7 -3
- data/lib/rigor/inference/receiver_alias.rb +90 -1
- data/lib/rigor/inference/receiver_blind_block.rb +219 -0
- data/lib/rigor/inference/refinement_mutation.rb +15 -11
- 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 +4615 -551
- data/lib/rigor/inference/statement_evaluator.rb +3176 -490
- data/lib/rigor/inference/stored_block_call.rb +54 -0
- data/lib/rigor/inference/string_mutation.rb +44 -7
- data/lib/rigor/inference/unknown_store_widening.rb +200 -0
- data/lib/rigor/inference/unthreaded_rebinds.rb +282 -0
- data/lib/rigor/language_server/debouncer.rb +0 -1
- data/lib/rigor/language_server/diagnostic_publisher.rb +3 -2
- data/lib/rigor/language_server/hover_renderer.rb +3 -3
- data/lib/rigor/language_server/project_context.rb +5 -3
- data/lib/rigor/mcp/server.rb +2 -1
- data/lib/rigor/plugin/base.rb +168 -5
- data/lib/rigor/plugin/box_probe.rb +91 -0
- data/lib/rigor/plugin/bundled_catalog.rb +1 -1
- data/lib/rigor/plugin/effect_attribution.rb +58 -4
- data/lib/rigor/plugin/loader.rb +2 -1
- data/lib/rigor/plugin/macro/block_as_method.rb +45 -6
- data/lib/rigor/plugin/manifest.rb +71 -10
- data/lib/rigor/plugin/registry.rb +35 -1
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +9 -3
- data/lib/rigor/plugin/template_unit.rb +196 -0
- data/lib/rigor/plugin.rb +1 -0
- data/lib/rigor/protection/discovery_seed.rb +3 -1
- data/lib/rigor/protection/kill_signature.rb +0 -1
- data/lib/rigor/protection/mutation_cache.rb +1 -2
- data/lib/rigor/rbs_extended.rb +27 -0
- data/lib/rigor/reflection/constant_ancestors.rb +97 -0
- data/lib/rigor/reflection/constant_path.rb +19 -6
- data/lib/rigor/reflection.rb +72 -105
- data/lib/rigor/scope/discovery_index.rb +135 -2
- data/lib/rigor/scope.rb +859 -49
- 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 +558 -31
- data/lib/rigor/sig_gen/inline_declarations.rb +184 -0
- data/lib/rigor/sig_gen/method_candidate.rb +47 -3
- data/lib/rigor/sig_gen/observation_collector.rb +1 -1
- data/lib/rigor/sig_gen/renderer.rb +124 -9
- data/lib/rigor/sig_gen/skip_reason_catalog.rb +44 -1
- data/lib/rigor/sig_gen/write_result.rb +19 -3
- data/lib/rigor/sig_gen/writer.rb +166 -35
- data/lib/rigor/sig_gen.rb +3 -0
- data/lib/rigor/signature_path_audit.rb +1 -1
- data/lib/rigor/source/node_walker.rb +0 -3
- data/lib/rigor/source/parameter_envelope.rb +72 -0
- data/lib/rigor/source.rb +1 -0
- data/lib/rigor/type/combinator.rb +88 -12
- data/lib/rigor/type/difference.rb +1 -0
- data/lib/rigor/type/hash_shape.rb +1 -1
- data/lib/rigor/type/refined.rb +1 -0
- data/lib/rigor/version.rb +1 -1
- data/lib/rigor.rb +1 -0
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/effects.rb +1 -0
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +9 -5
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +13 -4
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +0 -1
- 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 +239 -4
- 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/effects.rb +1 -0
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +9 -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 +380 -3
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +14 -6
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +281 -35
- data/plugins/rigor-activerecord/sig/active_record/relation.rbs +206 -31
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +25 -14
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext/effects.rb +9 -2
- data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +171 -5
- data/plugins/rigor-dry-monads/lib/rigor/plugin/dry_monads.rb +2 -0
- data/plugins/rigor-ethon/lib/rigor/plugin/ethon.rb +1 -0
- data/plugins/rigor-ffi/lib/rigor/plugin/ffi/types.rb +1 -1
- 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.rb +72 -2
- data/plugins/rigor-graphql/sig/graphql.rbs +485 -0
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +2 -0
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +11 -7
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +35 -37
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +0 -1
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +2 -0
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +1 -0
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +9 -17
- 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 +217 -36
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/schedule_scan.rb +1 -0
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +9 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +0 -1
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +46 -1
- data/plugins/rigor-sorbet/sig/sorbet.rbs +277 -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/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 +12 -10
- data/sig/rigor/inference/optimistic_origin.rbs +10 -0
- data/sig/rigor/inference.rbs +6 -4
- 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 +1 -1
- data/sig/rigor/plugin/loader.rbs +3 -3
- data/sig/rigor/plugin/manifest.rbs +50 -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 +7 -6
- data/sig/rigor/scope.rbs +135 -20
- data/sig/rigor/sig_gen/skip_reason_catalog.rbs +14 -7
- data/sig/rigor/source.rbs +4 -4
- data/sig/rigor/testing.rbs +10 -4
- data/sig/rigor/type.rbs +6 -0
- data/sig/rigor.rbs +38 -20
- data/skills/rigor-ask/SKILL.md +8 -5
- 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 +12 -25
- 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 +9 -7
- data/skills/rigor-project-init/references/01-detect.md +13 -9
- data/skills/rigor-project-init/references/02-configure.md +33 -8
- 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-protection-uplift/SKILL.md +4 -6
- data/skills/rigor-rbs-setup/SKILL.md +4 -2
- data/skills/rigor-type-oracle/SKILL.md +4 -6
- data/skills/rigor-type-oracle/references/01-oracle-commands.md +12 -8
- data/skills/rigor-type-oracle/references/03-gap-protocol.md +0 -3
- data/skills/rigor-unused-adjudicate/SKILL.md +4 -2
- data/skills/rigor-upgrade/SKILL.md +13 -8
- metadata +108 -1
|
@@ -29,6 +29,14 @@ module Rigor
|
|
|
29
29
|
# The {TypeTranslator} table documents coverage. Most of Sorbet's vocabulary translates; remaining
|
|
30
30
|
# gaps (`T.proc`, `T::Struct` subclasses, `T.attached_class`, etc.) degrade silently to `Dynamic[top]`.
|
|
31
31
|
#
|
|
32
|
+
# Issue #1097 — the plugin also ships `sig/sorbet.rbs`, a bundled declaration of the annotation DSL
|
|
33
|
+
# surface itself: `T`'s type-expression functions, the `T::X[...]` constructors, `T::Sig`'s `sig`
|
|
34
|
+
# verb (reached via the manifest `rbs_complete_extends:` bridge over `extend T::Sig`), the
|
|
35
|
+
# `DeclBuilder` the sig block `instance_eval`s on (via `block_as_methods:`), and the
|
|
36
|
+
# `T::Struct` / `T::Enum` family (via `rbs_complete_ancestors:`). The value-side assertions
|
|
37
|
+
# (`T.let`/`T.cast`/`T.must`/…) stay recogniser-owned — RBS cannot express "return the asserted
|
|
38
|
+
# type" — and `T`'s declared surface is intentionally partial behind `open_receivers:`.
|
|
39
|
+
#
|
|
32
40
|
# Architecture: per-run `Catalog` is built lazily on first access by walking every configured `paths:`
|
|
33
41
|
# entry's `.rb` files plus every `rbi_paths:` entry's `.rbi` files (slice 4) via the plugin's
|
|
34
42
|
# `IoBoundary`. The catalog is frozen after the first build and consulted by the `dynamic_return` rule
|
|
@@ -70,7 +78,43 @@ module Rigor
|
|
|
70
78
|
# effect of recursing into the parent root.
|
|
71
79
|
"rbi_paths" => { kind: :array, default: ["sorbet/rbi"] },
|
|
72
80
|
"enforce_sigil" => { kind: :boolean, default: true }
|
|
73
|
-
}
|
|
81
|
+
},
|
|
82
|
+
# #1097 — bundled sorbet-runtime DSL surface (`sig/sorbet.rbs`). `sig` itself reaches the
|
|
83
|
+
# class object through `extend T::Sig` (or the `< T::ImmutableStruct` / `< T::Enum`
|
|
84
|
+
# family, which carry the edge themselves), which is
|
|
85
|
+
# why `rbs_complete_extends:` — the extend-edge allow-list — carries `T::Sig` /
|
|
86
|
+
# `T::Helpers` / `T::Generic`, and `rbs_complete_ancestors:` carries the Struct/Enum family
|
|
87
|
+
# for the subclass bridge.
|
|
88
|
+
signature_paths: ["sig"],
|
|
89
|
+
rbs_complete_extends: %w[T::Sig T::Helpers T::Generic],
|
|
90
|
+
rbs_complete_ancestors: %w[T::Struct T::InexactStruct T::ImmutableStruct T::Enum],
|
|
91
|
+
# `sig { ... }` bodies are `instance_eval`'d on a `DeclBuilder`
|
|
92
|
+
# (`T::Private::Methods._run_builder`), so `params` / `returns` / `void` resolve on the
|
|
93
|
+
# builder, not the enclosing class. `T::Sig::WithoutRuntime.sig` is the direct-call twin —
|
|
94
|
+
# a singleton method on the module, matching by name equality.
|
|
95
|
+
block_as_methods: [
|
|
96
|
+
Rigor::Plugin::Macro::BlockAsMethod.new(
|
|
97
|
+
receiver_constraint: "T::Sig",
|
|
98
|
+
method_names: %i[sig],
|
|
99
|
+
self_type: "T::Private::Methods::DeclBuilder"
|
|
100
|
+
),
|
|
101
|
+
Rigor::Plugin::Macro::BlockAsMethod.new(
|
|
102
|
+
receiver_constraint: "T::Sig::WithoutRuntime",
|
|
103
|
+
method_names: %i[sig],
|
|
104
|
+
self_type: "T::Private::Methods::DeclBuilder"
|
|
105
|
+
)
|
|
106
|
+
],
|
|
107
|
+
# The declared surface is deliberately partial — `T` is an open module whose runtime
|
|
108
|
+
# surface is much larger than the DSL (version-dependent internals, `T::Private::*`,
|
|
109
|
+
# `T::Configuration`, `T::Utils`). Open receivers keep an unmodelled `T.something` opaque
|
|
110
|
+
# rather than a `call.undefined-method` false positive. `DeclBuilder` is NOT open —
|
|
111
|
+
# `sig { typo }` is a real bug and stays a diagnostic.
|
|
112
|
+
open_receivers: %w[T T::Sig T::Sig::WithoutRuntime T::Helpers T::Generic
|
|
113
|
+
T::Utils T::Configuration T::Private T::Private::Methods
|
|
114
|
+
T::Props T::Props::ClassMethods T::Props::CustomType
|
|
115
|
+
T::Types T::Types::Base T::Array T::Hash T::Set
|
|
116
|
+
T::Enumerable T::Enumerator T::Range T::Class
|
|
117
|
+
T::InexactStruct T::Struct T::ImmutableStruct T::Enum]
|
|
74
118
|
)
|
|
75
119
|
|
|
76
120
|
def init(services)
|
|
@@ -441,6 +485,7 @@ module Rigor
|
|
|
441
485
|
# Frozen empty bundle used when the `:catalog` producer failed (e.g. a project I/O error) so downstream
|
|
442
486
|
# reads see a well-formed shape rather than nil.
|
|
443
487
|
EMPTY_CATALOG_BUNDLE = { catalog: Catalog.new.freeze!, sigil_by_path: {}, parse_errors_by_path: {} }.freeze
|
|
488
|
+
Ractor.make_shareable(EMPTY_CATALOG_BUNDLE)
|
|
444
489
|
private_constant :EMPTY_CATALOG_BUNDLE
|
|
445
490
|
|
|
446
491
|
# @param root — directory or single file.
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# Bundled RBS for the sorbet-runtime annotation DSL (issue #1097).
|
|
2
|
+
#
|
|
3
|
+
# sorbet-runtime ships RBI, not RBS, so none of the annotation surface (`T`, `T::Sig`, the
|
|
4
|
+
# `DeclBuilder` behind `sig { ... }`, the `T::Array[...]` constructors, the `T::Helpers` /
|
|
5
|
+
# `T::Generic` class macros) resolves for the analyzer. This file declares that surface so the
|
|
6
|
+
# DSL *expressions themselves* type; the plugin's `AssertionRecognizer` continues to own the
|
|
7
|
+
# value-sensitive calls (`T.let` / `T.cast` / `T.must` / `T.bind` / `T.assert_type!` /
|
|
8
|
+
# `T.reveal_type` / `T.unsafe`) ahead of this RBS — the signatures here deliberately agree with
|
|
9
|
+
# it (`T.unsafe` stays `untyped`, `T.bind` returns `nil`) for the cases the recognizer declines.
|
|
10
|
+
#
|
|
11
|
+
# Provenance (docs/agents/type-authoring.md): `rigor sig-gen` cannot produce this file — the DSL
|
|
12
|
+
# methods are installed by `Module#extend` hooks and `instance_eval` in sorbet-runtime's source
|
|
13
|
+
# (sorbet-runtime 0.5.11766, `lib/types/{sig,_types,generic,helpers,struct,enum}.rb` and
|
|
14
|
+
# `lib/types/private/methods/decl_builder.rb`), so every entry was hand-derived by reading that
|
|
15
|
+
# source. Members that do not exist at that version's runtime location are deliberately absent.
|
|
16
|
+
#
|
|
17
|
+
# Two Rigor-side mechanisms complete the picture (manifest fields):
|
|
18
|
+
#
|
|
19
|
+
# - `rbs_complete_extends:` — `extend T::Sig` in a class/module body is what puts `sig` on the
|
|
20
|
+
# class object's singleton; the dispatch bridge resolves those calls through the module's
|
|
21
|
+
# instance surface declared here.
|
|
22
|
+
# - `block_as_methods:` — `sig`'s block is `instance_eval`'d on a `DeclBuilder`
|
|
23
|
+
# (`T::Private::Methods.declare_sig` → `DeclBuilder#instance_eval`), so `sig` bodies bind
|
|
24
|
+
# `self` to `T::Private::Methods::DeclBuilder`, NOT to the enclosing class.
|
|
25
|
+
|
|
26
|
+
module T
|
|
27
|
+
# `T::Boolean` is a runtime constant (`T.any(TrueClass, FalseClass)` → a `T::Types::Union`
|
|
28
|
+
# instance), not a module — it appears in `params`/`returns` argument position as a const read.
|
|
29
|
+
Boolean: ::T::Types::Union
|
|
30
|
+
|
|
31
|
+
# The type-ASSERTION functions (`T.let`, `T.cast`, `T.assert_type!`, `T.bind`, `T.must`,
|
|
32
|
+
# `T.must_because`, `T.reveal_type`, `T.absurd`, `T.unsafe`) are deliberately NOT declared here.
|
|
33
|
+
# Their static return is the *asserted* type (the second argument, translated) or the nil-stripped
|
|
34
|
+
# inner type — semantics RBS cannot express — so the plugin's `AssertionRecognizer` /
|
|
35
|
+
# `AbsurdRecognizer` owns them ahead of dispatch, and a declined call degrades through `T`'s
|
|
36
|
+
# `open_receivers:` entry to opaque rather than a wrong `X` reading.
|
|
37
|
+
|
|
38
|
+
# Type-expression constructors — used in `params`/`returns` argument position.
|
|
39
|
+
def self.nilable: (untyped type) -> ::T::Types::Base
|
|
40
|
+
def self.untyped: () -> ::T::Types::Base
|
|
41
|
+
def self.noreturn: () -> ::T::Types::Base
|
|
42
|
+
def self.anything: () -> ::T::Types::Base
|
|
43
|
+
def self.all: (untyped type_a, untyped type_b, *untyped types) -> ::T::Types::Base
|
|
44
|
+
def self.any: (untyped type_a, untyped type_b, *untyped types) -> ::T::Types::Base
|
|
45
|
+
def self.class_of: (untyped arg) -> ::T::Types::Base
|
|
46
|
+
def self.self_type: () -> ::T::Types::Base
|
|
47
|
+
def self.attached_class: () -> ::T::Types::Base
|
|
48
|
+
def self.type_parameter: (::Symbol name) -> ::T::Types::TypeParameter
|
|
49
|
+
# `type=nil, &blk` — the positional form is a kept-for-migration legacy path (`_types.rb`);
|
|
50
|
+
# the block form wraps in `T::Private::Types::TypeAlias`.
|
|
51
|
+
def self.type_alias: (?untyped type) ?{ () -> untyped } -> ::T::Types::Base
|
|
52
|
+
|
|
53
|
+
# `T.proc` returns a DeclBuilder in `Modes.proc` (`T::Private::Methods.start_proc`), so the
|
|
54
|
+
# `T.proc.params(x: Integer).returns(String)` chain resolves through the same builder surface.
|
|
55
|
+
def self.proc: () -> ::T::Private::Methods::DeclBuilder
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# `T::Sig` is a mixin a class EXTENDS (`extend T::Sig`) to gain the class-level `sig` verb —
|
|
59
|
+
# sorbet-runtime does not patch `Module`. `sig` itself returns nil at runtime
|
|
60
|
+
# (`declare_sig` stores the DeclarationBlock and returns nil).
|
|
61
|
+
module T::Sig
|
|
62
|
+
def sig: (?untyped arg0) ?{ () -> untyped } -> nil
|
|
63
|
+
|
|
64
|
+
# `T::Sig::WithoutRuntime.sig { ... }` is a no-op shim for contexts where the runtime wrapper
|
|
65
|
+
# cannot be installed; it is called ON the module, so `sig` here is a module-singleton method.
|
|
66
|
+
# `extend T::Sig::WithoutRuntime` installs nothing at runtime, so no instance `sig` is declared.
|
|
67
|
+
module WithoutRuntime
|
|
68
|
+
def self.sig: (?untyped arg0) ?{ () -> untyped } -> nil
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# The builder `sig`'s block is `instance_eval`'d on (`DeclBuilder#instance_eval(&blk)` via
|
|
73
|
+
# `T::Private::Methods._run_builder`). Every DSL method returns `self` so the
|
|
74
|
+
# `params(...).returns(...).checked(:always)` chain keeps typing.
|
|
75
|
+
class T::Private::Methods::DeclBuilder
|
|
76
|
+
def params: (*untyped unused_positional_params, **untyped params) -> self
|
|
77
|
+
def returns: (untyped type) -> self
|
|
78
|
+
def void: () -> self
|
|
79
|
+
def bind: (untyped type) -> self
|
|
80
|
+
def checked: (untyped level) -> self
|
|
81
|
+
def on_failure: (*untyped args) -> self
|
|
82
|
+
def abstract: () -> self
|
|
83
|
+
def final: () -> self
|
|
84
|
+
def override: (?allow_incompatible: bool | Symbol) -> self
|
|
85
|
+
def overridable: () -> self
|
|
86
|
+
def type_parameters: (*untyped names) -> self
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# The `T::X[...]` type constructors are modules with a singleton `[]` (`_types.rb`), returning the
|
|
90
|
+
# corresponding `T::Types::TypedX` instance. The carriers below exist so the constructor's return
|
|
91
|
+
# reads as a real nominal rather than `Dynamic[top]`.
|
|
92
|
+
module T::Array
|
|
93
|
+
def self.[]: (untyped type) -> ::T::Types::TypedArray
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
module T::Hash
|
|
97
|
+
def self.[]: (untyped keys, untyped values) -> ::T::Types::TypedHash
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
module T::Set
|
|
101
|
+
def self.[]: (untyped type) -> ::T::Types::TypedSet
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
module T::Enumerable
|
|
105
|
+
def self.[]: (untyped type) -> ::T::Types::TypedEnumerable
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
module T::Enumerator
|
|
109
|
+
def self.[]: (untyped type) -> ::T::Types::TypedEnumerator
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
module T::Range
|
|
113
|
+
def self.[]: (untyped type) -> ::T::Types::TypedRange
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
module T::Class
|
|
117
|
+
def self.[]: (untyped type) -> ::T::Types::TypedClass
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Carrier classes for the `T::X[...]` constructors and the `T.*` type-expression functions. The
|
|
121
|
+
# internal `T::Types::*` class names are the runtime classes (`types/types/*.rb`).
|
|
122
|
+
module T::Types
|
|
123
|
+
class Base
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
class TypedArray < Base
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
class TypedHash < Base
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
class TypedSet < Base
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
class TypedEnumerable < Base
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
class TypedEnumerator < Base
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
class TypedRange < Base
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
class TypedClass < Base
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
class Union < Base
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
class Intersection < Base
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
class TypeParameter < Base
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
class TypeMember < Base
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
class TypeTemplate < Base
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
class Proc < Base
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# `extend T::Helpers` installs the class/module declaration macros (`abstract!`, `interface!`,
|
|
167
|
+
# `final!`, `sealed!`, `requires_ancestor`, `mixes_in_class_methods`). All return void-ish values
|
|
168
|
+
# from `T::Private::{Abstract,Final,Sealed}` bookkeeping (`helpers.rb`).
|
|
169
|
+
module T::Helpers
|
|
170
|
+
def abstract!: () -> void
|
|
171
|
+
def interface!: () -> void
|
|
172
|
+
def final!: () -> void
|
|
173
|
+
def sealed!: () -> void
|
|
174
|
+
def mixes_in_class_methods: (::Module mod, *::Module mods) -> void
|
|
175
|
+
def requires_ancestor: () { () -> untyped } -> void
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# `extend T::Generic` installs the type-member macros — `Elem = type_member` is the common shape
|
|
179
|
+
# (`generic.rb`). `[]` is the generic-application stub (`def [](*types); self; end`).
|
|
180
|
+
module T::Generic
|
|
181
|
+
# `generic.rb` — `extend T::Generic` alone also installs the helper macros: the module
|
|
182
|
+
# `include`s `T::Helpers` (and `Kernel`), so its instance surface carries `abstract!` et al.
|
|
183
|
+
include T::Helpers
|
|
184
|
+
|
|
185
|
+
def []: (*untyped types) -> self
|
|
186
|
+
def type_member: (?untyped variance) ?{ () -> untyped } -> ::T::Types::TypeMember
|
|
187
|
+
def type_template: (?untyped variance) ?{ () -> untyped } -> ::T::Types::TypeTemplate
|
|
188
|
+
def has_attached_class!: (?untyped variance) ?{ () -> untyped } -> void
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# `T::Props` is the property mixin; its `included` hook `extend`s the includer with
|
|
192
|
+
# `ClassMethods` (`mixes_in_class_methods`), which is where `prop` / `const` live. The hook itself
|
|
193
|
+
# is not modelled — `include T::Props` alone does not put `prop` on the class in this
|
|
194
|
+
# declaration either — but the `T::Struct` family below declares the same `extend` edges directly,
|
|
195
|
+
# matching the runtime outcome for `< T::Struct` subclasses.
|
|
196
|
+
module T::Props
|
|
197
|
+
module ClassMethods
|
|
198
|
+
def prop: (::Symbol name, untyped cls, **untyped rules) -> void
|
|
199
|
+
def const: (::Symbol name, untyped cls_or_args, **untyped args) -> void
|
|
200
|
+
def props: () -> ::Hash[untyped, untyped]
|
|
201
|
+
def plugins: () -> ::Array[untyped]
|
|
202
|
+
def decorator: () -> ::T::Props::Decorator
|
|
203
|
+
def decorator_class: () -> ::Class
|
|
204
|
+
def validate_prop_value: (untyped prop, untyped val) -> void
|
|
205
|
+
def plugin: (untyped mod) -> void
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
class Decorator
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
module CustomType
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
module Serializable
|
|
215
|
+
# `serializable.rb` — lifted onto includers via `mixes_in_class_methods`.
|
|
216
|
+
module ClassMethods
|
|
217
|
+
def prop_by_serialized_forms: () -> ::Hash[untyped, untyped]
|
|
218
|
+
def from_hash: (untyped hash, ?bool strict) -> untyped
|
|
219
|
+
def from_hash!: (untyped hash) -> untyped
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
module Plugin
|
|
224
|
+
# `plugin.rb` — `mixes_in_class_methods(ClassMethods)`; `included` re-registers the plugin
|
|
225
|
+
# (`child.plugin(self)`), which is what extends `plugin::ClassMethods` onto the target.
|
|
226
|
+
module ClassMethods
|
|
227
|
+
def included: (untyped child) -> void
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# The `T::Struct` family. `struct.rb` has `T::InexactStruct` `include T::Props` (+Serializable,
|
|
233
|
+
# +Constructor); the `mixes_in_class_methods` hooks extend `T::Props::ClassMethods` (then the
|
|
234
|
+
# registered `T::Props::Plugin::ClassMethods`) and `T::Props::Serializable::ClassMethods` onto the
|
|
235
|
+
# class — verified against the runtime singleton ancestry. Neither `T::Sig` nor `T::Helpers` is
|
|
236
|
+
# extended here: `sig` inside a `class Doc < T::Struct` body raises at runtime unless the subclass
|
|
237
|
+
# adds `extend T::Sig` itself (dependabot's `TokenBucket` does exactly that). Only
|
|
238
|
+
# `T::ImmutableStruct` extends `T::Sig` (`struct.rb` — it annotates its own `initialize`). The
|
|
239
|
+
# edges are declared directly so subclasses resolve `prop` / `const` / `from_hash` through the
|
|
240
|
+
# `rbs_complete_ancestors` superclass bridge.
|
|
241
|
+
class T::InexactStruct
|
|
242
|
+
extend T::Props::ClassMethods
|
|
243
|
+
extend T::Props::Plugin::ClassMethods
|
|
244
|
+
extend T::Props::Serializable::ClassMethods
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
class T::Struct < T::InexactStruct
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
class T::ImmutableStruct < T::InexactStruct
|
|
251
|
+
extend T::Sig
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
# `T::Enum` — `enum.rb` `extend`s `T::Sig` and `T::Props::CustomType`; `enums` `yield`s its block
|
|
255
|
+
# so `X = new` inside keeps the subclass's class-object self.
|
|
256
|
+
class T::Enum
|
|
257
|
+
extend T::Sig
|
|
258
|
+
extend T::Props::CustomType
|
|
259
|
+
|
|
260
|
+
def self.enums: () { () -> untyped } -> void
|
|
261
|
+
def serialize: () -> ::String
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
# Namespace-only declarations so bare const reads (`T::Utils`, `T::Configuration`,
|
|
265
|
+
# `T::Private::Methods`) type as `Singleton[...]` instead of `Dynamic[top]`. Their singleton
|
|
266
|
+
# surface is intentionally NOT modelled — they are covered by `open_receivers:` so calls on them
|
|
267
|
+
# degrade to opaque rather than firing `call.undefined-method` on an unmodelled private API.
|
|
268
|
+
module T::Utils
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
module T::Configuration
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
module T::Private
|
|
275
|
+
module Methods
|
|
276
|
+
end
|
|
277
|
+
end
|
|
@@ -6,26 +6,88 @@ module Rigor
|
|
|
6
6
|
class LoadError < ::StandardError
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
+
# Tuple-shaped bucket key so rule-ID rows and message-pattern rows coexist: `message_regex` is
|
|
10
|
+
# `nil` for rule-ID rows and a `Regexp` for message-pattern rows; `rule` and `file` are always
|
|
11
|
+
# present (parse_row raises without them; the generator's group key carries both). `count`
|
|
12
|
+
# intentionally shadows `Struct#count` — PHPStan-compatible field name.
|
|
13
|
+
class Bucket < ::Struct[untyped]
|
|
14
|
+
# sig-gen gap: #1183 — Struct member types are not inferred from construction sites; every
|
|
15
|
+
# member row in this class (and the keyword ctor below) is hand-written.
|
|
16
|
+
def file: () -> String
|
|
17
|
+
# sig-gen gap: #1183 — as above.
|
|
18
|
+
def rule: () -> String
|
|
19
|
+
# sig-gen gap: #1183 — as above.
|
|
20
|
+
def message_regex: () -> Regexp?
|
|
21
|
+
# sig-gen gap: #1183 — as above.
|
|
22
|
+
def count: () -> Integer
|
|
23
|
+
# sig-gen gap: #1183 — as above.
|
|
24
|
+
def file=: (String) -> String
|
|
25
|
+
# sig-gen gap: #1183 — as above.
|
|
26
|
+
def rule=: (String) -> String
|
|
27
|
+
# sig-gen gap: #1183 — as above.
|
|
28
|
+
def message_regex=: (Regexp?) -> Regexp?
|
|
29
|
+
# sig-gen gap: #1183 — as above.
|
|
30
|
+
def count=: (Integer) -> Integer
|
|
31
|
+
# sig-gen gap: #1183 — as above.
|
|
32
|
+
def self.new: (?file: String, ?rule: String, ?message_regex: Regexp?, ?count: Integer) -> instance
|
|
33
|
+
# sig-gen gap: #1183 — as above.
|
|
34
|
+
def self.[]: (?file: String, ?rule: String, ?message_regex: Regexp?, ?count: Integer) -> instance
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# One bucket's drift state for `audit`. `status` is the four-way verdict `status_for` returns;
|
|
38
|
+
# `delta` is `actual_count - bucket.count` (positive = over threshold).
|
|
39
|
+
class DriftRow < ::Struct[untyped]
|
|
40
|
+
# sig-gen gap: #1183 — Struct member types are not inferred from construction sites; as above.
|
|
41
|
+
def bucket: () -> Bucket
|
|
42
|
+
# sig-gen gap: #1183 — as above.
|
|
43
|
+
def actual_count: () -> Integer
|
|
44
|
+
# sig-gen gap: #1183 — as above.
|
|
45
|
+
def status: () -> (:within | :over | :cleared | :reducible)
|
|
46
|
+
def delta: () -> Integer
|
|
47
|
+
# sig-gen gap: #1183 — as above.
|
|
48
|
+
def bucket=: (Bucket) -> Bucket
|
|
49
|
+
# sig-gen gap: #1183 — as above.
|
|
50
|
+
def actual_count=: (Integer) -> Integer
|
|
51
|
+
# sig-gen gap: #1183 — as above.
|
|
52
|
+
def status=: (:within | :over | :cleared | :reducible) -> (:within | :over | :cleared | :reducible)
|
|
53
|
+
# sig-gen gap: #1183 — as above.
|
|
54
|
+
def self.new: (?bucket: Bucket, ?actual_count: Integer, ?status: :within | :over | :cleared | :reducible) -> instance
|
|
55
|
+
# sig-gen gap: #1183 — as above.
|
|
56
|
+
def self.[]: (?bucket: Bucket, ?actual_count: Integer, ?status: :within | :over | :cleared | :reducible) -> instance
|
|
57
|
+
end
|
|
58
|
+
|
|
9
59
|
# Load a baseline file from disk.
|
|
10
60
|
# Returns `nil` when `path` is nil (no baseline configured).
|
|
11
61
|
# Raises {LoadError} on malformed or unsupported content.
|
|
12
62
|
def self.load: (::String? path, ?project_root: ::String) -> Baseline?
|
|
13
63
|
|
|
14
64
|
# Build a baseline from a current run's diagnostic stream.
|
|
15
|
-
def self.from_diagnostics: (untyped diagnostics, ?match_mode: :rule | :message) -> Baseline
|
|
65
|
+
def self.from_diagnostics: (untyped diagnostics, ?match_mode: :rule | :message, ?project_root: ::String | ::Pathname) -> Baseline
|
|
16
66
|
|
|
17
|
-
|
|
67
|
+
# Always an Array of Bucket — `initialize` freezes what it is given and every caller hands it
|
|
68
|
+
# Bucket instances (parse_row rows, from_diagnostics groups, `without`'s reject, or `[]`).
|
|
69
|
+
# sig-gen gap: #1154 — an `attr_reader` over an ivar assigned in `initialize` from a parameter
|
|
70
|
+
# is skipped (untyped return); the element type is hand-written.
|
|
71
|
+
attr_reader buckets: Array[Bucket]
|
|
18
72
|
|
|
19
|
-
|
|
73
|
+
# `project_root` is `Pathname.new`'d, so a `Pathname` is accepted as well as a `String`
|
|
74
|
+
# (`without` re-passes the stored Pathname).
|
|
75
|
+
def initialize: (Array[Bucket] buckets, ?project_root: ::String | ::Pathname) -> void
|
|
20
76
|
|
|
21
77
|
# Apply the baseline filter. Returns [surfaced_diagnostics, silenced_count].
|
|
22
|
-
|
|
78
|
+
# `diagnostics` stays `untyped`: `Analysis::Diagnostic`'s sig is partial (no `qualified_rule`),
|
|
79
|
+
# so a tighter param would put `diag.qualified_rule` behind an unsigned member. The declared
|
|
80
|
+
# `[Array[untyped], Integer]` diverges from sig-gen's inference
|
|
81
|
+
# (`[Array[untyped], untyped] | [untyped, 0]` — the literal seed and the accumulated local are
|
|
82
|
+
# unproven); the `Integer` count is the author's intent.
|
|
83
|
+
def filter: (untyped diagnostics) -> [Array[untyped], ::Integer]
|
|
23
84
|
|
|
24
|
-
# Report bucket-level drift for each recorded baseline bucket
|
|
25
|
-
|
|
85
|
+
# Report bucket-level drift for each recorded baseline bucket — one DriftRow per bucket, in
|
|
86
|
+
# baseline-file order.
|
|
87
|
+
def audit: (untyped diagnostics) -> Array[DriftRow]
|
|
26
88
|
|
|
27
89
|
# Return a new Baseline with the given buckets removed.
|
|
28
|
-
def without: (
|
|
90
|
+
def without: (Array[Bucket] buckets_to_drop) -> Baseline
|
|
29
91
|
|
|
30
92
|
# Serialise to a YAML string.
|
|
31
93
|
def to_yaml: () -> ::String
|
|
@@ -2,7 +2,7 @@ module Rigor
|
|
|
2
2
|
module Analysis
|
|
3
3
|
module CheckRules
|
|
4
4
|
def self?.diagnose: (path: String, root: untyped, scope_index: Hash[untyped, Scope]) -> Array[Diagnostic]
|
|
5
|
-
def self?.build_node_collectors: (String path, untyped scope_index) -> Hash[Symbol, untyped]
|
|
5
|
+
def self?.build_node_collectors: (String path, untyped scope_index, ?untyped root) -> Hash[Symbol, untyped]
|
|
6
6
|
def self?.node_collector_driver: (Hash[Symbol, untyped] collectors) -> untyped
|
|
7
7
|
def self?.shadow_verify_converged_collectors: (String path, untyped root, untyped scope_index, Hash[Symbol, untyped]? collectors) -> void
|
|
8
8
|
def self?.filter_suppressed: (Array[Diagnostic] diagnostics, comments: untyped, disabled_rules: Array[String]) -> Array[Diagnostic]
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
module Rigor
|
|
2
|
+
module Analysis
|
|
3
|
+
# Frozen snapshot of the project-wide pre-pass state the runner consumes — see
|
|
4
|
+
# lib/rigor/analysis/project_scan.rb for the full ownership/invalidation contract.
|
|
5
|
+
class ProjectScan < ::Data
|
|
6
|
+
# sig-gen gap: #1150 — `Data.define` member reads carry no type; `build_project_scan` fills
|
|
7
|
+
# this slot with the prepared `Plugin::Loader` result.
|
|
8
|
+
def plugin_registry: () -> Rigor::Plugin::Registry
|
|
9
|
+
|
|
10
|
+
# sig-gen gap: #1150 — as above (`DependencySourceInference::Builder.build` output, or
|
|
11
|
+
# `Index::EMPTY` when no dependencies are configured).
|
|
12
|
+
def dependency_source_index: () -> DependencySourceInference::Index
|
|
13
|
+
|
|
14
|
+
# `Inference::SyntheticMethodIndex` — the class is not yet declared under `sig/` (#1181
|
|
15
|
+
# backlog), so `untyped` is the honest member type for now.
|
|
16
|
+
def synthetic_method_index: () -> untyped
|
|
17
|
+
|
|
18
|
+
# `Inference::ProjectPatchedMethods` — unsigned like the slot above.
|
|
19
|
+
def project_patched_methods: () -> untyped
|
|
20
|
+
|
|
21
|
+
# sig-gen gap: #1150 — as above (`plugin_prepare_diagnostics` collects the
|
|
22
|
+
# `plugin_prepare_error_diagnostic` `Diagnostic`s, `[]` under pool mode).
|
|
23
|
+
def plugin_prepare_diagnostics: () -> Array[Analysis::Diagnostic]
|
|
24
|
+
|
|
25
|
+
# sig-gen gap: #1150 — as above. The pre-eval scanner deliberately emits a Hash shape (it
|
|
26
|
+
# must not depend on the analysis layer); the runner translates each row to a `Diagnostic`
|
|
27
|
+
# at the call site.
|
|
28
|
+
def pre_eval_diagnostics: () -> Array[{ path: String, line: Integer, column: Integer, severity: Symbol, rule: String, message: String }]
|
|
29
|
+
|
|
30
|
+
# `Analysis::TemplateUnits` — unsigned (#1181 backlog), kept `untyped`.
|
|
31
|
+
def template_units: () -> untyped
|
|
32
|
+
|
|
33
|
+
# sig-gen gap: #1150 — as above; constructor keywords mirror the member declarations.
|
|
34
|
+
def self.new: (
|
|
35
|
+
plugin_registry: Rigor::Plugin::Registry,
|
|
36
|
+
dependency_source_index: DependencySourceInference::Index,
|
|
37
|
+
synthetic_method_index: untyped,
|
|
38
|
+
project_patched_methods: untyped,
|
|
39
|
+
plugin_prepare_diagnostics: Array[Analysis::Diagnostic],
|
|
40
|
+
pre_eval_diagnostics: Array[{ path: String, line: Integer, column: Integer, severity: Symbol, rule: String, message: String }],
|
|
41
|
+
template_units: untyped
|
|
42
|
+
) -> instance
|
|
43
|
+
| (
|
|
44
|
+
Rigor::Plugin::Registry plugin_registry,
|
|
45
|
+
DependencySourceInference::Index dependency_source_index,
|
|
46
|
+
untyped synthetic_method_index,
|
|
47
|
+
untyped project_patched_methods,
|
|
48
|
+
Array[Analysis::Diagnostic] plugin_prepare_diagnostics,
|
|
49
|
+
Array[{ path: String, line: Integer, column: Integer, severity: Symbol, rule: String, message: String }] pre_eval_diagnostics,
|
|
50
|
+
untyped template_units
|
|
51
|
+
) -> instance
|
|
52
|
+
|
|
53
|
+
# sig-gen gap: #1150 — as above.
|
|
54
|
+
def self.[]: (
|
|
55
|
+
plugin_registry: Rigor::Plugin::Registry,
|
|
56
|
+
dependency_source_index: DependencySourceInference::Index,
|
|
57
|
+
synthetic_method_index: untyped,
|
|
58
|
+
project_patched_methods: untyped,
|
|
59
|
+
plugin_prepare_diagnostics: Array[Analysis::Diagnostic],
|
|
60
|
+
pre_eval_diagnostics: Array[{ path: String, line: Integer, column: Integer, severity: Symbol, rule: String, message: String }],
|
|
61
|
+
template_units: untyped
|
|
62
|
+
) -> instance
|
|
63
|
+
| (
|
|
64
|
+
Rigor::Plugin::Registry plugin_registry,
|
|
65
|
+
DependencySourceInference::Index dependency_source_index,
|
|
66
|
+
untyped synthetic_method_index,
|
|
67
|
+
untyped project_patched_methods,
|
|
68
|
+
Array[Analysis::Diagnostic] plugin_prepare_diagnostics,
|
|
69
|
+
Array[{ path: String, line: Integer, column: Integer, severity: Symbol, rule: String, message: String }] pre_eval_diagnostics,
|
|
70
|
+
untyped template_units
|
|
71
|
+
) -> instance
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
module Rigor
|
|
2
|
+
module Effects
|
|
3
|
+
# `effects.envelopes:` entries resolved against the label vocabulary — the configured stratum of
|
|
4
|
+
# the envelope precedence (ADR-103 WD1).
|
|
5
|
+
module ConfigEnvelopes
|
|
6
|
+
CONFIG_PATH: String
|
|
7
|
+
|
|
8
|
+
# One entry, resolved against the vocabulary. `bound` is `LabelSet::TOP` when some member of
|
|
9
|
+
# `effect:` is unrecognised — the fail-open rule.
|
|
10
|
+
class Entry < ::Data
|
|
11
|
+
# sig-gen gap: #1150 — `Data.define` member reads carry no type; `build` proves each of these.
|
|
12
|
+
def index: () -> Integer
|
|
13
|
+
|
|
14
|
+
# sig-gen gap: #1150 — as above (path glob, or nil when `namespace:` is set).
|
|
15
|
+
def match: () -> String?
|
|
16
|
+
|
|
17
|
+
# sig-gen gap: #1150 — as above (constant-path glob, or nil when `match:` is set).
|
|
18
|
+
def namespace: () -> String?
|
|
19
|
+
|
|
20
|
+
# sig-gen gap: #1150 — as above (`LabelSet::TOP` on an unrecognised label).
|
|
21
|
+
def bound: () -> LabelSet
|
|
22
|
+
|
|
23
|
+
# sig-gen gap: #1150 — as above (the `effect:` list exactly as written).
|
|
24
|
+
def labels: () -> Array[String]
|
|
25
|
+
|
|
26
|
+
# sig-gen gap: #1150 — as above (well-formed spellings the registry did not know).
|
|
27
|
+
def unknown_labels: () -> Array[String]
|
|
28
|
+
|
|
29
|
+
# sig-gen gap: #1150 — as above; keyword form mirrors the member declarations.
|
|
30
|
+
def self.new: (
|
|
31
|
+
index: Integer,
|
|
32
|
+
match: String?,
|
|
33
|
+
namespace: String?,
|
|
34
|
+
bound: LabelSet,
|
|
35
|
+
labels: Array[String],
|
|
36
|
+
unknown_labels: Array[String]
|
|
37
|
+
) -> instance
|
|
38
|
+
| (
|
|
39
|
+
Integer index,
|
|
40
|
+
String? match,
|
|
41
|
+
String? namespace,
|
|
42
|
+
LabelSet bound,
|
|
43
|
+
Array[String] labels,
|
|
44
|
+
Array[String] unknown_labels
|
|
45
|
+
) -> instance
|
|
46
|
+
|
|
47
|
+
# sig-gen gap: #1150 — as above.
|
|
48
|
+
def self.[]: (
|
|
49
|
+
index: Integer,
|
|
50
|
+
match: String?,
|
|
51
|
+
namespace: String?,
|
|
52
|
+
bound: LabelSet,
|
|
53
|
+
labels: Array[String],
|
|
54
|
+
unknown_labels: Array[String]
|
|
55
|
+
) -> instance
|
|
56
|
+
| (
|
|
57
|
+
Integer index,
|
|
58
|
+
String? match,
|
|
59
|
+
String? namespace,
|
|
60
|
+
LabelSet bound,
|
|
61
|
+
Array[String] labels,
|
|
62
|
+
Array[String] unknown_labels
|
|
63
|
+
) -> instance
|
|
64
|
+
|
|
65
|
+
# `.rigor.yml effects.envelopes[N]` — the location spelling diagnostics name.
|
|
66
|
+
def location: () -> String
|
|
67
|
+
|
|
68
|
+
# The bound quoted back in the config's own spelling.
|
|
69
|
+
def spelling: () -> String
|
|
70
|
+
|
|
71
|
+
def top?: () -> bool
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# `entries` are the shape-validated `Configuration#effects_envelopes` rows (String-keyed
|
|
75
|
+
# Hashes); `registry` is the `Effects::Registry` vocabulary — unsigned, so `untyped`.
|
|
76
|
+
def self?.build: (entries: Array[Hash[String, untyped]], registry: untyped) -> Array[Entry]
|
|
77
|
+
|
|
78
|
+
# One envelope per selected class, keyed by class name. `sources` is `Runner#effect_sources`'s
|
|
79
|
+
# shape; `project_root` is what those paths are relativised against.
|
|
80
|
+
def self?.for_classes: (
|
|
81
|
+
entries: Array[Entry],
|
|
82
|
+
class_names: Array[String],
|
|
83
|
+
?sources: Hash[String, Array[String]],
|
|
84
|
+
?project_root: String
|
|
85
|
+
) -> Hash[String, Envelope]
|
|
86
|
+
|
|
87
|
+
# The {Envelope} one entry puts on one class.
|
|
88
|
+
def self?.envelope_for: (Entry entry, String class_name) -> Envelope
|
|
89
|
+
|
|
90
|
+
# Whether one entry selects a class — `paths` is `Array()`d, so `untyped` is honest.
|
|
91
|
+
def self?.selects?: (Entry entry, String class_name, untyped paths) -> bool
|
|
92
|
+
|
|
93
|
+
# `File.fnmatch?` with `FNM_PATHNAME` — the ADR-28 path-glob shape.
|
|
94
|
+
def self?.path_match?: (String glob, String path) -> bool
|
|
95
|
+
|
|
96
|
+
# Constant-path glob over the `::`-separated FQN; both arguments are `to_s`d.
|
|
97
|
+
def self?.namespace_match?: (untyped glob, untyped class_name) -> bool
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|