rigortype 0.2.7 → 0.2.9
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/data/core_overlay/csv.rbs +28 -0
- data/data/core_overlay/psych.rbs +22 -0
- data/docs/handbook/01-getting-started.md +9 -1
- data/docs/handbook/02-everyday-types.md +4 -1
- data/docs/handbook/08-understanding-errors.md +3 -3
- data/docs/manual/01-installation.md +1 -0
- data/docs/manual/02-cli-reference.md +16 -7
- data/docs/manual/04-diagnostics.md +7 -4
- data/docs/manual/06-baseline.md +5 -2
- data/docs/manual/07-plugins.md +1 -1
- data/docs/manual/14-rails-quickstart.md +4 -2
- data/docs/manual/15-type-protection-coverage.md +27 -4
- data/docs/manual/plugins/rigor-actionpack.md +1 -1
- data/docs/manual/plugins/rigor-activerecord.md +12 -5
- data/docs/manual/plugins/rigor-rails-routes.md +11 -0
- 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 +248 -186
- 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 +62 -48
- 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 +46 -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_fork_scan.rb +55 -0
- data/lib/rigor/cli/protection_renderer.rb +5 -7
- data/lib/rigor/cli/protection_report.rb +34 -18
- 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/missing_gem_constant_index.rb +128 -0
- 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 +225 -304
- 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 +794 -1154
- 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/fork_map.rb +87 -0
- 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 +627 -727
- data/lib/rigor/inference/origin_lookup.rb +38 -0
- data/lib/rigor/inference/parameter_inference_collector.rb +154 -109
- 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 -821
- data/lib/rigor/inference/statement_evaluator.rb +754 -1114
- 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 +141 -184
- 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 +92 -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 +40 -48
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +140 -129
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +56 -59
- 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/structure_sql_parser.rb +172 -0
- data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +168 -241
- 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-activesupport-core-ext/sig/active_support/core_ext.rbs +32 -0
- 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/grape_api_discoverer.rb +189 -0
- 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 +61 -75
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +319 -505
- data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +91 -96
- 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/environment.rbs +1 -0
- data/sig/rigor/scope.rbs +6 -0
- metadata +9 -1
|
@@ -5,15 +5,12 @@ require "prism"
|
|
|
5
5
|
module Rigor
|
|
6
6
|
module Plugin
|
|
7
7
|
class DryTypes < Rigor::Plugin::Base
|
|
8
|
-
# Walks project source for `module X; include Dry.Types(); end`
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
# See {DryTypes} module-docstring for the floor / ceiling
|
|
12
|
-
# scoping.
|
|
8
|
+
# Walks project source for `module X; include Dry.Types(); end` shapes and emits a
|
|
9
|
+
# `{ "<X>::<Alias>" => "<UnderlyingClass>" }` alias table covering the dry-types canonical-shortcut
|
|
10
|
+
# names. See {DryTypes} module-docstring for the floor / ceiling scoping.
|
|
13
11
|
module AliasScanner
|
|
14
|
-
# The canonical-shortcut names dry-types exposes through
|
|
15
|
-
# `
|
|
16
|
-
# from the upstream gem.
|
|
12
|
+
# The canonical-shortcut names dry-types exposes through `include Dry.Types()`. Mirrors
|
|
13
|
+
# `Dry::Types.type_keys` from the upstream gem.
|
|
17
14
|
CANONICAL_ALIASES = {
|
|
18
15
|
"String" => "String",
|
|
19
16
|
"Integer" => "Integer",
|
|
@@ -32,29 +29,21 @@ module Rigor
|
|
|
32
29
|
"Any" => "Object"
|
|
33
30
|
}.freeze
|
|
34
31
|
|
|
35
|
-
# Slice 2 — nested-category aliases. dry-types installs
|
|
36
|
-
#
|
|
37
|
-
# (
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
#
|
|
41
|
-
# coercion
|
|
42
|
-
#
|
|
43
|
-
# that are category-specific (`Params::Nil`,
|
|
44
|
-
# `JSON::Symbol`). For Rigor's purposes the underlying
|
|
45
|
-
# class is the same regardless of category — coercion
|
|
46
|
-
# semantics are a runtime concern. We register every
|
|
47
|
-
# `<module>::<Category>::<Name>` mapping the upstream gem
|
|
48
|
-
# publishes so call-site references work uniformly.
|
|
32
|
+
# Slice 2 — nested-category aliases. dry-types installs four parallel coercion categories:
|
|
33
|
+
# `Coercible::*` (everything-to-target coercion), `Strict::*` (no coercion; raise if mismatch),
|
|
34
|
+
# `Params::*` (HTTP / query-string-style coercion, used by Hanami / Roda / dry-web in request
|
|
35
|
+
# handling), `JSON::*` (JSON-shape coercion). Each category exposes the same set of names as the
|
|
36
|
+
# canonical shortcuts above, plus a few additions that are category-specific (`Params::Nil`,
|
|
37
|
+
# `JSON::Symbol`). For Rigor's purposes the underlying class is the same regardless of category —
|
|
38
|
+
# coercion semantics are a runtime concern. We register every `<module>::<Category>::<Name>`
|
|
39
|
+
# mapping the upstream gem publishes so call-site references work uniformly.
|
|
49
40
|
NESTED_CATEGORIES = %w[Coercible Strict Params JSON].freeze
|
|
50
41
|
private_constant :NESTED_CATEGORIES
|
|
51
42
|
|
|
52
43
|
module_function
|
|
53
44
|
|
|
54
|
-
# @param paths [Array<String>] absolute paths to `.rb`
|
|
55
|
-
#
|
|
56
|
-
# @return [Hash{String => String}] frozen
|
|
57
|
-
# `{aliased_name => underlying_class_name}` map. Empty
|
|
45
|
+
# @param paths [Array<String>] absolute paths to `.rb` files the project's `paths:` resolves to.
|
|
46
|
+
# @return [Hash{String => String}] frozen `{aliased_name => underlying_class_name}` map. Empty
|
|
58
47
|
# when no `include Dry.Types()` declaration is found.
|
|
59
48
|
def scan(paths:)
|
|
60
49
|
results = paths.flat_map { |path| scan_file(path) }
|
|
@@ -64,16 +53,16 @@ module Rigor
|
|
|
64
53
|
base = canonical_table(modules)
|
|
65
54
|
results.each do |result|
|
|
66
55
|
result[:compositions].each do |const_name, underlying|
|
|
67
|
-
# Each result's compositions are scoped under that
|
|
68
|
-
#
|
|
56
|
+
# Each result's compositions are scoped under that result's enclosing module
|
|
57
|
+
# (`Types::Email`, etc.).
|
|
69
58
|
base["#{result[:module_name]}::#{const_name}"] ||= underlying
|
|
70
59
|
end
|
|
71
60
|
end
|
|
72
61
|
base.freeze
|
|
73
62
|
end
|
|
74
63
|
|
|
75
|
-
# Populates the canonical-shortcut + nested-category
|
|
76
|
-
#
|
|
64
|
+
# Populates the canonical-shortcut + nested-category table (15 + 15 × 4 = 75 entries per alias
|
|
65
|
+
# module).
|
|
77
66
|
def canonical_table(modules)
|
|
78
67
|
modules.each_with_object({}) do |module_name, acc|
|
|
79
68
|
CANONICAL_ALIASES.each do |alias_name, underlying|
|
|
@@ -96,22 +85,18 @@ module Rigor
|
|
|
96
85
|
{ module_name: module_info[:module_name], compositions: compositions }
|
|
97
86
|
end
|
|
98
87
|
rescue StandardError
|
|
99
|
-
# Missing-file / parse failures degrade to "no
|
|
100
|
-
#
|
|
101
|
-
#
|
|
102
|
-
# dropping unparseable files keeps the fact stable.
|
|
88
|
+
# Missing-file / parse failures degrade to "no contribution from this file"; the plugin's
|
|
89
|
+
# user-visible surface is the published fact, and dropping unparseable files keeps the fact
|
|
90
|
+
# stable.
|
|
103
91
|
[]
|
|
104
92
|
end
|
|
105
93
|
private_class_method :scan_file
|
|
106
94
|
|
|
107
|
-
# Walks a Prism AST collecting alias-module info:
|
|
108
|
-
#
|
|
109
|
-
# Dry.Types();
|
|
110
|
-
#
|
|
111
|
-
#
|
|
112
|
-
# alias scope. The `body:` field is the
|
|
113
|
-
# `Prism::StatementsNode` (or nil) we re-walk later for
|
|
114
|
-
# user-authored compositions (slice 3).
|
|
95
|
+
# Walks a Prism AST collecting alias-module info: `{module_name:, body:}` for every `module X;
|
|
96
|
+
# include Dry.Types(); …end` shape. Tracks the enclosing module chain so a nested `module App;
|
|
97
|
+
# module Types; include Dry.Types(); end; end` publishes `"App::Types"` as the alias scope. The
|
|
98
|
+
# `body:` field is the `Prism::StatementsNode` (or nil) we re-walk later for user-authored
|
|
99
|
+
# compositions (slice 3).
|
|
115
100
|
def collect_alias_modules(node, qualified_prefix)
|
|
116
101
|
return [] unless node.is_a?(Prism::Node)
|
|
117
102
|
|
|
@@ -127,9 +112,8 @@ module Rigor
|
|
|
127
112
|
end
|
|
128
113
|
current + children
|
|
129
114
|
when Prism::ClassNode
|
|
130
|
-
# Module-level declarations win; we don't recurse into
|
|
131
|
-
#
|
|
132
|
-
# canonical pattern is module-level.
|
|
115
|
+
# Module-level declarations win; we don't recurse into class bodies for `include
|
|
116
|
+
# Dry.Types()` because the canonical pattern is module-level.
|
|
133
117
|
[]
|
|
134
118
|
else
|
|
135
119
|
node.compact_child_nodes.flat_map { |c| collect_alias_modules(c, qualified_prefix) }
|
|
@@ -137,31 +121,20 @@ module Rigor
|
|
|
137
121
|
end
|
|
138
122
|
private_class_method :collect_alias_modules
|
|
139
123
|
|
|
140
|
-
# Slice 3 — user-authored composition recognition.
|
|
141
|
-
#
|
|
142
|
-
#
|
|
143
|
-
# `
|
|
144
|
-
#
|
|
145
|
-
# `Integer`, …) — or on a nested-category form
|
|
146
|
-
# (`Strict::String` etc.) — registers the LHS under
|
|
147
|
-
# the canonical head's underlying class. Unions
|
|
148
|
-
# (`String | Integer`) and intersections are skipped
|
|
149
|
-
# (no single underlying class).
|
|
124
|
+
# Slice 3 — user-authored composition recognition. Walks the alias-module body for `Email =
|
|
125
|
+
# String.constrained(...)` shapes. Each `ConstantWriteNode` whose RHS is a method chain rooted on
|
|
126
|
+
# a canonical-shortcut name (`String`, `Integer`, …) — or on a nested-category form
|
|
127
|
+
# (`Strict::String` etc.) — registers the LHS under the canonical head's underlying class. Unions
|
|
128
|
+
# (`String | Integer`) and intersections are skipped (no single underlying class).
|
|
150
129
|
#
|
|
151
|
-
# Slice 4 — transitive composition resolution. After
|
|
152
|
-
#
|
|
153
|
-
#
|
|
154
|
-
#
|
|
155
|
-
#
|
|
156
|
-
#
|
|
157
|
-
# `ManagerEmail =
|
|
158
|
-
#
|
|
159
|
-
# detection: `A = B; B = A` resolves neither (each
|
|
160
|
-
# LHS's resolution walk sees itself in the visited
|
|
161
|
-
# set and bails). Unknown references (`ManagerEmail =
|
|
162
|
-
# NotAComposition`) silently drop — the user is free
|
|
163
|
-
# to assign any constant to any other; the plugin only
|
|
164
|
-
# publishes facts when the underlying class is known.
|
|
130
|
+
# Slice 4 — transitive composition resolution. After the direct (slice-3) pass collects
|
|
131
|
+
# compositions whose RHS root is canonical, a second pass walks the remaining
|
|
132
|
+
# `ConstantWriteNode`s for RHS shapes that resolve THROUGH an already-published composition —
|
|
133
|
+
# e.g. `ManagerEmail = Email` (bare reference) or `ManagerEmail = Email.constrained(min_size: 3)`
|
|
134
|
+
# (method chain rooted on a composition LHS). Cycle detection: `A = B; B = A` resolves neither
|
|
135
|
+
# (each LHS's resolution walk sees itself in the visited set and bails). Unknown references
|
|
136
|
+
# (`ManagerEmail = NotAComposition`) silently drop — the user is free to assign any constant to
|
|
137
|
+
# any other; the plugin only publishes facts when the underlying class is known.
|
|
165
138
|
def collect_compositions(body)
|
|
166
139
|
return {} if body.nil?
|
|
167
140
|
|
|
@@ -188,14 +161,10 @@ module Rigor
|
|
|
188
161
|
end
|
|
189
162
|
private_class_method :collect_compositions
|
|
190
163
|
|
|
191
|
-
# Slice-4 helper. Returns the un-resolved RHS root
|
|
192
|
-
#
|
|
193
|
-
#
|
|
194
|
-
#
|
|
195
|
-
# `ConstantReadNode` / `ConstantPathNode` tail rather
|
|
196
|
-
# than canonical-only. Declines on union / intersection
|
|
197
|
-
# operators for the same single-underlying-class
|
|
198
|
-
# reason.
|
|
164
|
+
# Slice-4 helper. Returns the un-resolved RHS root constant name (not necessarily a
|
|
165
|
+
# CANONICAL_ALIASES entry) for transitive resolution. Mirrors {composition_head_canonical} but
|
|
166
|
+
# accepts any `ConstantReadNode` / `ConstantPathNode` tail rather than canonical-only. Declines on
|
|
167
|
+
# union / intersection operators for the same single-underlying-class reason.
|
|
199
168
|
def transitive_reference_name(node)
|
|
200
169
|
case node
|
|
201
170
|
when Prism::ConstantReadNode
|
|
@@ -211,14 +180,10 @@ module Rigor
|
|
|
211
180
|
end
|
|
212
181
|
private_class_method :transitive_reference_name
|
|
213
182
|
|
|
214
|
-
# Slice-4 helper. Resolves `lhs`'s RHS through the
|
|
215
|
-
# `
|
|
216
|
-
#
|
|
217
|
-
#
|
|
218
|
-
# `"String"`) or nil when no chain ends at a direct
|
|
219
|
-
# composition. Cycles silently return nil — every step
|
|
220
|
-
# adds the current lhs to `visited` and bails on
|
|
221
|
-
# re-entry.
|
|
183
|
+
# Slice-4 helper. Resolves `lhs`'s RHS through the `direct` (slice-3) compositions table, chaining
|
|
184
|
+
# through `ref_edges` for transitive references. Returns the canonical underlying-class name
|
|
185
|
+
# (e.g. `"String"`) or nil when no chain ends at a direct composition. Cycles silently return nil
|
|
186
|
+
# — every step adds the current lhs to `visited` and bails on re-entry.
|
|
222
187
|
def resolve_transitive_ref(lhs, direct, ref_edges, visited:)
|
|
223
188
|
return nil if visited.include?(lhs)
|
|
224
189
|
|
|
@@ -231,25 +196,19 @@ module Rigor
|
|
|
231
196
|
end
|
|
232
197
|
private_class_method :resolve_transitive_ref
|
|
233
198
|
|
|
234
|
-
# Walks an RHS expression looking for the canonical
|
|
235
|
-
#
|
|
236
|
-
# the canonical name (`"String"` etc.) or nil.
|
|
199
|
+
# Walks an RHS expression looking for the canonical shortcut name at the root of a method chain.
|
|
200
|
+
# Returns the canonical name (`"String"` etc.) or nil.
|
|
237
201
|
#
|
|
238
202
|
# Recognised shapes (recursively on `node.receiver`):
|
|
239
203
|
#
|
|
240
|
-
# - Bare `String` / `Integer` — `Prism::ConstantReadNode`
|
|
241
|
-
#
|
|
242
|
-
# - `Strict::String` / `Coercible::Integer` / etc. —
|
|
243
|
-
# `Prism::ConstantPathNode` whose tail is in
|
|
204
|
+
# - Bare `String` / `Integer` — `Prism::ConstantReadNode` whose name is in `CANONICAL_ALIASES`.
|
|
205
|
+
# - `Strict::String` / `Coercible::Integer` / etc. — `Prism::ConstantPathNode` whose tail is in
|
|
244
206
|
# `CANONICAL_ALIASES`.
|
|
245
|
-
# - `String.constrained(...)` / `.optional` /
|
|
246
|
-
# `.default(...)` / arbitrary single-arg method —
|
|
207
|
+
# - `String.constrained(...)` / `.optional` / `.default(...)` / arbitrary single-arg method —
|
|
247
208
|
# recurse on the receiver.
|
|
248
209
|
#
|
|
249
|
-
# Declines on `String | Integer` (union, `:|`) and
|
|
250
|
-
#
|
|
251
|
-
# table doesn't claim a single underlying class for
|
|
252
|
-
# a multi-class composition.
|
|
210
|
+
# Declines on `String | Integer` (union, `:|`) and `String & Foo` (intersection, `:&`) so the
|
|
211
|
+
# alias table doesn't claim a single underlying class for a multi-class composition.
|
|
253
212
|
def composition_head_canonical(node)
|
|
254
213
|
case node
|
|
255
214
|
when Prism::ConstantReadNode
|
|
@@ -266,12 +225,10 @@ module Rigor
|
|
|
266
225
|
end
|
|
267
226
|
private_class_method :composition_head_canonical
|
|
268
227
|
|
|
269
|
-
# `include Dry.Types()` at the top of the module body is the
|
|
270
|
-
#
|
|
271
|
-
#
|
|
272
|
-
#
|
|
273
|
-
# `default: :nominal` style accepted by upstream; we treat
|
|
274
|
-
# both as "alias-installing").
|
|
228
|
+
# `include Dry.Types()` at the top of the module body is the canonical alias declaration. We
|
|
229
|
+
# accept the call anywhere in the body (some projects guard it with a `if defined?` check). The
|
|
230
|
+
# argument list must be empty (or a kwargs-only `default: :nominal` style accepted by upstream;
|
|
231
|
+
# we treat both as "alias-installing").
|
|
275
232
|
def contains_dry_types_include?(body)
|
|
276
233
|
return false if body.nil?
|
|
277
234
|
|
|
@@ -295,10 +252,9 @@ module Rigor
|
|
|
295
252
|
end
|
|
296
253
|
private_class_method :tree_walk
|
|
297
254
|
|
|
298
|
-
# Matches `include Dry.Types()` (with or without kwargs).
|
|
299
|
-
#
|
|
300
|
-
#
|
|
301
|
-
# method call on the `Dry` constant naming `Types`.
|
|
255
|
+
# Matches `include Dry.Types()` (with or without kwargs). The receiver of the include call MUST
|
|
256
|
+
# be implicit (i.e., called on `self`), and the argument MUST be a method call on the `Dry`
|
|
257
|
+
# constant naming `Types`.
|
|
302
258
|
def include_call_targeting_dry_types?(node)
|
|
303
259
|
return false unless node.is_a?(Prism::CallNode)
|
|
304
260
|
return false unless node.name == :include && node.receiver.nil?
|
|
@@ -319,11 +275,9 @@ module Rigor
|
|
|
319
275
|
end
|
|
320
276
|
private_class_method :dry_types_call?
|
|
321
277
|
|
|
322
|
-
# Resolves a `Prism::ConstantPathNode` /
|
|
323
|
-
# `
|
|
324
|
-
#
|
|
325
|
-
# dynamic-prefix shape so the scanner treats those as
|
|
326
|
-
# opaque rather than guessing.
|
|
278
|
+
# Resolves a `Prism::ConstantPathNode` / `Prism::ConstantReadNode` chain to its dot-separated
|
|
279
|
+
# name (e.g. `"App::Types"`). Returns nil for the dynamic-prefix shape so the scanner treats
|
|
280
|
+
# those as opaque rather than guessing.
|
|
327
281
|
def qualified_name_for(node)
|
|
328
282
|
case node
|
|
329
283
|
when Prism::ConstantReadNode then node.name.to_s
|
|
@@ -17,56 +17,44 @@ module Rigor
|
|
|
17
17
|
# include Dry.Types()
|
|
18
18
|
# end
|
|
19
19
|
#
|
|
20
|
-
# and publishes the resulting `{aliased_name => underlying_class}`
|
|
21
|
-
#
|
|
22
|
-
# Other dry-rb adapter plugins consume this fact:
|
|
20
|
+
# and publishes the resulting `{aliased_name => underlying_class}` table as the `:dry_type_aliases`
|
|
21
|
+
# cross-plugin fact (ADR-9). Other dry-rb adapter plugins consume this fact:
|
|
23
22
|
#
|
|
24
|
-
# - `rigor-dry-struct` reads it so `attribute :city, Types::String`
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
# per-key type recognition in `schema { … }` / `params { … }`
|
|
29
|
-
# blocks (separate plugin slice).
|
|
23
|
+
# - `rigor-dry-struct` reads it so `attribute :city, Types::String` promotes `address.city` from
|
|
24
|
+
# `Dynamic[Top]` to `Nominal[String]` via ADR-18's `returns_from_arg:` fact lookup.
|
|
25
|
+
# - `rigor-dry-validation` / `rigor-dry-schema` read it for per-key type recognition in `schema { … }`
|
|
26
|
+
# / `params { … }` blocks (separate plugin slice).
|
|
30
27
|
#
|
|
31
28
|
# ## Floor / ceiling (slice 1)
|
|
32
29
|
#
|
|
33
30
|
# Slice 1 ships the **floor**:
|
|
34
31
|
#
|
|
35
|
-
# - Recognises `module X; include Dry.Types(); end` for any
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
#
|
|
41
|
-
# - Publishes the table as `{ "<Module>::<Alias>" =>
|
|
42
|
-
# "<UnderlyingClass>" }` so consumers can match on the
|
|
43
|
-
# qualified constant name they see in source.
|
|
32
|
+
# - Recognises `module X; include Dry.Types(); end` for any constant module name `X` (commonly
|
|
33
|
+
# `Types`, sometimes `MyTypes` / `AppTypes`).
|
|
34
|
+
# - Maps the **basic** dry-types constants: `String`, `Integer`, `Float`, `Decimal`, `Symbol`, `Bool`,
|
|
35
|
+
# `True`, `False`, `Nil`, `Date`, `DateTime`, `Time`, `Hash`, `Array`, `Any`.
|
|
36
|
+
# - Publishes the table as `{ "<Module>::<Alias>" => "<UnderlyingClass>" }` so consumers can match on
|
|
37
|
+
# the qualified constant name they see in source.
|
|
44
38
|
#
|
|
45
39
|
# Implemented beyond the floor:
|
|
46
40
|
#
|
|
47
|
-
# - Nested-namespace aliases (`Types::Coercible::Integer`,
|
|
48
|
-
# `Types::
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
#
|
|
52
|
-
# transitive resolution through composition chains) — the alias
|
|
53
|
-
# surface extends beyond the 15 canonical names.
|
|
41
|
+
# - Nested-namespace aliases (`Types::Coercible::Integer`, `Types::Strict::Symbol`,
|
|
42
|
+
# `Types::Params::Bool`, `Types::JSON::Date`) — the four coercion categories each map to the same
|
|
43
|
+
# underlying class as their canonical shortcut.
|
|
44
|
+
# - User-authored compositions (`Email = Types::String.constrained(...)`, transitive resolution
|
|
45
|
+
# through composition chains) — the alias surface extends beyond the 15 canonical names.
|
|
54
46
|
#
|
|
55
47
|
# Deferred:
|
|
56
48
|
#
|
|
57
|
-
# - `dry-types.unknown-alias` / `dry-types.alias-shadow`
|
|
58
|
-
#
|
|
59
|
-
# wasn't published.
|
|
49
|
+
# - `dry-types.unknown-alias` / `dry-types.alias-shadow` diagnostics when downstream code references
|
|
50
|
+
# a name that wasn't published.
|
|
60
51
|
#
|
|
61
52
|
# ## Why no `diagnostics_for_file` at the floor?
|
|
62
53
|
#
|
|
63
|
-
# The plugin's user-visible value at slice 1 is the published
|
|
64
|
-
#
|
|
65
|
-
#
|
|
66
|
-
#
|
|
67
|
-
# diagnostics. The diagnostics surface lands when the
|
|
68
|
-
# `dry-types.*` rule family becomes load-bearing for
|
|
69
|
-
# demand-driven cases.
|
|
54
|
+
# The plugin's user-visible value at slice 1 is the published fact — every downstream uplift
|
|
55
|
+
# (precision promotion in `address.city`, schema-key recognition in `rigor-dry-validation`) consumes
|
|
56
|
+
# the fact rather than the plugin itself emitting diagnostics. The diagnostics surface lands when the
|
|
57
|
+
# `dry-types.*` rule family becomes load-bearing for demand-driven cases.
|
|
70
58
|
class DryTypes < Rigor::Plugin::Base
|
|
71
59
|
manifest(
|
|
72
60
|
id: "dry-types",
|
|
@@ -75,12 +63,9 @@ module Rigor
|
|
|
75
63
|
produces: [:dry_type_aliases]
|
|
76
64
|
)
|
|
77
65
|
|
|
78
|
-
# Walks every project file once during `prepare(services)` to
|
|
79
|
-
#
|
|
80
|
-
#
|
|
81
|
-
# surface; each file's parse error degrades to "no
|
|
82
|
-
# contribution" without polluting the user-visible
|
|
83
|
-
# diagnostic stream.
|
|
66
|
+
# Walks every project file once during `prepare(services)` to build the alias table, then publishes
|
|
67
|
+
# via the ADR-9 fact store. The walk is bounded by the configured `paths:` surface; each file's
|
|
68
|
+
# parse error degrades to "no contribution" without polluting the user-visible diagnostic stream.
|
|
84
69
|
def prepare(services)
|
|
85
70
|
aliases = AliasScanner.scan(paths: scannable_paths(services))
|
|
86
71
|
return if aliases.empty?
|
|
@@ -98,11 +83,9 @@ module Rigor
|
|
|
98
83
|
|
|
99
84
|
private
|
|
100
85
|
|
|
101
|
-
# Resolves the project's `paths:` to a flat list of `.rb`
|
|
102
|
-
#
|
|
103
|
-
#
|
|
104
|
-
# exclude/sort surface because the alias table is a
|
|
105
|
-
# union — any duplicate scan is a no-op.
|
|
86
|
+
# Resolves the project's `paths:` to a flat list of `.rb` files the scanner walks. Mirrors
|
|
87
|
+
# `Analysis::Runner`'s `expand_paths` floor; we don't need the runner's full exclude/sort surface
|
|
88
|
+
# because the alias table is a union — any duplicate scan is a no-op.
|
|
106
89
|
def scannable_paths(services)
|
|
107
90
|
@scannable_paths ||= services.configuration.paths.flat_map do |entry|
|
|
108
91
|
if File.directory?(entry)
|
|
@@ -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/dry_types.rb` performs at load time.
|
|
3
|
+
# Gem entry point. Required by Rigor's plugin loader when `.rigor.yml` lists `rigor-dry-types` 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/dry_types.rb` performs at load time.
|
|
8
6
|
require_relative "rigor/plugin/dry_types"
|
|
@@ -5,18 +5,15 @@ require "prism"
|
|
|
5
5
|
module Rigor
|
|
6
6
|
module Plugin
|
|
7
7
|
class DryValidation < Rigor::Plugin::Base
|
|
8
|
-
# Walks project source for `class T < Dry::Validation::Contract`
|
|
9
|
-
#
|
|
8
|
+
# Walks project source for `class T < Dry::Validation::Contract` subclasses and returns the
|
|
9
|
+
# contract class FQN set.
|
|
10
10
|
#
|
|
11
|
-
# Recognition tightness: the superclass match accepts EITHER
|
|
12
|
-
#
|
|
13
|
-
# path
|
|
14
|
-
# (
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
# under `Dry::Validation` should use the explicit form.
|
|
18
|
-
# Unrelated `< MyApp::Validation::Contract` shapes with the
|
|
19
|
-
# same tail do NOT register.
|
|
11
|
+
# Recognition tightness: the superclass match accepts EITHER the fully-qualified
|
|
12
|
+
# `Dry::Validation::Contract` (3-segment path) OR the lexical-nested `Validation::Contract`
|
|
13
|
+
# (2-segment path, when the class body lives inside `module Dry`). The bare `< Contract` form
|
|
14
|
+
# (1-segment) is NOT recognised — too ambiguous; users who deeply nest under `Dry::Validation`
|
|
15
|
+
# should use the explicit form. Unrelated `< MyApp::Validation::Contract` shapes with the same tail
|
|
16
|
+
# do NOT register.
|
|
20
17
|
module ContractScanner
|
|
21
18
|
CONTRACT_FULL_PATH = %w[Dry Validation Contract].freeze
|
|
22
19
|
CONTRACT_LEXICAL_DRY_PATH = %w[Validation Contract].freeze
|
|
@@ -24,10 +21,8 @@ module Rigor
|
|
|
24
21
|
|
|
25
22
|
module_function
|
|
26
23
|
|
|
27
|
-
# @param paths [Array<String>] absolute paths to `.rb`
|
|
28
|
-
#
|
|
29
|
-
# @return [Array<String>] frozen, sorted list of
|
|
30
|
-
# recognized contract class FQNs (e.g.
|
|
24
|
+
# @param paths [Array<String>] absolute paths to `.rb` files the project's `paths:` resolves to.
|
|
25
|
+
# @return [Array<String>] frozen, sorted list of recognized contract class FQNs (e.g.
|
|
31
26
|
# `["App::NewUserContract", "Types::EmailContract"]`).
|
|
32
27
|
def scan(paths:)
|
|
33
28
|
contracts = []
|
|
@@ -77,11 +72,9 @@ module Rigor
|
|
|
77
72
|
end
|
|
78
73
|
private_class_method :collect_module_node
|
|
79
74
|
|
|
80
|
-
# Matches superclasses whose constant chain is EXACTLY
|
|
81
|
-
# `
|
|
82
|
-
# `
|
|
83
|
-
# — including same-tail-but-different-root chains and
|
|
84
|
-
# the ambiguous bare `Contract` — do not match.
|
|
75
|
+
# Matches superclasses whose constant chain is EXACTLY `Dry::Validation::Contract` (full path) OR
|
|
76
|
+
# EXACTLY `Validation::Contract` (lexical-Dry path). Other shapes — including
|
|
77
|
+
# same-tail-but-different-root chains and the ambiguous bare `Contract` — do not match.
|
|
85
78
|
def contract_subclass?(class_node)
|
|
86
79
|
superclass = class_node.superclass
|
|
87
80
|
return false if superclass.nil?
|
|
@@ -15,31 +15,23 @@ module Rigor
|
|
|
15
15
|
#
|
|
16
16
|
# Slice 1 floor:
|
|
17
17
|
#
|
|
18
|
-
# - Walks the project for `class T < Dry::Validation::Contract`
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
# -
|
|
23
|
-
# `Dry::Validation::Contract#call` (returns Result) and
|
|
24
|
-
# `Dry::Validation::Result#{success?, failure?, to_h}`.
|
|
25
|
-
# The manifest's `signature_paths: ["sig"]` auto-contributes
|
|
26
|
-
# the overlay (ADR-25) — no project-side wiring needed.
|
|
18
|
+
# - Walks the project for `class T < Dry::Validation::Contract` subclasses and publishes the
|
|
19
|
+
# resulting set of contract class FQNs as the `:dry_validation_contracts` ADR-9 cross-plugin fact.
|
|
20
|
+
# - Ships an RBS overlay (`sig/dry_validation.rbs`) typing `Dry::Validation::Contract#call` (returns
|
|
21
|
+
# Result) and `Dry::Validation::Result#{success?, failure?, to_h}`. The manifest's
|
|
22
|
+
# `signature_paths: ["sig"]` auto-contributes the overlay (ADR-25) — no project-side wiring needed.
|
|
27
23
|
#
|
|
28
24
|
# Slice 2 (deferred, per design note):
|
|
29
25
|
#
|
|
30
|
-
# - Integrate with `:dry_schema_table` (published by
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
# schema. Until this lands, `result.to_h` types as
|
|
34
|
-
# `Hash[Symbol, untyped]` (the generic RBS overlay shape).
|
|
26
|
+
# - Integrate with `:dry_schema_table` (published by `rigor-dry-schema`) so the `params { ... }`
|
|
27
|
+
# block inside a Contract contributes a typed `result.to_h` shape per the schema. Until this lands,
|
|
28
|
+
# `result.to_h` types as `Hash[Symbol, untyped]` (the generic RBS overlay shape).
|
|
35
29
|
#
|
|
36
|
-
# Slice 3 (deferred): `json { ... }` adapter parity with
|
|
37
|
-
# `params { ... }`. Same shape as slice 2.
|
|
30
|
+
# Slice 3 (deferred): `json { ... }` adapter parity with `params { ... }`. Same shape as slice 2.
|
|
38
31
|
#
|
|
39
|
-
# No ADR-3 amendment is needed for the validation surface
|
|
40
|
-
#
|
|
41
|
-
#
|
|
42
|
-
# existing bool flow facts).
|
|
32
|
+
# No ADR-3 amendment is needed for the validation surface itself; `Dry::Validation::Result` is a
|
|
33
|
+
# generic class, not a sum type (the `success?` / `failure?` predicates narrow via existing bool flow
|
|
34
|
+
# facts).
|
|
43
35
|
class DryValidation < Rigor::Plugin::Base
|
|
44
36
|
manifest(
|
|
45
37
|
id: "dry-validation",
|
|
@@ -47,9 +39,8 @@ module Rigor
|
|
|
47
39
|
description: "Recognises `class T < Dry::Validation::Contract` subclasses and " \
|
|
48
40
|
"publishes the contract FQN set.",
|
|
49
41
|
produces: [:dry_validation_contracts],
|
|
50
|
-
# Auto-contribute the bundled RBS overlay (Contract#call -> Result,
|
|
51
|
-
#
|
|
52
|
-
# signature_paths wiring is needed.
|
|
42
|
+
# Auto-contribute the bundled RBS overlay (Contract#call -> Result, Result#success?/#to_h/...)
|
|
43
|
+
# per ADR-25, so no project-side signature_paths wiring is needed.
|
|
53
44
|
signature_paths: ["sig"]
|
|
54
45
|
)
|
|
55
46
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# Gem entry point. Required by Rigor's plugin loader when
|
|
4
|
-
#
|
|
5
|
-
# Side-effects a `Rigor::Plugin.register` call via the
|
|
3
|
+
# Gem entry point. Required by Rigor's plugin loader when `.rigor.yml` lists `rigor-dry-validation`
|
|
4
|
+
# under `plugins:`. Side-effects a `Rigor::Plugin.register` call via the
|
|
6
5
|
# `lib/rigor/plugin/dry_validation.rb` class body.
|
|
7
6
|
require_relative "rigor/plugin/dry_validation"
|