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
@@ -6,16 +6,13 @@ require "rigor/source/literals"
6
6
  module Rigor
7
7
  module Plugin
8
8
  class DrySchema < Rigor::Plugin::Base
9
- # Walks project source for `Foo = Dry::Schema.{Params,JSON,define}
10
- # { ... }` shapes and emits a
11
- # `{schema_const_fqn => {required: {key => underlying_class}, optional: {…}}}`
12
- # table covering each schema's typed-key surface.
9
+ # Walks project source for `Foo = Dry::Schema.{Params,JSON,define} { ... }` shapes and emits a
10
+ # `{schema_const_fqn => {required: {key => underlying_class}, optional: {…}}}` table covering each
11
+ # schema's typed-key surface.
13
12
  module SchemaScanner
14
- # The dry-schema canonical-type symbols accepted as
15
- # predicate arguments. Maps each to the underlying Ruby
16
- # class name (the same vocabulary `rigor-dry-types`
17
- # uses for `CANONICAL_ALIASES`, intersected with what
18
- # dry-schema's predicate engine accepts).
13
+ # The dry-schema canonical-type symbols accepted as predicate arguments. Maps each to the
14
+ # underlying Ruby class name (the same vocabulary `rigor-dry-types` uses for `CANONICAL_ALIASES`,
15
+ # intersected with what dry-schema's predicate engine accepts).
19
16
  CANONICAL_TYPES = {
20
17
  string: "String",
21
18
  integer: "Integer",
@@ -30,12 +27,10 @@ module Rigor
30
27
  array: "Array"
31
28
  }.tap { |h| h[:nil] = "NilClass" }.freeze
32
29
 
33
- # The dry-schema predicate verbs that accept a type
34
- # argument. Each verb has a slightly different runtime
35
- # semantic (`filled` = present + non-empty; `value` =
36
- # present; `maybe` = present-or-nil; `each` = collection
37
- # element type) but for Rigor's purposes they all
38
- # contribute the same underlying class for the key.
30
+ # The dry-schema predicate verbs that accept a type argument. Each verb has a slightly different
31
+ # runtime semantic (`filled` = present + non-empty; `value` = present; `maybe` = present-or-nil;
32
+ # `each` = collection element type) but for Rigor's purposes they all contribute the same
33
+ # underlying class for the key.
39
34
  TYPE_BEARING_PREDICATES = %i[filled value maybe each].to_set.freeze
40
35
  private_constant :TYPE_BEARING_PREDICATES
41
36
 
@@ -45,17 +40,12 @@ module Rigor
45
40
 
46
41
  module_function
47
42
 
48
- # @param paths [Array<String>] absolute paths to `.rb`
49
- # files the project's `paths:` resolves to.
50
- # @param type_aliases [Hash{String => String}] the
51
- # ADR-9 `:dry_type_aliases` fact published by
52
- # `rigor-dry-types` when loaded. Used to resolve
53
- # `value(Types::Email)` references to their
54
- # underlying class. Empty when the plugin isn't
55
- # loaded.
56
- # @return [Hash{String => Hash{Symbol => Hash{Symbol => String}}}]
57
- # frozen per-schema typed-key table. Empty when no
58
- # recognisable schema declaration is found.
43
+ # @param paths [Array<String>] absolute paths to `.rb` files the project's `paths:` resolves to.
44
+ # @param type_aliases [Hash{String => String}] the ADR-9 `:dry_type_aliases` fact published by
45
+ # `rigor-dry-types` when loaded. Used to resolve `value(Types::Email)` references to their
46
+ # underlying class. Empty when the plugin isn't loaded.
47
+ # @return [Hash{String => Hash{Symbol => Hash{Symbol => String}}}] frozen per-schema typed-key
48
+ # table. Empty when no recognisable schema declaration is found.
59
49
  def scan(paths:, type_aliases: {})
60
50
  table = {}
61
51
  paths.each do |path|
@@ -77,11 +67,9 @@ module Rigor
77
67
  end
78
68
  private_class_method :scan_file
79
69
 
80
- # Walks the AST collecting `<Const> = Dry::Schema.X { ... }`
81
- # assignments at any nesting level. Tracks the enclosing
82
- # constant chain so a class-level `class Foo; SCHEMA =
83
- # Dry::Schema.Params { ... }; end` registers as
84
- # `"Foo::SCHEMA"`.
70
+ # Walks the AST collecting `<Const> = Dry::Schema.X { ... }` assignments at any nesting level.
71
+ # Tracks the enclosing constant chain so a class-level `class Foo; SCHEMA = Dry::Schema.Params
72
+ # { ... }; end` registers as `"Foo::SCHEMA"`.
85
73
  def collect_schemas(node, qualified_prefix, type_aliases)
