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
|
@@ -3,53 +3,35 @@
|
|
|
3
3
|
module Rigor
|
|
4
4
|
module Plugin
|
|
5
5
|
class RailsRoutes < Rigor::Plugin::Base
|
|
6
|
-
# Generates the catalogue of route helpers a `devise_for
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
# enumerates every generated helper); the generator
|
|
11
|
-
# mirrors it.
|
|
6
|
+
# Generates the catalogue of route helpers a `devise_for :resources` call adds to a Rails app's
|
|
7
|
+
# routing table. The set is fixed and well-documented (the
|
|
8
|
+
# [Devise wiki](https://github.com/heartcombo/devise/wiki/How-To:-Add-routes-helpers) enumerates
|
|
9
|
+
# every generated helper); the generator mirrors it.
|
|
12
10
|
#
|
|
13
|
-
# Used by `RoutesParser` when it sees a top-level
|
|
14
|
-
# `
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
# `
|
|
18
|
-
# check accepts the canonical signatures (Devise helpers
|
|
19
|
-
# take zero positional args plus an optional trailing
|
|
20
|
-
# options hash, which `HelperTable#accepts_arity?`
|
|
21
|
-
# already handles via the `arity + 1` rule).
|
|
11
|
+
# Used by `RoutesParser` when it sees a top-level `devise_for :name` (or `devise_for :name, skip:
|
|
12
|
+
# [...]`) call. Each generated helper is materialised as a `HelperTable::Entry` so the analyzer's
|
|
13
|
+
# `unknown-helper` rule recognises them and the arity check accepts the canonical signatures (Devise
|
|
14
|
+
# helpers take zero positional args plus an optional trailing options hash, which
|
|
15
|
+
# `HelperTable#accepts_arity?` already handles via the `arity + 1` rule).
|
|
22
16
|
#
|
|
23
17
|
# Scope:
|
|
24
18
|
#
|
|
25
|
-
# - Recognises the standard six controllers
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
# - Honours `
|
|
29
|
-
#
|
|
30
|
-
# -
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
# - `omniauth_callbacks` helpers are dynamic — the
|
|
37
|
-
# provider name is supplied at call time
|
|
38
|
-
# (`user_facebook_omniauth_authorize_path`) and Devise
|
|
39
|
-
# declares them from the configured providers, which
|
|
40
|
-
# live in an initializer this static parser does not
|
|
41
|
-
# read. The suffix patterns are registered in
|
|
42
|
-
# `OMNIAUTH_SUFFIXES` and consulted by
|
|
43
|
-
# `HelperTable#omniauth_match?`.
|
|
19
|
+
# - Recognises the standard six controllers (`:sessions`, `:passwords`, `:confirmations`, `:unlocks`,
|
|
20
|
+
# `:registrations`, `:omniauth_callbacks`).
|
|
21
|
+
# - Honours `skip: [...]` to suppress controllers the project disables.
|
|
22
|
+
# - Honours `path: "..."` to remap the URL path (does NOT remap the helper-name prefix — Devise uses
|
|
23
|
+
# the resource name for the helper, not the path).
|
|
24
|
+
# - Does NOT yet honour `as: "..."` overrides, `class_name:`, `controllers: { ... }` (these are rare;
|
|
25
|
+
# expand on demand).
|
|
26
|
+
# - `omniauth_callbacks` helpers are dynamic — the provider name is supplied at call time
|
|
27
|
+
# (`user_facebook_omniauth_authorize_path`) and Devise declares them from the configured providers,
|
|
28
|
+
# which live in an initializer this static parser does not read. The suffix patterns are registered
|
|
29
|
+
# in `OMNIAUTH_SUFFIXES` and consulted by `HelperTable#omniauth_match?`.
|
|
44
30
|
module DeviseRoutes
|
|
45
|
-
# The standard Devise controllers and the helper
|
|
46
|
-
#
|
|
47
|
-
# name
|
|
48
|
-
#
|
|
49
|
-
# the part BEFORE the resource-name segment (Rails
|
|
50
|
-
# produces `<prefix>_<resource>_<suffix>_path`; for
|
|
51
|
-
# the bare `<resource>_session_path` shape the prefix
|
|
52
|
-
# is empty).
|
|
31
|
+
# The standard Devise controllers and the helper actions each generates. Keys are the controller
|
|
32
|
+
# name; values are arrays of `[helper_prefix, http_method, action]` triples — `helper_prefix` is
|
|
33
|
+
# the part BEFORE the resource-name segment (Rails produces `<prefix>_<resource>_<suffix>_path`;
|
|
34
|
+
# for the bare `<resource>_session_path` shape the prefix is empty).
|
|
53
35
|
CONTROLLER_HELPERS = {
|
|
54
36
|
sessions: [
|
|
55
37
|
["new", "session", :get, :new],
|
|
@@ -77,13 +59,10 @@ module Rigor
|
|
|
77
59
|
]
|
|
78
60
|
}.freeze
|
|
79
61
|
|
|
80
|
-
# Dynamic-provider helper patterns. `_omniauth_authorize_path`
|
|
81
|
-
#
|
|
82
|
-
#
|
|
83
|
-
#
|
|
84
|
-
# `<resource>_<provider>_omniauth_(authorize|callback)_(path|url)`
|
|
85
|
-
# call as recognised when the resource is one the
|
|
86
|
-
# project declared via `devise_for`.
|
|
62
|
+
# Dynamic-provider helper patterns. `_omniauth_authorize_path` and `_omniauth_callback_path` are
|
|
63
|
+
# generated per configured provider (Facebook, GitHub, …) by an initializer this parser does not
|
|
64
|
+
# read. We treat any `<resource>_<provider>_omniauth_(authorize|callback)_(path|url)` call as
|
|
65
|
+
# recognised when the resource is one the project declared via `devise_for`.
|
|
87
66
|
OMNIAUTH_SUFFIXES = %w[
|
|
88
67
|
_omniauth_authorize_path _omniauth_authorize_url
|
|
89
68
|
_omniauth_callback_path _omniauth_callback_url
|
|
@@ -91,16 +70,12 @@ module Rigor
|
|
|
91
70
|
|
|
92
71
|
module_function
|
|
93
72
|
|
|
94
|
-
# @param resource [String, Symbol] the `devise_for`
|
|
95
|
-
#
|
|
96
|
-
#
|
|
97
|
-
#
|
|
98
|
-
# @
|
|
99
|
-
#
|
|
100
|
-
# @return [Array<HelperTable::Entry>] one entry per
|
|
101
|
-
# generated `_path` helper. The caller is expected to
|
|
102
|
-
# pair `_url` variants the same way `RoutesParser` does
|
|
103
|
-
# for other entries.
|
|
73
|
+
# @param resource [String, Symbol] the `devise_for` argument — typically `:users`. Used as both the
|
|
74
|
+
# helper-name segment (`new_user_session_path`) and to derive the resource path.
|
|
75
|
+
# @param skip [Array<Symbol>] controllers the project disables via `devise_for :users, skip:
|
|
76
|
+
# [:registrations]`.
|
|
77
|
+
# @return [Array<HelperTable::Entry>] one entry per generated `_path` helper. The caller is
|
|
78
|
+
# expected to pair `_url` variants the same way `RoutesParser` does for other entries.
|
|
104
79
|
def generate(resource:, skip: [])
|
|
105
80
|
resource_segment = singularize(resource.to_s)
|
|
106
81
|
skip_set = skip.to_set(&:to_sym)
|
|
@@ -126,21 +101,15 @@ module Rigor
|
|
|
126
101
|
end
|
|
127
102
|
end
|
|
128
103
|
|
|
129
|
-
# Devise also ships *scoped* helpers
|
|
130
|
-
# (`
|
|
131
|
-
# resource segment and take the scope as a positional
|
|
132
|
-
# argument: `new_password_path(resource_name)` is the
|
|
104
|
+
# Devise also ships *scoped* helpers (`Devise::Controllers::UrlHelpers`) that DROP the resource
|
|
105
|
+
# segment and take the scope as a positional argument: `new_password_path(resource_name)` is the
|
|
133
106
|
# bare form of `new_user_password_path`. Used inside
|
|
134
|
-
# `Auth::PasswordsController < Devise::PasswordsController`
|
|
135
|
-
#
|
|
136
|
-
# trailing options-hash bumps it via the existing
|
|
137
|
-
# `arity + 1` rule.
|
|
107
|
+
# `Auth::PasswordsController < Devise::PasswordsController` (Mastodon's idiom). Arity 1 (the
|
|
108
|
+
# scope), and a trailing options-hash bumps it via the existing `arity + 1` rule.
|
|
138
109
|
entries.concat(scoped_helpers(skip_set))
|
|
139
110
|
|
|
140
|
-
# `omniauth_authorize_path(scope, provider)` and
|
|
141
|
-
# `
|
|
142
|
-
# `Devise::Controllers::UrlHelpers` scoped helpers
|
|
143
|
-
# that delegate to the OmniAuth gem. Arity 2.
|
|
111
|
+
# `omniauth_authorize_path(scope, provider)` and `omniauth_callback_path(scope, provider)` are
|
|
112
|
+
# `Devise::Controllers::UrlHelpers` scoped helpers that delegate to the OmniAuth gem. Arity 2.
|
|
144
113
|
unless skip_set.include?(:omniauth_callbacks)
|
|
145
114
|
%w[omniauth_authorize_path omniauth_callback_path].each do |name|
|
|
146
115
|
entries << HelperTable::Entry.new(
|
|
@@ -156,11 +125,9 @@ module Rigor
|
|
|
156
125
|
entries
|
|
157
126
|
end
|
|
158
127
|
|
|
159
|
-
# Scoped helpers Devise exposes inside its controllers.
|
|
160
|
-
#
|
|
161
|
-
# scope
|
|
162
|
-
# Names mirror the qualified `<scope>_<name>_path`
|
|
163
|
-
# entries above, minus the scope segment.
|
|
128
|
+
# Scoped helpers Devise exposes inside its controllers. The arity-1 family — caller supplies the
|
|
129
|
+
# resource scope (`:user` etc.) as the first positional arg. Names mirror the qualified
|
|
130
|
+
# `<scope>_<name>_path` entries above, minus the scope segment.
|
|
164
131
|
SCOPED_HELPERS = {
|
|
165
132
|
sessions: %w[new_session_path session_path destroy_session_path],
|
|
166
133
|
passwords: %w[new_password_path edit_password_path password_path],
|
|
@@ -186,28 +153,22 @@ module Rigor
|
|
|
186
153
|
end
|
|
187
154
|
end
|
|
188
155
|
|
|
189
|
-
# Returns the set of OmniAuth pattern suffixes the
|
|
190
|
-
# analyzer
|
|
191
|
-
#
|
|
192
|
-
# when a `*_path` / `*_url` call's name does not match
|
|
193
|
-
# any registered entry and its prefix matches a Devise
|
|
194
|
-
# resource.
|
|
156
|
+
# Returns the set of OmniAuth pattern suffixes the analyzer accepts for a given resource. The
|
|
157
|
+
# analyzer consults this set (via `HelperTable#omniauth_match?`) when a `*_path` / `*_url` call's
|
|
158
|
+
# name does not match any registered entry and its prefix matches a Devise resource.
|
|
195
159
|
def omniauth_suffixes
|
|
196
160
|
OMNIAUTH_SUFFIXES
|
|
197
161
|
end
|
|
198
162
|
|
|
199
|
-
# ADR-39 — delegates to the shared inflector (real
|
|
200
|
-
#
|
|
201
|
-
# AS-replica this module used to duplicate from `RoutesParser`.
|
|
163
|
+
# ADR-39 — delegates to the shared inflector (real `ActiveSupport::Inflector` when available),
|
|
164
|
+
# replacing the tiny AS-replica this module used to duplicate from `RoutesParser`.
|
|
202
165
|
def singularize(word)
|
|
203
166
|
Rigor::Plugin::Inflector.singularize(word)
|
|
204
167
|
end
|
|
205
168
|
|
|
206
|
-
# Approximate path generation. We don't honour the
|
|
207
|
-
# `path
|
|
208
|
-
#
|
|
209
|
-
# informational and surfaces only in the `:helper` info
|
|
210
|
-
# diagnostic.
|
|
169
|
+
# Approximate path generation. We don't honour the `path:` Devise option here because the helper
|
|
170
|
+
# NAME is what the analyzer cares about; the `path` field is informational and surfaces only in
|
|
171
|
+
# the `:helper` info diagnostic.
|
|
211
172
|
def devise_path_for(resource_segment, controller, action)
|
|
212
173
|
plural = "#{resource_segment}s"
|
|
213
174
|
base = "/#{plural}"
|
|
@@ -3,39 +3,27 @@
|
|
|
3
3
|
module Rigor
|
|
4
4
|
module Plugin
|
|
5
5
|
class RailsRoutes < Rigor::Plugin::Base
|
|
6
|
-
# Generates the catalogue of OAuth route helpers a
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
# [Routing](https://github.com/doorkeeper-gem/doorkeeper/wiki/Customizing-routes)
|
|
11
|
-
# documentation; this module mirrors the canonical
|
|
12
|
-
# helper names.
|
|
6
|
+
# Generates the catalogue of OAuth route helpers a `use_doorkeeper do ... end` block adds to a Rails
|
|
7
|
+
# app's routing table. The set is the Doorkeeper gem's documented default — see Doorkeeper's
|
|
8
|
+
# [Routing](https://github.com/doorkeeper-gem/doorkeeper/wiki/Customizing-routes) documentation; this
|
|
9
|
+
# module mirrors the canonical helper names.
|
|
13
10
|
#
|
|
14
|
-
# Used by `RoutesParser` when it sees a `use_doorkeeper`
|
|
15
|
-
#
|
|
16
|
-
# `
|
|
17
|
-
#
|
|
18
|
-
# `oauth_application_path(:id)` / `oauth_authorized_application_path(:id)`
|
|
19
|
-
# forms is 1 (the `:id`); all other Doorkeeper helpers
|
|
20
|
-
# are arity 0.
|
|
11
|
+
# Used by `RoutesParser` when it sees a `use_doorkeeper` call. Each generated helper is materialised
|
|
12
|
+
# as a `HelperTable::Entry` so the analyzer's `unknown-helper` rule recognises them. Arity for the
|
|
13
|
+
# `oauth_application_path(:id)` / `oauth_authorized_application_path(:id)` forms is 1 (the `:id`);
|
|
14
|
+
# all other Doorkeeper helpers are arity 0.
|
|
21
15
|
#
|
|
22
16
|
# Scope:
|
|
23
17
|
#
|
|
24
|
-
# - Recognises the standard helper set: authorization,
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
# -
|
|
28
|
-
#
|
|
29
|
-
# - Does NOT yet honour `
|
|
30
|
-
# those change WHICH class serves the route but not
|
|
31
|
-
# the helper NAMES, so omitting them is sound.
|
|
32
|
-
# - Does NOT yet honour custom `as:` / `at:` on
|
|
33
|
-
# `use_doorkeeper` itself.
|
|
18
|
+
# - Recognises the standard helper set: authorization, token, revoke, introspect, token_info,
|
|
19
|
+
# userinfo, applications (resources), authorized_applications.
|
|
20
|
+
# - Honours `skip_controllers <names>` inside the block to omit the named controller's helpers.
|
|
21
|
+
# - Does NOT yet honour `controllers ...:` remappings — those change WHICH class serves the route but
|
|
22
|
+
# not the helper NAMES, so omitting them is sound.
|
|
23
|
+
# - Does NOT yet honour custom `as:` / `at:` on `use_doorkeeper` itself.
|
|
34
24
|
module DoorkeeperRoutes
|
|
35
|
-
# Per-controller helper catalogue. Keys are the
|
|
36
|
-
# `
|
|
37
|
-
# entries (name + arity + path + http_method).
|
|
38
|
-
# Both `_path` and `_url` variants are paired by
|
|
25
|
+
# Per-controller helper catalogue. Keys are the `skip_controllers :<key>` names; values are the
|
|
26
|
+
# entries (name + arity + path + http_method). Both `_path` and `_url` variants are paired by
|
|
39
27
|
# `RoutesParser` after registration.
|
|
40
28
|
CONTROLLER_HELPERS = {
|
|
41
29
|
authorizations: [
|
|
@@ -78,8 +66,7 @@ module Rigor
|
|
|
78
66
|
|
|
79
67
|
module_function
|
|
80
68
|
|
|
81
|
-
# @param skip [Array<Symbol>] controller names the
|
|
82
|
-
# project omits via `skip_controllers :name, ...`.
|
|
69
|
+
# @param skip [Array<Symbol>] controller names the project omits via `skip_controllers :name, ...`.
|
|
83
70
|
# @return [Array<HelperTable::Entry>] flattened entries.
|
|
84
71
|
def generate(skip: [])
|
|
85
72
|
skip_set = skip.to_set(&:to_sym)
|
|
@@ -5,76 +5,54 @@ require "prism"
|
|
|
5
5
|
module Rigor
|
|
6
6
|
module Plugin
|
|
7
7
|
class RailsRoutes < Rigor::Plugin::Base
|
|
8
|
-
# Walks `app/helpers/**/*.rb` (or any configured set of
|
|
9
|
-
# helper
|
|
10
|
-
#
|
|
11
|
-
# `
|
|
12
|
-
# project-defined `*_path` / `*_url` helpers (the
|
|
13
|
-
# canonical Rails pattern: a `UrlHelper` module exposing
|
|
14
|
-
# `full_asset_url`, `host_to_url`, `frontend_asset_url`,
|
|
15
|
-
# and so on).
|
|
8
|
+
# Walks `app/helpers/**/*.rb` (or any configured set of helper directories) and extracts every public
|
|
9
|
+
# module-level method name so the analyzer's `unknown-helper` rule does not false-fire on calls to
|
|
10
|
+
# project-defined `*_path` / `*_url` helpers (the canonical Rails pattern: a `UrlHelper` module
|
|
11
|
+
# exposing `full_asset_url`, `host_to_url`, `frontend_asset_url`, and so on).
|
|
16
12
|
#
|
|
17
13
|
# The discoverer is deliberately conservative:
|
|
18
14
|
#
|
|
19
|
-
# - Walks `def name(...)` declarations at the module /
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
# `
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
# where the receiver genuinely cannot see the method.
|
|
35
|
-
# - Ignores `def self.x` (singleton-method definitions) —
|
|
36
|
-
# Rails helpers are instance methods on the helper
|
|
37
|
-
# module; class-side `self.x` shapes are usually
|
|
38
|
-
# internal utilities, not view helpers.
|
|
39
|
-
# - Filters the resulting set to names ending in `_path`
|
|
40
|
-
# or `_url` (the dispatch surface the analyzer's rule
|
|
41
|
-
# actually cares about). A helper whose name does not
|
|
42
|
-
# end with either suffix is irrelevant to the rule's
|
|
43
|
-
# false-positive surface, so excluding it costs nothing
|
|
44
|
-
# and keeps the registered set focused.
|
|
15
|
+
# - Walks `def name(...)` declarations at the module / class top level. Nested `def` inside a method
|
|
16
|
+
# body or a `define_method` macro is NOT extracted (the same reason `rigor-actionpack` is not the
|
|
17
|
+
# canonical custom-helper source — metaprogrammed helpers are out of scope for a static scan).
|
|
18
|
+
# - **Visibility-agnostic.** A `private` / `protected` `def some_url` IS registered. The
|
|
19
|
+
# `unknown-helper` rule is a project-wide name-presence check, not a visibility check — if the user
|
|
20
|
+
# wrote a `_path` / `_url` method anywhere in `app/`, they very likely intend to call it (often
|
|
21
|
+
# Mastodon's pattern: a controller's `private def page_url(page)` invoked by a `link_to` in its own
|
|
22
|
+
# view). The core engine's `call.undefined-method` rule still catches the case where the receiver
|
|
23
|
+
# genuinely cannot see the method.
|
|
24
|
+
# - Ignores `def self.x` (singleton-method definitions) — Rails helpers are instance methods on the
|
|
25
|
+
# helper module; class-side `self.x` shapes are usually internal utilities, not view helpers.
|
|
26
|
+
# - Filters the resulting set to names ending in `_path` or `_url` (the dispatch surface the
|
|
27
|
+
# analyzer's rule actually cares about). A helper whose name does not end with either suffix is
|
|
28
|
+
# irrelevant to the rule's false-positive surface, so excluding it costs nothing and keeps the
|
|
29
|
+
# registered set focused.
|
|
45
30
|
#
|
|
46
31
|
# Out of scope (intentional):
|
|
47
32
|
#
|
|
48
|
-
# - Helpers defined via `define_method` or via macros like
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
# -
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
# companion `DeviseRoutes` generator; other gem-injected
|
|
55
|
-
# helpers fall to ADR-25 plugin-contributed RBS or the
|
|
56
|
-
# ADR-10 `dependencies.source_inference:` path.
|
|
33
|
+
# - Helpers defined via `define_method` or via macros like `inheritance_traversed_helpers`. These
|
|
34
|
+
# would need ADR-16 macro substrate or per-plugin custom recognizers.
|
|
35
|
+
# - Helpers inherited from gems (`Devise::Controllers::Helpers`, `ViteRails::TagHelpers`, etc.).
|
|
36
|
+
# Those need their own handling — Devise auto-routes are covered by the companion `DeviseRoutes`
|
|
37
|
+
# generator; other gem-injected helpers fall to ADR-25 plugin-contributed RBS or the ADR-10
|
|
38
|
+
# `dependencies.source_inference:` path.
|
|
57
39
|
module HelperDiscoverer
|
|
58
40
|
HELPER_SUFFIXES = [/_path\z/, /_url\z/].freeze
|
|
59
41
|
|
|
60
42
|
module_function
|
|
61
43
|
|
|
62
|
-
# @param contents_per_path [Hash{String => String}]
|
|
63
|
-
#
|
|
64
|
-
#
|
|
65
|
-
#
|
|
66
|
-
# @return [Set<String>] method names suitable for
|
|
67
|
-
# inclusion in the `HelperTable`'s custom-helper set.
|
|
44
|
+
# @param contents_per_path [Hash{String => String}] file path → source text. The caller is
|
|
45
|
+
# responsible for reading files (typically through the trusted `IoBoundary` so cache invalidation
|
|
46
|
+
# works).
|
|
47
|
+
# @return [Set<String>] method names suitable for inclusion in the `HelperTable`'s custom-helper set.
|
|
68
48
|
def discover(contents_per_path)
|
|
69
49
|
names = []
|
|
70
50
|
contents_per_path.each_value do |contents|
|
|
71
51
|
names.concat(extract_from_contents(contents))
|
|
72
52
|
rescue StandardError
|
|
73
|
-
# Skip any file whose AST walk explodes — discovery
|
|
74
|
-
#
|
|
75
|
-
#
|
|
76
|
-
# rules will still surface the parse failure on the
|
|
77
|
-
# affected file through the core pipeline.
|
|
53
|
+
# Skip any file whose AST walk explodes — discovery is best-effort and a parse failure in one
|
|
54
|
+
# helper file MUST NOT abort discovery for the rest. Other rules will still surface the parse
|
|
55
|
+
# failure on the affected file through the core pipeline.
|
|
78
56
|
next
|
|
79
57
|
end
|
|
80
58
|
names.to_set
|
|
@@ -89,17 +67,9 @@ module Rigor
|
|
|
89
67
|
walker.helper_names
|
|
90
68
|
end
|
|
91
69
|
|
|
92
|
-
# Per-file AST walker.
|
|
93
|
-
#
|
|
94
|
-
#
|
|
95
|
-
# `private` is excluded.
|
|
96
|
-
#
|
|
97
|
-
# The walker is recursive into module / class bodies so
|
|
98
|
-
# `module UrlHelpers; module Routing; def foo_url; end;
|
|
99
|
-
# end; end` registers `foo_url`. It does NOT recurse
|
|
100
|
-
# into method bodies (a `def inside def` would be
|
|
101
|
-
# `define_method`-shaped, which we skip per the
|
|
102
|
-
# docstring).
|
|
70
|
+
# Per-file AST walker. The walker is recursive into module / class bodies so `module UrlHelpers;
|
|
71
|
+
# module Routing; def foo_url; end; end; end` registers `foo_url`. It does NOT recurse into method
|
|
72
|
+
# bodies (a `def inside def` would be `define_method`-shaped, which we skip per the docstring).
|
|
103
73
|
class ModuleBodyWalker
|
|
104
74
|
attr_reader :helper_names
|
|
105
75
|
|
|
@@ -134,11 +104,9 @@ module Rigor
|
|
|
134
104
|
def visit_statements(body)
|
|
135
105
|
return if body.nil?
|
|
136
106
|
|
|
137
|
-
# Visibility tracking is intentionally absent — see
|
|
138
|
-
#
|
|
139
|
-
#
|
|
140
|
-
# a controller IS registered so a caller in the
|
|
141
|
-
# paired view does not false-fire `unknown-helper`.
|
|
107
|
+
# Visibility tracking is intentionally absent — see the "visibility-agnostic" point in the
|
|
108
|
+
# module docstring. A `private def page_url(page)` inside a controller IS registered so a
|
|
109
|
+
# caller in the paired view does not false-fire `unknown-helper`.
|
|
142
110
|
statements_of(body).each do |stmt|
|
|
143
111
|
case stmt
|
|
144
112
|
when Prism::DefNode
|
|
@@ -6,71 +6,50 @@ require_relative "doorkeeper_routes"
|
|
|
6
6
|
module Rigor
|
|
7
7
|
module Plugin
|
|
8
8
|
class RailsRoutes < Rigor::Plugin::Base
|
|
9
|
-
# Frozen catalogue of route helpers parsed from
|
|
10
|
-
# `
|
|
11
|
-
# (`users_path`, `edit_user_path`, …) to the metadata
|
|
12
|
-
# downstream consumers and the analyzer's per-call
|
|
9
|
+
# Frozen catalogue of route helpers parsed from `config/routes.rb`. Each entry maps a helper name
|
|
10
|
+
# (`users_path`, `edit_user_path`, …) to the metadata downstream consumers and the analyzer's per-call
|
|
13
11
|
# validation need:
|
|
14
12
|
#
|
|
15
|
-
# - `arity`: number of positional arguments the helper
|
|
16
|
-
# takes. `users_path` → 0; `user_path(:id)` → 1;
|
|
13
|
+
# - `arity`: number of positional arguments the helper takes. `users_path` → 0; `user_path(:id)` → 1;
|
|
17
14
|
# `user_post_path(:user_id, :id)` → 2.
|
|
18
|
-
# - `path`: the path template Rails generates
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
# helper sense — it's path-sensitive only).
|
|
25
|
-
# - `action`: `:index` / `:show` / `:new` / `:edit` /
|
|
26
|
-
# `:create` / `:update` / `:destroy` for resourceful
|
|
27
|
-
# routes; `:custom` for explicit `get`/`post`/etc.;
|
|
28
|
-
# `:root` for the root route.
|
|
15
|
+
# - `path`: the path template Rails generates (`/users/:user_id/posts/:id`).
|
|
16
|
+
# - `http_method`: `:get` / `:post` / `:patch` / `:put` / `:delete` for the canonical action; `nil`
|
|
17
|
+
# for helpers that span multiple methods (a `resources` show helper isn't HTTP-method-specific in
|
|
18
|
+
# the helper sense — it's path-sensitive only).
|
|
19
|
+
# - `action`: `:index` / `:show` / `:new` / `:edit` / `:create` / `:update` / `:destroy` for
|
|
20
|
+
# resourceful routes; `:custom` for explicit `get`/`post`/etc.; `:root` for the root route.
|
|
29
21
|
#
|
|
30
|
-
# Both `_path` and `_url` forms share the same metadata —
|
|
31
|
-
#
|
|
32
|
-
# once with `_url`) for `O(1)` lookup at the call site.
|
|
22
|
+
# Both `_path` and `_url` forms share the same metadata — the table records each helper twice (once
|
|
23
|
+
# with `_path`, once with `_url`) for `O(1)` lookup at the call site.
|
|
33
24
|
class HelperTable
|
|
34
25
|
Entry = Data.define(:name, :arity, :path, :http_method, :action)
|
|
35
26
|
|
|
36
27
|
attr_reader :entries, :custom_helpers, :devise_resources
|
|
37
28
|
|
|
38
|
-
# @param entries [Array<Entry>] freshly built; the
|
|
39
|
-
#
|
|
40
|
-
#
|
|
41
|
-
#
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
#
|
|
45
|
-
#
|
|
46
|
-
#
|
|
47
|
-
#
|
|
48
|
-
# @param devise_resources [Enumerable<String>] resource
|
|
49
|
-
# names declared via `devise_for :resource` (already
|
|
50
|
-
# singularised, e.g. `"user"`). Used to recognise the
|
|
51
|
-
# dynamic OmniAuth helper family
|
|
52
|
-
# (`<resource>_<provider>_omniauth_(authorize|callback)_(path|url)`)
|
|
53
|
-
# whose provider segment is supplied at runtime — no
|
|
54
|
-
# per-name entry is registered for them but they MUST
|
|
55
|
-
# NOT fire `unknown-helper` either.
|
|
29
|
+
# @param entries [Array<Entry>] freshly built; the factory below is the canonical construction path.
|
|
30
|
+
# @param custom_helpers [Enumerable<String>] names of project-defined helper methods (typically
|
|
31
|
+
# pulled from `app/helpers/**/*.rb` by {HelperDiscoverer}) that the analyzer should treat as
|
|
32
|
+
# known — they do NOT correspond to a route but their presence MUST NOT fire `unknown-helper`. No
|
|
33
|
+
# arity / path metadata is recorded; the analyzer skips the route-side checks for these names.
|
|
34
|
+
# @param devise_resources [Enumerable<String>] resource names declared via `devise_for :resource`
|
|
35
|
+
# (already singularised, e.g. `"user"`). Used to recognise the dynamic OmniAuth helper family
|
|
36
|
+
# (`<resource>_<provider>_omniauth_(authorize|callback)_(path|url)`) whose provider segment is
|
|
37
|
+
# supplied at runtime — no per-name entry is registered for them but they MUST NOT fire
|
|
38
|
+
# `unknown-helper` either.
|
|
56
39
|
def initialize(entries, custom_helpers: [], devise_resources: [])
|
|
57
40
|
@entries = entries.freeze
|
|
58
|
-
# Multimap: a single helper name can map to multiple
|
|
59
|
-
#
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
# returns the first entry (preserving the previous
|
|
63
|
-
# API); `accepts_arity?` checks against every entry.
|
|
41
|
+
# Multimap: a single helper name can map to multiple entries when an uncountable-noun resource
|
|
42
|
+
# registers both an arity-0 index helper and an arity-1 show helper under the same `news_path`
|
|
43
|
+
# name. `find` returns the first entry (preserving the previous API); `accepts_arity?` checks
|
|
44
|
+
# against every entry.
|
|
64
45
|
@by_name = entries.group_by(&:name).transform_values(&:freeze).freeze
|
|
65
46
|
@custom_helpers = custom_helpers.to_set.freeze
|
|
66
47
|
@devise_resources = devise_resources.to_set(&:to_s).freeze
|
|
67
48
|
freeze
|
|
68
49
|
end
|
|
69
50
|
|
|
70
|
-
# @return [Entry, nil] First matching entry; for the
|
|
71
|
-
#
|
|
72
|
-
# (the show helper is also registered but starts
|
|
73
|
-
# second).
|
|
51
|
+
# @return [Entry, nil] First matching entry; for the uncountable-noun case this is the index helper
|
|
52
|
+
# (the show helper is also registered but starts second).
|
|
74
53
|
def find(helper_name)
|
|
75
54
|
@by_name[helper_name.to_s]&.first
|
|
76
55
|
end
|
|
@@ -80,14 +59,10 @@ module Rigor
|
|
|
80
59
|
@by_name.key?(helper_name.to_s)
|
|
81
60
|
end
|
|
82
61
|
|
|
83
|
-
# True when `helper_name` is either a registered route
|
|
84
|
-
# helper, a
|
|
85
|
-
#
|
|
86
|
-
#
|
|
87
|
-
# `unknown-helper` rule consults this predicate to
|
|
88
|
-
# decide whether to fire — `known?` alone misses
|
|
89
|
-
# custom helpers and OmniAuth providers, which would
|
|
90
|
-
# then false-fire on canonical Rails-app patterns.
|
|
62
|
+
# True when `helper_name` is either a registered route helper, a discovered project-defined custom
|
|
63
|
+
# helper, OR a dynamic OmniAuth-shaped helper for one of the declared `devise_for` resources. The
|
|
64
|
+
# `unknown-helper` rule consults this predicate to decide whether to fire — `known?` alone misses
|
|
65
|
+
# custom helpers and OmniAuth providers, which would then false-fire on canonical Rails-app patterns.
|
|
91
66
|
def recognised?(helper_name)
|
|
92
67
|
name = helper_name.to_s
|
|
93
68
|
return true if @by_name.key?(name)
|
|
@@ -96,11 +71,9 @@ module Rigor
|
|
|
96
71
|
omniauth_match?(name)
|
|
97
72
|
end
|
|
98
73
|
|
|
99
|
-
# `<resource>_<provider>_omniauth_(authorize|callback)_(path|url)` — when
|
|
100
|
-
#
|
|
101
|
-
#
|
|
102
|
-
# provider segment is opaque to a static parser, so we
|
|
103
|
-
# accept any non-empty token between the resource and
|
|
74
|
+
# `<resource>_<provider>_omniauth_(authorize|callback)_(path|url)` — when `<resource>` matches a
|
|
75
|
+
# declared `devise_for` resource the helper is dynamic-provider Devise OmniAuth. The provider
|
|
76
|
+
# segment is opaque to a static parser, so we accept any non-empty token between the resource and
|
|
104
77
|
# the omniauth suffix.
|
|
105
78
|
def omniauth_match?(name)
|
|
106
79
|
return false if @devise_resources.empty?
|
|
@@ -115,19 +88,16 @@ module Rigor
|
|
|
115
88
|
end
|
|
116
89
|
end
|
|
117
90
|
|
|
118
|
-
# @return [Boolean] true when any entry under this
|
|
119
|
-
# helper name accepts the given positional arity.
|
|
91
|
+
# @return [Boolean] true when any entry under this helper name accepts the given positional arity.
|
|
120
92
|
#
|
|
121
|
-
# Rails helpers have the signature `helper(*segments, options = {})`,
|
|
122
|
-
#
|
|
123
|
-
#
|
|
124
|
-
# `user_path(@u, pagination_params(...))`).
|
|
93
|
+
# Rails helpers have the signature `helper(*segments, options = {})`, so `expected + 1` is always
|
|
94
|
+
# valid — the extra argument is treated as a query-params/options hash (e.g. `users_path(page: 2)`
|
|
95
|
+
# or `user_path(@u, pagination_params(...))`).
|
|
125
96
|
def accepts_arity?(helper_name, arity)
|
|
126
97
|
(@by_name[helper_name.to_s] || []).any? { |entry| entry.arity == arity || entry.arity + 1 == arity }
|
|
127
98
|
end
|
|
128
99
|
|
|
129
|
-
# @return [Array<Integer>] all accepted positional
|
|
130
|
-
# arities for a helper name. Empty when unknown.
|
|
100
|
+
# @return [Array<Integer>] all accepted positional arities for a helper name. Empty when unknown.
|
|
131
101
|
def acceptable_arities(helper_name)
|
|
132
102
|
(@by_name[helper_name.to_s] || []).map(&:arity).uniq
|
|
133
103
|
end
|
|
@@ -146,11 +116,9 @@ module Rigor
|
|
|
146
116
|
end
|
|
147
117
|
|
|
148
118
|
def to_h
|
|
149
|
-
# Plain dump for fact-store publishing (ADR-9). Each
|
|
150
|
-
#
|
|
151
|
-
#
|
|
152
|
-
# the full arity set so cross-plugin consumers can
|
|
153
|
-
# honour the uncountable-noun multi-arity case.
|
|
119
|
+
# Plain dump for fact-store publishing (ADR-9). Each name serialises as a small Hash for the
|
|
120
|
+
# FIRST entry under that name, with `acceptable_arities` carrying the full arity set so
|
|
121
|
+
# cross-plugin consumers can honour the uncountable-noun multi-arity case.
|
|
154
122
|
@by_name.transform_values do |group|
|
|
155
123
|
entry = group.first
|
|
156
124
|
{ name: entry.name, arity: entry.arity, path: entry.path,
|