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
|
@@ -14,16 +14,12 @@ require_relative "command"
|
|
|
14
14
|
|
|
15
15
|
module Rigor
|
|
16
16
|
class CLI
|
|
17
|
-
# `rigor plugins` — reports the activation status of every
|
|
18
|
-
#
|
|
19
|
-
# `rigor-project-init` SKILL, CI gates, `rigor init`) can
|
|
20
|
-
# verify their plugin configuration is actually doing what
|
|
17
|
+
# `rigor plugins` — reports the activation status of every plugin entry in `.rigor.yml` so users (and the
|
|
18
|
+
# `rigor-project-init` SKILL, CI gates, `rigor init`) can verify their plugin configuration is actually doing what
|
|
21
19
|
# they think.
|
|
22
20
|
#
|
|
23
|
-
# The command is read-only and idempotent: it loads the
|
|
24
|
-
#
|
|
25
|
-
# runs `Plugin::Loader.load` to attempt instantiation, then
|
|
26
|
-
# prints a table of:
|
|
21
|
+
# The command is read-only and idempotent: it loads the project's `.rigor.yml` (same discovery as `rigor check`),
|
|
22
|
+
# runs `Plugin::Loader.load` to attempt instantiation, then prints a table of:
|
|
27
23
|
#
|
|
28
24
|
# - load status (`loaded` / `load-error` with reason);
|
|
29
25
|
# - resolved manifest id, version, description;
|
|
@@ -39,13 +35,12 @@ module Rigor
|
|
|
39
35
|
# class — `node_rule` node types, `dynamic_return` receivers,
|
|
40
36
|
# `narrowing_facts` methods.
|
|
41
37
|
#
|
|
42
|
-
# `--capabilities` switches to a focused catalogue of just the
|
|
43
|
-
#
|
|
44
|
-
#
|
|
45
|
-
# surface that lets an agent enumerate what every plugin does.
|
|
38
|
+
# `--capabilities` switches to a focused catalogue of just the narrow-protocol gate values + produced/consumed facts
|
|
39
|
+
# (ADR-37 § "Machine-readable capability catalogue") — the AI-legibility surface that lets an agent enumerate what
|
|
40
|
+
# every plugin does.
|
|
46
41
|
#
|
|
47
|
-
# Output formats: `text` (default, human-readable table) and
|
|
48
|
-
#
|
|
42
|
+
# Output formats: `text` (default, human-readable table) and `json` (for tooling — SKILLs, CI gates, editor
|
|
43
|
+
# integrations).
|
|
49
44
|
#
|
|
50
45
|
# Exit codes:
|
|
51
46
|
# - `0` — every configured plugin loaded.
|
|
@@ -83,13 +78,10 @@ module Rigor
|
|
|
83
78
|
|
|
84
79
|
private
|
|
85
80
|
|
|
86
|
-
# Picks the renderer view. `--capabilities` switches to the
|
|
87
|
-
#
|
|
88
|
-
#
|
|
89
|
-
#
|
|
90
|
-
# contributes: the node-rule node types, the dynamic-return
|
|
91
|
-
# receivers, the type-specifier methods, and the produced /
|
|
92
|
-
# consumed facts. The default view stays the full activation report.
|
|
81
|
+
# Picks the renderer view. `--capabilities` switches to the focused extension-protocol catalogue (ADR-37 §
|
|
82
|
+
# "Machine-readable capability catalogue") — per plugin, only the gate values that tell a reader (or an AI agent)
|
|
83
|
+
# exactly what the plugin contributes: the node-rule node types, the dynamic-return receivers, the type-specifier
|
|
84
|
+
# methods, and the produced / consumed facts. The default view stays the full activation report.
|
|
93
85
|
def render(renderer, options)
|
|
94
86
|
json = options.fetch(:format) == "json"
|
|
95
87
|
if options.fetch(:capabilities)
|
|
@@ -120,22 +112,18 @@ module Rigor
|
|
|
120
112
|
raise OptionParser::InvalidArgument, "unsupported format: #{options.fetch(:format)}"
|
|
121
113
|
end
|
|
122
114
|
|
|
123
|
-
# Runs the plugin loader against the project configuration
|
|
124
|
-
#
|
|
125
|
-
# a plain Hash with the fields enumerated in the class
|
|
126
|
-
# docstring so the renderer (text + JSON) reads from a
|
|
115
|
+
# Runs the plugin loader against the project configuration and returns a row per declared plugin entry. Each row
|
|
116
|
+
# is a plain Hash with the fields enumerated in the class docstring so the renderer (text + JSON) reads from a
|
|
127
117
|
# single shape.
|
|
128
118
|
#
|
|
129
|
-
# The loader catches require / init failures and surfaces
|
|
130
|
-
# them through `registry.load_errors`; we merge those back
|
|
119
|
+
# The loader catches require / init failures and surfaces them through `registry.load_errors`; we merge those back
|
|
131
120
|
# into the per-entry rows by matching on `plugin_ref`.
|
|
132
121
|
def build_rows(configuration)
|
|
133
122
|
services = build_services(configuration)
|
|
134
123
|
registry = Plugin::Loader.load(configuration: configuration, services: services)
|
|
135
124
|
|
|
136
125
|
rows = configuration.plugins.map { |entry| row_for_entry(entry, registry) }
|
|
137
|
-
# Surface registry-level errors that did not bind to an
|
|
138
|
-
# entry (e.g. dependency-cycle errors that name multiple
|
|
126
|
+
# Surface registry-level errors that did not bind to an entry (e.g. dependency-cycle errors that name multiple
|
|
139
127
|
# plugins). The renderer treats these as "orphan" errors.
|
|
140
128
|
orphan_errors = orphan_load_errors(registry, rows)
|
|
141
129
|
rows + orphan_errors
|
|
@@ -154,18 +142,15 @@ module Rigor
|
|
|
154
142
|
gem_name = entry_gem_name(entry)
|
|
155
143
|
config = entry_config(entry)
|
|
156
144
|
plugin = registry.plugins.find do |p|
|
|
157
|
-
# The loader has already matched the entry to a plugin
|
|
158
|
-
#
|
|
159
|
-
# the entry was a String) or the explicit id (when the
|
|
160
|
-
# entry was a Hash with `id:`).
|
|
145
|
+
# The loader has already matched the entry to a plugin class; we can identify it by either the gem name (when
|
|
146
|
+
# the entry was a String) or the explicit id (when the entry was a Hash with `id:`).
|
|
161
147
|
plugin_matches_entry?(p, gem_name, entry_id(entry))
|
|
162
148
|
end
|
|
163
149
|
|
|
164
150
|
if plugin
|
|
165
151
|
loaded_row(plugin, gem_name, config)
|
|
166
152
|
else
|
|
167
|
-
# Find the load error whose plugin_ref names this entry
|
|
168
|
-
# (the ref is set by Loader to the gem name on require
|
|
153
|
+
# Find the load error whose plugin_ref names this entry (the ref is set by Loader to the gem name on require
|
|
169
154
|
# failures and to the manifest id on later failures).
|
|
170
155
|
error = registry.load_errors.find do |e|
|
|
171
156
|
ref = e.plugin_ref.to_s
|
|
@@ -178,8 +163,7 @@ module Rigor
|
|
|
178
163
|
def plugin_matches_entry?(plugin, gem_name, entry_id)
|
|
179
164
|
return true if entry_id && plugin.manifest.id == entry_id
|
|
180
165
|
|
|
181
|
-
# A bare gem entry conventionally has manifest.id equal to
|
|
182
|
-
# the gem name with the `rigor-` prefix stripped.
|
|
166
|
+
# A bare gem entry conventionally has manifest.id equal to the gem name with the `rigor-` prefix stripped.
|
|
183
167
|
derived_id = gem_name.delete_prefix("rigor-")
|
|
184
168
|
[derived_id, gem_name].include?(plugin.manifest.id)
|
|
185
169
|
end
|
|
@@ -192,12 +176,10 @@ module Rigor
|
|
|
192
176
|
.merge(load_error: nil)
|
|
193
177
|
end
|
|
194
178
|
|
|
195
|
-
# ADR-37 narrow extension protocols. Unlike the 10 declarative
|
|
196
|
-
#
|
|
197
|
-
#
|
|
198
|
-
#
|
|
199
|
-
# types, receiver class names, specified method names — are the
|
|
200
|
-
# greppable, enumerable surface the capability catalogue exposes.
|
|
179
|
+
# ADR-37 narrow extension protocols. Unlike the 10 declarative manifest fields, these are class-level DSLs
|
|
180
|
+
# (`node_rule` / `dynamic_return` / `narrowing_facts`), so they are read off the plugin class rather than the
|
|
181
|
+
# manifest. The gate values — node types, receiver class names, specified method names — are the greppable,
|
|
182
|
+
# enumerable surface the capability catalogue exposes.
|
|
201
183
|
def narrow_protocol_fields(plugin)
|
|
202
184
|
klass = plugin.class
|
|
203
185
|
{
|
|
@@ -269,10 +251,8 @@ module Rigor
|
|
|
269
251
|
}
|
|
270
252
|
end
|
|
271
253
|
|
|
272
|
-
# For each `signature_paths:` directory the plugin resolves
|
|
273
|
-
#
|
|
274
|
-
# quick `.rbs`-file count. The count is a sanity signal:
|
|
275
|
-
# an empty bundle directory loads silently today but
|
|
254
|
+
# For each `signature_paths:` directory the plugin resolves against its gem root, report the absolute path and a
|
|
255
|
+
# quick `.rbs`-file count. The count is a sanity signal: an empty bundle directory loads silently today but
|
|
276
256
|
# contributes nothing.
|
|
277
257
|
def signature_path_rows(plugin)
|
|
278
258
|
plugin.signature_paths.map do |abs|
|
|
@@ -317,10 +297,8 @@ module Rigor
|
|
|
317
297
|
end
|
|
318
298
|
end
|
|
319
299
|
|
|
320
|
-
# Build orphan-error rows for load errors whose `plugin_ref`
|
|
321
|
-
#
|
|
322
|
-
# dependency-cycle naming a plugin we already accounted for
|
|
323
|
-
# but reported alongside another). De-duplicates against
|
|
300
|
+
# Build orphan-error rows for load errors whose `plugin_ref` did not bind to any configured plugin entry (e.g. a
|
|
301
|
+
# dependency-cycle naming a plugin we already accounted for but reported alongside another). De-duplicates against
|
|
324
302
|
# errors we already attached.
|
|
325
303
|
def orphan_load_errors(registry, rows)
|
|
326
304
|
attached_refs = rows.compact.flat_map { |row| [row[:gem], row[:id]].compact }.to_set
|
|
@@ -4,15 +4,11 @@ require "json"
|
|
|
4
4
|
|
|
5
5
|
module Rigor
|
|
6
6
|
class CLI
|
|
7
|
-
# Renderer for `rigor plugins`. Produces a human-readable
|
|
8
|
-
#
|
|
9
|
-
# shape (the Hash documented on
|
|
10
|
-
# {Rigor::CLI::PluginsCommand#loaded_row}).
|
|
7
|
+
# Renderer for `rigor plugins`. Produces a human-readable text table and a JSON representation from the same row
|
|
8
|
+
# shape (the Hash documented on {Rigor::CLI::PluginsCommand#loaded_row}).
|
|
11
9
|
#
|
|
12
|
-
# The two formats carry the same content; JSON is meant for
|
|
13
|
-
#
|
|
14
|
-
# for interactive inspection. Rows are printed in the order
|
|
15
|
-
# the loader resolved them.
|
|
10
|
+
# The two formats carry the same content; JSON is meant for tooling (SKILLs, CI, editor integrations) while text is
|
|
11
|
+
# for interactive inspection. Rows are printed in the order the loader resolved them.
|
|
16
12
|
class PluginsRenderer # rubocop:disable Metrics/ClassLength
|
|
17
13
|
def initialize(rows:, configuration_path:)
|
|
18
14
|
@rows = rows
|
|
@@ -42,12 +38,10 @@ module Rigor
|
|
|
42
38
|
)
|
|
43
39
|
end
|
|
44
40
|
|
|
45
|
-
# ADR-37 § "Machine-readable capability catalogue" — the focused
|
|
46
|
-
#
|
|
47
|
-
#
|
|
48
|
-
#
|
|
49
|
-
# what the plugin does: node-rule node types, dynamic-return
|
|
50
|
-
# receivers, type-specifier methods, and produced / consumed facts.
|
|
41
|
+
# ADR-37 § "Machine-readable capability catalogue" — the focused per-plugin extension-protocol dump. Only loaded
|
|
42
|
+
# plugins appear (a plugin that failed to load contributes no capabilities), and each carries only the gate values
|
|
43
|
+
# an agent enumerates to learn what the plugin does: node-rule node types, dynamic-return receivers,
|
|
44
|
+
# type-specifier methods, and produced / consumed facts.
|
|
51
45
|
def capabilities_json
|
|
52
46
|
JSON.pretty_generate(
|
|
53
47
|
{
|
|
@@ -84,9 +78,8 @@ module Rigor
|
|
|
84
78
|
lines
|
|
85
79
|
end
|
|
86
80
|
|
|
87
|
-
# The non-empty capability surfaces for a plugin, each as a
|
|
88
|
-
#
|
|
89
|
-
# single source of truth shared between the text and JSON views.
|
|
81
|
+
# The non-empty capability surfaces for a plugin, each as a `label: a, b, c` string. Data-driven so the catalogue
|
|
82
|
+
# stays a single source of truth shared between the text and JSON views.
|
|
90
83
|
def capability_surfaces(row)
|
|
91
84
|
[
|
|
92
85
|
["node_rule", row[:node_rule_types]],
|
|
@@ -169,9 +162,8 @@ module Rigor
|
|
|
169
162
|
lines
|
|
170
163
|
end
|
|
171
164
|
|
|
172
|
-
# ADR-37 narrow extension protocols (node_rule / dynamic_return /
|
|
173
|
-
#
|
|
174
|
-
# declarative surfaces; `--capabilities` is the focused view.
|
|
165
|
+
# ADR-37 narrow extension protocols (node_rule / dynamic_return / narrowing_facts). Surfaced in the full report
|
|
166
|
+
# alongside the declarative surfaces; `--capabilities` is the focused view.
|
|
175
167
|
def narrow_protocol_lines(row)
|
|
176
168
|
lines = []
|
|
177
169
|
lines << " node_rule: #{row[:node_rule_types].join(', ')}" if row[:node_rule_types].any?
|
|
@@ -4,14 +4,12 @@ require "prism"
|
|
|
4
4
|
|
|
5
5
|
module Rigor
|
|
6
6
|
class CLI
|
|
7
|
-
# Re-lexes Ruby source with Prism and wraps each token in an
|
|
8
|
-
#
|
|
7
|
+
# Re-lexes Ruby source with Prism and wraps each token in an ANSI colour escape, producing IRB-style syntax
|
|
8
|
+
# highlighting.
|
|
9
9
|
#
|
|
10
|
-
# Rigor ships no runtime dependencies (ADR-0), so the `irb`
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
# annotate` re-parses its annotated output through here before
|
|
14
|
-
# printing.
|
|
10
|
+
# Rigor ships no runtime dependencies (ADR-0), so the `irb` gem's `IRB::Color` is not available; this module
|
|
11
|
+
# reproduces the same effect from Prism's own token stream. `rigor annotate` re-parses its annotated output through
|
|
12
|
+
# here before printing.
|
|
15
13
|
module PrismColorizer
|
|
16
14
|
module_function
|
|
17
15
|
|
|
@@ -41,9 +39,8 @@ module Rigor
|
|
|
41
39
|
# @return [String] the source with ANSI colour escapes, or
|
|
42
40
|
# the input unchanged when lexing surfaces an error.
|
|
43
41
|
def colorize(source)
|
|
44
|
-
# Sources read under a POSIX locale arrive tagged US-ASCII even
|
|
45
|
-
#
|
|
46
|
-
# do not raise on multibyte comments.
|
|
42
|
+
# Sources read under a POSIX locale arrive tagged US-ASCII even when they carry UTF-8 bytes; retag so the token
|
|
43
|
+
# regexes below do not raise on multibyte comments.
|
|
47
44
|
source = source.dup.force_encoding(Encoding::UTF_8) unless source.encoding == Encoding::UTF_8
|
|
48
45
|
result = Prism.lex(source)
|
|
49
46
|
return source unless result.errors.empty?
|
|
@@ -51,9 +48,8 @@ module Rigor
|
|
|
51
48
|
render(source, result.value)
|
|
52
49
|
end
|
|
53
50
|
|
|
54
|
-
# Prism token offsets are BYTE offsets — slice with byteslice, or
|
|
55
|
-
#
|
|
56
|
-
# subsequent token boundary.
|
|
51
|
+
# Prism token offsets are BYTE offsets — slice with byteslice, or any multibyte character earlier in the source
|
|
52
|
+
# shifts every subsequent token boundary.
|
|
57
53
|
def render(source, lexed)
|
|
58
54
|
out = +""
|
|
59
55
|
offset = 0
|
|
@@ -73,10 +69,8 @@ module Rigor
|
|
|
73
69
|
out
|
|
74
70
|
end
|
|
75
71
|
|
|
76
|
-
# The token after a `SYMBOL_BEGIN` (`:`) carries the symbol
|
|
77
|
-
#
|
|
78
|
-
# keyword token — so it is painted with the symbol colour
|
|
79
|
-
# regardless of its own token type.
|
|
72
|
+
# The token after a `SYMBOL_BEGIN` (`:`) carries the symbol name — and Prism lexes `:then` / `:class` etc. as a
|
|
73
|
+
# keyword token — so it is painted with the symbol colour regardless of its own token type.
|
|
80
74
|
def effective_category(token_type, previous_type)
|
|
81
75
|
return :symbol if previous_type == :SYMBOL_BEGIN
|
|
82
76
|
|
|
@@ -87,8 +81,8 @@ module Rigor
|
|
|
87
81
|
sgr = CATEGORY_SGR.fetch(category)
|
|
88
82
|
return text if sgr.nil? || text.empty?
|
|
89
83
|
|
|
90
|
-
# Keep a trailing newline outside the colour span so the
|
|
91
|
-
#
|
|
84
|
+
# Keep a trailing newline outside the colour span so the reset sits on the token's own line (comments include
|
|
85
|
+
# it).
|
|
92
86
|
trailing = text[/\s*\z/] || ""
|
|
93
87
|
body = trailing.empty? ? text : text[0...-trailing.length]
|
|
94
88
|
return text if body.empty?
|
|
@@ -6,17 +6,15 @@ require_relative "../inference/dynamic_origin"
|
|
|
6
6
|
|
|
7
7
|
module Rigor
|
|
8
8
|
class CLI
|
|
9
|
-
# Renders an {ProtectionReport} (ADR-63 Tier 1) as text or JSON. The text
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
# framing is always *where to add a type*, never "your code is broken".
|
|
9
|
+
# Renders an {ProtectionReport} (ADR-63 Tier 1) as text or JSON. The text form leads with the protected ratio, then
|
|
10
|
+
# the highest-traffic untyped dispatches ("add a type here"), then the lowest-protected files. The framing is always
|
|
11
|
+
# *where to add a type*, never "your code is broken".
|
|
13
12
|
class ProtectionRenderer
|
|
14
13
|
TOP_CALLS = 15
|
|
15
14
|
TOP_FILES = 10
|
|
16
15
|
|
|
17
|
-
# ADR-73 P6 / ADR-75 WD2 — the actionable axis for each tractability
|
|
18
|
-
#
|
|
19
|
-
# how) a type can close it.
|
|
16
|
+
# ADR-73 P6 / ADR-75 WD2 — the actionable axis for each tractability category, shown next to a hole's origin so a
|
|
17
|
+
# user knows whether (and how) a type can close it.
|
|
20
18
|
TRACTABILITY_HINTS = {
|
|
21
19
|
Inference::DynamicOrigin::ADD_RBS => "add RBS",
|
|
22
20
|
Inference::DynamicOrigin::ENABLE_PLUGIN => "enable a plugin / pre_eval",
|
|
@@ -4,31 +4,37 @@ require_relative "../inference/dynamic_origin"
|
|
|
4
4
|
|
|
5
5
|
module Rigor
|
|
6
6
|
class CLI
|
|
7
|
-
# ADR-63 Tier 1 — aggregates per-file {Inference::ProtectionScanner}
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
# untyped dispatches, where a receiver annotation buys the most catching
|
|
12
|
-
# power.
|
|
7
|
+
# ADR-63 Tier 1 — aggregates per-file {Inference::ProtectionScanner} results into a project-level protection report:
|
|
8
|
+
# the protected ratio, the per-file breakdown, and a ranked "add a type here" list keyed by the method called on an
|
|
9
|
+
# unprotected (`Dynamic`) receiver — the highest-traffic untyped dispatches, where a receiver annotation buys the
|
|
10
|
+
# most catching power.
|
|
13
11
|
FileProtection = Data.define(:path, :protected_count, :unprotected_count, :ratio)
|
|
14
12
|
UntypedCall = Data.define(:method_name, :count, :examples, :dynamic_origin)
|
|
15
13
|
|
|
16
|
-
ProtectionReport = Data.define(:files, :untyped_calls, :parse_errors) do
|
|
14
|
+
ProtectionReport = Data.define(:files, :untyped_calls, :parse_errors, :cause_site_counts) do
|
|
17
15
|
def total_protected = files.sum(&:protected_count)
|
|
18
16
|
def total_unprotected = files.sum(&:unprotected_count)
|
|
19
17
|
def grand_total = total_protected + total_unprotected
|
|
20
18
|
def ratio = grand_total.zero? ? 1.0 : total_protected.to_f / grand_total
|
|
21
19
|
|
|
22
|
-
# ADR-73 P6 — total dispatch-site count per tractability axis across
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
# run yields `{}`.
|
|
20
|
+
# ADR-73 P6 / ADR-82 — total dispatch-site count per tractability axis across the classified holes (those with a
|
|
21
|
+
# recorded `dynamic_origin`), so a user sees at a glance how much of the untyped surface a type can actually close
|
|
22
|
+
# (`add_rbs`) vs. needs a plugin (`enable_plugin`) vs. is an engine gap. Keys are omitted when zero; an
|
|
23
|
+
# all-unclassified run yields `{}`. Computed per-site from `cause_site_counts` (not per method-group-dominant
|
|
24
|
+
# cause) so a group with mixed causes is attributed accurately.
|
|
28
25
|
def tractability_summary
|
|
29
|
-
|
|
30
|
-
axis =
|
|
31
|
-
acc[axis] +=
|
|
26
|
+
cause_site_counts.each_with_object(Hash.new(0)) do |(cause, count), acc|
|
|
27
|
+
axis = cause && Inference::DynamicOrigin.tractability(cause)
|
|
28
|
+
acc[axis] += count if axis
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# ADR-82 — per-site count of every dynamic-origin cause across all holes, including the causeless sites
|
|
33
|
+
# (keyed `"none"`). Unlike `add_a_type_here`'s per-method-group dominant cause, this is an exact
|
|
34
|
+
# per-site tally, so it is the faithful measure of provenance coverage (how many holes carry any cause).
|
|
35
|
+
def cause_site_totals
|
|
36
|
+
cause_site_counts.each_with_object({}) do |(cause, count), acc|
|
|
37
|
+
acc[(cause || :none).to_s] = count
|
|
32
38
|
end
|
|
33
39
|
end
|
|
34
40
|
|
|
@@ -38,6 +44,7 @@ module Rigor
|
|
|
38
44
|
"unprotected" => total_unprotected,
|
|
39
45
|
"protection_ratio" => ratio.round(4),
|
|
40
46
|
"tractability_summary" => tractability_summary.transform_keys(&:to_s),
|
|
47
|
+
"cause_site_counts" => cause_site_totals,
|
|
41
48
|
"files" => files.map do |f|
|
|
42
49
|
{ "path" => f.path, "protected" => f.protected_count,
|
|
43
50
|
"unprotected" => f.unprotected_count, "ratio" => f.ratio.round(4) }
|
|
@@ -60,6 +67,7 @@ module Rigor
|
|
|
60
67
|
def initialize
|
|
61
68
|
@files = []
|
|
62
69
|
@calls = Hash.new { |h, k| h[k] = { count: 0, examples: [], origins: Hash.new(0) } }
|
|
70
|
+
@cause_site_counts = Hash.new(0)
|
|
63
71
|
@parse_errors = []
|
|
64
72
|
end
|
|
65
73
|
|
|
@@ -73,6 +81,7 @@ module Rigor
|
|
|
73
81
|
bucket[:count] += 1
|
|
74
82
|
bucket[:examples] << "#{path}:#{site.line}" if bucket[:examples].size < 3
|
|
75
83
|
bucket[:origins][site.dynamic_origin] += 1 if site.dynamic_origin
|
|
84
|
+
@cause_site_counts[site.dynamic_origin] += 1
|
|
76
85
|
end
|
|
77
86
|
end
|
|
78
87
|
|
|
@@ -87,7 +96,8 @@ module Rigor
|
|
|
87
96
|
dynamic_origin: origin)
|
|
88
97
|
end
|
|
89
98
|
untyped = calls.sort_by { |c| [-c.count, c.method_name] }
|
|
90
|
-
ProtectionReport.new(files: @files, untyped_calls: untyped, parse_errors: @parse_errors
|
|
99
|
+
ProtectionReport.new(files: @files, untyped_calls: untyped, parse_errors: @parse_errors,
|
|
100
|
+
cause_site_counts: @cause_site_counts)
|
|
91
101
|
end
|
|
92
102
|
end
|
|
93
103
|
end
|
data/lib/rigor/cli/renderable.rb
CHANGED
|
@@ -6,12 +6,10 @@ module Rigor
|
|
|
6
6
|
class CLI
|
|
7
7
|
# Output-format dispatch shared by the `--format text|json` renderers.
|
|
8
8
|
#
|
|
9
|
-
# Each renderer included this and then implemented `render_text` /
|
|
10
|
-
#
|
|
11
|
-
# the format
|
|
12
|
-
#
|
|
13
|
-
# it keeps the unsupported-format wording and the text/json contract
|
|
14
|
-
# in a single place as new renderers and formats are added.
|
|
9
|
+
# Each renderer included this and then implemented `render_text` / `render_json`; the `render(data, format:)` entry
|
|
10
|
+
# point — route by the format string, raise one consistent `OptionParser::InvalidArgument` on anything else — was
|
|
11
|
+
# copied verbatim into every one. Centralising it keeps the unsupported-format wording and the text/json contract in
|
|
12
|
+
# a single place as new renderers and formats are added.
|
|
15
13
|
module Renderable
|
|
16
14
|
def render(data, format:)
|
|
17
15
|
case format
|
|
@@ -11,15 +11,12 @@ module Rigor
|
|
|
11
11
|
class CLI
|
|
12
12
|
# Executes `rigor show-bleedingedge` (ADR-50 § WD2).
|
|
13
13
|
#
|
|
14
|
-
# Prints the bleeding-edge overlay — the Rigor-maintained set of the
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
# release, so the command currently reports an empty set; it becomes
|
|
19
|
-
# the inspection surface ADR-50 describes once a feature is queued.
|
|
14
|
+
# Prints the bleeding-edge overlay — the Rigor-maintained set of the next major's queued changes
|
|
15
|
+
# ({Rigor::BleedingEdge}) — as an explicit list, and reports which of them the project's `bleeding_edge:`
|
|
16
|
+
# configuration adopts. The overlay is empty in this release, so the command currently reports an empty set; it
|
|
17
|
+
# becomes the inspection surface ADR-50 describes once a feature is queued.
|
|
20
18
|
#
|
|
21
|
-
# Read-only: it loads `.rigor.yml` to resolve the active selection
|
|
22
|
-
# but runs no analysis.
|
|
19
|
+
# Read-only: it loads `.rigor.yml` to resolve the active selection but runs no analysis.
|
|
23
20
|
class ShowBleedingedgeCommand < Command
|
|
24
21
|
USAGE = "Usage: rigor show-bleedingedge [options]"
|
|
25
22
|
|
|
@@ -11,30 +11,20 @@ module Rigor
|
|
|
11
11
|
class CLI
|
|
12
12
|
# Executes the `rigor sig-gen` command — ADR-14 slices 1–3.
|
|
13
13
|
#
|
|
14
|
-
# Walks the given paths (or `configuration.paths` when none
|
|
15
|
-
#
|
|
16
|
-
# via {Rigor::SigGen::
|
|
17
|
-
#
|
|
18
|
-
# `--diff`; slice 1) or writes them to the project signature
|
|
19
|
-
# tree via {Rigor::SigGen::Writer} (`--write`; slice 2).
|
|
14
|
+
# Walks the given paths (or `configuration.paths` when none are supplied), classifies every reachable instance
|
|
15
|
+
# method via {Rigor::SigGen::Generator}, and either prints the resulting RBS skeletons / unified-style diffs
|
|
16
|
+
# (`--print`, `--diff`; slice 1) or writes them to the project signature tree via {Rigor::SigGen::Writer}
|
|
17
|
+
# (`--write`; slice 2).
|
|
20
18
|
#
|
|
21
|
-
# `--write` follows the established Ruby community
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
# to the file; non-existent target files are created. User-
|
|
26
|
-
# authored declarations are NEVER replaced unless
|
|
27
|
-
# `--overwrite` is set AND the candidate is a
|
|
28
|
-
# `tighter-return`.
|
|
19
|
+
# `--write` follows the established Ruby community convention: `lib/foo/bar.rb` → `sig/foo/bar.rbs`. New methods are
|
|
20
|
+
# inserted into the matching class declaration just before its closing `end`; new classes are appended to the file;
|
|
21
|
+
# non-existent target files are created. User-authored declarations are NEVER replaced unless `--overwrite` is set
|
|
22
|
+
# AND the candidate is a `tighter-return`.
|
|
29
23
|
#
|
|
30
|
-
# Parameter policy defaults to `untyped`. `--params=observed`
|
|
31
|
-
# (
|
|
32
|
-
# the
|
|
33
|
-
#
|
|
34
|
-
# directory exists), unions per-position arg types, and the
|
|
35
|
-
# generator emits the union per ADR-5 clause 2.
|
|
36
|
-
# `--params=observed-strict` stays reserved-but-inert until
|
|
37
|
-
# the capability-role catalog ships (rejected with a usage
|
|
24
|
+
# Parameter policy defaults to `untyped`. `--params=observed` (slice 3) opts in to caller-side observation
|
|
25
|
+
# harvesting: the `ObservationCollector` walks `--observe=PATH...` (default `spec/` when no flag is given AND a
|
|
26
|
+
# `spec/` directory exists), unions per-position arg types, and the generator emits the union per ADR-5 clause 2.
|
|
27
|
+
# `--params=observed-strict` stays reserved-but-inert until the capability-role catalog ships (rejected with a usage
|
|
38
28
|
# error so the surface stays stable).
|
|
39
29
|
class SigGenCommand < Command
|
|
40
30
|
USAGE = "Usage: rigor sig-gen [options] [paths]"
|
|
@@ -86,10 +76,8 @@ module Rigor
|
|
|
86
76
|
SigGen::Renderer.new(out: @out).render_write(results: results, format: options.fetch(:format))
|
|
87
77
|
end
|
|
88
78
|
|
|
89
|
-
# Slice 3 — collect call-site argument observations when
|
|
90
|
-
#
|
|
91
|
-
# not specified, default to `spec/` (skipped silently
|
|
92
|
-
# when the directory is absent).
|
|
79
|
+
# Slice 3 — collect call-site argument observations when `--params=observed` is set. When `--observe=PATH` is not
|
|
80
|
+
# specified, default to `spec/` (skipped silently when the directory is absent).
|
|
93
81
|
def collect_observations(configuration, options)
|
|
94
82
|
return {} if options.fetch(:params) != "observed"
|
|
95
83
|
|