86
74
  return {} if node.nil?
87
75
 
@@ -119,8 +107,7 @@ module Rigor
119
107
  end
120
108
  private_class_method :collect_schema_assignment
121
109
 
122
- # Matches `Dry::Schema.Params { ... }` /
123
- # `Dry::Schema.JSON { ... }` / `Dry::Schema.define { ... }`.
110
+ # Matches `Dry::Schema.Params { ... }` / `Dry::Schema.JSON { ... }` / `Dry::Schema.define { ... }`.
124
111
  def schema_entry_call?(node)
125
112
  return false unless node.is_a?(Prism::CallNode)
126
113
  return false unless SCHEMA_ENTRY_NAMES.include?(node.name)
@@ -147,10 +134,9 @@ module Rigor
147
134
  end
148
135
  private_class_method :collect_schema_shape
149
136
 
150
- # Walks every top-level `required(:key).<predicate>(...)` /
151
- # `optional(:key).<predicate>(...)` chain in the block
152
- # body. The block's body is either a `Prism::StatementsNode`
153
- # (multi-statement) or a single expression node.
137
+ # Walks every top-level `required(:key).<predicate>(...)` / `optional(:key).<predicate>(...)`
138
+ # chain in the block body. The block's body is either a `Prism::StatementsNode` (multi-statement)
139
+ # or a single expression node.
154
140
  def walk_block_body(block_node, &)
155
141
  body = block_node.body
156
142
  return if body.nil?
@@ -160,13 +146,10 @@ module Rigor
160
146
  end
161
147
  private_class_method :walk_block_body
162
148
 
163
- # `required(:key).filled(:string)` parses as a CallNode
164
- # whose receiver is the `required(:key)` call. Walk the
165
- # chain inward looking for the type-bearing predicate at
166
- # the head; the key sits on the chain's tail. The
167
- # `each(<Type>)` predicate yields a list-of-element
168
- # type info (`{type: <T>, list: true}`); other type-bearing
169
- # predicates (`filled`/`value`/`maybe`) yield scalar info
149
+ # `required(:key).filled(:string)` parses as a CallNode whose receiver is the `required(:key)`
150
+ # call. Walk the chain inward looking for the type-bearing predicate at the head; the key sits on
151
+ # the chain's tail. The `each(<Type>)` predicate yields a list-of-element type info (`{type: <T>,
152
+ # list: true}`); other type-bearing predicates (`filled`/`value`/`maybe`) yield scalar info
170
153
  # (`{type: <T>, list: false}`).
171
154
  def visit_chain(node, &block)
172
155
  return unless node.is_a?(Prism::CallNode)
@@ -179,11 +162,9 @@ module Rigor
179
162
  end
180
163
  private_class_method :visit_chain
181
164
 
182
- # `required(:key).filled(:string).value(...)...` — the
183
- # OUTERMOST call's receiver chain ends in the
184
- # `required(:key)` / `optional(:key)` call. Recurse on
185
- # `node.receiver` until we hit the `required` /
186
- # `optional` call, recording the key + kind.
165
+ # `required(:key).filled(:string).value(...)...` — the OUTERMOST call's receiver chain ends in
166
+ # the `required(:key)` / `optional(:key)` call. Recurse on `node.receiver` until we hit the
167
+ # `required` / `optional` call, recording the key + kind.
187
168
  def extract_key_and_kind(node)
188
169
  current = node
189
170
  while current.is_a?(Prism::CallNode)
@@ -199,11 +180,9 @@ module Rigor
199
180
  end
200
181
  private_class_method :extract_key_and_kind
201
182
 
202
- # Walks the call chain finding the first type-bearing
203
- # predicate (`filled` / `value` / `maybe` / `each`) and
204
- # extracts its argument type. Returns a `{type:, list:}`
205
- # tuple (`each` is the only verb that produces a list)
206
- # or nil when no recognisable type sits on the chain.
183
+ # Walks the call chain finding the first type-bearing predicate (`filled` / `value` / `maybe` /
184
+ # `each`) and extracts its argument type. Returns a `{type:, list:}` tuple (`each` is the only
185
+ # verb that produces a list) or nil when no recognisable type sits on the chain.
207
186
  def walk_predicate_chain(node)
