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.
Files changed (433) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/data/core_overlay/csv.rbs +28 -0
  4. data/data/core_overlay/psych.rbs +22 -0
  5. data/docs/handbook/01-getting-started.md +9 -1
  6. data/docs/handbook/02-everyday-types.md +4 -1
  7. data/docs/handbook/08-understanding-errors.md +3 -3
  8. data/docs/manual/01-installation.md +1 -0
  9. data/docs/manual/02-cli-reference.md +16 -7
  10. data/docs/manual/04-diagnostics.md +7 -4
  11. data/docs/manual/06-baseline.md +5 -2
  12. data/docs/manual/07-plugins.md +1 -1
  13. data/docs/manual/14-rails-quickstart.md +4 -2
  14. data/docs/manual/15-type-protection-coverage.md +27 -4
  15. data/docs/manual/plugins/rigor-actionpack.md +1 -1
  16. data/docs/manual/plugins/rigor-activerecord.md +12 -5
  17. data/docs/manual/plugins/rigor-rails-routes.md +11 -0
  18. data/lib/rigor/analysis/baseline.rb +56 -96
  19. data/lib/rigor/analysis/buffer_binding.rb +13 -20
  20. data/lib/rigor/analysis/check_rules/always_truthy_condition_collector.rb +29 -48
  21. data/lib/rigor/analysis/check_rules/dead_assignment_collector.rb +35 -54
  22. data/lib/rigor/analysis/check_rules/ivar_write_collector.rb +23 -37
  23. data/lib/rigor/analysis/check_rules/main_pass_collector.rb +16 -23
  24. data/lib/rigor/analysis/check_rules/rule_walk.rb +48 -71
  25. data/lib/rigor/analysis/check_rules/self_closedness_scanner.rb +19 -28
  26. data/lib/rigor/analysis/check_rules/unreachable_clause_collector.rb +48 -67
  27. data/lib/rigor/analysis/check_rules.rb +174 -274
  28. data/lib/rigor/analysis/dependency_recorder.rb +26 -38
  29. data/lib/rigor/analysis/dependency_source_inference/boundary_cross_reporter.rb +13 -25
  30. data/lib/rigor/analysis/dependency_source_inference/builder.rb +17 -30
  31. data/lib/rigor/analysis/dependency_source_inference/gem_resolver.rb +15 -26
  32. data/lib/rigor/analysis/dependency_source_inference/index.rb +45 -76
  33. data/lib/rigor/analysis/dependency_source_inference/return_type_heuristic.rb +23 -40
  34. data/lib/rigor/analysis/dependency_source_inference/walker.rb +50 -83
  35. data/lib/rigor/analysis/dependency_source_inference.rb +6 -10
  36. data/lib/rigor/analysis/diagnostic.rb +48 -75
  37. data/lib/rigor/analysis/erb_template_detector.rb +13 -18
  38. data/lib/rigor/analysis/fact_store.rb +12 -22
  39. data/lib/rigor/analysis/incremental.rb +47 -63
  40. data/lib/rigor/analysis/incremental_session.rb +74 -100
  41. data/lib/rigor/analysis/project_scan.rb +12 -23
  42. data/lib/rigor/analysis/result.rb +3 -5
  43. data/lib/rigor/analysis/rule_catalog.rb +67 -95
  44. data/lib/rigor/analysis/run_stats.rb +38 -61
  45. data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +101 -160
  46. data/lib/rigor/analysis/runner/pool_coordinator.rb +121 -188
  47. data/lib/rigor/analysis/runner/project_pre_passes.rb +62 -96
  48. data/lib/rigor/analysis/runner/run_snapshots.rb +12 -18
  49. data/lib/rigor/analysis/runner.rb +220 -333
  50. data/lib/rigor/analysis/self_call_resolution_recorder.rb +30 -43
  51. data/lib/rigor/analysis/worker_session.rb +64 -102
  52. data/lib/rigor/ast/type_node.rb +6 -8
  53. data/lib/rigor/ast.rb +6 -10
  54. data/lib/rigor/bleeding_edge.rb +27 -35
  55. data/lib/rigor/builtins/hkt_builtins.rb +7 -14
  56. data/lib/rigor/builtins/imported_refinements.rb +106 -149
  57. data/lib/rigor/builtins/predefined_constant_refinements.rb +51 -65
  58. data/lib/rigor/builtins/regex_refinement.rb +32 -43
  59. data/lib/rigor/builtins/static_return_refinements.rb +57 -81
  60. data/lib/rigor/cache/descriptor.rb +58 -94
  61. data/lib/rigor/cache/incremental_snapshot.rb +32 -48
  62. data/lib/rigor/cache/rbs_cache_producer.rb +10 -15
  63. data/lib/rigor/cache/rbs_class_ancestor_table.rb +10 -16
  64. data/lib/rigor/cache/rbs_class_type_param_names.rb +10 -16
  65. data/lib/rigor/cache/rbs_constant_table.rb +8 -13
  66. data/lib/rigor/cache/rbs_descriptor.rb +8 -13
  67. data/lib/rigor/cache/rbs_environment.rb +11 -19
  68. data/lib/rigor/cache/rbs_environment_marshal_patch.rb +11 -19
  69. data/lib/rigor/cache/rbs_known_class_names.rb +8 -12
  70. data/lib/rigor/cache/store.rb +248 -186
  71. data/lib/rigor/cli/annotate_command.rb +51 -88
  72. data/lib/rigor/cli/baseline_command.rb +10 -17
  73. data/lib/rigor/cli/check_command.rb +121 -199
  74. data/lib/rigor/cli/check_runner_factory.rb +8 -14
  75. data/lib/rigor/cli/ci_detector.rb +9 -14
  76. data/lib/rigor/cli/command.rb +8 -14
  77. data/lib/rigor/cli/coverage_command.rb +62 -48
  78. data/lib/rigor/cli/coverage_mutation.rb +14 -19
  79. data/lib/rigor/cli/coverage_report.rb +0 -2
  80. data/lib/rigor/cli/coverage_scan.rb +7 -11
  81. data/lib/rigor/cli/diagnostic_formats.rb +46 -62
  82. data/lib/rigor/cli/diff_command.rb +10 -20
  83. data/lib/rigor/cli/docs_command.rb +26 -40
  84. data/lib/rigor/cli/doctor_command.rb +8 -9
  85. data/lib/rigor/cli/explain_command.rb +4 -7
  86. data/lib/rigor/cli/fused_protection_renderer.rb +4 -5
  87. data/lib/rigor/cli/fused_protection_report.rb +6 -8
  88. data/lib/rigor/cli/lsp_command.rb +11 -19
  89. data/lib/rigor/cli/mcp_command.rb +4 -6
  90. data/lib/rigor/cli/mutation_protection_renderer.rb +3 -4
  91. data/lib/rigor/cli/mutation_protection_report.rb +6 -9
  92. data/lib/rigor/cli/options.rb +11 -19
  93. data/lib/rigor/cli/plugin_command.rb +18 -30
  94. data/lib/rigor/cli/plugins_command.rb +29 -51
  95. data/lib/rigor/cli/plugins_renderer.rb +12 -20
  96. data/lib/rigor/cli/prism_colorizer.rb +13 -19
  97. data/lib/rigor/cli/protection_fork_scan.rb +55 -0
  98. data/lib/rigor/cli/protection_renderer.rb +5 -7
  99. data/lib/rigor/cli/protection_report.rb +34 -18
  100. data/lib/rigor/cli/renderable.rb +4 -6
  101. data/lib/rigor/cli/show_bleedingedge_command.rb +5 -8
  102. data/lib/rigor/cli/sig_gen_command.rb +14 -26
  103. data/lib/rigor/cli/skill_command.rb +30 -47
  104. data/lib/rigor/cli/skill_describe.rb +40 -64
  105. data/lib/rigor/cli/trace_command.rb +9 -16
  106. data/lib/rigor/cli/trace_renderer.rb +35 -51
  107. data/lib/rigor/cli/triage_command.rb +6 -10
  108. data/lib/rigor/cli/triage_renderer.rb +1 -2
  109. data/lib/rigor/cli/type_of_command.rb +14 -23
  110. data/lib/rigor/cli/type_of_renderer.rb +3 -5
  111. data/lib/rigor/cli/type_scan_command.rb +6 -10
  112. data/lib/rigor/cli/type_scan_renderer.rb +3 -5
  113. data/lib/rigor/cli/type_scan_report.rb +2 -3
  114. data/lib/rigor/cli/upgrade_command.rb +2 -3
  115. data/lib/rigor/cli.rb +16 -28
  116. data/lib/rigor/config_audit.rb +35 -44
  117. data/lib/rigor/configuration/dependencies.rb +41 -70
  118. data/lib/rigor/configuration/severity_profile.rb +28 -42
  119. data/lib/rigor/configuration.rb +150 -241
  120. data/lib/rigor/environment/bundle_sig_discovery.rb +74 -118
  121. data/lib/rigor/environment/class_registry.rb +19 -26
  122. data/lib/rigor/environment/constant_type_cache_holder.rb +14 -21
  123. data/lib/rigor/environment/hkt_registry_holder.rb +6 -12
  124. data/lib/rigor/environment/lockfile_resolver.rb +31 -47
  125. data/lib/rigor/environment/missing_gem_constant_index.rb +128 -0
  126. data/lib/rigor/environment/rbs_collection_discovery.rb +39 -63
  127. data/lib/rigor/environment/rbs_coverage_report.rb +24 -42
  128. data/lib/rigor/environment/rbs_loader.rb +420 -518
  129. data/lib/rigor/environment/reflection.rb +28 -53
  130. data/lib/rigor/environment/reporters.rb +13 -24
  131. data/lib/rigor/environment.rb +225 -304
  132. data/lib/rigor/flow_contribution/conflict.rb +16 -27
  133. data/lib/rigor/flow_contribution/element.rb +7 -12
  134. data/lib/rigor/flow_contribution/fact.rb +33 -57
  135. data/lib/rigor/flow_contribution/merge_result.rb +6 -9
  136. data/lib/rigor/flow_contribution/merger.rb +32 -47
  137. data/lib/rigor/flow_contribution.rb +37 -55
  138. data/lib/rigor/inference/acceptance.rb +133 -219
  139. data/lib/rigor/inference/block_parameter_binder.rb +52 -82
  140. data/lib/rigor/inference/body_fixpoint.rb +22 -30
  141. data/lib/rigor/inference/budget_trace.rb +43 -63
  142. data/lib/rigor/inference/builtins/array_catalog.rb +4 -6
  143. data/lib/rigor/inference/builtins/comparable_catalog.rb +4 -6
  144. data/lib/rigor/inference/builtins/complex_catalog.rb +13 -19
  145. data/lib/rigor/inference/builtins/date_catalog.rb +38 -67
  146. data/lib/rigor/inference/builtins/encoding_catalog.rb +22 -36
  147. data/lib/rigor/inference/builtins/enumerable_catalog.rb +4 -6
  148. data/lib/rigor/inference/builtins/exception_catalog.rb +38 -57
  149. data/lib/rigor/inference/builtins/hash_catalog.rb +9 -14
  150. data/lib/rigor/inference/builtins/method_catalog.rb +29 -48
  151. data/lib/rigor/inference/builtins/numeric_catalog.rb +13 -18
  152. data/lib/rigor/inference/builtins/pathname_catalog.rb +8 -13
  153. data/lib/rigor/inference/builtins/proc_catalog.rb +38 -62
  154. data/lib/rigor/inference/builtins/random_catalog.rb +21 -32
  155. data/lib/rigor/inference/builtins/range_catalog.rb +12 -21
  156. data/lib/rigor/inference/builtins/rational_catalog.rb +9 -15
  157. data/lib/rigor/inference/builtins/re_catalog.rb +29 -48
  158. data/lib/rigor/inference/builtins/set_catalog.rb +18 -27
  159. data/lib/rigor/inference/builtins/string_catalog.rb +12 -19
  160. data/lib/rigor/inference/builtins/struct_catalog.rb +18 -30
  161. data/lib/rigor/inference/builtins/time_catalog.rb +28 -44
  162. data/lib/rigor/inference/closure_escape_analyzer.rb +44 -67
  163. data/lib/rigor/inference/coverage_scanner.rb +13 -18
  164. data/lib/rigor/inference/def_return_typer.rb +8 -14
  165. data/lib/rigor/inference/dynamic_origin.rb +23 -20
  166. data/lib/rigor/inference/expression_typer.rb +794 -1154
  167. data/lib/rigor/inference/fallback.rb +8 -12
  168. data/lib/rigor/inference/fallback_tracer.rb +4 -10
  169. data/lib/rigor/inference/flow_tracer.rb +25 -36
  170. data/lib/rigor/inference/fork_map.rb +87 -0
  171. data/lib/rigor/inference/hkt_body.rb +45 -68
  172. data/lib/rigor/inference/hkt_body_parser.rb +33 -52
  173. data/lib/rigor/inference/hkt_reducer.rb +38 -59
  174. data/lib/rigor/inference/hkt_registry.rb +50 -76
  175. data/lib/rigor/inference/indexed_narrowing.rb +55 -81
  176. data/lib/rigor/inference/macro_block_self_type.rb +21 -34
  177. data/lib/rigor/inference/method_dispatcher/array_to_h_folding.rb +11 -18
  178. data/lib/rigor/inference/method_dispatcher/block_folding.rb +49 -83
  179. data/lib/rigor/inference/method_dispatcher/call_context.rb +16 -23
  180. data/lib/rigor/inference/method_dispatcher/cgi_folding.rb +13 -22
  181. data/lib/rigor/inference/method_dispatcher/constant_folding.rb +307 -454
  182. data/lib/rigor/inference/method_dispatcher/data_folding.rb +24 -34
  183. data/lib/rigor/inference/method_dispatcher/file_folding.rb +22 -37
  184. data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +52 -81
  185. data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +51 -78
  186. data/lib/rigor/inference/method_dispatcher/literal_string_folding.rb +60 -97
  187. data/lib/rigor/inference/method_dispatcher/math_folding.rb +23 -34
  188. data/lib/rigor/inference/method_dispatcher/member_shape_projection.rb +18 -26
  189. data/lib/rigor/inference/method_dispatcher/method_folding.rb +37 -71
  190. data/lib/rigor/inference/method_dispatcher/overload_selector.rb +114 -182
  191. data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +122 -193
  192. data/lib/rigor/inference/method_dispatcher/receiver_affinity.rb +15 -24
  193. data/lib/rigor/inference/method_dispatcher/reduce_folding.rb +64 -93
  194. data/lib/rigor/inference/method_dispatcher/regexp_folding.rb +31 -45
  195. data/lib/rigor/inference/method_dispatcher/set_folding.rb +6 -9
  196. data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +356 -511
  197. data/lib/rigor/inference/method_dispatcher/shellwords_folding.rb +22 -32
  198. data/lib/rigor/inference/method_dispatcher/singleton_folding.rb +15 -21
  199. data/lib/rigor/inference/method_dispatcher/struct_folding.rb +66 -82
  200. data/lib/rigor/inference/method_dispatcher/time_folding.rb +10 -15
  201. data/lib/rigor/inference/method_dispatcher/uri_folding.rb +9 -13
  202. data/lib/rigor/inference/method_dispatcher.rb +378 -524
  203. data/lib/rigor/inference/method_parameter_binder.rb +81 -114
  204. data/lib/rigor/inference/multi_target_binder.rb +51 -68
  205. data/lib/rigor/inference/mutation_widening.rb +115 -158
  206. data/lib/rigor/inference/narrowing.rb +627 -727
  207. data/lib/rigor/inference/origin_lookup.rb +38 -0
  208. data/lib/rigor/inference/parameter_inference_collector.rb +154 -109
  209. data/lib/rigor/inference/precision_scanner.rb +26 -35
  210. data/lib/rigor/inference/project_patched_methods.rb +20 -32
  211. data/lib/rigor/inference/project_patched_scanner.rb +23 -37
  212. data/lib/rigor/inference/protection_scanner.rb +16 -18
  213. data/lib/rigor/inference/rbs_type_translator.rb +49 -66
  214. data/lib/rigor/inference/scope_indexer.rb +473 -821
  215. data/lib/rigor/inference/statement_evaluator.rb +754 -1114
  216. data/lib/rigor/inference/struct_fold_safety.rb +34 -48
  217. data/lib/rigor/inference/synthetic_method.rb +9 -16
  218. data/lib/rigor/inference/synthetic_method_index.rb +20 -35
  219. data/lib/rigor/inference/synthetic_method_scanner.rb +63 -103
  220. data/lib/rigor/language_server/buffer_resolution.rb +6 -9
  221. data/lib/rigor/language_server/buffer_table.rb +11 -18
  222. data/lib/rigor/language_server/completion_provider.rb +69 -116
  223. data/lib/rigor/language_server/debouncer.rb +16 -25
  224. data/lib/rigor/language_server/diagnostic_publisher.rb +26 -40
  225. data/lib/rigor/language_server/document_symbol_provider.rb +14 -19
  226. data/lib/rigor/language_server/folding_range_provider.rb +11 -19
  227. data/lib/rigor/language_server/hover_provider.rb +8 -11
  228. data/lib/rigor/language_server/hover_renderer.rb +56 -93
  229. data/lib/rigor/language_server/loop.rb +14 -19
  230. data/lib/rigor/language_server/project_context.rb +46 -74
  231. data/lib/rigor/language_server/selection_range_provider.rb +9 -12
  232. data/lib/rigor/language_server/server.rb +55 -83
  233. data/lib/rigor/language_server/signature_help_provider.rb +29 -46
  234. data/lib/rigor/language_server/synchronized_writer.rb +4 -7
  235. data/lib/rigor/language_server/uri.rb +8 -13
  236. data/lib/rigor/language_server.rb +4 -6
  237. data/lib/rigor/mcp/loop.rb +2 -3
  238. data/lib/rigor/mcp/server.rb +4 -7
  239. data/lib/rigor/mcp.rb +3 -6
  240. data/lib/rigor/plugin/access_denied_error.rb +5 -8
  241. data/lib/rigor/plugin/additional_initializer.rb +21 -31
  242. data/lib/rigor/plugin/base.rb +335 -518
  243. data/lib/rigor/plugin/blueprint.rb +14 -23
  244. data/lib/rigor/plugin/box.rb +18 -29
  245. data/lib/rigor/plugin/fact_store.rb +16 -26
  246. data/lib/rigor/plugin/inflector.rb +37 -53
  247. data/lib/rigor/plugin/io_boundary.rb +33 -56
  248. data/lib/rigor/plugin/isolation.rb +42 -55
  249. data/lib/rigor/plugin/load_error.rb +10 -15
  250. data/lib/rigor/plugin/loader.rb +30 -49
  251. data/lib/rigor/plugin/macro/block_as_method.rb +20 -32
  252. data/lib/rigor/plugin/macro/heredoc_template.rb +35 -58
  253. data/lib/rigor/plugin/macro/nested_class_template.rb +22 -36
  254. data/lib/rigor/plugin/macro/trait_registry.rb +34 -51
  255. data/lib/rigor/plugin/macro.rb +10 -15
  256. data/lib/rigor/plugin/manifest.rb +85 -144
  257. data/lib/rigor/plugin/node_context.rb +14 -22
  258. data/lib/rigor/plugin/node_rule_walk.rb +49 -74
  259. data/lib/rigor/plugin/protocol_contract.rb +25 -39
  260. data/lib/rigor/plugin/registry.rb +132 -205
  261. data/lib/rigor/plugin/services.rb +21 -33
  262. data/lib/rigor/plugin/source_rbs_synthesis_reporter.rb +11 -19
  263. data/lib/rigor/plugin/trust_policy.rb +24 -38
  264. data/lib/rigor/plugin/type_node_resolver.rb +15 -24
  265. data/lib/rigor/protection/diagnostic_oracle.rb +11 -13
  266. data/lib/rigor/protection/mutation_scanner.rb +27 -35
  267. data/lib/rigor/protection/mutator.rb +50 -70
  268. data/lib/rigor/protection/test_suite_oracle.rb +20 -27
  269. data/lib/rigor/rbs_extended/conformance_checker.rb +48 -68
  270. data/lib/rigor/rbs_extended/hkt_directives.rb +28 -54
  271. data/lib/rigor/rbs_extended/reporter.rb +24 -40
  272. data/lib/rigor/rbs_extended.rb +107 -197
  273. data/lib/rigor/reflection.rb +68 -86
  274. data/lib/rigor/scope/discovery_index.rb +14 -19
  275. data/lib/rigor/scope.rb +255 -310
  276. data/lib/rigor/sig_gen/classification.rb +6 -10
  277. data/lib/rigor/sig_gen/generator.rb +197 -323
  278. data/lib/rigor/sig_gen/layout_index.rb +12 -20
  279. data/lib/rigor/sig_gen/method_candidate.rb +12 -17
  280. data/lib/rigor/sig_gen/observation_collector.rb +38 -70
  281. data/lib/rigor/sig_gen/observed_call.rb +13 -23
  282. data/lib/rigor/sig_gen/path_mapper.rb +17 -29
  283. data/lib/rigor/sig_gen/renderer.rb +7 -13
  284. data/lib/rigor/sig_gen/type_elaborator.rb +15 -28
  285. data/lib/rigor/sig_gen/write_result.rb +8 -16
  286. data/lib/rigor/sig_gen/writer.rb +95 -174
  287. data/lib/rigor/sig_gen.rb +3 -6
  288. data/lib/rigor/signature_path_audit.rb +24 -30
  289. data/lib/rigor/source/constant_path.rb +10 -14
  290. data/lib/rigor/source/literals.rb +31 -45
  291. data/lib/rigor/source/node_locator.rb +9 -11
  292. data/lib/rigor/source/node_walker.rb +9 -13
  293. data/lib/rigor/source.rb +3 -4
  294. data/lib/rigor/testing.rb +16 -20
  295. data/lib/rigor/triage/catalogue.rb +38 -62
  296. data/lib/rigor/triage.rb +31 -52
  297. data/lib/rigor/trinary.rb +9 -13
  298. data/lib/rigor/type/acceptance_router.rb +4 -6
  299. data/lib/rigor/type/accepts_result.rb +10 -14
  300. data/lib/rigor/type/app.rb +19 -27
  301. data/lib/rigor/type/bot.rb +4 -6
  302. data/lib/rigor/type/bound_method.rb +10 -15
  303. data/lib/rigor/type/combinator.rb +165 -257
  304. data/lib/rigor/type/constant.rb +23 -34
  305. data/lib/rigor/type/data_class.rb +10 -15
  306. data/lib/rigor/type/data_instance.rb +14 -20
  307. data/lib/rigor/type/difference.rb +21 -32
  308. data/lib/rigor/type/dynamic.rb +3 -5
  309. data/lib/rigor/type/hash_shape.rb +32 -18
  310. data/lib/rigor/type/integer_range.rb +11 -16
  311. data/lib/rigor/type/intersection.rb +27 -42
  312. data/lib/rigor/type/nominal.rb +10 -15
  313. data/lib/rigor/type/plain_lattice.rb +9 -13
  314. data/lib/rigor/type/refined.rb +67 -114
  315. data/lib/rigor/type/singleton.rb +4 -6
  316. data/lib/rigor/type/struct_class.rb +11 -16
  317. data/lib/rigor/type/struct_instance.rb +15 -21
  318. data/lib/rigor/type/tuple.rb +14 -19
  319. data/lib/rigor/type/union.rb +30 -42
  320. data/lib/rigor/type_node/generic.rb +14 -26
  321. data/lib/rigor/type_node/identifier.rb +12 -19
  322. data/lib/rigor/type_node.rb +3 -12
  323. data/lib/rigor/value_semantics.rb +16 -21
  324. data/lib/rigor/version.rb +1 -1
  325. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/analyzer.rb +18 -30
  326. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_discoverer.rb +16 -29
  327. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable/channel_index.rb +12 -23
  328. data/plugins/rigor-actioncable/lib/rigor/plugin/actioncable.rb +22 -39
  329. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/analyzer.rb +26 -46
  330. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_discoverer.rb +51 -87
  331. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer/mailer_index.rb +10 -17
  332. data/plugins/rigor-actionmailer/lib/rigor/plugin/actionmailer.rb +26 -39
  333. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/analyzer.rb +141 -184
  334. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_discoverer.rb +30 -51
  335. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack/controller_index.rb +57 -92
  336. data/plugins/rigor-actionpack/lib/rigor/plugin/actionpack.rb +92 -108
  337. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/analyzer.rb +13 -22
  338. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_discoverer.rb +15 -25
  339. data/plugins/rigor-activejob/lib/rigor/plugin/activejob/job_index.rb +8 -13
  340. data/plugins/rigor-activejob/lib/rigor/plugin/activejob.rb +16 -24
  341. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/analyzer.rb +40 -48
  342. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_discoverer.rb +140 -129
  343. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/model_index.rb +56 -59
  344. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_parser.rb +27 -41
  345. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/schema_table.rb +16 -24
  346. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord/structure_sql_parser.rb +172 -0
  347. data/plugins/rigor-activerecord/lib/rigor/plugin/activerecord.rb +168 -241
  348. data/plugins/rigor-activerecord/lib/rigor-activerecord.rb +3 -5
  349. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/analyzer.rb +8 -14
  350. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_discoverer.rb +9 -15
  351. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage/attachment_index.rb +4 -7
  352. data/plugins/rigor-activestorage/lib/rigor/plugin/activestorage.rb +23 -41
  353. data/plugins/rigor-activestorage/lib/rigor-activestorage.rb +3 -5
  354. data/plugins/rigor-activesupport-core-ext/lib/rigor/plugin/activesupport_core_ext.rb +6 -10
  355. data/plugins/rigor-activesupport-core-ext/lib/rigor-activesupport-core-ext.rb +8 -11
  356. data/plugins/rigor-activesupport-core-ext/sig/active_support/core_ext.rbs +32 -0
  357. data/plugins/rigor-devise/lib/rigor/plugin/devise.rb +30 -45
  358. data/plugins/rigor-devise/lib/rigor-devise.rb +3 -5
  359. data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema/schema_scanner.rb +43 -69
  360. data/plugins/rigor-dry-schema/lib/rigor/plugin/dry_schema.rb +26 -35
  361. data/plugins/rigor-dry-schema/lib/rigor-dry-schema.rb +3 -5
  362. data/plugins/rigor-dry-struct/lib/rigor/plugin/dry_struct.rb +30 -47
  363. data/plugins/rigor-dry-struct/lib/rigor-dry-struct.rb +3 -5
  364. data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types/alias_scanner.rb +67 -113
  365. data/plugins/rigor-dry-types/lib/rigor/plugin/dry_types.rb +29 -46
  366. data/plugins/rigor-dry-types/lib/rigor-dry-types.rb +3 -5
  367. data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation/contract_scanner.rb +13 -20
  368. data/plugins/rigor-dry-validation/lib/rigor/plugin/dry_validation.rb +14 -23
  369. data/plugins/rigor-dry-validation/lib/rigor-dry-validation.rb +2 -3
  370. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/analyzer.rb +22 -37
  371. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_discoverer.rb +28 -46
  372. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot/factory_index.rb +13 -17
  373. data/plugins/rigor-factorybot/lib/rigor/plugin/factorybot.rb +30 -47
  374. data/plugins/rigor-graphql/lib/rigor/plugin/graphql/type_scanner.rb +52 -80
  375. data/plugins/rigor-graphql/lib/rigor/plugin/graphql.rb +21 -31
  376. data/plugins/rigor-graphql/lib/rigor-graphql.rb +3 -5
  377. data/plugins/rigor-hanami/lib/rigor/plugin/hanami/action_checker.rb +11 -17
  378. data/plugins/rigor-hanami/lib/rigor/plugin/hanami.rb +20 -34
  379. data/plugins/rigor-mangrove/lib/rigor/plugin/mangrove.rb +45 -75
  380. data/plugins/rigor-minitest/lib/rigor/plugin/minitest/assertion_analyzer.rb +22 -36
  381. data/plugins/rigor-minitest/lib/rigor/plugin/minitest.rb +22 -41
  382. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/analyzer.rb +17 -32
  383. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_discoverer.rb +6 -12
  384. data/plugins/rigor-pundit/lib/rigor/plugin/pundit/policy_index.rb +4 -8
  385. data/plugins/rigor-pundit/lib/rigor/plugin/pundit.rb +17 -32
  386. data/plugins/rigor-rails/lib/rigor-rails.rb +11 -18
  387. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/analyzer.rb +58 -92
  388. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_index.rb +20 -34
  389. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n/locale_loader.rb +20 -31
  390. data/plugins/rigor-rails-i18n/lib/rigor/plugin/rails_i18n.rb +49 -82
  391. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/analyzer.rb +55 -92
  392. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/devise_routes.rb +51 -90
  393. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/doorkeeper_routes.rb +17 -30
  394. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/grape_api_discoverer.rb +189 -0
  395. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_discoverer.rb +38 -70
  396. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/helper_table.rb +61 -75
  397. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes/routes_parser.rb +319 -505
  398. data/plugins/rigor-rails-routes/lib/rigor/plugin/rails_routes.rb +91 -96
  399. data/plugins/rigor-rbs-inline/lib/rigor/plugin/rbs_inline.rb +32 -54
  400. data/plugins/rigor-rbs-inline/lib/rigor-rbs-inline.rb +8 -13
  401. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/analyzer.rb +9 -16
  402. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_scope_index.rb +24 -39
  403. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/let_type_resolver.rb +13 -22
  404. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/matcher_analyzer.rb +34 -56
  405. data/plugins/rigor-rspec/lib/rigor/plugin/rspec/scope_walker.rb +22 -42
  406. data/plugins/rigor-rspec/lib/rigor/plugin/rspec.rb +43 -75
  407. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/have_http_status_analyzer.rb +27 -39
  408. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails/http_status_codes.rb +14 -19
  409. data/plugins/rigor-rspec-rails/lib/rigor/plugin/rspec_rails.rb +20 -34
  410. data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers/analyzer.rb +28 -47
  411. data/plugins/rigor-shoulda-matchers/lib/rigor/plugin/shoulda_matchers.rb +21 -37
  412. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/analyzer.rb +13 -22
  413. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_discoverer.rb +18 -31
  414. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq/worker_index.rb +6 -10
  415. data/plugins/rigor-sidekiq/lib/rigor/plugin/sidekiq.rb +14 -29
  416. data/plugins/rigor-sinatra/lib/rigor/plugin/sinatra.rb +23 -41
  417. data/plugins/rigor-sinatra/lib/rigor-sinatra.rb +3 -5
  418. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/absurd_recognizer.rb +23 -38
  419. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/assertion_recognizer.rb +57 -96
  420. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog.rb +22 -35
  421. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/catalog_walker.rb +41 -69
  422. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/method_signature.rb +6 -10
  423. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sig_parser.rb +24 -41
  424. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/sigil_detector.rb +29 -50
  425. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet/type_translator.rb +55 -88
  426. data/plugins/rigor-sorbet/lib/rigor/plugin/sorbet.rb +159 -262
  427. data/plugins/rigor-statesman/lib/rigor/plugin/statesman.rb +21 -29
  428. data/plugins/rigor-statesman/lib/rigor-statesman.rb +3 -5
  429. data/plugins/rigor-typescript-utility-types/lib/rigor/plugin/typescript_utility_types.rb +23 -37
  430. data/plugins/rigor-typescript-utility-types/lib/rigor-typescript-utility-types.rb +4 -6
  431. data/sig/rigor/environment.rbs +1 -0
  432. data/sig/rigor/scope.rbs +6 -0
  433. metadata +9 -1
