rigortype 0.2.7 → 0.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/docs/manual/04-diagnostics.md +7 -4
- data/docs/manual/06-baseline.md +5 -2
- data/docs/manual/15-type-protection-coverage.md +6 -4
- data/lib/rigor/analysis/baseline.rb +56 -96
- data/lib/rigor/analysis/buffer_binding.rb +13 -20
- data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +29 -48
- data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +35 -54
- data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +23 -37
- data/lib/rigor/analysis/check_rules/main_pass_collector.rb +16 -23
- data/lib/rigor/analysis/check_rules/rule_walk.rb +48 -71
- data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +19 -28
- data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +48 -67
- data/lib/rigor/analysis/check_rules.rb +174 -274
- data/lib/rigor/analysis/dependency_recorder.rb +26 -38
- data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +13 -25
- data/lib/rigor/analysis/dependency_source_inference/builder.rb +17 -30
- data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +15 -26
- data/lib/rigor/analysis/dependency_source_inference/index.rb +45 -76
- data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +23 -40
- data/lib/rigor/analysis/dependency_source_inference/walker.rb +50 -83
- data/lib/rigor/analysis/dependency_source_inference.rb +6 -10
- data/lib/rigor/analysis/diagnostic.rb +48 -75
- data/lib/rigor/analysis/erb_template_detector.rb +13 -18
- data/lib/rigor/analysis/fact_store.rb +12 -22
- data/lib/rigor/analysis/incremental.rb +47 -63
- data/lib/rigor/analysis/incremental_session.rb +74 -100
- data/lib/rigor/analysis/project_scan.rb +12 -23
- data/lib/rigor/analysis/result.rb +3 -5
- data/lib/rigor/analysis/rule_catalog.rb +67 -95
- data/lib/rigor/analysis/run_stats.rb +38 -61
- data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +101 -160
- data/lib/rigor/analysis/runner/pool_coordinator.rb +121 -188
- data/lib/rigor/analysis/runner/project_pre_passes.rb +62 -96
- data/lib/rigor/analysis/runner/run_snapshots.rb +12 -18
- data/lib/rigor/analysis/runner.rb +220 -333
- data/lib/rigor/analysis/self_call_resolution_recorder.rb +30 -43
- data/lib/rigor/analysis/worker_session.rb +64 -102
- data/lib/rigor/ast/type_node.rb +6 -8
- data/lib/rigor/ast.rb +6 -10
- data/lib/rigor/bleeding_edge.rb +27 -35
- data/lib/rigor/builtins/hkt_builtins.rb +7 -14
- data/lib/rigor/builtins/imported_refinements.rb +106 -149
- data/lib/rigor/builtins/predefined_constant_refinements.rb +51 -65
- data/lib/rigor/builtins/regex_refinement.rb +32 -43
- data/lib/rigor/builtins/static_return_refinements.rb +57 -81
- data/lib/rigor/cache/descriptor.rb +58 -94
- data/lib/rigor/cache/incremental_snapshot.rb +32 -48
- data/lib/rigor/cache/rbs_cache_producer.rb +10 -15
- data/lib/rigor/cache/rbs_class_ancestor_table.rb +10 -16
- data/lib/rigor/cache/rbs_class_type_param_names.rb +10 -16
- data/lib/rigor/cache/rbs_constant_table.rb +8 -13
- data/lib/rigor/cache/rbs_descriptor.rb +8 -13
- data/lib/rigor/cache/rbs_environment.rb +11 -19
- data/lib/rigor/cache/rbs_environment_marshal_patch.rb +11 -19
- data/lib/rigor/cache/rbs_known_class_names.rb +8 -12
- data/lib/rigor/cache/store.rb +96 -151
- data/lib/rigor/cli/annotate_command.rb +51 -88
- data/lib/rigor/cli/baseline_command.rb +10 -17
- data/lib/rigor/cli/check_command.rb +121 -199
- data/lib/rigor/cli/check_runner_factory.rb +8 -14
- data/lib/rigor/cli/ci_detector.rb +9 -14
- data/lib/rigor/cli/command.rb +8 -14
- data/lib/rigor/cli/coverage_command.rb +19 -26
- data/lib/rigor/cli/coverage_mutation.rb +14 -19
- data/lib/rigor/cli/coverage_report.rb +0 -2
- data/lib/rigor/cli/coverage_scan.rb +7 -11
- data/lib/rigor/cli/diagnostic_formats.rb +43 -62
- data/lib/rigor/cli/diff_command.rb +10 -20
- data/lib/rigor/cli/docs_command.rb +26 -40
- data/lib/rigor/cli/doctor_command.rb +8 -9
- data/lib/rigor/cli/explain_command.rb +4 -7
- data/lib/rigor/cli/fused_protection_renderer.rb +4 -5
- data/lib/rigor/cli/fused_protection_report.rb +6 -8
- data/lib/rigor/cli/lsp_command.rb +11 -19
- data/lib/rigor/cli/mcp_command.rb +4 -6
- data/lib/rigor/cli/mutation_protection_renderer.rb +3 -4
- data/lib/rigor/cli/mutation_protection_report.rb +6 -9
- data/lib/rigor/cli/options.rb +11 -19
- data/lib/rigor/cli/plugin_command.rb +18 -30
- data/lib/rigor/cli/plugins_command.rb +29 -51
- data/lib/rigor/cli/plugins_renderer.rb +12 -20
- data/lib/rigor/cli/prism_colorizer.rb +13 -19
- data/lib/rigor/cli/protection_renderer.rb +5 -7
- data/lib/rigor/cli/protection_report.rb +27 -17
- data/lib/rigor/cli/renderable.rb +4 -6
- data/lib/rigor/cli/show_bleedingedge_command.rb +5 -8
- data/lib/rigor/cli/sig_gen_command.rb +14 -26
- data/lib/rigor/cli/skill_command.rb +30 -47
- data/lib/rigor/cli/skill_describe.rb +40 -64
- data/lib/rigor/cli/trace_command.rb +9 -16
- data/lib/rigor/cli/trace_renderer.rb +35 -51
- data/lib/rigor/cli/triage_command.rb +6 -10
- data/lib/rigor/cli/triage_renderer.rb +1 -2
- data/lib/rigor/cli/type_of_command.rb +14 -23
- data/lib/rigor/cli/type_of_renderer.rb +3 -5
- data/lib/rigor/cli/type_scan_command.rb +6 -10
- data/lib/rigor/cli/type_scan_renderer.rb +3 -5
- data/lib/rigor/cli/type_scan_report.rb +2 -3
- data/lib/rigor/cli/upgrade_command.rb +2 -3
- data/lib/rigor/cli.rb +16 -28
- data/lib/rigor/config_audit.rb +35 -44
- data/lib/rigor/configuration/dependencies.rb +41 -70
- data/lib/rigor/configuration/severity_profile.rb +28 -42
- data/lib/rigor/configuration.rb +150 -241
- data/lib/rigor/environment/bundle_sig_discovery.rb +74 -118
- data/lib/rigor/environment/class_registry.rb +19 -26
- data/lib/rigor/environment/constant_type_cache_holder.rb +14 -21
- data/lib/rigor/environment/hkt_registry_holder.rb +6 -12
- data/lib/rigor/environment/lockfile_resolver.rb +31 -47
- data/lib/rigor/environment/rbs_collection_discovery.rb +39 -63
- data/lib/rigor/environment/rbs_coverage_report.rb +24 -42
- data/lib/rigor/environment/rbs_loader.rb +420 -518
- data/lib/rigor/environment/reflection.rb +28 -53
- data/lib/rigor/environment/reporters.rb +13 -24
- data/lib/rigor/environment.rb +176 -291
- data/lib/rigor/flow_contribution/conflict.rb +16 -27
- data/lib/rigor/flow_contribution/element.rb +7 -12
- data/lib/rigor/flow_contribution/fact.rb +33 -57
- data/lib/rigor/flow_contribution/merge_result.rb +6 -9
- data/lib/rigor/flow_contribution/merger.rb +32 -47
- data/lib/rigor/flow_contribution.rb +37 -55
- data/lib/rigor/inference/acceptance.rb +133 -219
- data/lib/rigor/inference/block_parameter_binder.rb +52 -82
- data/lib/rigor/inference/body_fixpoint.rb +22 -30
- data/lib/rigor/inference/budget_trace.rb +43 -63
- data/lib/rigor/inference/builtins/array_catalog.rb +4 -6
- data/lib/rigor/inference/builtins/comparable_catalog.rb +4 -6
- data/lib/rigor/inference/builtins/complex_catalog.rb +13 -19
- data/lib/rigor/inference/builtins/date_catalog.rb +38 -67
- data/lib/rigor/inference/builtins/encoding_catalog.rb +22 -36
- data/lib/rigor/inference/builtins/enumerable_catalog.rb +4 -6
- data/lib/rigor/inference/builtins/exception_catalog.rb +38 -57
- data/lib/rigor/inference/builtins/hash_catalog.rb +9 -14
- data/lib/rigor/inference/builtins/method_catalog.rb +29 -48
- data/lib/rigor/inference/builtins/numeric_catalog.rb +13 -18
- data/lib/rigor/inference/builtins/pathname_catalog.rb +8 -13
- data/lib/rigor/inference/builtins/proc_catalog.rb +38 -62
- data/lib/rigor/inference/builtins/random_catalog.rb +21 -32
- data/lib/rigor/inference/builtins/range_catalog.rb +12 -21
- data/lib/rigor/inference/builtins/rational_catalog.rb +9 -15
- data/lib/rigor/inference/builtins/re_catalog.rb +29 -48
- data/lib/rigor/inference/builtins/set_catalog.rb +18 -27
- data/lib/rigor/inference/builtins/string_catalog.rb +12 -19
- data/lib/rigor/inference/builtins/struct_catalog.rb +18 -30
- data/lib/rigor/inference/builtins/time_catalog.rb +28 -44
- data/lib/rigor/inference/closure_escape_analyzer.rb +44 -67
- data/lib/rigor/inference/coverage_scanner.rb +13 -18
- data/lib/rigor/inference/def_return_typer.rb +8 -14
- data/lib/rigor/inference/dynamic_origin.rb +23 -20
- data/lib/rigor/inference/expression_typer.rb +774 -1152
- data/lib/rigor/inference/fallback.rb +8 -12
- data/lib/rigor/inference/fallback_tracer.rb +4 -10
- data/lib/rigor/inference/flow_tracer.rb +25 -36
- data/lib/rigor/inference/hkt_body.rb +45 -68
- data/lib/rigor/inference/hkt_body_parser.rb +33 -52
- data/lib/rigor/inference/hkt_reducer.rb +38 -59
- data/lib/rigor/inference/hkt_registry.rb +50 -76
- data/lib/rigor/inference/indexed_narrowing.rb +55 -81
- data/lib/rigor/inference/macro_block_self_type.rb +21 -34
- data/lib/rigor/inference/method_dispatcher/array_to_h_folding.rb +11 -18
- data/lib/rigor/inference/method_dispatcher/block_folding.rb +49 -83
- data/lib/rigor/inference/method_dispatcher/call_context.rb +16 -23
- data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +13 -22
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +307 -454
- data/lib/rigor/inference/method_dispatcher/data_folding.rb +24 -34
- data/lib/rigor/inference/method_dispatcher/file_folding.rb +22 -37
- data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +52 -81
- data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +51 -78
- data/lib/rigor/inference/method_dispatcher/literal_string_folding.rb +60 -97
- data/lib/rigor/inference/method_dispatcher/math_folding.rb +23 -34
- data/lib/rigor/inference/method_dispatcher/member_shape_projection.rb +18 -26
- data/lib/rigor/inference/method_dispatcher/method_folding.rb +37 -71
- data/lib/rigor/inference/method_dispatcher/overload_selector.rb +114 -182
- data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +122 -193
- data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +15 -24
- data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +64 -93
- data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +31 -45
- data/lib/rigor/inference/method_dispatcher/set_folding.rb +6 -9
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +356 -511
- data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +22 -32
- data/lib/rigor/inference/method_dispatcher/singleton_folding.rb +15 -21
- data/lib/rigor/inference/method_dispatcher/struct_folding.rb +66 -82
- data/lib/rigor/inference/method_dispatcher/time_folding.rb +10 -15
- data/lib/rigor/inference/method_dispatcher/uri_folding.rb +9 -13
- data/lib/rigor/inference/method_dispatcher.rb +378 -524
- data/lib/rigor/inference/method_parameter_binder.rb +81 -114
- data/lib/rigor/inference/multi_target_binder.rb +51 -68
- data/lib/rigor/inference/mutation_widening.rb +115 -158
- data/lib/rigor/inference/narrowing.rb +509 -727
- data/lib/rigor/inference/origin_lookup.rb +38 -0
- data/lib/rigor/inference/parameter_inference_collector.rb +100 -100
- data/lib/rigor/inference/precision_scanner.rb +26 -35
- data/lib/rigor/inference/project_patched_methods.rb +20 -32
- data/lib/rigor/inference/project_patched_scanner.rb +23 -37
- data/lib/rigor/inference/protection_scanner.rb +16 -18
- data/lib/rigor/inference/rbs_type_translator.rb +49 -66
- data/lib/rigor/inference/scope_indexer.rb +473 -817
- data/lib/rigor/inference/statement_evaluator.rb +706 -1111
- data/lib/rigor/inference/struct_fold_safety.rb +34 -48
- data/lib/rigor/inference/synthetic_method.rb +9 -16
- data/lib/rigor/inference/synthetic_method_index.rb +20 -35
- data/lib/rigor/inference/synthetic_method_scanner.rb +63 -103
- data/lib/rigor/language_server/buffer_resolution.rb +6 -9
- data/lib/rigor/language_server/buffer_table.rb +11 -18
- data/lib/rigor/language_server/completion_provider.rb +69 -116
- data/lib/rigor/language_server/debouncer.rb +16 -25
- data/lib/rigor/language_server/diagnostic_publisher.rb +26 -40
- data/lib/rigor/language_server/document_symbol_provider.rb +14 -19
- data/lib/rigor/language_server/folding_range_provider.rb +11 -19
- data/lib/rigor/language_server/hover_provider.rb +8 -11
- data/lib/rigor/language_server/hover_renderer.rb +56 -93
- data/lib/rigor/language_server/loop.rb +14 -19
- data/lib/rigor/language_server/project_context.rb +46 -74
- data/lib/rigor/language_server/selection_range_provider.rb +9 -12
- data/lib/rigor/language_server/server.rb +55 -83
- data/lib/rigor/language_server/signature_help_provider.rb +29 -46
- data/lib/rigor/language_server/synchronized_writer.rb +4 -7
- data/lib/rigor/language_server/uri.rb +8 -13
- data/lib/rigor/language_server.rb +4 -6
- data/lib/rigor/mcp/loop.rb +2 -3
- data/lib/rigor/mcp/server.rb +4 -7
- data/lib/rigor/mcp.rb +3 -6
- data/lib/rigor/plugin/access_denied_error.rb +5 -8
- data/lib/rigor/plugin/additional_initializer.rb +21 -31
- data/lib/rigor/plugin/base.rb +335 -518
- data/lib/rigor/plugin/blueprint.rb +14 -23
- data/lib/rigor/plugin/box.rb +18 -29
- data/lib/rigor/plugin/fact_store.rb +16 -26
- data/lib/rigor/plugin/inflector.rb +37 -53
- data/lib/rigor/plugin/io_boundary.rb +33 -56
- data/lib/rigor/plugin/isolation.rb +42 -55
- data/lib/rigor/plugin/load_error.rb +10 -15
- data/lib/rigor/plugin/loader.rb +30 -49
- data/lib/rigor/plugin/macro/block_as_method.rb +20 -32
- data/lib/rigor/plugin/macro/heredoc_template.rb +35 -58
- data/lib/rigor/plugin/macro/nested_class_template.rb +22 -36
- data/lib/rigor/plugin/macro/trait_registry.rb +34 -51
- data/lib/rigor/plugin/macro.rb +10 -15
- data/lib/rigor/plugin/manifest.rb +85 -144
- data/lib/rigor/plugin/node_context.rb +14 -22
- data/lib/rigor/plugin/node_rule_walk.rb +49 -74
- data/lib/rigor/plugin/protocol_contract.rb +25 -39
- data/lib/rigor/plugin/registry.rb +132 -205
- data/lib/rigor/plugin/services.rb +21 -33
- data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +11 -19
- data/lib/rigor/plugin/trust_policy.rb +24 -38
- data/lib/rigor/plugin/type_node_resolver.rb +15 -24
- data/lib/rigor/protection/diagnostic_oracle.rb +11 -13
- data/lib/rigor/protection/mutation_scanner.rb +27 -35
- data/lib/rigor/protection/mutator.rb +50 -70
- data/lib/rigor/protection/test_suite_oracle.rb +20 -27
- data/lib/rigor/rbs_extended/conformance_checker.rb +48 -68
- data/lib/rigor/rbs_extended/hkt_directives.rb +28 -54
- data/lib/rigor/rbs_extended/reporter.rb +24 -40
- data/lib/rigor/rbs_extended.rb +107 -197
- data/lib/rigor/reflection.rb +68 -86
- data/lib/rigor/scope/discovery_index.rb +14 -19
- data/lib/rigor/scope.rb +255 -310
- data/lib/rigor/sig_gen/classification.rb +6 -10
- data/lib/rigor/sig_gen/generator.rb +197 -323
- data/lib/rigor/sig_gen/layout_index.rb +12 -20
- data/lib/rigor/sig_gen/method_candidate.rb +12 -17
- data/lib/rigor/sig_gen/observation_collector.rb +38 -70
- data/lib/rigor/sig_gen/observed_call.rb +13 -23
- data/lib/rigor/sig_gen/path_mapper.rb +17 -29
- data/lib/rigor/sig_gen/renderer.rb +7 -13
- data/lib/rigor/sig_gen/type_elaborator.rb +15 -28
- data/lib/rigor/sig_gen/write_result.rb +8 -16
- data/lib/rigor/sig_gen/writer.rb +95 -174
- data/lib/rigor/sig_gen.rb +3 -6
- data/lib/rigor/signature_path_audit.rb +24 -30
- data/lib/rigor/source/constant_path.rb +10 -14
- data/lib/rigor/source/literals.rb +31 -45
- data/lib/rigor/source/node_locator.rb +9 -11
- data/lib/rigor/source/node_walker.rb +9 -13
- data/lib/rigor/source.rb +3 -4
- data/lib/rigor/testing.rb +16 -20
- data/lib/rigor/triage/catalogue.rb +38 -62
- data/lib/rigor/triage.rb +31 -52
- data/lib/rigor/trinary.rb +9 -13
- data/lib/rigor/type/acceptance_router.rb +4 -6
- data/lib/rigor/type/accepts_result.rb +10 -14
- data/lib/rigor/type/app.rb +19 -27
- data/lib/rigor/type/bot.rb +4 -6
- data/lib/rigor/type/bound_method.rb +10 -15
- data/lib/rigor/type/combinator.rb +165 -257
- data/lib/rigor/type/constant.rb +23 -34
- data/lib/rigor/type/data_class.rb +10 -15
- data/lib/rigor/type/data_instance.rb +14 -20
- data/lib/rigor/type/difference.rb +21 -32
- data/lib/rigor/type/dynamic.rb +3 -5
- data/lib/rigor/type/hash_shape.rb +32 -18
- data/lib/rigor/type/integer_range.rb +11 -16
- data/lib/rigor/type/intersection.rb +27 -42
- data/lib/rigor/type/nominal.rb +10 -15
- data/lib/rigor/type/plain_lattice.rb +9 -13
- data/lib/rigor/type/refined.rb +67 -114
- data/lib/rigor/type/singleton.rb +4 -6
- data/lib/rigor/type/struct_class.rb +11 -16
- data/lib/rigor/type/struct_instance.rb +15 -21
- data/lib/rigor/type/tuple.rb +14 -19
- data/lib/rigor/type/union.rb +30 -42
- data/lib/rigor/type_node/generic.rb +14 -26
- data/lib/rigor/type_node/identifier.rb +12 -19
- data/lib/rigor/type_node.rb +3 -12
- data/lib/rigor/value_semantics.rb +16 -21
- data/lib/rigor/version.rb +1 -1
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +18 -30
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +16 -29
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +12 -23
- data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +22 -39
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +26 -46
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +51 -87
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +10 -17
- data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +26 -39
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +118 -176
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +30 -51
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +57 -92
- data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +71 -108
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +13 -22
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +15 -25
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +8 -13
- data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +16 -24
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +30 -47
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +79 -129
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +36 -57
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +27 -41
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +16 -24
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +148 -235
- data/plugins/rigor-activerecord/lib/rigor-activerecord.rb +3 -5
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/analyzer.rb +8 -14
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +9 -15
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_index.rb +4 -7
- data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +23 -41
- data/plugins/rigor-activestorage/lib/rigor-activestorage.rb +3 -5
- data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +6 -10
- data/plugins/rigor-activesupport-core-ext/lib/rigor-activesupport-core-ext.rb +8 -11
- data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +30 -45
- data/plugins/rigor-devise/lib/rigor-devise.rb +3 -5
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +43 -69
- data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +26 -35
- data/plugins/rigor-dry-schema/lib/rigor-dry-schema.rb +3 -5
- data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +30 -47
- data/plugins/rigor-dry-struct/lib/rigor-dry-struct.rb +3 -5
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +67 -113
- data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +29 -46
- data/plugins/rigor-dry-types/lib/rigor-dry-types.rb +3 -5
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -20
- data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +14 -23
- data/plugins/rigor-dry-validation/lib/rigor-dry-validation.rb +2 -3
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +22 -37
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +28 -46
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +13 -17
- data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +30 -47
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +52 -80
- data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +21 -31
- data/plugins/rigor-graphql/lib/rigor-graphql.rb +3 -5
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami/action_checker.rb +11 -17
- data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +20 -34
- data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +45 -75
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +22 -36
- data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +22 -41
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +17 -32
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +6 -12
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +4 -8
- data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +17 -32
- data/plugins/rigor-rails/lib/rigor-rails.rb +11 -18
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +58 -92
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +20 -34
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +20 -31
- data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +49 -82
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +55 -92
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +51 -90
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +17 -30
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +38 -70
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +42 -74
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +280 -497
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +54 -89
- data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +32 -54
- data/plugins/rigor-rbs-inline/lib/rigor-rbs-inline.rb +8 -13
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +9 -16
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +24 -39
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +13 -22
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +34 -56
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec/scope_walker.rb +22 -42
- data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +43 -75
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +27 -39
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/http_status_codes.rb +14 -19
- data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +20 -34
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +28 -47
- data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +21 -37
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +13 -22
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +18 -31
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +6 -10
- data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +14 -29
- data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +23 -41
- data/plugins/rigor-sinatra/lib/rigor-sinatra.rb +3 -5
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +23 -38
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +57 -96
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +22 -35
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +41 -69
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/method_signature.rb +6 -10
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +24 -41
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +29 -50
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +55 -88
- data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +159 -262
- data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +21 -29
- data/plugins/rigor-statesman/lib/rigor-statesman.rb +3 -5
- data/plugins/rigor-typescript-utility-types/lib/rigor/plugin/typescript_utility_types.rb +23 -37
- data/plugins/rigor-typescript-utility-types/lib/rigor-typescript-utility-types.rb +4 -6
- data/sig/rigor/scope.rbs +6 -0
- metadata +2 -1
|
@@ -5,17 +5,13 @@ require "prism"
|
|
|
5
5
|
module Rigor
|
|
6
6
|
module Plugin
|
|
7
7
|
class Activestorage < Rigor::Plugin::Base
|
|
8
|
-
# Per-file walker. Emits one `:info` `attachment-call`
|
|
9
|
-
# diagnostic
|
|
10
|
-
#
|
|
11
|
-
# plugin recognised so users can verify the model →
|
|
12
|
-
# attachment mapping the plugin sees.
|
|
8
|
+
# Per-file walker. Emits one `:info` `attachment-call` diagnostic per recognised attachment access
|
|
9
|
+
# on a known AR class. The diagnostic surfaces what the plugin recognised so users can verify the
|
|
10
|
+
# model → attachment mapping the plugin sees.
|
|
13
11
|
#
|
|
14
|
-
# No `:error` diagnostics here — the `dynamic_return`
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
# `rigor-activerecord`'s `unknown-column`) is deferred:
|
|
18
|
-
# it requires a coupled receiver-class narrowing pass.
|
|
12
|
+
# No `:error` diagnostics here — the `dynamic_return` return-type narrowing carries the
|
|
13
|
+
# type-checking value. An `unknown-attachment` rule (similar to `rigor-activerecord`'s
|
|
14
|
+
# `unknown-column`) is deferred: it requires a coupled receiver-class narrowing pass.
|
|
19
15
|
class Analyzer
|
|
20
16
|
attr_reader :diagnostics
|
|
21
17
|
|
|
@@ -47,10 +43,8 @@ module Rigor
|
|
|
47
43
|
@attachment_index.attachments_for("::#{owner}")
|
|
48
44
|
return if attachments.nil?
|
|
49
45
|
|
|
50
|
-
# Only flag when the method matches a known
|
|
51
|
-
#
|
|
52
|
-
# provides the narrowing; the diagnostic just
|
|
53
|
-
# confirms the recognition).
|
|
46
|
+
# Only flag when the method matches a known attachment name (the `dynamic_return` rule provides
|
|
47
|
+
# the narrowing; the diagnostic just confirms the recognition).
|
|
54
48
|
attachment = attachments.find { |a| a[:name] == node.name.to_s }
|
|
55
49
|
return if attachment.nil?
|
|
56
50
|
|
|
@@ -6,10 +6,8 @@ require "rigor/source/literals"
|
|
|
6
6
|
module Rigor
|
|
7
7
|
module Plugin
|
|
8
8
|
class Activestorage < Rigor::Plugin::Base
|
|
9
|
-
# Walks the configured model search paths via the plugin's
|
|
10
|
-
#
|
|
11
|
-
# collects `has_one_attached` / `has_many_attached`
|
|
12
|
-
# declarations.
|
|
9
|
+
# Walks the configured model search paths via the plugin's `IoBoundary`, parses each `.rb` file
|
|
10
|
+
# with Prism, and collects `has_one_attached` / `has_many_attached` declarations.
|
|
13
11
|
#
|
|
14
12
|
# Returns rows the {AttachmentIndex} consumes:
|
|
15
13
|
#
|
|
@@ -19,17 +17,13 @@ module Rigor
|
|
|
19
17
|
#
|
|
20
18
|
# Limitations (intentional for v0.1.0 of the plugin):
|
|
21
19
|
#
|
|
22
|
-
# - The walker matches any class declaration that
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
# `rigor-activerecord`
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
# - Only Symbol-literal attachment names are recognised.
|
|
30
|
-
# `has_one_attached(args)` or computed names decline.
|
|
31
|
-
# - Modules (`class Admin::User`) are recognised; the
|
|
32
|
-
# resulting class name is the lexical path
|
|
20
|
+
# - The walker matches any class declaration that contains a `has_*_attached` call. Whether the
|
|
21
|
+
# class IS an ActiveRecord model is not verified here — `rigor-activerecord` provides that check
|
|
22
|
+
# via its own model index. The analyser is intentionally lenient so the plugin runs standalone in
|
|
23
|
+
# projects that haven't loaded `rigor-activerecord` yet.
|
|
24
|
+
# - Only Symbol-literal attachment names are recognised. `has_one_attached(args)` or computed names
|
|
25
|
+
# decline.
|
|
26
|
+
# - Modules (`class Admin::User`) are recognised; the resulting class name is the lexical path
|
|
33
27
|
# (`Admin::User`).
|
|
34
28
|
class AttachmentDiscoverer
|
|
35
29
|
ATTACHMENT_METHODS = {
|
|
@@ -3,16 +3,13 @@
|
|
|
3
3
|
module Rigor
|
|
4
4
|
module Plugin
|
|
5
5
|
class Activestorage < Rigor::Plugin::Base
|
|
6
|
-
# Maps a discovered class name to the list of attachment
|
|
7
|
-
#
|
|
8
|
-
# round-trips it through the standard pair.
|
|
6
|
+
# Maps a discovered class name to the list of attachment rows declared on it. Marshal-clean so the
|
|
7
|
+
# cache producer round-trips it through the standard pair.
|
|
9
8
|
#
|
|
10
9
|
# Each row is `{ name:, kind: }`:
|
|
11
10
|
#
|
|
12
|
-
# - `name` — String, the attachment method name as the
|
|
13
|
-
#
|
|
14
|
-
# - `kind` — `:singular` (`has_one_attached`) or
|
|
15
|
-
# `:collection` (`has_many_attached`).
|
|
11
|
+
# - `name` — String, the attachment method name as the user invokes it (`"avatar"`).
|
|
12
|
+
# - `kind` — `:singular` (`has_one_attached`) or `:collection` (`has_many_attached`).
|
|
16
13
|
class AttachmentIndex
|
|
17
14
|
attr_reader :entries
|
|
18
15
|
|
|
@@ -8,26 +8,18 @@ require_relative "activestorage/analyzer"
|
|
|
8
8
|
|
|
9
9
|
module Rigor
|
|
10
10
|
module Plugin
|
|
11
|
-
# rigor-activestorage — recognises `has_one_attached` /
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
# calls (`user.avatar.attached?`) route through Rigor's
|
|
15
|
-
# normal dispatch.
|
|
11
|
+
# rigor-activestorage — recognises `has_one_attached` / `has_many_attached` macros on ActiveRecord
|
|
12
|
+
# models and contributes attachment accessor return types so chained calls (`user.avatar.attached?`)
|
|
13
|
+
# route through Rigor's normal dispatch.
|
|
16
14
|
#
|
|
17
15
|
# ## Architecture
|
|
18
16
|
#
|
|
19
|
-
# One discovery pass per run reads the configured AR model
|
|
20
|
-
#
|
|
21
|
-
# `
|
|
22
|
-
#
|
|
23
|
-
# `
|
|
24
|
-
#
|
|
25
|
-
# stand-alone (mirrors `rigor-activerecord`'s
|
|
26
|
-
# `ModelDiscoverer`) so the plugin works even when
|
|
27
|
-
# `rigor-activerecord` is not loaded; when it IS loaded,
|
|
28
|
-
# the published `:model_index` fact (ADR-9 cross-plugin
|
|
29
|
-
# API) drives the same class set so the two plugins agree
|
|
30
|
-
# on what counts as a model.
|
|
17
|
+
# One discovery pass per run reads the configured AR model paths (default `app/models/`) via the
|
|
18
|
+
# plugin's `IoBoundary`, walks each `.rb` file with Prism, and collects `has_one_attached :avatar` /
|
|
19
|
+
# `has_many_attached :photos` macros into an {AttachmentIndex} keyed by class name. The walker is
|
|
20
|
+
# stand-alone (mirrors `rigor-activerecord`'s `ModelDiscoverer`) so the plugin works even when
|
|
21
|
+
# `rigor-activerecord` is not loaded; when it IS loaded, the published `:model_index` fact (ADR-9
|
|
22
|
+
# cross-plugin API) drives the same class set so the two plugins agree on what counts as a model.
|
|
31
23
|
#
|
|
32
24
|
# ## Configuration
|
|
33
25
|
#
|
|
@@ -39,9 +31,8 @@ module Rigor
|
|
|
39
31
|
#
|
|
40
32
|
# `model_search_paths` defaults to `["app/models"]`.
|
|
41
33
|
#
|
|
42
|
-
# The class name `Rigor::Plugin::Activestorage` (single
|
|
43
|
-
#
|
|
44
|
-
# used by `rigor-activerecord`.
|
|
34
|
+
# The class name `Rigor::Plugin::Activestorage` (single capital A) matches the constant-distinguishing
|
|
35
|
+
# convention used by `rigor-activerecord`.
|
|
45
36
|
class Activestorage < Rigor::Plugin::Base
|
|
46
37
|
manifest(
|
|
47
38
|
id: "activestorage",
|
|
@@ -53,11 +44,9 @@ module Rigor
|
|
|
53
44
|
consumes: [{ plugin_id: "activerecord", name: :model_index, optional: true }]
|
|
54
45
|
)
|
|
55
46
|
|
|
56
|
-
# Cached: attachment index. Walks every `.rb` file under
|
|
57
|
-
#
|
|
58
|
-
#
|
|
59
|
-
# in-block reads are captured into the record-and-validate
|
|
60
|
-
# dependency descriptor after the block runs.
|
|
47
|
+
# Cached: attachment index. Walks every `.rb` file under `model_search_paths` for `has_*_attached`
|
|
48
|
+
# macros. `watch:` (ADR-60 WD3) covers model-file additions; the discoverer's in-block reads are
|
|
49
|
+
# captured into the record-and-validate dependency descriptor after the block runs.
|
|
61
50
|
producer :attachment_index, watch: -> { [[@model_search_paths, "**/*.rb"]] } do |_params|
|
|
62
51
|
rows = AttachmentDiscoverer.new(
|
|
63
52
|
io_boundary: io_boundary,
|
|
@@ -80,18 +69,12 @@ module Rigor
|
|
|
80
69
|
Analyzer.new(path: path, attachment_index: index).analyze(root).diagnostics
|
|
81
70
|
end
|
|
82
71
|
|
|
83
|
-
# Return-type contribution: when the receiver is
|
|
84
|
-
# `Nominal[
|
|
85
|
-
#
|
|
86
|
-
#
|
|
87
|
-
# `
|
|
88
|
-
#
|
|
89
|
-
# model class names from the attachment index.
|
|
90
|
-
# The chained call (`.attached?`, `.purge`, `.url`)
|
|
91
|
-
# then resolves through ActiveStorage's RBS surface.
|
|
92
|
-
# Attachment setters (`user.avatar=`) decline — they
|
|
93
|
-
# take side-effecting argument types that the RBS
|
|
94
|
-
# surface already covers.
|
|
72
|
+
# Return-type contribution: when the receiver is `Nominal[Model]` and the method matches a
|
|
73
|
+
# discovered attachment, narrows to `Nominal[ActiveStorage::Attached::One]` (singular) or
|
|
74
|
+
# `Nominal[ActiveStorage::Attached::Many]` (collection) via a `dynamic_return` rule keyed on the
|
|
75
|
+
# live set of model class names from the attachment index. The chained call (`.attached?`, `.purge`,
|
|
76
|
+
# `.url`) then resolves through ActiveStorage's RBS surface. Attachment setters (`user.avatar=`)
|
|
77
|
+
# decline — they take side-effecting argument types that the RBS surface already covers.
|
|
95
78
|
dynamic_return receivers: -> { attachment_index&.class_names || [] } do |call_node, scope|
|
|
96
79
|
next nil unless call_node.is_a?(Prism::CallNode)
|
|
97
80
|
next nil if call_node.receiver.nil?
|
|
@@ -129,10 +112,9 @@ module Rigor
|
|
|
129
112
|
def attachment_index
|
|
130
113
|
return @attachment_index if @attachment_index
|
|
131
114
|
|
|
132
|
-
# ADR-60 WD3 record-and-validate: the producer's in-block
|
|
133
|
-
#
|
|
134
|
-
#
|
|
135
|
-
# producer's `watch:` covers model-file additions.
|
|
115
|
+
# ADR-60 WD3 record-and-validate: the producer's in-block `AttachmentDiscoverer` reads are
|
|
116
|
+
# captured into the dependency descriptor after the block runs, and the producer's `watch:`
|
|
117
|
+
# covers model-file additions.
|
|
136
118
|
@attachment_index = cache_for(:attachment_index, params: {}).call
|
|
137
119
|
rescue Plugin::AccessDeniedError => e
|
|
138
120
|
@load_errors << "rigor-activestorage: #{e.message}"
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# Entry point matching the `rigor-<id>` gem-name convention.
|
|
4
|
-
#
|
|
5
|
-
# `
|
|
6
|
-
# plugin's actual implementation under the `rigor/plugin/`
|
|
7
|
-
# namespace so the require / register pair fires.
|
|
3
|
+
# Entry point matching the `rigor-<id>` gem-name convention. The Plugin::Loader's `require_gem!` step
|
|
4
|
+
# calls `require "rigor-activestorage"`, and this file loads the plugin's actual implementation under
|
|
5
|
+
# the `rigor/plugin/` namespace so the require / register pair fires.
|
|
8
6
|
require "rigor/plugin/activestorage"
|
|
@@ -4,14 +4,11 @@ require "rigor/plugin"
|
|
|
4
4
|
|
|
5
5
|
module Rigor
|
|
6
6
|
module Plugin
|
|
7
|
-
# ADR-25 — a pure RBS-bundle plugin. It ships NO analyzer code:
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
# this gem's root and `Environment.for_project` merges it into
|
|
13
|
-
# the RBS environment, so the ActiveSupport core-extension
|
|
14
|
-
# selectors (`3.days`, `"x".squish`, `Time.current`, …) resolve.
|
|
7
|
+
# ADR-25 — a pure RBS-bundle plugin. It ships NO analyzer code: no `diagnostics_for_file`, no
|
|
8
|
+
# `dynamic_return`. Its whole contribution is the manifest's `signature_paths: ["sig"]`, which
|
|
9
|
+
# declares the bundled ActiveSupport `core_ext` RBS directory. `Plugin::Loader` resolves that
|
|
10
|
+
# directory against this gem's root and `Environment.for_project` merges it into the RBS environment,
|
|
11
|
+
# so the ActiveSupport core-extension selectors (`3.days`, `"x".squish`, `Time.current`, …) resolve.
|
|
15
12
|
#
|
|
16
13
|
# Activate it like any plugin — no path, no vendoring:
|
|
17
14
|
#
|
|
@@ -23,8 +20,7 @@ module Rigor
|
|
|
23
20
|
class ActivesupportCoreExt < Rigor::Plugin::Base
|
|
24
21
|
manifest(
|
|
25
22
|
id: "activesupport-core-ext",
|
|
26
|
-
# Bumped 2026-05-28 — added Date#midnight /
|
|
27
|
-
# at_midnight / beginning_of_day / end_of_day (Rails
|
|
23
|
+
# Bumped 2026-05-28 — added Date#midnight / at_midnight / beginning_of_day / end_of_day (Rails
|
|
28
24
|
# aliases that return Time, not Date).
|
|
29
25
|
version: "0.2.0",
|
|
30
26
|
description: "RBS bundle for the most-frequently-flagged ActiveSupport core_ext extensions.",
|
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# rigor-activesupport-core-ext — a community-maintained RBS bundle
|
|
4
|
-
#
|
|
3
|
+
# rigor-activesupport-core-ext — a community-maintained RBS bundle for the most-frequently-flagged
|
|
4
|
+
# ActiveSupport core extensions.
|
|
5
5
|
#
|
|
6
|
-
# Per ADR-25 this gem is a pure RBS-bundle *plugin*: it ships a
|
|
7
|
-
# `
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
# resolves and loads the bundled `sig/` automatically, with no
|
|
11
|
-
# hand-written path:
|
|
6
|
+
# Per ADR-25 this gem is a pure RBS-bundle *plugin*: it ships a `sig/` directory and a trivial
|
|
7
|
+
# `Rigor::Plugin::Base` subclass whose manifest declares `signature_paths: ["sig"]`. Activate it by
|
|
8
|
+
# listing the gem under `.rigor.yml`'s `plugins:` — Rigor resolves and loads the bundled `sig/`
|
|
9
|
+
# automatically, with no hand-written path:
|
|
12
10
|
#
|
|
13
11
|
# # .rigor.yml
|
|
14
12
|
# plugins:
|
|
15
13
|
# - rigor-activesupport-core-ext
|
|
16
14
|
#
|
|
17
|
-
# Coverage scope and rationale: see `README.md` in this directory
|
|
18
|
-
#
|
|
19
|
-
# survey that established the selector ranking.
|
|
15
|
+
# Coverage scope and rationale: see `README.md` in this directory and
|
|
16
|
+
# `docs/notes/20260515-real-world-rails-survey.md` for the survey that established the selector ranking.
|
|
20
17
|
require_relative "rigor/plugin/activesupport_core_ext"
|
|
@@ -4,26 +4,21 @@ require "rigor/plugin"
|
|
|
4
4
|
|
|
5
5
|
module Rigor
|
|
6
6
|
module Plugin
|
|
7
|
-
# ADR-16 Tier B worked plugin: recognises Devise's model-side
|
|
8
|
-
# `
|
|
9
|
-
# subclasses and explodes each strategy's module RBS into the
|
|
10
|
-
# calling class.
|
|
7
|
+
# ADR-16 Tier B worked plugin: recognises Devise's model-side `devise :strategy_a, :strategy_b` DSL on
|
|
8
|
+
# `ActiveRecord::Base` subclasses and explodes each strategy's module RBS into the calling class.
|
|
11
9
|
#
|
|
12
|
-
# Per the per-library survey (§ Devise), Devise's `devise(*modules)`
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
# `Devise
|
|
17
|
-
# calling class
|
|
18
|
-
#
|
|
19
|
-
# Devise's `lib/devise/modules.rb` and the pre-pass scanner
|
|
20
|
-
# synthesises one SyntheticMethod per (calling class, included
|
|
21
|
-
# module instance method) pair into the SyntheticMethodIndex.
|
|
10
|
+
# Per the per-library survey (§ Devise), Devise's `devise(*modules)` at `lib/devise/models.rb:79-112`
|
|
11
|
+
# is a **table-driven include sequence**: each Symbol argument resolves through
|
|
12
|
+
# `Devise::Models.const_get(m.to_s.classify)` to a concrete `Devise::Models::*` module, which is then
|
|
13
|
+
# mixed into the calling class. The substrate replays the same shape statically — the manifest's
|
|
14
|
+
# `modules_by_symbol:` mirrors Devise's `lib/devise/modules.rb` and the pre-pass scanner synthesises
|
|
15
|
+
# one SyntheticMethod per (calling class, included module instance method) pair into the
|
|
16
|
+
# SyntheticMethodIndex.
|
|
22
17
|
#
|
|
23
18
|
# ## Reach
|
|
24
19
|
#
|
|
25
|
-
# The full set of strategies Devise registers via
|
|
26
|
-
# `
|
|
20
|
+
# The full set of strategies Devise registers via `Devise.add_module` at gem load (per
|
|
21
|
+
# `lib/devise/modules.rb`):
|
|
27
22
|
#
|
|
28
23
|
# - `:database_authenticatable` — password + email auth core
|
|
29
24
|
# - `:recoverable` — password-reset flow
|
|
@@ -37,41 +32,31 @@ module Rigor
|
|
|
37
32
|
# - `:omniauthable` — OmniAuth providers
|
|
38
33
|
# - `:authenticatable` — always-included base module
|
|
39
34
|
#
|
|
40
|
-
# The substrate's pre-pass scanner consults each module's RBS
|
|
41
|
-
# via
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
# `send_reset_password_instructions`, etc. resolve through the
|
|
45
|
-
# synthetic-method tier without `call.undefined-method`.
|
|
35
|
+
# The substrate's pre-pass scanner consults each module's RBS via `Environment::RbsLoader#instance_definition`
|
|
36
|
+
# to enumerate method names. A user project providing real Devise via Bundler will see methods like
|
|
37
|
+
# `valid_password?`, `send_reset_password_instructions`, etc. resolve through the synthetic-method
|
|
38
|
+
# tier without `call.undefined-method`.
|
|
46
39
|
#
|
|
47
40
|
# ## Precision tier
|
|
48
41
|
#
|
|
49
|
-
# The scanner records `origin_module:` in each synthetic
|
|
50
|
-
#
|
|
51
|
-
#
|
|
52
|
-
# `
|
|
53
|
-
# authored RBS return types win: `valid_password?` returns
|
|
54
|
-
# `bool`, not `Dynamic[T]`. Unknown return types degrade
|
|
55
|
-
# gracefully to `Dynamic[T]`.
|
|
42
|
+
# The scanner records `origin_module:` in each synthetic method's provenance. The dispatcher's
|
|
43
|
+
# slice-6a TierB path (`promote_via_origin_module`) redispatches on `Nominal[origin_module]` via
|
|
44
|
+
# `RbsDispatch`, so Devise's authored RBS return types win: `valid_password?` returns `bool`, not
|
|
45
|
+
# `Dynamic[T]`. Unknown return types degrade gracefully to `Dynamic[T]`.
|
|
56
46
|
#
|
|
57
47
|
# ## Scope
|
|
58
48
|
#
|
|
59
|
-
# - Recognises model-side `devise :a, :b` on any AR::Base
|
|
60
|
-
#
|
|
61
|
-
# - `Devise::Models::Authenticatable` is always_included
|
|
62
|
-
#
|
|
63
|
-
#
|
|
64
|
-
#
|
|
65
|
-
#
|
|
66
|
-
#
|
|
67
|
-
#
|
|
68
|
-
# -
|
|
69
|
-
#
|
|
70
|
-
# slice that consumes ADR-9 fact-store entries from a
|
|
71
|
-
# `rigor-rails-routes`-style walker.
|
|
72
|
-
# - Per-strategy `ClassMethods` extend (Devise's `extend
|
|
73
|
-
# Mod::ClassMethods` pattern) is NOT yet wired — slice 3
|
|
74
|
-
# covers instance methods only per WD13 floor.
|
|
49
|
+
# - Recognises model-side `devise :a, :b` on any AR::Base subclass; trait symbol set mirrors
|
|
50
|
+
# `lib/devise/modules.rb`.
|
|
51
|
+
# - `Devise::Models::Authenticatable` is always_included (matches Devise's `with_options model: true`).
|
|
52
|
+
# - Unknown trait symbols silently skipped (per slice-3 design judgment (2)). User initializers that
|
|
53
|
+
# call `Devise.add_module :my_strategy, ...` are NOT seen — that path requires a separate scanner
|
|
54
|
+
# for `config/initializers/` and is deferred.
|
|
55
|
+
# - Controller-side helpers (`current_user`, `authenticate_user!`, etc.) are Tier C work, NOT Tier B;
|
|
56
|
+
# deferred to a future slice that consumes ADR-9 fact-store entries from a `rigor-rails-routes`-style
|
|
57
|
+
# walker.
|
|
58
|
+
# - Per-strategy `ClassMethods` extend (Devise's `extend Mod::ClassMethods` pattern) is NOT yet wired
|
|
59
|
+
# — slice 3 covers instance methods only per WD13 floor.
|
|
75
60
|
class Devise < Rigor::Plugin::Base
|
|
76
61
|
manifest(
|
|
77
62
|
id: "devise",
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# Gem entry point. Required by Rigor's plugin loader when
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
# `Rigor::Plugin.register`, which the body of
|
|
7
|
-
# `lib/rigor/plugin/devise.rb` performs at load time.
|
|
3
|
+
# Gem entry point. Required by Rigor's plugin loader when `.rigor.yml` lists `rigor-devise` under
|
|
4
|
+
# `plugins:`. The loader expects this `require` to side-effect a call to `Rigor::Plugin.register`,
|
|
5
|
+
# which the body of `lib/rigor/plugin/devise.rb` performs at load time.
|
|
8
6
|
require_relative "rigor/plugin/devise"
|
|
@@ -6,16 +6,13 @@ require "rigor/source/literals"
|
|
|
6
6
|
module Rigor
|
|
7
7
|
module Plugin
|
|
8
8
|
class DrySchema < Rigor::Plugin::Base
|
|
9
|
-
# Walks project source for `Foo = Dry::Schema.{Params,JSON,define}
|
|
10
|
-
# {
|
|
11
|
-
#
|
|
12
|
-
# table covering each schema's typed-key surface.
|
|
9
|
+
# Walks project source for `Foo = Dry::Schema.{Params,JSON,define} { ... }` shapes and emits a
|
|
10
|
+
# `{schema_const_fqn => {required: {key => underlying_class}, optional: {…}}}` table covering each
|
|
11
|
+
# schema's typed-key surface.
|
|
13
12
|
module SchemaScanner
|
|
14
|
-
# The dry-schema canonical-type symbols accepted as
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
# uses for `CANONICAL_ALIASES`, intersected with what
|
|
18
|
-
# dry-schema's predicate engine accepts).
|
|
13
|
+
# The dry-schema canonical-type symbols accepted as predicate arguments. Maps each to the
|
|
14
|
+
# underlying Ruby class name (the same vocabulary `rigor-dry-types` uses for `CANONICAL_ALIASES`,
|
|
15
|
+
# intersected with what dry-schema's predicate engine accepts).
|
|
19
16
|
CANONICAL_TYPES = {
|
|
20
17
|
string: "String",
|
|
21
18
|
integer: "Integer",
|
|
@@ -30,12 +27,10 @@ module Rigor
|
|
|
30
27
|
array: "Array"
|
|
31
28
|
}.tap { |h| h[:nil] = "NilClass" }.freeze
|
|
32
29
|
|
|
33
|
-
# The dry-schema predicate verbs that accept a type
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
#
|
|
37
|
-
# element type) but for Rigor's purposes they all
|
|
38
|
-
# contribute the same underlying class for the key.
|
|
30
|
+
# The dry-schema predicate verbs that accept a type argument. Each verb has a slightly different
|
|
31
|
+
# runtime semantic (`filled` = present + non-empty; `value` = present; `maybe` = present-or-nil;
|
|
32
|
+
# `each` = collection element type) but for Rigor's purposes they all contribute the same
|
|
33
|
+
# underlying class for the key.
|
|
39
34
|
TYPE_BEARING_PREDICATES = %i[filled value maybe each].to_set.freeze
|
|
40
35
|
private_constant :TYPE_BEARING_PREDICATES
|
|
41
36
|
|
|
@@ -45,17 +40,12 @@ module Rigor
|
|
|
45
40
|
|
|
46
41
|
module_function
|
|
47
42
|
|
|
48
|
-
# @param paths [Array<String>] absolute paths to `.rb`
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
#
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
# underlying class. Empty when the plugin isn't
|
|
55
|
-
# loaded.
|
|
56
|
-
# @return [Hash{String => Hash{Symbol => Hash{Symbol => String}}}]
|
|
57
|
-
# frozen per-schema typed-key table. Empty when no
|
|
58
|
-
# recognisable schema declaration is found.
|
|
43
|
+
# @param paths [Array<String>] absolute paths to `.rb` files the project's `paths:` resolves to.
|
|
44
|
+
# @param type_aliases [Hash{String => String}] the ADR-9 `:dry_type_aliases` fact published by
|
|
45
|
+
# `rigor-dry-types` when loaded. Used to resolve `value(Types::Email)` references to their
|
|
46
|
+
# underlying class. Empty when the plugin isn't loaded.
|
|
47
|
+
# @return [Hash{String => Hash{Symbol => Hash{Symbol => String}}}] frozen per-schema typed-key
|
|
48
|
+
# table. Empty when no recognisable schema declaration is found.
|
|
59
49
|
def scan(paths:, type_aliases: {})
|
|
60
50
|
table = {}
|
|
61
51
|
paths.each do |path|
|
|
@@ -77,11 +67,9 @@ module Rigor
|
|
|
77
67
|
end
|
|
78
68
|
private_class_method :scan_file
|
|
79
69
|
|
|
80
|
-
# Walks the AST collecting `<Const> = Dry::Schema.X { ... }`
|
|
81
|
-
#
|
|
82
|
-
#
|
|
83
|
-
# Dry::Schema.Params { ... }; end` registers as
|
|
84
|
-
# `"Foo::SCHEMA"`.
|
|
70
|
+
# Walks the AST collecting `<Const> = Dry::Schema.X { ... }` assignments at any nesting level.
|
|
71
|
+
# Tracks the enclosing constant chain so a class-level `class Foo; SCHEMA = Dry::Schema.Params
|
|
72
|
+
# { ... }; end` registers as `"Foo::SCHEMA"`.
|
|
85
73
|
def collect_schemas(node, qualified_prefix, type_aliases)
|
|
86
74
|
return {} if node.nil?
|
|
87
75
|
|
|
@@ -119,8 +107,7 @@ module Rigor
|
|
|
119
107
|
end
|
|
120
108
|
private_class_method :collect_schema_assignment
|
|
121
109
|
|
|
122
|
-
# Matches `Dry::Schema.Params { ... }` /
|
|
123
|
-
# `Dry::Schema.JSON { ... }` / `Dry::Schema.define { ... }`.
|
|
110
|
+
# Matches `Dry::Schema.Params { ... }` / `Dry::Schema.JSON { ... }` / `Dry::Schema.define { ... }`.
|
|
124
111
|
def schema_entry_call?(node)
|
|
125
112
|
return false unless node.is_a?(Prism::CallNode)
|
|
126
113
|
return false unless SCHEMA_ENTRY_NAMES.include?(node.name)
|
|
@@ -147,10 +134,9 @@ module Rigor
|
|
|
147
134
|
end
|
|
148
135
|
private_class_method :collect_schema_shape
|
|
149
136
|
|
|
150
|
-
# Walks every top-level `required(:key).<predicate>(...)` /
|
|
151
|
-
#
|
|
152
|
-
#
|
|
153
|
-
# (multi-statement) or a single expression node.
|
|
137
|
+
# Walks every top-level `required(:key).<predicate>(...)` / `optional(:key).<predicate>(...)`
|
|
138
|
+
# chain in the block body. The block's body is either a `Prism::StatementsNode` (multi-statement)
|
|
139
|
+
# or a single expression node.
|
|
154
140
|
def walk_block_body(block_node, &)
|
|
155
141
|
body = block_node.body
|
|
156
142
|
return if body.nil?
|
|
@@ -160,13 +146,10 @@ module Rigor
|
|
|
160
146
|
end
|
|
161
147
|
private_class_method :walk_block_body
|
|
162
148
|
|
|
163
|
-
# `required(:key).filled(:string)` parses as a CallNode
|
|
164
|
-
#
|
|
165
|
-
# chain
|
|
166
|
-
#
|
|
167
|
-
# `each(<Type>)` predicate yields a list-of-element
|
|
168
|
-
# type info (`{type: <T>, list: true}`); other type-bearing
|
|
169
|
-
# predicates (`filled`/`value`/`maybe`) yield scalar info
|
|
149
|
+
# `required(:key).filled(:string)` parses as a CallNode whose receiver is the `required(:key)`
|
|
150
|
+
# call. Walk the chain inward looking for the type-bearing predicate at the head; the key sits on
|
|
151
|
+
# the chain's tail. The `each(<Type>)` predicate yields a list-of-element type info (`{type: <T>,
|
|
152
|
+
# list: true}`); other type-bearing predicates (`filled`/`value`/`maybe`) yield scalar info
|
|
170
153
|
# (`{type: <T>, list: false}`).
|
|
171
154
|
def visit_chain(node, &block)
|
|
172
155
|
return unless node.is_a?(Prism::CallNode)
|
|
@@ -179,11 +162,9 @@ module Rigor
|
|
|
179
162
|
end
|
|
180
163
|
private_class_method :visit_chain
|
|
181
164
|
|
|
182
|
-
# `required(:key).filled(:string).value(...)...` — the
|
|
183
|
-
#
|
|
184
|
-
# `required
|
|
185
|
-
# `node.receiver` until we hit the `required` /
|
|
186
|
-
# `optional` call, recording the key + kind.
|
|
165
|
+
# `required(:key).filled(:string).value(...)...` — the OUTERMOST call's receiver chain ends in
|
|
166
|
+
# the `required(:key)` / `optional(:key)` call. Recurse on `node.receiver` until we hit the
|
|
167
|
+
# `required` / `optional` call, recording the key + kind.
|
|
187
168
|
def extract_key_and_kind(node)
|
|
188
169
|
current = node
|
|
189
170
|
while current.is_a?(Prism::CallNode)
|
|
@@ -199,11 +180,9 @@ module Rigor
|
|
|
199
180
|
end
|
|
200
181
|
private_class_method :extract_key_and_kind
|
|
201
182
|
|
|
202
|
-
# Walks the call chain finding the first type-bearing
|
|
203
|
-
#
|
|
204
|
-
#
|
|
205
|
-
# tuple (`each` is the only verb that produces a list)
|
|
206
|
-
# or nil when no recognisable type sits on the chain.
|
|
183
|
+
# Walks the call chain finding the first type-bearing predicate (`filled` / `value` / `maybe` /
|
|
184
|
+
# `each`) and extracts its argument type. Returns a `{type:, list:}` tuple (`each` is the only
|
|
185
|
+
# verb that produces a list) or nil when no recognisable type sits on the chain.
|
|
207
186
|
def walk_predicate_chain(node)
|
|
208
187
|
current = node
|
|
209
188
|
while current.is_a?(Prism::CallNode)
|
|
@@ -217,12 +196,10 @@ module Rigor
|
|
|
217
196
|
end
|
|
218
197
|
private_class_method :walk_predicate_chain
|
|
219
198
|
|
|
220
|
-
# Reads the first positional argument of a `filled(:string)`
|
|
221
|
-
#
|
|
222
|
-
#
|
|
223
|
-
#
|
|
224
|
-
# name for downstream type-alias resolution. Returns nil
|
|
225
|
-
# for anything else.
|
|
199
|
+
# Reads the first positional argument of a `filled(:string)` / `value(:integer)` /
|
|
200
|
+
# `maybe(Types::Email)` call. Returns either the canonical-type-symbol's underlying class
|
|
201
|
+
# ("String" / "Integer" / …), or the constant's qualified name for downstream type-alias
|
|
202
|
+
# resolution. Returns nil for anything else.
|
|
226
203
|
def extract_type_from_predicate(call_node)
|
|
227
204
|
arg = call_node.arguments&.arguments&.first
|
|
228
205
|
case arg
|
|
@@ -236,12 +213,10 @@ module Rigor
|
|
|
236
213
|
end
|
|
237
214
|
private_class_method :extract_type_from_predicate
|
|
238
215
|
|
|
239
|
-
# In-place: any value's `type:` slot in `bucket` that
|
|
240
|
-
#
|
|
241
|
-
#
|
|
242
|
-
#
|
|
243
|
-
# bucket (no fact contribution rather than misleading
|
|
244
|
-
# data). The `list:` slot rides along unchanged.
|
|
216
|
+
# In-place: any value's `type:` slot in `bucket` that doesn't already match a canonical class
|
|
217
|
+
# (e.g. `"Types::Email"`) gets resolved through the type_aliases fact. Unresolvable values drop
|
|
218
|
+
# from the bucket (no fact contribution rather than misleading data). The `list:` slot rides along
|
|
219
|
+
# unchanged.
|
|
245
220
|
def remap_aliases!(bucket, type_aliases)
|
|
246
221
|
canonical_set = CANONICAL_TYPES.values.to_set
|
|
247
222
|
bucket.each_pair.to_a.each do |key, info|
|
|
@@ -258,9 +233,8 @@ module Rigor
|
|
|
258
233
|
end
|
|
259
234
|
private_class_method :remap_aliases!
|
|
260
235
|
|
|
261
|
-
# Constant-path serialiser: `Dry::Schema` -> "Dry::Schema",
|
|
262
|
-
#
|
|
263
|
-
# doesn't expose as ConstantRead/PathNode.
|
|
236
|
+
# Constant-path serialiser: `Dry::Schema` -> "Dry::Schema", bare `Foo` -> "Foo". Returns nil for
|
|
237
|
+
# shapes Prism doesn't expose as ConstantRead/PathNode.
|
|
264
238
|
def constant_name_for(node)
|
|
265
239
|
return nil if node.nil?
|
|
266
240
|
|