208
187
  current = node
209
188
  while current.is_a?(Prism::CallNode)
@@ -217,12 +196,10 @@ module Rigor
217
196
  end
218
197
  private_class_method :walk_predicate_chain
219
198
 
220
- # Reads the first positional argument of a `filled(:string)`
221
- # / `value(:integer)` / `maybe(Types::Email)` call. Returns
222
- # either the canonical-type-symbol's underlying class
223
- # ("String" / "Integer" / …), or the constant's qualified
224
- # name for downstream type-alias resolution. Returns nil
225
- # for anything else.
199
+ # Reads the first positional argument of a `filled(:string)` / `value(:integer)` /
200
+ # `maybe(Types::Email)` call. Returns either the canonical-type-symbol's underlying class
201
+ # ("String" / "Integer" / …), or the constant's qualified name for downstream type-alias
202
+ # resolution. Returns nil for anything else.
226
203
  def extract_type_from_predicate(call_node)
227
204
  arg = call_node.arguments&.arguments&.first
228
205
  case arg
@@ -236,12 +213,10 @@ module Rigor
236
213
  end
237
214
  private_class_method :extract_type_from_predicate
238
215
 
239
- # In-place: any value's `type:` slot in `bucket` that
240
- # doesn't already match a canonical class (e.g.
241
- # `"Types::Email"`) gets resolved through the
242
- # type_aliases fact. Unresolvable values drop from the
243
- # bucket (no fact contribution rather than misleading
244
- # data). The `list:` slot rides along unchanged.
216
+ # In-place: any value's `type:` slot in `bucket` that doesn't already match a canonical class
217
+ # (e.g. `"Types::Email"`) gets resolved through the type_aliases fact. Unresolvable values drop
218
+ # from the bucket (no fact contribution rather than misleading data). The `list:` slot rides along
219
+ # unchanged.
245
220
  def remap_aliases!(bucket, type_aliases)
246
221
  canonical_set = CANONICAL_TYPES.values.to_set
247
222
  bucket.each_pair.to_a.each do |key, info|
@@ -258,9 +233,8 @@ module Rigor
258
233
  end
259
234
  private_class_method :remap_aliases!
260
235
 
261
- # Constant-path serialiser: `Dry::Schema` -> "Dry::Schema",
262
- # bare `Foo` -> "Foo". Returns nil for shapes Prism
263
- # doesn't expose as ConstantRead/PathNode.
236
+ # Constant-path serialiser: `Dry::Schema` -> "Dry::Schema", bare `Foo` -> "Foo". Returns nil for
237
+ # shapes Prism doesn't expose as ConstantRead/PathNode.
264
238
  def constant_name_for(node)
265
239
  return nil if node.nil?
266
240
 
@@ -10,7 +10,8 @@ module Rigor
10
10
  module Plugin
11
11
  # rigor-dry-schema — Tier A per
12
12
  # [ADR-12](../../../../../docs/adr/12-dry-rb-packaging.md) and the
13
- # slicing plan in [docs/design/20260517-dry-validation-slicing.md](../../../../../docs/design/20260517-dry-validation-slicing.md).
13
+ # slicing plan in
14
+ # [docs/design/20260517-dry-validation-slicing.md](../../../../../docs/design/20260517-dry-validation-slicing.md).
14
15
  #
15
16
  # Recognises the canonical dry-schema declaration shapes:
16
17
  #
@@ -28,51 +29,42 @@ module Rigor
28
29
  # required(:foo).value(:string)
29
30
  # end
30
31
  #
31
- # and publishes the resulting
32
- # `{schema_const_fqn => {required: {key => underlying_class}, optional: {…}}}`
33
- # table as the `:dry_schema_table` cross-plugin fact (ADR-9).
34
- # Downstream `rigor-dry-validation` consumes the fact for
35
- # per-Contract typed-payload synthesis.
32
+ # and publishes the resulting `{schema_const_fqn => {required: {key => underlying_class}, optional:
33
+ # {…}}}` table as the `:dry_schema_table` cross-plugin fact (ADR-9). Downstream `rigor-dry-validation`
34
+ # consumes the fact for per-Contract typed-payload synthesis.
36
35
  #
37
36
  # ## Predicate type recognition
38
37
  #