@@ -12,51 +12,41 @@ module Rigor
12
12
  # [Rails plugins roadmap](../../../../../docs/design/20260508-rails-plugins-roadmap.md)
13
13
  # § "3D".
14
14
  #
15
- # Recognises `class T < GraphQL::Schema::Object` subclasses
16
- # and walks every `field :name, Type, null: false` declaration
17
- # inside, publishing the resulting field-type map as the
18
- # `:graphql_type_table` cross-plugin fact (ADR-9). The macro
19
- # expansion library survey at
20
- # [docs/notes/20260515-macro-expansion-library-survey.md](../../../../../docs/notes/20260515-macro-expansion-library-survey.md)
21
- # § "GraphQL-Ruby" documents WHY this is a pure metadata-recorder
22
- # plugin rather than an ADR-16 substrate consumer: graphql-ruby's
23
- # `field` DSL emits NO Ruby methods (it just records a
24
- # `Schema::Field` on the class's `own_fields`). The user writes
25
- # resolver methods themselves; rigor's value here is producing a
26
- # static type table downstream consumers can cross-reference.
15
+ # Recognises `class T < GraphQL::Schema::Object` subclasses and walks every `field :name, Type,
16
+ # null: false` declaration inside, publishing the resulting field-type map as the
17
+ # `:graphql_type_table` cross-plugin fact (ADR-9). The macro expansion library survey at
18
+ # docs/notes/20260515-macro-expansion-library-survey.md § "GraphQL-Ruby" documents WHY this is a
19
+ # pure metadata-recorder plugin rather than an ADR-16
20
+ # substrate consumer: graphql-ruby's `field` DSL emits NO Ruby methods (it just records a
21
+ # `Schema::Field` on the class's `own_fields`). The user writes resolver methods themselves; rigor's
22
+ # value here is producing a static type table downstream consumers can cross-reference.
27
23
  #
28
24
  # ## What downstream consumers DO with the published facts
29
25
  #
30
- # The tables are the substrate for two future capabilities
31
- # (demand-driven, not yet implemented):
26
+ # The tables are the substrate for two future capabilities (demand-driven, not yet implemented):
32
27
  #
33
- # - Resolver-method check: for each `field :name, Type` whose
34
- # `name` is also defined as a Ruby method on the class, verify
35
- # the method's return type matches `Type`'s underlying class.
36
- # - Schema-query result typing: a future `rigor-graphql-execute`
37
- # plugin could type `Schema.execute(query).to_h` against the
38
- # queried fields.
28
+ # - Resolver-method check: for each `field :name, Type` whose `name` is also defined as a Ruby method
29
+ # on the class, verify the method's return type matches `Type`'s underlying class.
30
+ # - Schema-query result typing: a future `rigor-graphql-execute` plugin could type
31
+ # `Schema.execute(query).to_h` against the queried fields.
39
32
  #
40
33
  # ## What's recognised
41
34
  #
42
- # - `class T < GraphQL::Schema::Object` subclasses (including
43
- # nested namespaces); `field :name, Type, null: ...`
44
- # declarations with constant-reference or list-array types
45
- # and GraphQL→Ruby scalar mapping.
35
+ # - `class T < GraphQL::Schema::Object` subclasses (including nested namespaces); `field :name, Type,
36
+ # null: ...` declarations with constant-reference or list-array types and GraphQL→Ruby scalar
37
+ # mapping.
46
38
  # - `class T < GraphQL::Schema::Enum`; `value "ACTIVE"` calls.