39
- # Each `required(:key).<predicate>(<arg>)` row maps the predicate
40
- # argument to an underlying Ruby class via the dry-schema
41
- # canonical-type vocabulary:
38
+ # Each `required(:key).<predicate>(<arg>)` row maps the predicate argument to an underlying Ruby
39
+ # class via the dry-schema canonical-type vocabulary:
42
40
  #
43
- # - `:string` / `:integer` / `:float` / `:decimal` / `:symbol` /
44
- # `:bool` / `:nil` / `:date` / `:date_time` / `:time` / `:hash`
45
- # / `:array` map to their underlying class.
46
- # - The four predicate verbs `filled` / `value` / `maybe` /
47
- # `each` are accepted on the same row; their semantic
48
- # difference (whether the value is nullable or coerced) does
49
- # not change the underlying class for Rigor's purposes.
50
- # - References to dry-types aliases (`value(Types::Email)`,
51
- # `filled(Types::String)`) resolve through the
52
- # `:dry_type_aliases` ADR-9 fact published by `rigor-dry-types`
53
- # when that plugin is loaded; without it the row degrades to
54
- # "no type contribution from this key".
41
+ # - `:string` / `:integer` / `:float` / `:decimal` / `:symbol` / `:bool` / `:nil` / `:date` /
42
+ # `:date_time` / `:time` / `:hash` / `:array` map to their underlying class.
43
+ # - The four predicate verbs `filled` / `value` / `maybe` / `each` are accepted on the same row; their
44
+ # semantic difference (whether the value is nullable or coerced) does not change the underlying
45
+ # class for Rigor's purposes.
46
+ # - References to dry-types aliases (`value(Types::Email)`, `filled(Types::String)`) resolve through
47
+ # the `:dry_type_aliases` ADR-9 fact published by `rigor-dry-types` when that plugin is loaded;
48
+ # without it the row degrades to "no type contribution from this key".
55
49
  #
56
50
  # ## Floor / ceiling (slice 1)
57
51
  #
58
52
  # Slice 1 ships the **floor**:
59
53
  #
60
- # - Top-level `Foo = Dry::Schema.{Params,JSON,define} { ... }`
61
- # assignments. Class-level constants (`class Bar; SCHEMA =
62
- # Dry::Schema.Params { ... }; end`) work too — the walker
63
- # prefixes the enclosing constant chain.
64
- # - `required(:key).<predicate>(:type_symbol_or_constant)` rows
65
- # for the canonical-type vocabulary above.
54
+ # - Top-level `Foo = Dry::Schema.{Params,JSON,define} { ... }` assignments. Class-level constants
55
+ # (`class Bar; SCHEMA = Dry::Schema.Params { ... }; end`) work too — the walker prefixes the
56
+ # enclosing constant chain.
57
+ # - `required(:key).<predicate>(:type_symbol_or_constant)` rows for the canonical-type vocabulary
58
+ # above.
66
59
  # - Publishes the table; no user-facing diagnostics yet.
67
60
  #
68
61
  # The **ceiling** (slice 2+):
69
62
  #
70
- # - Synthesise typed `result.to_h` returns from each schema
71
- # via ADR-16 Tier C heredoc-template substrate.
63
+ # - Synthesise typed `result.to_h` returns from each schema via ADR-16 Tier C heredoc-template
64
+ # substrate.
72
65
  # - Nested schemas (`schema(do ... end)` inside another row).
73
66
  # - `predicates(:size?)` / `each { ... }` recursion.
74
- # - Per-row `dry-schema.unknown-predicate` /
75
- # `dry-schema.unknown-type` `:info` diagnostics when a
67
+ # - Per-row `dry-schema.unknown-predicate` / `dry-schema.unknown-type` `:info` diagnostics when a
76
68
  # row's predicate or type symbol isn't recognised.
77
69
  class DrySchema < Rigor::Plugin::Base
78
70
  manifest(
@@ -84,10 +76,9 @@ module Rigor
84
76
  consumes: [{ plugin_id: "dry-types", name: :dry_type_aliases, optional: true }]
85
77
  )
86
78
 
87
- # Walks every project file once during `prepare(services)` to
88
- # build the schema table, then publishes via the ADR-9 fact
89
- # store. Mirrors the rigor-dry-types `#prepare` shape — the
90
- # walk is bounded by `paths:`, parse errors degrade silently.
79
+ # Walks every project file once during `prepare(services)` to build the schema table, then publishes
80
+ # via the ADR-9 fact store. Mirrors the rigor-dry-types `#prepare` shape — the walk is bounded by
81
+ # `paths:`, parse errors degrade silently.
91
82
  def prepare(services)
92
83
  type_aliases = services.fact_store.read(plugin_id: "dry-types", name: :dry_type_aliases) || {}
93
84
  table = SchemaScanner.scan(paths: scannable_paths(services), type_aliases: type_aliases)
@@ -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-dry-schema` 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/dry_schema.rb` performs at load time.
3
+ # Gem entry point. Required by Rigor's plugin loader when `.rigor.yml` lists `rigor-dry-schema` under
4
+ # `plugins:`. The loader expects this `require` to side-effect a call to `Rigor::Plugin.register`,
5
+ # which the body of `lib/rigor/plugin/dry_schema.rb` performs at load time.
8
6
  require_relative "rigor/plugin/dry_schema"
@@ -4,16 +4,13 @@ require "rigor/plugin"
4
4
 
5
5
  module Rigor
6
6
  module Plugin
7
- # ADR-16 Tier C worked plugin: recognises dry-struct's class-
8
- # level `attribute :name, T` DSL and synthesises a reader on
9
- # the enclosing `Dry::Struct` subclass.
7
+ # ADR-16 Tier C worked plugin: recognises dry-struct's class-level `attribute :name, T` DSL and
8
+ # synthesises a reader on the enclosing `Dry::Struct` subclass.
10
9
  #
11
- # dry-struct's `Dry::Struct::ClassInterface#attribute` (per the
12
- # per-library survey, `lib/dry/struct/class_interface.rb:86-88`
13
- # in the upstream gem) is the textbook Tier C target — a
14
- # class-level DSL call enumerates a literal Symbol argument, and
15
- # `class_interface.rb:452-464` `class_eval`s a heredoc
16
- # interpolating that Symbol into a getter:
10
+ # dry-struct's `Dry::Struct::ClassInterface#attribute` (per the per-library survey,
11
+ # `lib/dry/struct/class_interface.rb:86-88` in the upstream gem) is the textbook Tier C target — a
12
+ # class-level DSL call enumerates a literal Symbol argument, and `class_interface.rb:452-464`
13
+ # `class_eval`s a heredoc interpolating that Symbol into a getter:
17
14
  #
18
15
  # class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
19
16
  # def #{key} # def city
@@ -21,44 +18,36 @@ module Rigor
21
18
  # end
22
19
  # RUBY
23
20
  #
24
- # The substrate replays the same contract statically. For
25
- # source like:
21
+ # The substrate replays the same contract statically. For source like:
26
22
  #
27
23
  # class Address < Dry::Struct
28
24
  # attribute :city, Types::String
29
25
  # attribute :country, Types::String
30
26
  # end
31
27
  #
32
- # the pre-pass scans the file, sees `attribute :city, ...`, and
33
- # synthesises `Address#city` as a SyntheticMethod the dispatcher
34
- # surfaces below RBS dispatch. Bare `address.city` calls in
35
- # other files then dispatch through the synthetic record rather
36
- # than falling through to `call.undefined-method`.
28
+ # the pre-pass scans the file, sees `attribute :city, ...`, and synthesises `Address#city` as a
29
+ # SyntheticMethod the dispatcher surfaces below RBS dispatch. Bare `address.city` calls in other
30
+ # files then dispatch through the synthetic record rather than falling through to
31
+ # `call.undefined-method`.
37
32
  #
38
33
  # ## Precision model (ADR-16 WD13 + ADR-18)
39
34
  #
40
- # The synthetic reader's return type is resolved via ADR-18's
41
- # `returns_from_arg:` fact lookup: the call-site's second argument
42
- # (`Types::String` etc.) is looked up through the `:dry_type_aliases`
43
- # fact published by `rigor-dry-types`, yielding `Nominal[String]`
44
- # for common cases. When the lookup misses (e.g. inline method-chain
45
- # argument whose chain-head isn't currently extracted), the row
35
+ # The synthetic reader's return type is resolved via ADR-18's `returns_from_arg:` fact lookup: the
36
+ # call-site's second argument (`Types::String` etc.) is looked up through the `:dry_type_aliases`
37
+ # fact published by `rigor-dry-types`, yielding `Nominal[String]` for common cases. When the lookup
38
+ # misses (e.g. inline method-chain argument whose chain-head isn't currently extracted), the row
46
39
  # falls back to `Dynamic[Top]` silently.
47
40
  #