47
- # - `class T < GraphQL::Schema::InputObject` /
48
- # `GraphQL::Schema::Mutation`; `argument :name, Type,
39
+ # - `class T < GraphQL::Schema::InputObject` / `GraphQL::Schema::Mutation`; `argument :name, Type,
49
40
  # required: ...` declarations.
50
41
  # - No user-facing diagnostics yet.
51
42
  #
52
43
  # ## Deferred (demand-driven)
53
44
  #
54
45
  # - **`resolver:` / `mutation:` reroute** recognition.
55
- # - **String type expressions** (`field :foo, "User"`) — defeats
56
- # static resolution by design (graphql-ruby's `BuildType.parse_type`
57
- # constantizes at runtime); a future slice could surface these
58
- # as `graphql.string-type` `:info` diagnostics pointing the
59
- # user at the constant-reference form for static typing.
46
+ # - **String type expressions** (`field :foo, "User"`) — defeats static resolution by design
47
+ # (graphql-ruby's `BuildType.parse_type` constantizes at runtime); a future slice could surface
48
+ # these as `graphql.string-type` `:info` diagnostics pointing the user at the constant-reference
49
+ # form for static typing.
60
50
  class Graphql < Rigor::Plugin::Base
61
51
  manifest(
62
52
  id: "graphql",
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Gem entry point. Required by Rigor's plugin loader when
4
- # `.rigor.yml` lists `rigor-graphql` under `plugins:`. The
5
- # loader expects this `require` to side-effect a call to
6
- # `Rigor::Plugin.register`, which the body of
7
- # `lib/rigor/plugin/graphql.rb` performs at load time.
3
+ # Gem entry point. Required by Rigor's plugin loader when `.rigor.yml` lists `rigor-graphql` 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/graphql.rb` performs at load time.
8
6
  require_relative "rigor/plugin/graphql"
@@ -5,16 +5,12 @@ require "prism"
5
5
  module Rigor
6
6
  module Plugin
7
7
  class Hanami < Rigor::Plugin::Base
8
- # Checks the "presence" half of the Hanami::Action
9
- # ADR-28 protocol contract.
8
+ # Checks the "presence" half of the Hanami::Action ADR-28 protocol contract.
10
9
  #
11
- # Every class defined in a file matching a contract's
12
- # `path_glob` must declare `#handle(request, response)`.
13
- # The "provide" halfbinding `Hanami::Action::Request`
14
- # and `Hanami::Action::Response` into the method body
15
- # is handled engine-side by
16
- # `Inference::MethodParameterBinder`. Return type is
17
- # void so no conformance check is performed here.
10
+ # Every class defined in a file matching a contract's `path_glob` must declare `#handle(request,
11
+ # response)`. The "provide" half — binding `Hanami::Action::Request` and `Hanami::Action::Response`
12
+ # into the method body is handled engine-side by `Inference::MethodParameterBinder`. Return type
13
+ # is void so no conformance check is performed here.
18
14
  class ActionChecker
19
15
  FNMATCH_FLAGS = File::FNM_PATHNAME | File::FNM_EXTGLOB
20
16
 
@@ -22,11 +18,10 @@ module Rigor
22
18
  @contracts = contracts
23
19
  end
24
20
 
25
- # Per-`ClassNode` check over the engine-owned walk (ADR-37):
26
- # called once per class node the `node_rule` in `hanami.rb`
27
- # dispatches, against every contract whose `path_glob` matches
28
- # the file. No cross-class-node state is needed, so the checker
29
- # ships no `class_nodes` traversal of its own.
21
+ # Per-`ClassNode` check over the engine-owned walk (ADR-37): called once per class node the
22
+ # `node_rule` in `hanami.rb` dispatches, against every contract whose `path_glob` matches the
23
+ # file. No cross-class-node state is needed, so the checker ships no `class_nodes` traversal of
24
+ # its own.
30
25
  def check_class(class_node, path:)
31
26
  @contracts.filter_map do |contract|
32
27
  next unless path_matches?(contract.path_glob, path)
@@ -42,9 +37,8 @@ module Rigor
42
37
 
43
38
  private
44
39
 
45
- # Contract globs are project-root-relative; the analyzer
46
- # may supply a relative or absolute path, so the glob is
47
- # matched both directly and with a `**/`-prefixed suffix.
40
+ # Contract globs are project-root-relative; the analyzer may supply a relative or absolute path,
41
+ # so the glob is matched both directly and with a `**/`-prefixed suffix.
48
42
  def path_matches?(glob, path)
49
43
  return false if path.nil?
50
44
 
@@ -9,37 +9,28 @@ module Rigor
9
9
  module Plugin
10
10
  # rigor-hanami — enforces the Hanami::Action protocol.
11
11
  #
12
- # Hanami 3.x actions inherit from `Hanami::Action` and
13
- # define a single entry-point:
12
+ # Hanami 3.x actions inherit from `Hanami::Action` and define a single entry-point:
14
13
  #
15
14
  # def handle(request, response)
16
15
  # response.status = 200
17
16
  # response.body = "Hello"
18
17
  # end
19
18
  #
20
- # The method is void — the response is mutated in-place;
21
- # the return value is discarded by the framework.
19
+ # The method is void — the response is mutated in-place; the return value is discarded by the
20
+ # framework.
22
21
  #
23
- # This plugin uses the **ADR-28 path-scoped
24
- # method-protocol contract** to:
22
+ # This plugin uses the **ADR-28 path-scoped method-protocol contract** to:
25
23
  #
26
- # 1. **Provide** `Hanami::Action::Request` and
27
- # `Hanami::Action::Response` as the types of the
28
- # first and second parameters of every `#handle`
29
- # method defined inside `app/actions/**/*.rb`.
30
- # The engine substitutes these types for the usual
31
- # `Dynamic[Top]` fallback, so misuse of `request` or
32
- # `response` inside an action body surfaces as a
33
- # core diagnostic.
24
+ # 1. **Provide** `Hanami::Action::Request` and `Hanami::Action::Response` as the types of the first
25
+ # and second parameters of every `#handle` method defined inside `app/actions/**/*.rb`. The
26
+ # engine substitutes these types for the usual `Dynamic[Top]` fallback, so misuse of `request` or
27
+ # `response` inside an action body surfaces as a core diagnostic.
34
28
  #
35
- # 2. **Check** that every class under `app/actions/`
36
- # defines `#handle`. Missing definitions emit
29
+ # 2. **Check** that every class under `app/actions/` defines `#handle`. Missing definitions emit
37
30
  # `missing-handle-method`.
38
31
  #
39
- # Return-type conformance is NOT checked — Hanami
40
- # actions are void by contract, and checking a void
41
- # return would produce false positives on every `if`
42
- # branch that doesn't end with an explicit `nil`.
32
+ # Return-type conformance is NOT checked — Hanami actions are void by contract, and checking a void
33
+ # return would produce false positives on every `if` branch that doesn't end with an explicit `nil`.
43
34
  #
44
35
  # ## Configuration
45
36
  #
@@ -55,10 +46,8 @@ module Rigor
55
46
  # | action class defines no `#handle` | `:error` | `missing-handle-method` |
56
47
  # | `request` / `response` misuse in body | core engine diagnostic |
57
48
  #
58
- # A misused `request` or `response` (e.g.
59
- # `request.no_such_method`) surfaces as a standard
60
- # engine `call.undefined-method` diagnostic once the
61
- # plugin provides the parameter types.
49
+ # A misused `request` or `response` (e.g. `request.no_such_method`) surfaces as a standard engine
50
+ # `call.undefined-method` diagnostic once the plugin provides the parameter types.
62
51
  class Hanami < Rigor::Plugin::Base
63
52
  manifest(
64
53
  id: "hanami",
@@ -91,20 +80,17 @@ module Rigor
91
80
  end
92
81
  end
93
82
 
94
- # ADR-28: override so the per-project `action_path` config
95
- # reaches both the engine's parameter-provision tier and
96
- # this plugin's check half.
83
+ # ADR-28: override so the per-project `action_path` config reaches both the engine's
84
+ # parameter-provision tier and this plugin's check half.
97
85
  def protocol_contracts
98
86
  @protocol_contracts || manifest.protocol_contracts
99
87
  end
100
88
 
101
- # ADR-37 — per-class-node validation over the engine-owned walk.
102
- # Each `Prism::ClassNode` is checked against every contract
103
- # independently, so the plugin no longer ships its own `class_nodes`
104
- # traversal; `ActionChecker#check_class` keeps the per-class
105
- # contract logic. (A per-class contract check is exactly what
106
- # `node_rule` is for — the return type is void, so no `scope`
107
- # query is needed.)
89
+ # ADR-37 — per-class-node validation over the engine-owned walk. Each `Prism::ClassNode` is checked
90
+ # against every contract independently, so the plugin no longer ships its own `class_nodes`
91
+ # traversal; `ActionChecker#check_class` keeps the per-class contract logic. (A per-class contract
92
+ # check is exactly what `node_rule` is for — the return type is void, so no `scope` query is
93
+ # needed.)
108
94
  node_rule Prism::ClassNode do |node, _scope, path|
109
95
  contracts = protocol_contracts
110
96
  next [] if contracts.empty?
@@ -5,75 +5,54 @@ require "rigor/plugin"
5
5
 
6
6
  module Rigor
7
7
  module Plugin
8
- # rigor-mangrove — precision plugin for the
9
- # [Mangrove](https://github.com/kazzix14/mangrove) functional
8
+ # rigor-mangrove — precision plugin for the [Mangrove](https://github.com/kazzix14/mangrove) functional
10
9
  # toolkit (Result / Option carriers).
11
10
  #
12
11
  # ## Why this plugin exists (and what it deliberately is NOT)
13
12
  #
14
- # Mangrove is a Sorbet-first library: every carrier method is
15
- # annotated with an inline `sig { ... }`, and the Enum DSL's
16
- # dynamic variants are materialised by a bundled Tapioca DSL
17
- # compiler. So the *type source* for Mangrove is already
18
- # covered by `rigor-sorbet` (sig ingestion + RBI walking) —
19
- # this plugin is NOT a parallel type source. See
20
- # `docs/notes/20260530-mangrove-library-survey.md`.
13
+ # Mangrove is a Sorbet-first library: every carrier method is annotated with an inline `sig { ... }`, and
14
+ # the Enum DSL's dynamic variants are materialised by a bundled Tapioca DSL compiler. So the *type source*
15
+ # for Mangrove is already covered by `rigor-sorbet` (sig ingestion + RBI walking) — this plugin is NOT a
16
+ # parallel type source. See `docs/notes/20260530-mangrove-library-survey.md`.
21
17
  #
22
- # What sig-ingestion (Sorbet-level precision) structurally
23
- # cannot do is **instantiate the carrier's generic
24
- # type-member at the unwrap call site**. Mangrove's `Result`
25
- # interface declares:
18
+ # What sig-ingestion (Sorbet-level precision) structurally cannot do is **instantiate the carrier's generic
19
+ # type-member at the unwrap call site**. Mangrove's `Result` interface declares:
26
20
  #
27
21
  # sig { abstract.returns(OkType) }
28
22
  # def unwrap!; end
29
23
  #
30
- # `OkType` is a `type_member(:out)`. When the receiver's
31
- # static type is `Mangrove::Result[String, StandardError]`,
32
- # `unwrap!` *should* yield `String` but resolving the
33
- # abstract `OkType` to the receiver's first type argument is
34
- # generic instantiation, which neither `rigor-sorbet` (it
35
- # contributes the cataloged sig's return type verbatim) nor a
36
- # bare-`def unwrap!: () -> untyped` RBS stub performs. The
37
- # call degrades to `Dynamic[top]`.
24
+ # `OkType` is a `type_member(:out)`. When the receiver's static type is
25
+ # `Mangrove::Result[String, StandardError]`, `unwrap!` *should* yield `String` — but resolving the abstract
26
+ # `OkType` to the receiver's first type argument is generic instantiation, which neither `rigor-sorbet` (it
27
+ # contributes the cataloged sig's return type verbatim) nor a bare-`def unwrap!: () -> untyped` RBS stub
28
+ # performs. The call degrades to `Dynamic[top]`.
38
29
  #
39
- # This plugin closes exactly that gap. At every recognised
40
- # unwrap-family call on a known Mangrove carrier, it reads the
41
- # receiver's `Rigor::Type::Nominal#type_args` and contributes
42
- # the first argument (the `OkType` / `InnerType`) as the
43
- # call's return type. The receiver type is already known, so
44
- # this only ever *sharpens* an existing `Dynamic[top]` into a
45
- # concrete type — it never invents a receiver type and never
46
- # emits a diagnostic of its own, so it cannot frighten working
47
- # code (Rigor's false-positive discipline).
30
+ # This plugin closes exactly that gap. At every recognised unwrap-family call on a known Mangrove carrier,
31
+ # it reads the receiver's `Rigor::Type::Nominal#type_args` and contributes the first argument (the
32
+ # `OkType` / `InnerType`) as the call's return type. The receiver type is already known, so this only ever
33
+ # *sharpens* an existing `Dynamic[top]` into a concrete type — it never invents a receiver type and never
34
+ # emits a diagnostic of its own, so it cannot frighten working code (Rigor's false-positive discipline).
48
35
  #
49
36
  # ## Scope (slice 1)
50
37
  #
51
- # - Result unwrap family → `OkType` (`type_args[0]`):
52
- # `unwrap!`, `unwrap_in`, `expect!`, `expect_with!`,
53
- # `unwrap_or_raise!`, `unwrap_or_raise_with!`,
54
- # `unwrap_or_raise_inner!`.
55
- # - Option unwrap family → `InnerType` (`type_args[0]`):
56
- # `unwrap`, `unwrap!`, `unwrap_or`, `expect!`,
38
+ # - Result unwrap family → `OkType` (`type_args[0]`): `unwrap!`, `unwrap_in`, `expect!`, `expect_with!`,
39
+ # `unwrap_or_raise!`, `unwrap_or_raise_with!`, `unwrap_or_raise_inner!`.
40
+ # - Option unwrap family → `InnerType` (`type_args[0]`): `unwrap`, `unwrap!`, `unwrap_or`, `expect!`,
57
41
  # `expect_with!`.
58
42
  #
59
- # The contribution fires only when the receiver resolves to a
60
- # carrier Nominal carrying a non-empty `type_args` — i.e. when
61
- # the Result/Option came from a method whose declared return
62
- # type is an applied generic (`-> Result[String, E]`), the
63
- # realistic Mangrove shape. The bare-constructor shape
64
- # (`Result::Ok.new("x")`) currently yields a raw Nominal with
65
- # no `type_args` (the engine does not infer generics from
66
- # constructor arguments), so the plugin no-ops there rather
67
- # than guessing — a conservative floor, not a regression.
43
+ # The contribution fires only when the receiver resolves to a carrier Nominal carrying a non-empty
44
+ # `type_args` — i.e. when the Result/Option came from a method whose declared return type is an applied
45
+ # generic (`-> Result[String, E]`), the realistic Mangrove shape. The bare-constructor shape
46
+ # (`Result::Ok.new("x")`) currently yields a raw Nominal with no `type_args` (the engine does not infer
47
+ # generics from constructor arguments), so the plugin no-ops there rather than guessing — a conservative
48
+ # floor, not a regression.
68
49
  #
69
50
  # ## Out of scope (tracked elsewhere)
70
51
  #
71
- # - `is_a?(Result::Ok)` / `Some` / `None` exhaustive
72
- # narrowing — core control-flow analysis over a sealed
52
+ # - `is_a?(Result::Ok)` / `Some` / `None` exhaustive narrowing — core control-flow analysis over a sealed
73
53
  # hierarchy, not a plugin surface.
74
- # - The `variants do variant Const, Type end` Enum DSL is handled
75
- # via ADR-36 `nested_class_templates:` in this plugin's manifest
76
- # (Slice A — see `nested_class_templates:` block below).
54
+ # - The `variants do variant Const, Type end` Enum DSL is handled via ADR-36 `nested_class_templates:` in
55
+ # this plugin's manifest (Slice A — see `nested_class_templates:` block below).
77
56
  class Mangrove < Rigor::Plugin::Base
78
57
  manifest(
79
58
  id: "mangrove",
@@ -90,10 +69,9 @@ module Rigor
90
69
  # end
91
70
  # end
92
71
  #
93
- # mints `Shape::Circle < Shape` with `#inner : Float`. The
94
- # substrate resolves the variant constant + its `#inner`
95
- # reader statically so `Shape::Circle.new(1.0).inner`
96
- # types as `Float` without running Mangrove's `const_missing`.
72
+ # mints `Shape::Circle < Shape` with `#inner : Float`. The substrate resolves the variant constant +
73
+ # its `#inner` reader statically so `Shape::Circle.new(1.0).inner` types as `Float` without running
74
+ # Mangrove's `const_missing`.
97
75
  nested_class_templates: [
98
76
  Rigor::Plugin::Macro::NestedClassTemplate.new(
99
77
  receiver_constraint: "Mangrove::Enum",
@@ -106,11 +84,9 @@ module Rigor
106
84
  ]
107
85
  )
108
86
 
109
- # Carrier class names whose FIRST type argument is the
110
- # value the unwrap family yields (`OkType` for Result,
111
- # `InnerType` for Option). Matched with and without a
112
- # leading `::` because `scope.type_of` reports the lexical
113
- # form while user code may root the constant.
87
+ # Carrier class names whose FIRST type argument is the value the unwrap family yields (`OkType` for
88
+ # Result, `InnerType` for Option). Matched with and without a leading `::` because `scope.type_of`
89
+ # reports the lexical form while user code may root the constant.
114
90
  RESULT_CARRIERS = [
115
91
  "Mangrove::Result",
116
92
  "Mangrove::Result::Ok",
@@ -123,23 +99,19 @@ module Rigor
123
99
  "Mangrove::Option::None"
124
100
  ].freeze
125
101
 
126
- # Methods on the Result carriers that return `OkType`
127
- # (`type_args[0]`). All of these are documented as yielding
128
- # the success value, raising / short-circuiting on `Err`.
102
+ # Methods on the Result carriers that return `OkType` (`type_args[0]`). All of these are documented as
103
+ # yielding the success value, raising / short-circuiting on `Err`.
129
104
  RESULT_UNWRAP_METHODS = %i[
130
105
  unwrap! unwrap_in expect! expect_with!
131
106
  unwrap_or_raise! unwrap_or_raise_with! unwrap_or_raise_inner!
132
107
  ].freeze
133
108
 
134
- # Methods on the Option carriers that return `InnerType`
135
- # (`type_args[0]`).
109
+ # Methods on the Option carriers that return `InnerType` (`type_args[0]`).
136
110
  OPTION_UNWRAP_METHODS = %i[unwrap unwrap! unwrap_or expect! expect_with!].freeze
137
111
 
138
- # ADR-37 slice 2 — a pure return-type contributor. The engine
139
- # gates on the receiver being a known carrier class (so the block
140
- # only runs on Result/Option receivers); the block then confirms
141
- # the call is an unwrap method on an instantiated carrier and
142
- # yields the carried `type_args[0]`.
112
+ # ADR-37 slice 2 — a pure return-type contributor. The engine gates on the receiver being a known
113
+ # carrier class (so the block only runs on Result/Option receivers); the block then confirms the call
114
+ # is an unwrap method on an instantiated carrier and yields the carried `type_args[0]`.
143
115
  dynamic_return receivers: (RESULT_CARRIERS + OPTION_CARRIERS) do |call_node, scope|
144
116
  receiver = call_node.receiver
145
117
  next nil if receiver.nil?
@@ -152,18 +124,16 @@ module Rigor
152
124
 
153
125
  private
154
126
 
155
- # @return [Rigor::Type, nil] the receiver's inferred type, or
156
- # nil when the engine raises on a synthetic / unrecognised
157
- # node (mirrors rigor-sorbet's defensive degrade).
127
+ # @return [Rigor::Type, nil] the receiver's inferred type, or nil when the engine raises on a synthetic
128
+ # / unrecognised node (mirrors rigor-sorbet's defensive degrade).
158
129
  def receiver_type_of(receiver, scope)
159
130
  scope.type_of(receiver)
160
131
  rescue StandardError
161
132
  nil
162
133
  end
163
134
 
164
- # The value the unwrap family yields for this receiver, or
165
- # nil when the call is not an unwrap on a known carrier, or
166
- # the carrier is raw (no `type_args` to instantiate).
135
+ # The value the unwrap family yields for this receiver, or nil when the call is not an unwrap on a
136
+ # known carrier, or the carrier is raw (no `type_args` to instantiate).
167
137
  def carried_type(receiver_type, method_name)
168
138
  class_name = normalize(receiver_type.class_name)
169
139
  type_args = receiver_type.type_args
@@ -8,9 +8,8 @@ require "rigor/flow_contribution/fact"
8
8
  module Rigor
9
9
  module Plugin
10
10
  class Minitest < Rigor::Plugin::Base
11
- # Recognises the four shapes of Minitest / Test::Unit
12
- # assertions and emits a `post_return_fact` that narrows
13
- # the named local on the post-call edge.
11
+ # Recognises the four shapes of Minitest / Test::Unit assertions and emits a `post_return_fact` that
12
+ # narrows the named local on the post-call edge.
14
13
  #
15
14
  # ## Recognised call shapes
16
15
  #
@@ -29,9 +28,8 @@ module Rigor
29
28
  # refute_nil(x) → narrow x AWAY from nil
30
29
  # refute_equal(literal, x) → narrow x AWAY from Constant<literal>
31
30
  #
32
- # Test::Unit's `assert_not_nil(x)` / `assert_not_equal(...)` /
33
- # `assert_not_kind_of(...)` / `assert_not_instance_of(...)`
34
- # share the recognizer with `refute_*` (they're aliases).
31
+ # Test::Unit's `assert_not_nil(x)` / `assert_not_equal(...)` / `assert_not_kind_of(...)` /
32
+ # `assert_not_instance_of(...)` share the recognizer with `refute_*` (they're aliases).
35
33
  #
36
34
  # ### (3) Minitest/spec `_(x).must_*` (positive) ###
37
35
  #
@@ -41,12 +39,10 @@ module Rigor
41
39
  # _(x).must_equal(literal) → narrow x to Constant<literal>
42
40
  # _(x).must_match(regex) → narrow x to String
43
41
  #
44
- # The legacy bare `x.must_be_kind_of(T)` form (Minitest <
45
- # 6.0 monkey-patched onto Object) is intentionally NOT
46
- # recognised the receiver is the value itself rather
47
- # than a wrapping `_(value)`, so the analyzer has nothing
48
- # to narrow against. Users who still rely on the legacy
49
- # form should migrate to `_(x).must_*`.
42
+ # The legacy bare `x.must_be_kind_of(T)` form (Minitest < 6.0 monkey-patched onto Object) is
43
+ # intentionally NOT recognised the receiver is the value itself rather than a wrapping `_(value)`,
44
+ # so the analyzer has nothing to narrow against. Users who still rely on the legacy form should
45
+ # migrate to `_(x).must_*`.
50
46
  #
51
47
  # ### (4) Minitest/spec `_(x).wont_*` (negative) ###
52
48
  #
@@ -56,14 +52,10 @@ module Rigor
56
52
  #
57
53
  # ## Not yet recognised
58
54
  #
59
- # `assert_predicate(x, :foo?)` (custom predicate) /
60
- # `assert_respond_to(x, :method)` / `assert_includes` /
61
- # `assert_operator` / `assert_throws` /
62
- # `assert_raises(T) { ... }` etc. each either needs a
63
- # carrier Rigor doesn't model today (predicate-state,
64
- # respond-to-set) or a multi-edge fact that the
65
- # `post_return_facts` slot can't express. Queued for
66
- # follow-up slices.
55
+ # `assert_predicate(x, :foo?)` (custom predicate) / `assert_respond_to(x, :method)` / `assert_includes`
56
+ # / `assert_operator` / `assert_throws` / `assert_raises(T) { ... }` etc. — each either needs a
57
+ # carrier Rigor doesn't model today (predicate-state, respond-to-set) or a multi-edge fact that the
58
+ # `post_return_facts` slot can't express. Queued for follow-up slices.
67
59
  module AssertionAnalyzer
68
60
  module_function
69
61
 
@@ -83,16 +75,12 @@ module Rigor
83
75
 
84
76
  # --- assert_* / refute_* / assert_not_* form ---
85
77
 
86
- # Maps each recognised assertion name to a tuple
87
- # `[shape, negative]`. `shape` is one of:
78
+ # Maps each recognised assertion name to a tuple `[shape, negative]`. `shape` is one of:
88
79
  #
89
- # - :class_then_local — `assert_kind_of(T, x)`, T at
90
- # args[0], local at args[1].
80
+ # - :class_then_local — `assert_kind_of(T, x)`, T at args[0], local at args[1].
91
81
  # - :nil_local — `assert_nil(x)`, local at args[0].
92
- # - :literal_then_local — `assert_equal(literal, x)`,
93
- # literal at args[0], local at args[1].
94
- # - :regex_then_local — `assert_match(regex, x)`,
95
- # regex at args[0], local at args[1].
82
+ # - :literal_then_local — `assert_equal(literal, x)`, literal at args[0], local at args[1].
83
+ # - :regex_then_local `assert_match(regex, x)`, regex at args[0], local at args[1].
96
84
  ASSERT_FORM = {
97
85
  assert_kind_of: [:class_then_local, false],
98
86
  assert_instance_of: [:class_then_local, false],
@@ -123,8 +111,7 @@ module Rigor
123
111
 
124
112
  # --- _(x).must_* / .wont_* form ---
125
113
 
126
- # Maps the spec-style matcher names to `[shape,
127
- # negative]`. `shape`:
114
+ # Maps the spec-style matcher names to `[shape, negative]`. `shape`:
128
115
  # - :class_arg — `_(x).must_be_kind_of(T)`, T at args[0].
129
116
  # - :no_arg_nil — `_(x).must_be_nil`, no args.
130
117
  # - :literal_arg — `_(x).must_equal(literal)`, literal at args[0].
@@ -144,8 +131,8 @@ module Rigor
144
131
  }.freeze
145
132
  private_constant :SPEC_MATCHER_FORM
146
133
 
147
- # ADR-37 slice 2 — the method names this analyzer narrows on,
148
- # for the plugin's `narrowing_facts methods:` gate.
134
+ # ADR-37 slice 2 — the method names this analyzer narrows on, for the plugin's
135
+ # `narrowing_facts methods:` gate.
149
136
  SUPPORTED_METHODS = (ASSERT_FORM.keys + SPEC_MATCHER_FORM.keys).freeze
150
137
 
151
138
  def spec_form_fact(call_node, environment:)
@@ -160,10 +147,9 @@ module Rigor
160
147
  fact_for_spec_shape(shape, target_local, args, negative: negative, environment: environment)
161
148
  end
162
149
 
163
- # `_(x)` returns a `Minitest::Expectation` wrapping x.
164
- # Some specs use `value(x)` or `expect(x)` interchangeably
165
- # (Minitest provides all three as aliases). Recognises the
166
- # local-variable arg in any of those receiver-call shapes.
150
+ # `_(x)` returns a `Minitest::Expectation` wrapping x. Some specs use `value(x)` or `expect(x)`
151
+ # interchangeably (Minitest provides all three as aliases). Recognises the local-variable arg in
152
+ # any of those receiver-call shapes.
167
153
  SPEC_WRAPPER_NAMES = %i[_ value expect].freeze
168
154
  private_constant :SPEC_WRAPPER_NAMES
169
155