48
41
  # ## Scope (slice 2c minimum)
49
42
  #
50
43
  # - Recognises `attribute :name, T` at class body top level.
51
- # - Recognises `attribute? :name, T` via a separate template
52
- # entry (omittable attribute; same reader name, `?` stripped).
53
- # - Synthesises **only the reader** — the other survey-listed
54
- # emit rows (`schema` key, `to_h` row, `[:key]` access, `.new`
55
- # kwarg) are not yet wired by the substrate (they require
56
- # either RBS-level shape synthesis or additional substrate
57
- # primitives). Slice 2c stops at the reader.
58
- # - Nested-block form (`attribute :details do ... end` minting
59
- # `Address::Details`) is out of scope for slice 2c; that
60
- # pattern needs Tier A + Tier C composition + const_set
61
- # emission. Deferred.
44
+ # - Recognises `attribute? :name, T` via a separate template entry (omittable attribute; same reader
45
+ # name, `?` stripped).
46
+ # - Synthesises **only the reader** — the other survey-listed emit rows (`schema` key, `to_h` row,
47
+ # `[:key]` access, `.new` kwarg) are not yet wired by the substrate (they require either RBS-level
48
+ # shape synthesis or additional substrate primitives). Slice 2c stops at the reader.
49
+ # - Nested-block form (`attribute :details do ... end` minting `Address::Details`) is out of scope
50
+ # for slice 2c; that pattern needs Tier A + Tier C composition + const_set emission. Deferred.
62
51
  class DryStruct < Rigor::Plugin::Base
63
52
  manifest(
64
53
  id: "dry-struct",
@@ -66,26 +55,20 @@ module Rigor
66
55
  description: "Recognises dry-struct `attribute :name, T` DSL via ADR-16 Tier C; " \
67
56
  "promotes the reader's return type through ADR-18's `returns_from_arg:` " \
68
57
  "by consuming `rigor-dry-types`'s `:dry_type_aliases` fact.",
69
- # ADR-9 consumption — the precision-promotion path
70
- # below uses `:dry_type_aliases` published by
71
- # `rigor-dry-types`. The fact is optional: when the
72
- # `rigor-dry-types` plugin isn't loaded, the
73
- # `returns_from_arg:` lookup misses and the synthetic
74
- # readers fall back to `Dynamic[Top]` (the pre-ADR-18
75
- # floor).
58
+ # ADR-9 consumption — the precision-promotion path below uses `:dry_type_aliases` published by
59
+ # `rigor-dry-types`. The fact is optional: when the `rigor-dry-types` plugin isn't loaded, the
60
+ # `returns_from_arg:` lookup misses and the synthetic readers fall back to `Dynamic[Top]` (the
61
+ # pre-ADR-18 floor).
76
62
  consumes: [{ plugin_id: "dry-types", name: :dry_type_aliases, optional: true }],
77
63
  heredoc_templates: [
78
64
  Rigor::Plugin::Macro::HeredocTemplate.new(
79
65
  receiver_constraint: "Dry::Struct",
80
66
  method_name: :attribute,
81
67
  symbol_arg_position: 0,
82
- # ADR-18 — the synthetic reader's return type comes
83
- # from the call site's second argument
84
- # (`Types::String` etc.), resolved through the
85
- # `:dry_type_aliases` fact. When the lookup misses
86
- # (e.g. inline `attribute :tag, Types::String.constrained(...)`,
87
- # whose receiver chain head isn't currently
88
- # extracted), the row falls back to Dynamic[Top].
68
+ # ADR-18 — the synthetic reader's return type comes from the call site's second argument
69
+ # (`Types::String` etc.), resolved through the `:dry_type_aliases` fact. When the lookup
70
+ # misses (e.g. inline `attribute :tag, Types::String.constrained(...)`, whose receiver chain
71
+ # head isn't currently extracted), the row falls back to Dynamic[Top].
89
72
  emit: [{
90
73
  name: "\#{name}",
91
74
  returns_from_arg: {
@@ -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-dry-struct` 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/dry_struct.rb` performs at load time.
3
+ # Gem entry point. Required by Rigor's plugin loader when `.rigor.yml` lists `rigor-dry-struct` under
4
+ # `plugins:`. The loader expects this `require` to side-effect a call to `Rigor::Plugin.register`,
5
+ # which the body of `lib/rigor/plugin/dry_struct.rb` performs at load time.
8
6
  require_relative "rigor/plugin/dry_struct"