hecks 3.13.0 → 4.0.0

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 (440) hide show
  1. checksums.yaml +4 -4
  2. data/examples/pizzas/adapters/fake_processor.rb +34 -0
  3. data/examples/pizzas/adapters/payment_signature.rb +66 -0
  4. data/examples/pizzas/adapters/payment_webhook.rb +87 -0
  5. data/examples/pizzas/bluebook/pizzas.behaviors +33 -0
  6. data/examples/pizzas/bluebook/pizzas.bluebook +4 -4
  7. data/examples/pizzas/bluebook/pizzas.hecksagon +5 -3
  8. data/examples/pizzas/config.ru +22 -0
  9. data/lib/hecks/adapters/driven/prism.rb +0 -2
  10. data/lib/hecks/adapters/driven.rb +0 -2
  11. data/lib/hecks/adapters/driving/json.rb +1 -7
  12. data/lib/hecks/bluebook/dsl/attribute_collector.rb +15 -5
  13. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +2 -2
  14. data/lib/hecks/bluebook/dsl/derivation_words.rb +58 -0
  15. data/lib/hecks/bluebook/dsl/translation_builder.rb +6 -37
  16. data/lib/hecks/bluebook/expression/ast_json.rb +0 -9
  17. data/lib/hecks/bluebook/hecksagon.rb +1 -1
  18. data/lib/hecks/bluebook/meta_validator/translation_judge/rules.rb +7 -10
  19. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +4 -8
  20. data/lib/hecks/bluebook/meta_validator.rb +0 -11
  21. data/lib/hecks/bluebook/named_pattern.rb +33 -0
  22. data/lib/hecks/bluebook/translation.rb +18 -10
  23. data/lib/hecks/bluebook/translation_expression/evaluator.rb +63 -0
  24. data/lib/hecks/bluebook/translation_expression/parser.rb +127 -0
  25. data/lib/hecks/bluebook/translation_expression.rb +39 -0
  26. data/lib/hecks/bluebook/translation_plan.rb +70 -0
  27. data/lib/hecks/bluebook.rb +3 -0
  28. data/lib/hecks/chapters.rb +3 -3
  29. data/lib/hecks/cli/domain_stub.rb +1 -1
  30. data/lib/hecks/cli/interview_aggregate.rb +4 -4
  31. data/lib/hecks/composer/adapters/claude_composer.adapter +3 -0
  32. data/lib/hecks/composer/adapters/claude_composer.rb +83 -0
  33. data/lib/hecks/composer/adapters/fake_agent.adapter +3 -0
  34. data/lib/hecks/composer/adapters/fake_agent.rb +55 -0
  35. data/lib/hecks/composer/adapters/jev.adapter +3 -0
  36. data/lib/hecks/composer/adapters/jev.rb +66 -0
  37. data/lib/hecks/composer/agent.rb +113 -0
  38. data/lib/hecks/composer/assistant.rb +110 -0
  39. data/lib/hecks/composer/behavior_run.rb +53 -0
  40. data/lib/hecks/composer/bluebook/composer.bluebook +178 -0
  41. data/lib/hecks/composer/bluebook/composer.hecksagon +16 -0
  42. data/lib/hecks/composer/board.rb +65 -0
  43. data/lib/hecks/composer/board_edit/command_text.rb +39 -0
  44. data/lib/hecks/composer/board_edit/source.rb +84 -0
  45. data/lib/hecks/composer/board_edit.rb +144 -0
  46. data/lib/hecks/composer/check.rb +89 -0
  47. data/lib/hecks/composer/domains.rb +81 -0
  48. data/lib/hecks/composer/jobs.rb +134 -0
  49. data/lib/hecks/composer/layout.rb +37 -0
  50. data/lib/hecks/composer/live.rb +150 -0
  51. data/lib/hecks/composer/outline.rb +48 -0
  52. data/lib/hecks/composer/page.html +989 -0
  53. data/lib/hecks/composer/panels.rb +142 -0
  54. data/lib/hecks/composer/parse.rb +83 -0
  55. data/lib/hecks/composer/plain.rb +28 -0
  56. data/lib/hecks/composer/ports/composer_agent.port +7 -0
  57. data/lib/hecks/composer/session.rb +141 -0
  58. data/lib/hecks/composer/toolbox.rb +166 -0
  59. data/lib/hecks/composer/web.rb +156 -0
  60. data/lib/hecks/composer/workbench.rb +51 -0
  61. data/lib/hecks/composer/workspace.rb +81 -0
  62. data/lib/hecks/composer.rb +17 -0
  63. data/lib/hecks/corpus/adapters.rb +22 -0
  64. data/lib/hecks/corpus/rust.rb +1 -1
  65. data/lib/hecks/corpus/worlds.rb +19 -0
  66. data/lib/hecks/corpus.rb +5 -0
  67. data/lib/hecks/deploy/bluebook/deploy.bluebook +34 -34
  68. data/lib/hecks/forms/app/commands.rb +2 -3
  69. data/lib/hecks/forms/app/queries.rb +2 -3
  70. data/lib/hecks/forms/app/records.rb +17 -5
  71. data/lib/hecks/forms/command_form_renderer.rb +42 -16
  72. data/lib/hecks/forms/field_controls.rb +2 -2
  73. data/lib/hecks/forms/field_renderer.rb +1 -1
  74. data/lib/hecks/forms/field_shape.rb +36 -17
  75. data/lib/hecks/forms/index_renderer.rb +2 -1
  76. data/lib/hecks/forms/page.rb +1 -1
  77. data/lib/hecks/forms/params.rb +0 -13
  78. data/lib/hecks/forms/query_form_renderer.rb +7 -6
  79. data/lib/hecks/forms/record_renderer.rb +11 -7
  80. data/lib/hecks/forms/rule_words.rb +100 -0
  81. data/lib/hecks/forms/value_object_shape.rb +2 -1
  82. data/lib/hecks/framework/bluebook/change.bluebook +2 -2
  83. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +0 -3
  84. data/lib/hecks/fuzzing/domain_generator/block_rendering.rb +1 -1
  85. data/lib/hecks/fuzzing/isolated_boot/worlds.rb +3 -6
  86. data/lib/hecks/fuzzing/replay/filters.rb +2 -6
  87. data/lib/hecks/gate/stages.yml +25 -0
  88. data/lib/hecks/grammar/evolve/seeds.rb +0 -6
  89. data/lib/hecks/grammar/evolve.rb +0 -3
  90. data/lib/hecks/grammar/translation.bluebook +1 -1
  91. data/lib/hecks/hecks/adapters/codebase/composing.rb +56 -0
  92. data/lib/hecks/hecks/adapters/codebase/source_tree.rb +3 -1
  93. data/lib/hecks/hecks/adapters/journal_store/changes.rb +0 -26
  94. data/lib/hecks/hecks/adapters/journal_store/examination.rb +2 -23
  95. data/lib/hecks/hecks/adapters/journal_store/readings.rb +3 -11
  96. data/lib/hecks/hecks/adapters/journal_store.rb +0 -11
  97. data/lib/hecks/hecks/adapters/rehearsal/inquiry.rb +4 -11
  98. data/lib/hecks/hecks/adapters/rehearsal/memory_store.rb +0 -9
  99. data/lib/hecks/hecks/adapters/rehearsal/postgres_reading.rb +0 -4
  100. data/lib/hecks/hecks/codebase.behaviors +6 -0
  101. data/lib/hecks/hecks/codebase.bluebook +58 -37
  102. data/lib/hecks/hecks/composer.behaviors +68 -0
  103. data/lib/hecks/hecks/context_map.hecksagon +1 -1
  104. data/lib/hecks/hecks/custodian.behaviors +0 -6
  105. data/lib/hecks/hecks/custodian.bluebook +15 -92
  106. data/lib/hecks/hecks/hecks.bluebook +2 -2
  107. data/lib/hecks/hecks/hecks.hecksagon +2 -2
  108. data/lib/hecks/hecks/hecks.world +1 -1
  109. data/lib/hecks/hecks/rehearsal.bluebook +10 -16
  110. data/lib/hecks/hecks/tooling.bluebook +22 -22
  111. data/lib/hecks/kernel_capabilities/templates.rb +4 -4
  112. data/lib/hecks/kernel_capabilities.rb +1 -1
  113. data/lib/hecks/language/bluebook/aggregate.bluebook +1 -0
  114. data/lib/hecks/language/bluebook/command.bluebook +1 -0
  115. data/lib/hecks/language/bluebook/entity.bluebook +1 -0
  116. data/lib/hecks/language/bluebook/query.bluebook +1 -0
  117. data/lib/hecks/language/bluebook/shape.bluebook +8 -7
  118. data/lib/hecks/language/bluebook/vocabulary.bluebook +2 -3
  119. data/lib/hecks/language/hecksagon/port_operation.bluebook +1 -0
  120. data/lib/hecks/language/translation/translation_aggregate.bluebook +21 -24
  121. data/lib/hecks/ports/access_control.rb +2 -2
  122. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +3 -41
  123. data/lib/hecks/ports/persistence/plugins/era/lineage/coverage.rb +7 -7
  124. data/lib/hecks/ports/persistence/plugins/era/lineage/rewrite.rb +25 -2
  125. data/lib/hecks/ports/persistence/plugins/era/lineage/rules.rb +4 -4
  126. data/lib/hecks/ports/persistence/plugins/era/lineage.rb +17 -25
  127. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/base_sql.rb +0 -12
  128. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/domain_rename.rb +1 -1
  129. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +2 -22
  130. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +0 -1
  131. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +9 -3
  132. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +3 -29
  133. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/refusals.rb +2 -26
  134. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +6 -33
  135. data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +3 -3
  136. data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +2 -4
  137. data/lib/hecks/ports/persistence/plugins/era/translation/expression_sql.rb +52 -0
  138. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +23 -29
  139. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +1 -1
  140. data/lib/hecks/ports/persistence/plugins/era/translation.rb +0 -1
  141. data/lib/hecks/ports/persistence/plugins/era.rb +3 -6
  142. data/lib/hecks/ports.rb +0 -1
  143. data/lib/hecks/projection_files.rb +3 -1
  144. data/lib/hecks/projections/deploy/templates/lambda/nat_comment_oauth.tmpl +1 -1
  145. data/lib/hecks/projections/glossary/entries.rb +10 -4
  146. data/lib/hecks/projections/glossary/groups.rb +42 -0
  147. data/lib/hecks/projections/glossary/html/page.rb +7 -2
  148. data/lib/hecks/projections/glossary/html/parser.rb +1 -1
  149. data/lib/hecks/projections/glossary/html/sections.rb +31 -11
  150. data/lib/hecks/projections/glossary/html.rb +1 -2
  151. data/lib/hecks/projections/glossary/markdown.rb +31 -28
  152. data/lib/hecks/projections/glossary/mermaid.rb +3 -0
  153. data/lib/hecks/projections/glossary/page.css +143 -153
  154. data/lib/hecks/projections/glossary/page.js +63 -3
  155. data/lib/hecks/projections/glossary/sentences/actions.rb +88 -0
  156. data/lib/hecks/projections/glossary/sentences/paths.rb +77 -0
  157. data/lib/hecks/projections/glossary/sentences/queries.rb +90 -0
  158. data/lib/hecks/projections/glossary/sentences/value_objects.rb +32 -5
  159. data/lib/hecks/projections/glossary/sentences.rb +13 -3
  160. data/lib/hecks/projections/glossary/slugs.rb +4 -1
  161. data/lib/hecks/projections/glossary.rb +2 -1
  162. data/lib/hecks/projections/plain_english.rb +97 -0
  163. data/lib/hecks/projections/rust_vocabulary/arguments.rb +2 -2
  164. data/lib/hecks/projections/rust_vocabulary/enum_body.rb +20 -25
  165. data/lib/hecks/projections/rust_vocabulary/tests.rb +2 -2
  166. data/lib/hecks/projections/rust_vocabulary.rb +14 -6
  167. data/lib/hecks/projections/site/cms_editor/color.rb +0 -6
  168. data/lib/hecks/projections/statements/actions.rb +99 -0
  169. data/lib/hecks/projections/statements/relationships.rb +86 -0
  170. data/lib/hecks/projections/statements.rb +15 -24
  171. data/lib/hecks/projector/exporter/adapters.rb +112 -0
  172. data/lib/hecks/projector/exporter/translations.rb +18 -35
  173. data/lib/hecks/projector/exporter/worlds.rb +103 -0
  174. data/lib/hecks/projector/exporter.rb +5 -1
  175. data/lib/hecks/quality_control/adapters/agent.rb +6 -7
  176. data/lib/hecks/quality_control/adapters/agent_profile.rb +16 -114
  177. data/lib/hecks/quality_control/cli/qa_mine_combinations.rb +1 -1
  178. data/lib/hecks/quality_control/quality_control.bluebook +51 -51
  179. data/lib/hecks/runtime/loader/boot_steps.rb +0 -20
  180. data/lib/hecks/runtime/outbox.rb +2 -9
  181. data/lib/hecks/runtime/port_operation_interpreter.rb +1 -9
  182. data/lib/hecks/runtime/remote_dispatcher.rb +2 -2
  183. data/lib/hecks/runtime/value.rb +13 -0
  184. data/lib/hecks/rust_build/project_rust/target_ir.rb +23 -4
  185. data/lib/hecks/rust_build/wasm.rb +0 -12
  186. data/lib/hecks/rust_build/write_if_changed.rb +12 -12
  187. data/lib/hecks/rust_format.rb +77 -0
  188. data/lib/hecks/site/bluebook/site.bluebook +5 -5
  189. data/lib/hecks/sme/bluebook/sme.bluebook +12 -12
  190. data/lib/hecks/tickets/bluebook/tickets.bluebook +3 -3
  191. data/lib/hecks/tools/fuzz_sweep/findings.rb +3 -9
  192. data/lib/hecks/tools/fuzz_sweep.rb +1 -3
  193. data/lib/hecks/tools/translation_audit/verdicts.rb +3 -28
  194. data/lib/hecks/tools/translation_audit.rb +8 -10
  195. data/lib/hecks/tools/translation_scaffold/reporting.rb +1 -1
  196. data/lib/hecks/version.rb +1 -1
  197. data/lib/hecks/vocabulary.rb +2 -1
  198. data/lib/hecks.rb +3 -0
  199. data/prebuilt/{58208399bada10b0db99928c48e38789288fc58f7b71a72b21bfa386680e32ed.marshal → 02c09c73b272c1fb5a9ae6d87bb5e5e529208e00f6b4b597dc2c0fd70a9c0964.marshal} +0 -0
  200. data/prebuilt/{2b59737fbdbd5f44edda0fddce2611f45d76087b3a7c782d1f1a17ea58c77948.marshal → bb84a835cf6a15136bad5ca03aa5bf93a5b92f5f72444618d3ef2412b987fb32.marshal} +0 -0
  201. data/prebuilt/verdicts-f1f10da14c8e8f01b4c9b7e3e2d74be8cd2bf4676364ed17fa16975d2a076d75.json +1 -0
  202. data/rust/Cargo.toml +40 -0
  203. data/rust/build/Cargo.toml +36 -0
  204. data/rust/build/clippy.toml +4 -0
  205. data/rust/build/src/adapters_pass.rs +196 -0
  206. data/rust/build/src/binding_pass.rs +54 -13
  207. data/rust/build/src/build_artifact.rs +23 -5
  208. data/rust/build/src/cargo_sync.rs +69 -26
  209. data/rust/build/src/lineage_pass.rs +101 -87
  210. data/rust/build/src/main.rs +11 -2
  211. data/rust/build/src/pipeline.rs +80 -19
  212. data/rust/build/src/reserved_names.rs +6 -50
  213. data/rust/build/src/resolve.rs +82 -35
  214. data/rust/build/src/rustfmt.rs +100 -0
  215. data/rust/build/src/seams_pass.rs +85 -16
  216. data/rust/build/src/subprocess.rs +30 -6
  217. data/rust/build/src/tmp.rs +5 -2
  218. data/rust/build/src/translation_pass.rs +72 -22
  219. data/rust/build/src/world_pass.rs +109 -0
  220. data/rust/clippy.toml +4 -0
  221. data/rust/codegen/Cargo.toml +36 -0
  222. data/rust/codegen/clippy.toml +4 -0
  223. data/rust/codegen/src/asks.rs +40 -14
  224. data/rust/codegen/src/attr.rs +2 -2
  225. data/rust/codegen/src/bridging.rs +676 -117
  226. data/rust/codegen/src/commands.rs +979 -373
  227. data/rust/codegen/src/constraints.rs +88 -25
  228. data/rust/codegen/src/dependency_planning.rs +128 -34
  229. data/rust/codegen/src/domain_generator.rs +300 -170
  230. data/rust/codegen/src/exemplar.rs +87 -32
  231. data/rust/codegen/src/expr_emitter.rs +54 -6
  232. data/rust/codegen/src/fielded.rs +193 -41
  233. data/rust/codegen/src/hecks_naming.rs +124 -16
  234. data/rust/codegen/src/hecks_naming_tests.rs +81 -0
  235. data/rust/codegen/src/json.rs +80 -44
  236. data/rust/codegen/src/json_codec.rs +585 -149
  237. data/rust/codegen/src/literal.rs +104 -138
  238. data/rust/codegen/src/main.rs +145 -52
  239. data/rust/codegen/src/manifest.rs +76 -14
  240. data/rust/codegen/src/mutations.rs +1212 -239
  241. data/rust/codegen/src/naming.rs +111 -60
  242. data/rust/codegen/src/optional_pass.rs +90 -28
  243. data/rust/codegen/src/ports.rs +5 -4
  244. data/rust/codegen/src/prelude.rs +139 -49
  245. data/rust/codegen/src/queries.rs +601 -226
  246. data/rust/codegen/src/reactions.rs +268 -74
  247. data/rust/codegen/src/read_models.rs +606 -205
  248. data/rust/codegen/src/reference_specs.rs +16 -3
  249. data/rust/codegen/src/registry.rs +128 -79
  250. data/rust/codegen/src/reserved_names.rs +6 -50
  251. data/rust/codegen/src/shared.rs +71 -22
  252. data/rust/codegen/src/sidecars.rs +15 -5
  253. data/rust/codegen/src/skip_reason.rs +8 -2
  254. data/rust/codegen/src/types.rs +306 -108
  255. data/rust/host/Cargo.lock +1 -0
  256. data/rust/host/Cargo.toml +40 -4
  257. data/rust/host/HECKS_RELEASE +1 -1
  258. data/rust/host/clippy.toml +4 -0
  259. data/rust/host/src/api.rs +698 -218
  260. data/rust/host/src/auth.rs +491 -214
  261. data/rust/host/src/b64.rs +91 -0
  262. data/rust/host/src/bin/expr_harness.rs +6 -2
  263. data/rust/host/src/bin/lineage_harness.rs +47 -11
  264. data/rust/host/src/bin/mint_harness.rs +70 -37
  265. data/rust/host/src/bin/validate_harness.rs +16 -8
  266. data/rust/host/src/boot.rs +144 -68
  267. data/rust/host/src/boundary_fuzz/api.rs +130 -32
  268. data/rust/host/src/boundary_fuzz/auth.rs +108 -23
  269. data/rust/host/src/boundary_fuzz/expr_json.rs +85 -11
  270. data/rust/host/src/boundary_fuzz/ir.rs +164 -12
  271. data/rust/host/src/boundary_fuzz/server.rs +283 -36
  272. data/rust/host/src/boundary_fuzz/web.rs +56 -8
  273. data/rust/host/src/checkout.rs +78 -32
  274. data/rust/host/src/clock.rs +8 -0
  275. data/rust/host/src/commerce_ir.rs +333 -95
  276. data/rust/host/src/crypto.rs +33 -0
  277. data/rust/host/src/dispatch.rs +990 -331
  278. data/rust/host/src/expr_json.rs +1021 -273
  279. data/rust/host/src/extension.rs +24 -4
  280. data/rust/host/src/field_hints.rs +11 -7
  281. data/rust/host/src/fuzz_support.rs +85 -13
  282. data/rust/host/src/host.rs +100 -0
  283. data/rust/host/src/http.rs +22 -0
  284. data/rust/host/src/ir.rs +326 -16
  285. data/rust/host/src/journal.rs +277 -176
  286. data/rust/host/src/lambda_client.rs +219 -53
  287. data/rust/host/src/lib.rs +16 -4
  288. data/rust/host/src/log.rs +62 -11
  289. data/rust/host/src/mint.rs +1153 -326
  290. data/rust/host/src/needs.rs +185 -44
  291. data/rust/host/src/payments/keystore.rs +197 -45
  292. data/rust/host/src/payments/roles.rs +191 -0
  293. data/rust/host/src/payments/tests.rs +1445 -275
  294. data/rust/host/src/payments.rs +409 -121
  295. data/rust/host/src/platform_signin/attack_tests.rs +5 -5
  296. data/rust/host/src/platform_signin/config.rs +11 -11
  297. data/rust/host/src/platform_signin/cookie.rs +2 -2
  298. data/rust/host/src/platform_signin/extension.rs +2 -1
  299. data/rust/host/src/platform_signin/handler.rs +9 -8
  300. data/rust/host/src/platform_signin/jti.rs +4 -2
  301. data/rust/host/src/platform_signin/jwks.rs +2 -1
  302. data/rust/host/src/platform_signin/jws.rs +2 -37
  303. data/rust/host/src/platform_signin/known_answer_tests.rs +5 -1
  304. data/rust/host/src/platform_signin/mode_tests.rs +5 -3
  305. data/rust/host/src/platform_signin/pages.rs +20 -20
  306. data/rust/host/src/platform_signin/session.rs +8 -1
  307. data/rust/host/src/platform_signin/settings.rs +6 -6
  308. data/rust/host/src/platform_signin/strict_json.rs +12 -9
  309. data/rust/host/src/platform_signin/verify.rs +41 -41
  310. data/rust/host/src/platform_signin/wiring_support.rs +13 -18
  311. data/rust/host/src/presentation.rs +207 -63
  312. data/rust/host/src/presentation_write.rs +502 -187
  313. data/rust/host/src/query_step.rs +69 -18
  314. data/rust/host/src/rate_limit.rs +541 -142
  315. data/rust/host/src/reference_transform.rs +77 -25
  316. data/rust/host/src/reference_validate.rs +443 -104
  317. data/rust/host/src/resend.rs +190 -55
  318. data/rust/host/src/secrets.rs +116 -21
  319. data/rust/host/src/server.rs +483 -104
  320. data/rust/host/src/storage_shape.rs +88 -21
  321. data/rust/host/src/test_pg.rs +17 -7
  322. data/rust/host/src/ui_schema.rs +495 -207
  323. data/rust/host/src/wasm_runner.rs +21 -6
  324. data/rust/host/src/web/commerce.rs +101 -23
  325. data/rust/host/src/web/newsletter/cooldown.rs +10 -3
  326. data/rust/host/src/web/newsletter/template.rs +26 -7
  327. data/rust/host/src/web/newsletter/tests.rs +112 -23
  328. data/rust/host/src/web/newsletter.rs +209 -59
  329. data/rust/host/src/web/newsletter_send.rs +251 -79
  330. data/rust/host/src/web/registration_receipt/tests.rs +16 -4
  331. data/rust/host/src/web/registration_receipt.rs +100 -24
  332. data/rust/host/src/web/registrations.rs +1384 -332
  333. data/rust/host/src/web/resend_webhook.rs +138 -80
  334. data/rust/host/src/web.rs +2416 -508
  335. data/rust/lsp/Cargo.toml +36 -0
  336. data/rust/lsp/clippy.toml +4 -0
  337. data/rust/lsp/src/json.rs +29 -22
  338. data/rust/lsp/src/main.rs +81 -31
  339. data/rust/lsp/src/outline.rs +23 -7
  340. data/rust/lsp/src/rpc.rs +17 -4
  341. data/rust/parser/Cargo.toml +36 -0
  342. data/rust/parser/clippy.toml +4 -0
  343. data/rust/parser/src/build/closed_sets.rs +6 -1
  344. data/rust/parser/src/build/identity.rs +4 -3
  345. data/rust/parser/src/build/mod.rs +1 -0
  346. data/rust/parser/src/build/named_pattern.rs +26 -0
  347. data/rust/parser/src/build/naming.rs +2 -80
  348. data/rust/parser/src/build/pattern_subset.rs +6 -8
  349. data/rust/parser/src/build/query_derive.rs +3 -1
  350. data/rust/parser/src/build/query_inference.rs +14 -5
  351. data/rust/parser/src/build/read_model.rs +4 -1
  352. data/rust/parser/src/build/references.rs +4 -3
  353. data/rust/parser/src/canonical.rs +34 -15
  354. data/rust/parser/src/emit.rs +187 -105
  355. data/rust/parser/src/expr/ast_json.rs +134 -42
  356. data/rust/parser/src/expr/evaluator.rs +27 -9
  357. data/rust/parser/src/expr/mod.rs +54 -13
  358. data/rust/parser/src/expr/resolver.rs +299 -92
  359. data/rust/parser/src/ir.rs +35 -3
  360. data/rust/parser/src/keywords.rs +7168 -510
  361. data/rust/parser/src/lex.rs +11 -25
  362. data/rust/parser/src/lib.rs +1 -0
  363. data/rust/parser/src/main.rs +65 -6
  364. data/rust/parser/src/parse/adapter.rs +157 -0
  365. data/rust/parser/src/parse/aggregate.rs +19 -10
  366. data/rust/parser/src/parse/chapter.rs +16 -17
  367. data/rust/parser/src/parse/command.rs +35 -16
  368. data/rust/parser/src/parse/domain_port.rs +4 -7
  369. data/rust/parser/src/parse/entity.rs +21 -11
  370. data/rust/parser/src/parse/hecksagon.rs +10 -4
  371. data/rust/parser/src/parse/lifecycle.rs +9 -5
  372. data/rust/parser/src/parse/mod.rs +43 -91
  373. data/rust/parser/src/parse/needs.rs +21 -12
  374. data/rust/parser/src/parse/policy.rs +2 -2
  375. data/rust/parser/src/parse/process_manager.rs +9 -11
  376. data/rust/parser/src/parse/query.rs +8 -4
  377. data/rust/parser/src/parse/read_model.rs +57 -16
  378. data/rust/parser/src/parse/value_object.rs +7 -2
  379. data/rust/parser/src/parse/world.rs +322 -0
  380. data/rust/parser/src/ruby_value.rs +7 -6
  381. data/rust/src/exemplar/json.rs +4 -4
  382. data/rust/src/exemplar/mutations.rs +18 -0
  383. data/rust/src/exemplar/read_models.rs +1 -10
  384. data/rust/src/kernel/attribute_shapes/composite.rs +54 -14
  385. data/rust/src/kernel/attribute_shapes/list.rs +2 -2
  386. data/rust/src/kernel/attribute_shapes/mod.rs +8 -8
  387. data/rust/src/kernel/attribute_shapes/scalar.rs +2 -2
  388. data/rust/src/kernel/cli.rs +229 -112
  389. data/rust/src/kernel/dispatch.rs +323 -115
  390. data/rust/src/kernel/dispatch_guard_tests.rs +327 -65
  391. data/rust/src/kernel/expr.rs +203 -86
  392. data/rust/src/kernel/expression_operators/arithmetic.rs +138 -25
  393. data/rust/src/kernel/expression_operators/comparison.rs +87 -2
  394. data/rust/src/kernel/expression_operators/enumeration.rs +106 -22
  395. data/rust/src/kernel/expression_operators/logical.rs +9 -3
  396. data/rust/src/kernel/expression_operators/membership.rs +3 -1
  397. data/rust/src/kernel/expression_operators/mod.rs +34 -21
  398. data/rust/src/kernel/expression_operators/pattern_match.rs +46 -11
  399. data/rust/src/kernel/expression_operators/positional.rs +84 -30
  400. data/rust/src/kernel/expression_operators/presence.rs +52 -13
  401. data/rust/src/kernel/expression_operators/sign_test.rs +3 -1
  402. data/rust/src/kernel/expression_operators/sized.rs +24 -8
  403. data/rust/src/kernel/expression_operators/text.rs +120 -27
  404. data/rust/src/kernel/expression_operators/to_string.rs +10 -4
  405. data/rust/src/kernel/json.rs +230 -148
  406. data/rust/src/kernel/mod.rs +46 -33
  407. data/rust/src/kernel/named_query.rs +63 -15
  408. data/rust/src/kernel/needs.rs +112 -25
  409. data/rust/src/kernel/orchestrate.rs +980 -581
  410. data/rust/src/kernel/orchestrate_guard_tests.rs +538 -140
  411. data/rust/src/kernel/pattern.rs +107 -34
  412. data/rust/src/kernel/query_comparators.rs +118 -41
  413. data/rust/src/kernel/query_ordering.rs +13 -5
  414. data/rust/src/kernel/read_model.rs +479 -181
  415. data/rust/src/kernel/reference_lookup.rs +122 -26
  416. data/rust/src/kernel/repository.rs +293 -66
  417. data/rust/src/kernel/routing.rs +58 -42
  418. data/rust/src/kernel/ruby_float.rs +139 -0
  419. data/rust/src/kernel/vocab/aggregate_dispatch_order.rs +57 -57
  420. data/rust/src/kernel/vocab/entity_dispatch_order.rs +54 -54
  421. data/rust/src/kernel/vocab/field_hint.rs +19 -25
  422. data/rust/src/kernel/vocab/mod.rs +6 -6
  423. data/rust/src/kernel/vocab/query_comparator.rs +23 -24
  424. data/rust/src/kernel/vocab/refusal_template.rs +501 -297
  425. data/rust/src/lib.rs +50 -0
  426. data/rust/src/main.rs +4 -1
  427. data/rust/web/Cargo.toml +36 -0
  428. data/rust/web/clippy.toml +4 -0
  429. metadata +85 -15
  430. data/examples/pizzas/bluebook/hecksagon/mock_stripe_payment_adapter.rb +0 -36
  431. data/lib/hecks/adapters/driven/google_authentication.adapter +0 -3
  432. data/lib/hecks/adapters/driven/google_authentication.rb +0 -99
  433. data/lib/hecks/adapters/driven/mock_stripe_adapter.adapter +0 -3
  434. data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +0 -32
  435. data/lib/hecks/ports/authentication.port +0 -6
  436. data/lib/hecks/ports/authentication.rb +0 -67
  437. data/lib/hecks/ports/persistence/plugins/era/translation/approval_file.rb +0 -255
  438. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +0 -22
  439. data/prebuilt/verdicts-48318ca172edd21443b1ad02801c697fff100b746e828f09db987647641a5df2.json +0 -1
  440. data/rust/host/src/approval.rs +0 -652
@@ -5,37 +5,13 @@ use crate::exemplar::Exemplar;
5
5
  use crate::json::Json;
6
6
  use crate::manifest::{ruby_inspect, Manifest};
7
7
  use crate::registry::{
8
- AggregateEntry, CommandEntry, EntityCommandEntry, EntityIdentityEntry, NestedEntityCommandEntry, PortEntry,
9
- ReferenceCheck, TenantBoundaryCheck,
8
+ AggregateEntry, CommandEntry, EntityCommandEntry, EntityIdentityEntry,
9
+ NestedEntityCommandEntry, PortEntry, ReferenceCheck, TenantBoundaryCheck,
10
10
  };
11
+ use crate::shared::{lifecycle_extra_field, puts_blank, puts_str};
11
12
  use crate::{commands, json_codec, mutations, ports, queries, reactions, read_models, types};
12
13
  use std::collections::HashMap;
13
14
 
14
- fn puts_str(out: &mut String, s: &str) {
15
- out.push_str(s);
16
- if !s.ends_with('\n') {
17
- out.push('\n');
18
- }
19
- }
20
-
21
- fn puts_blank(out: &mut String) {
22
- out.push('\n');
23
- }
24
-
25
- fn lifecycle_extra_field(node: &Json) -> Vec<(String, String)> {
26
- match node.get("lifecycle") {
27
- None => vec![],
28
- Some(lifecycle) => {
29
- let field = lifecycle.get("field").and_then(Json::as_str).unwrap_or("");
30
- let ident = crate::naming::rust_ident_field(field);
31
- vec![(
32
- crate::naming::rust_field(field),
33
- format!("crate::kernel::Json::Str(self.{ident}.clone())"),
34
- )]
35
- }
36
- }
37
- }
38
-
39
15
  pub struct GeneratedFile {
40
16
  pub name: String,
41
17
  pub content: String,
@@ -63,7 +39,7 @@ fn reference_checks(
63
39
  aggregates_by_name: &HashMap<String, &Json>,
64
40
  unsupported_names: &[String],
65
41
  ) -> Vec<ReferenceCheck> {
66
- let attrs = command.get("attributes").map(Json::each).unwrap_or(&[]);
42
+ let attrs = command.get("attributes").map_or_default(Json::each);
67
43
  attrs
68
44
  .iter()
69
45
  .filter_map(|attr| {
@@ -72,7 +48,7 @@ fn reference_checks(
72
48
  if unsupported_names.iter().any(|n| n == target_name) {
73
49
  return None;
74
50
  }
75
- let identified_by = target.get("identified_by").map(Json::each).unwrap_or(&[]);
51
+ let identified_by = target.get("identified_by").map_or_default(Json::each);
76
52
  let heads = identified_by
77
53
  .iter()
78
54
  .map(|p| p.to_s().split('.').next().unwrap_or("").to_string())
@@ -109,9 +85,9 @@ fn state_reference_checks(
109
85
  unsupported_names: &[String],
110
86
  value_objects_by_name: &HashMap<String, &Json>,
111
87
  ) -> Vec<ReferenceCheck> {
112
- let agg_attrs = aggregate.get("attributes").map(Json::each).unwrap_or(&[]);
113
- let cmd_mutations = command.get("mutations").map(Json::each).unwrap_or(&[]);
114
- let cmd_attrs = command.get("attributes").map(Json::each).unwrap_or(&[]);
88
+ let agg_attrs = aggregate.get("attributes").map_or_default(Json::each);
89
+ let cmd_mutations = command.get("mutations").map_or_default(Json::each);
90
+ let cmd_attrs = command.get("attributes").map_or_default(Json::each);
115
91
 
116
92
  agg_attrs
117
93
  .iter()
@@ -122,11 +98,21 @@ fn state_reference_checks(
122
98
  let mutation = cmd_mutations.iter().find(|m| {
123
99
  m.get("op").map(Json::to_s).as_deref() == Some("set")
124
100
  && m.get("target").map(Json::to_s).as_deref() == Some(attr_name)
125
- && m.get("source").and_then(|s| s.get("kind")).map(Json::to_s).as_deref() == Some("argument")
101
+ && m.get("source")
102
+ .and_then(|s| s.get("kind"))
103
+ .map(Json::to_s)
104
+ .as_deref()
105
+ == Some("argument")
126
106
  })?;
127
107
 
128
- let source_name = mutation.get("source").and_then(|s| s.get("name")).map(Json::to_s).unwrap_or_default();
129
- let source_attr = cmd_attrs.iter().find(|a| crate::attr::name(a) == source_name)?;
108
+ let source_name = mutation
109
+ .get("source")
110
+ .and_then(|s| s.get("name"))
111
+ .map(Json::to_s)
112
+ .unwrap_or_default();
113
+ let source_attr = cmd_attrs
114
+ .iter()
115
+ .find(|a| crate::attr::name(a) == source_name)?;
130
116
  if crate::naming::reference_target(crate::attr::type_name(source_attr)).is_some() {
131
117
  return None;
132
118
  }
@@ -147,7 +133,7 @@ fn state_reference_checks(
147
133
  return None;
148
134
  }
149
135
 
150
- let identified_by = target.get("identified_by").map(Json::each).unwrap_or(&[]);
136
+ let identified_by = target.get("identified_by").map_or_default(Json::each);
151
137
  let heads = identified_by
152
138
  .iter()
153
139
  .map(|p| p.to_s().split('.').next().unwrap_or("").to_string())
@@ -178,10 +164,13 @@ fn state_reference_checks(
178
164
  fn tenant_field_for(aggregate: &Json) -> Option<String> {
179
165
  aggregate
180
166
  .get("queries")
181
- .map(Json::each)
182
- .unwrap_or(&[])
167
+ .map_or_default(Json::each)
183
168
  .iter()
184
- .find_map(|q| q.get("authorization").and_then(|a| a.get("tenant")).map(Json::to_s))
169
+ .find_map(|q| {
170
+ q.get("authorization")
171
+ .and_then(|a| a.get("tenant"))
172
+ .map(Json::to_s)
173
+ })
185
174
  }
186
175
 
187
176
  /// Write-side tenant boundary checks for a command's references.
@@ -198,14 +187,22 @@ fn tenant_boundary_checks(
198
187
  let Some(own_tenant_field) = tenant_field_for(aggregate) else {
199
188
  return Vec::new();
200
189
  };
201
- let cmd_attrs = command.get("attributes").map(Json::each).unwrap_or(&[]);
202
- let Some(own_tenant_attr) = cmd_attrs.iter().find(|a| crate::attr::name(a) == own_tenant_field) else {
190
+ let cmd_attrs = command.get("attributes").map_or_default(Json::each);
191
+ let Some(own_tenant_attr) = cmd_attrs
192
+ .iter()
193
+ .find(|a| crate::attr::name(a) == own_tenant_field)
194
+ else {
203
195
  return Vec::new();
204
196
  };
205
- let Some(own_accessor) = state_reference_check_accessor(own_tenant_attr, value_objects_by_name) else {
197
+ let Some(own_accessor) = state_reference_check_accessor(own_tenant_attr, value_objects_by_name)
198
+ else {
206
199
  return Vec::new();
207
200
  };
208
- let aggregate_name = aggregate.get("name").and_then(Json::as_str).unwrap_or("").to_string();
201
+ let aggregate_name = aggregate
202
+ .get("name")
203
+ .and_then(Json::as_str)
204
+ .unwrap_or("")
205
+ .to_string();
209
206
 
210
207
  cmd_attrs
211
208
  .iter()
@@ -216,12 +213,17 @@ fn tenant_boundary_checks(
216
213
  return None;
217
214
  }
218
215
  let target_tenant_field = tenant_field_for(target)?;
219
- let target_attrs = target.get("attributes").map(Json::each).unwrap_or(&[]);
216
+ let target_attrs = target.get("attributes").map_or_default(Json::each);
220
217
  let target_tenant_attr = target_attrs
221
218
  .iter()
222
219
  .find(|a| crate::attr::name(a) == target_tenant_field)?;
223
- let target_accessor = state_reference_check_accessor(target_tenant_attr, value_objects_by_name)?;
224
- let target_decl_name = target.get("name").and_then(Json::as_str).unwrap_or("").to_string();
220
+ let target_accessor =
221
+ state_reference_check_accessor(target_tenant_attr, value_objects_by_name)?;
222
+ let target_decl_name = target
223
+ .get("name")
224
+ .and_then(Json::as_str)
225
+ .unwrap_or("")
226
+ .to_string();
225
227
 
226
228
  Some(TenantBoundaryCheck {
227
229
  reference_field: crate::attr::name(attr).to_string(),
@@ -251,7 +253,7 @@ fn list_reference_check_item(
251
253
  return Some("item".to_string());
252
254
  }
253
255
  let vo = value_objects_by_name.get(type_name)?;
254
- let vo_attrs = vo.get("attributes").map(Json::each).unwrap_or(&[]);
256
+ let vo_attrs = vo.get("attributes").map_or_default(Json::each);
255
257
  if vo_attrs.len() != 1 || crate::attr::type_name(&vo_attrs[0]) != "String" {
256
258
  return None;
257
259
  }
@@ -265,7 +267,10 @@ fn list_reference_check_item(
265
267
  ///
266
268
  /// `None` for a multi-attribute value object, or an optional one: `check_reference`'s
267
269
  /// optional template assumes `Option<String>`.
268
- fn state_reference_check_accessor(source_attr: &Json, value_objects_by_name: &HashMap<String, &Json>) -> Option<String> {
270
+ fn state_reference_check_accessor(
271
+ source_attr: &Json,
272
+ value_objects_by_name: &HashMap<String, &Json>,
273
+ ) -> Option<String> {
269
274
  let name = crate::attr::name(source_attr);
270
275
  if crate::naming::effective_scalar_type(crate::attr::type_name(source_attr)).is_some() {
271
276
  return Some(name.to_string());
@@ -275,12 +280,15 @@ fn state_reference_check_accessor(source_attr: &Json, value_objects_by_name: &Ha
275
280
  if crate::attr::optional(source_attr) {
276
281
  return None;
277
282
  }
278
- let vo_attrs = vo.get("attributes").map(Json::each).unwrap_or(&[]);
283
+ let vo_attrs = vo.get("attributes").map_or_default(Json::each);
279
284
  if vo_attrs.len() != 1 {
280
285
  return None;
281
286
  }
282
287
 
283
- Some(format!("{name}.{}", crate::naming::rust_ident_field(crate::attr::name(&vo_attrs[0]))))
288
+ Some(format!(
289
+ "{name}.{}",
290
+ crate::naming::rust_ident_field(crate::attr::name(&vo_attrs[0]))
291
+ ))
284
292
  }
285
293
 
286
294
  pub fn generate(
@@ -292,7 +300,7 @@ pub fn generate(
292
300
  let resolved_ir = types::with_resolved_projection_types(ir);
293
301
  let ir = &resolved_ir;
294
302
  let domain_name = ir.get("name").and_then(Json::as_str).unwrap_or("");
295
- let all_aggregates = ir.get("aggregates").map(Json::each).unwrap_or(&[]);
303
+ let all_aggregates = ir.get("aggregates").map_or_default(Json::each);
296
304
  let aggregates_by_name: HashMap<String, &Json> = all_aggregates
297
305
  .iter()
298
306
  .map(|a| {
@@ -309,7 +317,7 @@ pub fn generate(
309
317
  let unsupported_names: Vec<String> = all_aggregates
310
318
  .iter()
311
319
  .filter(|a| {
312
- let vos = a.get("value_objects").map(Json::each).unwrap_or(&[]);
320
+ let vos = a.get("value_objects").map_or_default(Json::each);
313
321
  let vo_by_name: HashMap<String, &Json> = vos
314
322
  .iter()
315
323
  .map(|vo| {
@@ -337,18 +345,24 @@ pub fn generate(
337
345
  let mut manifest = Manifest::default();
338
346
  let process_managers: Vec<Json> = ir
339
347
  .get("process_managers")
340
- .map(Json::each)
341
- .unwrap_or(&[])
348
+ .map_or_default(Json::each)
342
349
  .to_vec();
343
350
 
344
351
  // Owner of each value object across the whole domain: a command attribute can name a value
345
352
  // object declared by another aggregate. Last writer wins per name.
346
353
  let mut domain_value_object_owner: HashMap<String, String> = HashMap::new();
347
354
  for a in all_aggregates {
348
- let owner = a.get("name").and_then(Json::as_str).unwrap_or("").to_string();
349
- for vo in a.get("value_objects").map(Json::each).unwrap_or(&[]) {
355
+ let owner = a
356
+ .get("name")
357
+ .and_then(Json::as_str)
358
+ .unwrap_or("")
359
+ .to_string();
360
+ for vo in a.get("value_objects").map_or_default(Json::each) {
350
361
  domain_value_object_owner.insert(
351
- vo.get("name").and_then(Json::as_str).unwrap_or("").to_string(),
362
+ vo.get("name")
363
+ .and_then(Json::as_str)
364
+ .unwrap_or("")
365
+ .to_string(),
352
366
  owner.clone(),
353
367
  );
354
368
  }
@@ -357,19 +371,23 @@ pub fn generate(
357
371
  // a cross-aggregate argument. Each aggregate's own map wins a name collision.
358
372
  let mut domain_value_objects_by_name: HashMap<String, &Json> = HashMap::new();
359
373
  for a in all_aggregates {
360
- for vo in a.get("value_objects").map(Json::each).unwrap_or(&[]) {
361
- domain_value_objects_by_name.insert(vo.get("name").and_then(Json::as_str).unwrap_or("").to_string(), vo);
374
+ for vo in a.get("value_objects").map_or_default(Json::each) {
375
+ domain_value_objects_by_name.insert(
376
+ vo.get("name")
377
+ .and_then(Json::as_str)
378
+ .unwrap_or("")
379
+ .to_string(),
380
+ vo,
381
+ );
362
382
  }
363
383
  }
364
384
 
365
385
  for aggregate in all_aggregates {
366
386
  let agg_name = aggregate.get("name").and_then(Json::as_str).unwrap_or("");
367
387
 
368
- let value_objects = aggregate
369
- .get("value_objects")
370
- .map(Json::each)
371
- .unwrap_or(&[]);
372
- let mut value_objects_by_name: HashMap<String, &Json> = domain_value_objects_by_name.clone();
388
+ let value_objects = aggregate.get("value_objects").map_or_default(Json::each);
389
+ let mut value_objects_by_name: HashMap<String, &Json> =
390
+ domain_value_objects_by_name.clone();
373
391
  value_objects_by_name.extend(value_objects.iter().map(|vo| {
374
392
  (
375
393
  vo.get("name")
@@ -388,23 +406,47 @@ pub fn generate(
388
406
  "attribute type(s) {} not generated yet (a bare, non-list entity-typed attribute isn't resolved to a Rust type)",
389
407
  unsupported.join(", ")
390
408
  );
391
- manifest.skipped_as("aggregate", format!("{domain_name}::{agg_name}"), "attribute_type", aggregate_reason.clone());
409
+ manifest.skipped_as(
410
+ "aggregate",
411
+ format!("{domain_name}::{agg_name}"),
412
+ "attribute_type",
413
+ aggregate_reason.clone(),
414
+ );
392
415
  let cascade = format!("owning aggregate not generated: {aggregate_reason}");
393
- for command in aggregate.get("commands").map(Json::each).unwrap_or(&[]) {
394
- manifest.skipped_as("command", format!("{domain_name}::{agg_name}.{}", node_name(command)), "owning_aggregate", cascade.clone());
416
+ for command in aggregate.get("commands").map_or_default(Json::each) {
417
+ manifest.skipped_as(
418
+ "command",
419
+ format!("{domain_name}::{agg_name}.{}", node_name(command)),
420
+ "owning_aggregate",
421
+ cascade.clone(),
422
+ );
395
423
  }
396
- for entity in aggregate.get("entities").map(Json::each).unwrap_or(&[]) {
424
+ for entity in aggregate.get("entities").map_or_default(Json::each) {
397
425
  let entity_verb = format!("{domain_name}::{agg_name}.{}", node_name(entity));
398
- manifest.skipped_as("entity", entity_verb.clone(), "owning_aggregate", cascade.clone());
399
- for command in entity.get("commands").map(Json::each).unwrap_or(&[]) {
400
- manifest.skipped_as("entity_command", format!("{entity_verb}.{}", node_name(command)), "owning_aggregate", cascade.clone());
426
+ manifest.skipped_as(
427
+ "entity",
428
+ entity_verb.clone(),
429
+ "owning_aggregate",
430
+ cascade.clone(),
431
+ );
432
+ for command in entity.get("commands").map_or_default(Json::each) {
433
+ manifest.skipped_as(
434
+ "entity_command",
435
+ format!("{entity_verb}.{}", node_name(command)),
436
+ "owning_aggregate",
437
+ cascade.clone(),
438
+ );
401
439
  }
402
440
  }
403
- for port in aggregate.get("ports").map(Json::each).unwrap_or(&[]) {
404
- for operation in port.get("operations").map(Json::each).unwrap_or(&[]) {
441
+ for port in aggregate.get("ports").map_or_default(Json::each) {
442
+ for operation in port.get("operations").map_or_default(Json::each) {
405
443
  manifest.skipped_as(
406
444
  "port_operation",
407
- format!("{domain_name}::{agg_name}.{}.{}", node_name(port), node_name(operation)),
445
+ format!(
446
+ "{domain_name}::{agg_name}.{}.{}",
447
+ node_name(port),
448
+ node_name(operation)
449
+ ),
408
450
  "owning_aggregate",
409
451
  cascade.clone(),
410
452
  );
@@ -428,7 +470,11 @@ pub fn generate(
428
470
  );
429
471
  puts_str(&mut out, "#![allow(dead_code, unused_variables)]");
430
472
  puts_str(&mut out, "use crate::kernel::Expr;");
431
- for line in crate::bridging::cross_aggregate_vo_imports(aggregate, &domain_value_object_owner, mod_name) {
473
+ for line in crate::bridging::cross_aggregate_vo_imports(
474
+ aggregate,
475
+ &domain_value_object_owner,
476
+ mod_name,
477
+ ) {
432
478
  puts_str(&mut out, &line);
433
479
  }
434
480
  puts_blank(&mut out);
@@ -444,8 +490,8 @@ pub fn generate(
444
490
  ),
445
491
  );
446
492
  puts_blank(&mut out);
447
- let closed_set = vo.get("closed_set").map(Json::as_bool).unwrap_or(false);
448
- let attrs = vo.get("attributes").map(Json::each).unwrap_or(&[]);
493
+ let closed_set = vo.get("closed_set").is_some_and(Json::as_bool);
494
+ let attrs = vo.get("attributes").map_or_default(Json::each);
449
495
  if closed_set && attrs.len() == 1 {
450
496
  puts_str(&mut out, &json_codec::emit_closed_set_codec(exemplar, vo));
451
497
  } else if closed_set {
@@ -458,7 +504,7 @@ pub fn generate(
458
504
  crate::naming::rust_ident(vo.get("name").and_then(Json::as_str).unwrap_or(""));
459
505
  puts_str(
460
506
  &mut out,
461
- &json_codec::emit_to_json_flat(exemplar, &name, attrs, &value_objects_by_name, false, &[], None),
507
+ &json_codec::emit_to_json_flat(exemplar, &name, attrs, false, &[], None),
462
508
  );
463
509
  puts_blank(&mut out);
464
510
  // `Some(&[])` refuses unknown keys: without it a mistyped nested field (`value`
@@ -476,6 +522,7 @@ pub fn generate(
476
522
  false,
477
523
  false,
478
524
  None,
525
+ None,
479
526
  ),
480
527
  );
481
528
  }
@@ -488,12 +535,21 @@ pub fn generate(
488
535
  // identity shape, not its command routability.
489
536
  let mut registry_entities: Vec<EntityIdentityEntry> = Vec::new();
490
537
 
491
- for entity in aggregate.get("entities").map(Json::each).unwrap_or(&[]) {
538
+ for entity in aggregate.get("entities").map_or_default(Json::each) {
492
539
  let entity_verb = format!("{domain_name}::{agg_name}.{}", node_name(entity));
493
540
  manifest.generated("entity", entity_verb.clone());
494
541
  registry_entities.push(EntityIdentityEntry {
495
- name: entity.get("name").and_then(Json::as_str).unwrap_or("").to_string(),
496
- identified_by: entity.get("identified_by").map(Json::each).unwrap_or(&[]).iter().map(Json::to_s).collect(),
542
+ name: entity
543
+ .get("name")
544
+ .and_then(Json::as_str)
545
+ .unwrap_or("")
546
+ .to_string(),
547
+ identified_by: entity
548
+ .get("identified_by")
549
+ .map_or_default(Json::each)
550
+ .iter()
551
+ .map(Json::to_s)
552
+ .collect(),
497
553
  });
498
554
  puts_str(
499
555
  &mut out,
@@ -502,7 +558,7 @@ pub fn generate(
502
558
  puts_blank(&mut out);
503
559
  let entity_name_ident =
504
560
  crate::naming::rust_ident(entity.get("name").and_then(Json::as_str).unwrap_or(""));
505
- let entity_attrs = entity.get("attributes").map(Json::each).unwrap_or(&[]);
561
+ let entity_attrs = entity.get("attributes").map_or_default(Json::each);
506
562
  let extra = lifecycle_extra_field(entity);
507
563
  puts_str(
508
564
  &mut out,
@@ -510,7 +566,6 @@ pub fn generate(
510
566
  exemplar,
511
567
  &entity_name_ident,
512
568
  entity_attrs,
513
- &value_objects_by_name,
514
569
  false,
515
570
  &extra,
516
571
  None,
@@ -538,7 +593,7 @@ pub fn generate(
538
593
  // dispatch at depth 2 additionally needs the same check on `nested`.
539
594
  let entity_can_route = json_codec::extract_id_supported(entity);
540
595
 
541
- for nested in entity.get("entities").map(Json::each).unwrap_or(&[]) {
596
+ for nested in entity.get("entities").map_or_default(Json::each) {
542
597
  let nested_verb = format!("{entity_verb}.{}", node_name(nested));
543
598
  manifest.generated("entity", nested_verb.clone());
544
599
  puts_str(
@@ -549,7 +604,7 @@ pub fn generate(
549
604
  let nested_name_ident = crate::naming::rust_ident(
550
605
  nested.get("name").and_then(Json::as_str).unwrap_or(""),
551
606
  );
552
- let nested_attrs = nested.get("attributes").map(Json::each).unwrap_or(&[]);
607
+ let nested_attrs = nested.get("attributes").map_or_default(Json::each);
553
608
  let nested_extra = lifecycle_extra_field(nested);
554
609
  puts_str(
555
610
  &mut out,
@@ -557,7 +612,6 @@ pub fn generate(
557
612
  exemplar,
558
613
  &nested_name_ident,
559
614
  nested_attrs,
560
- &value_objects_by_name,
561
615
  false,
562
616
  &nested_extra,
563
617
  None,
@@ -588,16 +642,23 @@ pub fn generate(
588
642
  if unrouted_supported {
589
643
  puts_str(&mut out, &json_codec::emit_extract_id(exemplar, nested));
590
644
  puts_blank(&mut out);
591
- puts_str(&mut out, &json_codec::emit_extract_id_lenient(exemplar, nested));
645
+ puts_str(
646
+ &mut out,
647
+ &json_codec::emit_extract_id_lenient(exemplar, nested),
648
+ );
592
649
  puts_blank(&mut out);
593
650
  puts_str(&mut out, &json_codec::emit_extract_wants(exemplar, nested));
594
651
  puts_blank(&mut out);
595
652
  }
596
653
 
597
- let nested_identified_by = nested.get("identified_by").map(Json::each).unwrap_or(&[]);
598
- for command in nested.get("commands").map(Json::each).unwrap_or(&[]) {
654
+ let nested_identified_by = nested.get("identified_by").map_or_default(Json::each);
655
+ for command in nested.get("commands").map_or_default(Json::each) {
599
656
  let nested_command_verb = format!("{nested_verb}.{}", node_name(command));
600
- if let Some(reason) = commands::entity_command_skip_reason(command, nested, &value_objects_by_name) {
657
+ if let Some(reason) = commands::entity_command_skip_reason(
658
+ command,
659
+ nested,
660
+ &value_objects_by_name,
661
+ ) {
601
662
  manifest.skipped("entity_command", nested_command_verb, reason);
602
663
  continue;
603
664
  }
@@ -632,7 +693,8 @@ pub fn generate(
632
693
  }),
633
694
  );
634
695
 
635
- let nested_command_name = command.get("name").and_then(Json::as_str).unwrap_or("");
696
+ let nested_command_name =
697
+ command.get("name").and_then(Json::as_str).unwrap_or("");
636
698
  let entity_name_str = entity.get("name").and_then(Json::as_str).unwrap_or("");
637
699
  let nested_name_str = nested.get("name").and_then(Json::as_str).unwrap_or("");
638
700
  nested_entity_commands.push(NestedEntityCommandEntry {
@@ -653,15 +715,8 @@ pub fn generate(
653
715
  reference_checks: reference_checks(command, &aggregates_by_name, &unsupported_names),
654
716
  reference_specs: crate::reference_specs::reference_specs(
655
717
  domain_name,
656
- command.get("attributes").map(Json::each).unwrap_or(&[]),
718
+ command.get("attributes").map_or_default(Json::each),
657
719
  ),
658
- attributes: command
659
- .get("attributes")
660
- .map(Json::each)
661
- .unwrap_or(&[])
662
- .iter()
663
- .map(|a| a.get("name").map(Json::to_s).unwrap_or_default())
664
- .collect(),
665
720
  invariant_check_lines: commands::invariant_checks_for(
666
721
  exemplar,
667
722
  command,
@@ -672,8 +727,7 @@ pub fn generate(
672
727
  entity_name: entity_name_str.to_string(),
673
728
  entity_identity_reading: entity
674
729
  .get("identified_by")
675
- .map(Json::each)
676
- .unwrap_or(&[])
730
+ .map_or_default(Json::each)
677
731
  .iter()
678
732
  .map(Json::to_s)
679
733
  .collect::<Vec<_>>()
@@ -692,7 +746,10 @@ pub fn generate(
692
746
  if entity_can_route {
693
747
  puts_str(&mut out, &json_codec::emit_extract_id(exemplar, entity));
694
748
  puts_blank(&mut out);
695
- puts_str(&mut out, &json_codec::emit_extract_id_lenient(exemplar, entity));
749
+ puts_str(
750
+ &mut out,
751
+ &json_codec::emit_extract_id_lenient(exemplar, entity),
752
+ );
696
753
  puts_blank(&mut out);
697
754
  puts_str(&mut out, &json_codec::emit_extract_wants(exemplar, entity));
698
755
  puts_blank(&mut out);
@@ -700,9 +757,11 @@ pub fn generate(
700
757
  puts_blank(&mut out);
701
758
  }
702
759
 
703
- for command in entity.get("commands").map(Json::each).unwrap_or(&[]) {
760
+ for command in entity.get("commands").map_or_default(Json::each) {
704
761
  let entity_command_verb = format!("{entity_verb}.{}", node_name(command));
705
- if let Some(reason) = commands::entity_command_skip_reason(command, entity, &value_objects_by_name) {
762
+ if let Some(reason) =
763
+ commands::entity_command_skip_reason(command, entity, &value_objects_by_name)
764
+ {
706
765
  manifest.skipped("entity_command", entity_command_verb, reason);
707
766
  continue;
708
767
  }
@@ -739,7 +798,7 @@ pub fn generate(
739
798
  manifest.routed("entity_command", entity_command_verb);
740
799
 
741
800
  let entity_command_name = command.get("name").and_then(Json::as_str).unwrap_or("");
742
- let identified_by = entity.get("identified_by").map(Json::each).unwrap_or(&[]);
801
+ let identified_by = entity.get("identified_by").map_or_default(Json::each);
743
802
  entity_commands.push(EntityCommandEntry {
744
803
  verb: format!(
745
804
  "{domain_name}::{agg_name}.{entity_name_ident}.{entity_command_name}",
@@ -769,12 +828,11 @@ pub fn generate(
769
828
  ),
770
829
  reference_specs: crate::reference_specs::reference_specs(
771
830
  domain_name,
772
- command.get("attributes").map(Json::each).unwrap_or(&[]),
831
+ command.get("attributes").map_or_default(Json::each),
773
832
  ),
774
833
  attributes: command
775
834
  .get("attributes")
776
- .map(Json::each)
777
- .unwrap_or(&[])
835
+ .map_or_default(Json::each)
778
836
  .iter()
779
837
  .map(|a| a.get("name").map(Json::to_s).unwrap_or_default())
780
838
  .collect(),
@@ -807,7 +865,10 @@ pub fn generate(
807
865
  &types::emit_record(exemplar, &record_for_struct, &value_objects_by_name),
808
866
  );
809
867
  puts_blank(&mut out);
810
- let record_attrs_owned = record_for_struct.get("attributes").map(Json::each).unwrap_or(&[]).to_vec();
868
+ let record_attrs_owned = record_for_struct
869
+ .get("attributes")
870
+ .map_or_default(Json::each)
871
+ .to_vec();
811
872
  let record_attrs = record_attrs_owned.as_slice();
812
873
  let extra = lifecycle_extra_field(aggregate);
813
874
  puts_str(
@@ -816,7 +877,6 @@ pub fn generate(
816
877
  exemplar,
817
878
  &record_name,
818
879
  record_attrs,
819
- &value_objects_by_name,
820
880
  true,
821
881
  &extra,
822
882
  Some(aggregate),
@@ -836,7 +896,7 @@ pub fn generate(
836
896
  ),
837
897
  );
838
898
  puts_blank(&mut out);
839
- puts_str(&mut out, &format!("impl crate::kernel::ToJson for {record_name} {{\n fn to_json(&self) -> crate::kernel::Json {{\n {record_name}::to_json(self)\n }}\n}}\n"));
899
+ puts_str(&mut out, &format!("impl crate::kernel::ToJson for {record_name} {{\n fn to_json(&self) -> crate::kernel::Json {{\n Self::to_json(self)\n }}\n}}\n"));
840
900
  puts_blank(&mut out);
841
901
  puts_str(&mut out, &types::emit_set_projected_field(aggregate));
842
902
  puts_blank(&mut out);
@@ -852,9 +912,11 @@ pub fn generate(
852
912
  puts_blank(&mut out);
853
913
 
854
914
  let mut registry_commands: Vec<CommandEntry> = Vec::new();
855
- for command in aggregate.get("commands").map(Json::each).unwrap_or(&[]) {
915
+ for command in aggregate.get("commands").map_or_default(Json::each) {
856
916
  let command_verb = format!("{domain_name}::{agg_name}.{}", node_name(command));
857
- if let Some(reason) = commands::command_skip_reason(command, aggregate, &value_objects_by_name) {
917
+ if let Some(reason) =
918
+ commands::command_skip_reason(command, aggregate, &value_objects_by_name)
919
+ {
858
920
  manifest.skipped("command", command_verb, reason);
859
921
  continue;
860
922
  }
@@ -874,10 +936,10 @@ pub fn generate(
874
936
 
875
937
  let command_name = command.get("name").and_then(Json::as_str).unwrap_or("");
876
938
  let args_struct = format!("{}Args", crate::naming::rust_ident(command_name));
877
- let cmd_attrs = command.get("attributes").map(Json::each).unwrap_or(&[]);
939
+ let cmd_attrs = command.get("attributes").map_or_default(Json::each);
878
940
  puts_str(
879
941
  &mut out,
880
- &json_codec::emit_to_json_flat_sparse(exemplar, &args_struct, cmd_attrs, &value_objects_by_name),
942
+ &json_codec::emit_to_json_flat_sparse(exemplar, &args_struct, cmd_attrs),
881
943
  );
882
944
  puts_blank(&mut out);
883
945
  let allowlist =
@@ -894,6 +956,7 @@ pub fn generate(
894
956
  true,
895
957
  true,
896
958
  Some(&aggregates_by_name),
959
+ Some(agg_name),
897
960
  ),
898
961
  );
899
962
  puts_blank(&mut out);
@@ -901,11 +964,16 @@ pub fn generate(
901
964
  // order by `kernel::decode_aggregate_arguments`.
902
965
  puts_str(
903
966
  &mut out,
904
- &json_codec::emit_argument_gates(&args_struct, command_name, cmd_attrs, Some(&allowlist)),
967
+ &json_codec::emit_argument_gates(
968
+ &args_struct,
969
+ command_name,
970
+ cmd_attrs,
971
+ Some(&allowlist),
972
+ ),
905
973
  );
906
974
  puts_blank(&mut out);
907
975
 
908
- let creates = crate::shared::creates_owner(aggregate, command, &value_objects_by_name);
976
+ let creates = crate::shared::creates_owner(aggregate, command);
909
977
  let identity = mutations::identity_components(aggregate, command);
910
978
  let identity_extra_params: Vec<String> = if creates {
911
979
  identity.iter().filter_map(|c| c.head.clone()).collect()
@@ -936,8 +1004,15 @@ pub fn generate(
936
1004
  identity_extra_params,
937
1005
  // `state_reference_checks` only adds entries `reference_checks` did not cover.
938
1006
  reference_checks: {
939
- let mut checks = reference_checks(command, &aggregates_by_name, &unsupported_names);
940
- checks.extend(state_reference_checks(aggregate, command, &aggregates_by_name, &unsupported_names, &value_objects_by_name));
1007
+ let mut checks =
1008
+ reference_checks(command, &aggregates_by_name, &unsupported_names);
1009
+ checks.extend(state_reference_checks(
1010
+ aggregate,
1011
+ command,
1012
+ &aggregates_by_name,
1013
+ &unsupported_names,
1014
+ &value_objects_by_name,
1015
+ ));
941
1016
  checks
942
1017
  },
943
1018
  tenant_boundary_checks: tenant_boundary_checks(
@@ -963,11 +1038,16 @@ pub fn generate(
963
1038
  }
964
1039
 
965
1040
  let mut port_operations: Vec<PortEntry> = Vec::new();
966
- for port in aggregate.get("ports").map(Json::each).unwrap_or(&[]) {
1041
+ for port in aggregate.get("ports").map_or_default(Json::each) {
967
1042
  let port_name = port.get("name").and_then(Json::as_str).unwrap_or("");
968
- for operation in port.get("operations").map(Json::each).unwrap_or(&[]) {
969
- let operation_verb = format!("{domain_name}::{agg_name}.{port_name}.{}", node_name(operation));
970
- if let Some(reason) = ports::port_operation_skip_reason(operation, agg_name, &value_objects_by_name) {
1043
+ for operation in port.get("operations").map_or_default(Json::each) {
1044
+ let operation_verb = format!(
1045
+ "{domain_name}::{agg_name}.{port_name}.{}",
1046
+ node_name(operation)
1047
+ );
1048
+ if let Some(reason) =
1049
+ ports::port_operation_skip_reason(operation, agg_name, &value_objects_by_name)
1050
+ {
971
1051
  manifest.skipped("port_operation", operation_verb, reason);
972
1052
  continue;
973
1053
  }
@@ -988,7 +1068,7 @@ pub fn generate(
988
1068
  puts_blank(&mut out);
989
1069
 
990
1070
  let operation_name = operation.get("name").and_then(Json::as_str).unwrap_or("");
991
- let operation_attrs = operation.get("attributes").map(Json::each).unwrap_or(&[]);
1071
+ let operation_attrs = operation.get("attributes").map_or_default(Json::each);
992
1072
  let legacy_receiver_field = operation_attrs
993
1073
  .iter()
994
1074
  .find(|attr| {
@@ -999,19 +1079,19 @@ pub fn generate(
999
1079
  // A `to:`-declared operation has no Reference-typed attribute; its receiver is a
1000
1080
  // plain attribute named for the aggregate's identified_by field. Kept apart from
1001
1081
  // legacy_receiver_field because `split_aggregate_receiver` must not strip it.
1002
- let to_receiver_field = if operation.get("to").and_then(Json::as_str) == Some(agg_name) {
1003
- // `identified_by` holds identity paths: a value-object identity is dotted
1004
- // ("reference.value"), while the attribute is named "reference".
1005
- aggregate
1006
- .get("identified_by")
1007
- .map(Json::each)
1008
- .unwrap_or(&[])
1009
- .first()
1010
- .map(Json::to_s)
1011
- .and_then(|s| s.split('.').next().map(str::to_string))
1012
- } else {
1013
- None
1014
- };
1082
+ let to_receiver_field =
1083
+ if operation.get("to").and_then(Json::as_str) == Some(agg_name) {
1084
+ // `identified_by` holds identity paths: a value-object identity is dotted
1085
+ // ("reference.value"), while the attribute is named "reference".
1086
+ aggregate
1087
+ .get("identified_by")
1088
+ .map_or_default(Json::each)
1089
+ .first()
1090
+ .map(Json::to_s)
1091
+ .and_then(|s| s.split('.').next().map(str::to_string))
1092
+ } else {
1093
+ None
1094
+ };
1015
1095
  let operation_reference_checks =
1016
1096
  reference_checks(operation, &aggregates_by_name, &unsupported_names)
1017
1097
  .into_iter()
@@ -1019,7 +1099,6 @@ pub fn generate(
1019
1099
  .collect();
1020
1100
  port_operations.push(PortEntry {
1021
1101
  verb: format!("{domain_name}::{agg_name}.{port_name}.{operation_name}"),
1022
- name: operation_name.to_string(),
1023
1102
  fn_name: format!(
1024
1103
  "{}_{}",
1025
1104
  port_name.to_lowercase(),
@@ -1054,9 +1133,14 @@ pub fn generate(
1054
1133
  domain_name: domain_name.to_string(),
1055
1134
  reference_specs: crate::reference_specs::reference_specs(
1056
1135
  domain_name,
1057
- aggregate.get("attributes").map(Json::each).unwrap_or(&[]),
1136
+ aggregate.get("attributes").map_or_default(Json::each),
1058
1137
  ),
1059
- identified_by: aggregate.get("identified_by").map(Json::each).unwrap_or(&[]).iter().map(Json::to_s).collect(),
1138
+ identified_by: aggregate
1139
+ .get("identified_by")
1140
+ .map_or_default(Json::each)
1141
+ .iter()
1142
+ .map(Json::to_s)
1143
+ .collect(),
1060
1144
  entities: registry_entities,
1061
1145
  });
1062
1146
  }
@@ -1065,10 +1149,7 @@ pub fn generate(
1065
1149
  let assignments_verb = queries::provided_assignments(ir);
1066
1150
  for aggregate in all_aggregates {
1067
1151
  let agg_name = aggregate.get("name").and_then(Json::as_str).unwrap_or("");
1068
- let value_objects = aggregate
1069
- .get("value_objects")
1070
- .map(Json::each)
1071
- .unwrap_or(&[]);
1152
+ let value_objects = aggregate.get("value_objects").map_or_default(Json::each);
1072
1153
  let value_objects_by_name: HashMap<String, &Json> = value_objects
1073
1154
  .iter()
1074
1155
  .map(|vo| {
@@ -1082,40 +1163,74 @@ pub fn generate(
1082
1163
  })
1083
1164
  .collect();
1084
1165
 
1085
- for query in aggregate.get("queries").map(Json::each).unwrap_or(&[]) {
1166
+ for query in aggregate.get("queries").map_or_default(Json::each) {
1086
1167
  let query_name = query.get("name").and_then(Json::as_str).unwrap_or("");
1087
- if let Some(reason) = queries::query_skip_reason(query, aggregate, &value_objects_by_name, &aggregates_by_name) {
1088
- manifest.skipped("query", format!("{domain_name}::{agg_name}.{query_name}"), reason);
1168
+ if let Some(reason) = queries::query_skip_reason(
1169
+ query,
1170
+ aggregate,
1171
+ &value_objects_by_name,
1172
+ &aggregates_by_name,
1173
+ ) {
1174
+ manifest.skipped(
1175
+ "query",
1176
+ format!("{domain_name}::{agg_name}.{query_name}"),
1177
+ reason,
1178
+ );
1089
1179
  continue;
1090
1180
  }
1091
1181
  manifest.generated("query", format!("{domain_name}::{agg_name}.{query_name}"));
1092
1182
 
1093
- let (conditions, reference_hop_conditions) = queries::query_conditions_and_hops(domain_name, query, aggregate, &aggregates_by_name);
1183
+ let (conditions, reference_hop_conditions) = queries::query_conditions_and_hops(
1184
+ domain_name,
1185
+ query,
1186
+ aggregate,
1187
+ &aggregates_by_name,
1188
+ );
1094
1189
  query_defs.push(queries::QueryDef {
1095
1190
  verb: format!("{domain_name}::{agg_name}.{query_name}"),
1096
1191
  aggregate: format!("{domain_name}::{agg_name}"),
1097
- arg_checks: queries::query_arg_checks(query, &format!("crate::generated::{mod_name}::{}", crate::naming::aggregate_module(agg_name)), &value_objects_by_name),
1192
+ arg_checks: queries::query_arg_checks(
1193
+ query,
1194
+ &format!(
1195
+ "crate::generated::{mod_name}::{}",
1196
+ crate::naming::aggregate_module(agg_name)
1197
+ ),
1198
+ &value_objects_by_name,
1199
+ ),
1098
1200
  conditions,
1099
1201
  reference_hop_conditions,
1100
- order_by: query.get("order_by").map(|ob| queries::emit_query_order_by(ob, query.get("null_semantics"))),
1202
+ order_by: query
1203
+ .get("order_by")
1204
+ .map(|ob| queries::emit_query_order_by(ob, query.get("null_semantics"))),
1101
1205
  offset: query.get("offset").map(queries::emit_query_offset),
1102
1206
  limit: query.get("limit").map(queries::emit_query_limit),
1103
- authorization: queries::emit_query_authorization(query_name, query.get("authorization")),
1104
- assignments: assignments_verb.as_deref() == Some(format!("{agg_name}.{query_name}").as_str()),
1207
+ authorization: queries::emit_query_authorization(
1208
+ query_name,
1209
+ query.get("authorization"),
1210
+ ),
1211
+ assignments: assignments_verb.as_deref()
1212
+ == Some(format!("{agg_name}.{query_name}").as_str()),
1105
1213
  entity: None,
1106
1214
  });
1107
1215
  }
1108
1216
 
1109
1217
  // Entity queries, one level down.
1110
1218
  let aggregate_id = format!("{domain_name}::{agg_name}");
1111
- let attrs = aggregate.get("attributes").map(Json::each).unwrap_or(&[]);
1112
- for entity in aggregate.get("entities").map(Json::each).unwrap_or(&[]) {
1219
+ let attrs = aggregate.get("attributes").map_or_default(Json::each);
1220
+ for entity in aggregate.get("entities").map_or_default(Json::each) {
1113
1221
  let entity_name = entity.get("name").and_then(Json::as_str).unwrap_or("");
1114
- let list_attr = attrs.iter().find(|a| crate::attr::list(a) && crate::attr::type_name(a) == entity_name);
1115
- for query in entity.get("queries").map(Json::each).unwrap_or(&[]) {
1222
+ let list_attr = attrs
1223
+ .iter()
1224
+ .find(|a| crate::attr::list(a) && crate::attr::type_name(a) == entity_name);
1225
+ for query in entity.get("queries").map_or_default(Json::each) {
1116
1226
  let query_name = query.get("name").and_then(Json::as_str).unwrap_or("");
1117
1227
  let query_verb = format!("{aggregate_id}.{entity_name}.{query_name}");
1118
- if let Some(reason) = queries::entity_query_skip_reason(query, entity, list_attr.is_some(), &value_objects_by_name) {
1228
+ if let Some(reason) = queries::entity_query_skip_reason(
1229
+ query,
1230
+ entity,
1231
+ list_attr.is_some(),
1232
+ &value_objects_by_name,
1233
+ ) {
1119
1234
  manifest.skipped("query", query_verb, reason);
1120
1235
  continue;
1121
1236
  }
@@ -1123,8 +1238,7 @@ pub fn generate(
1123
1238
  manifest.generated("query", query_verb);
1124
1239
  let identity_keys = entity
1125
1240
  .get("identified_by")
1126
- .map(Json::each)
1127
- .unwrap_or(&[])
1241
+ .map_or_default(Json::each)
1128
1242
  .iter()
1129
1243
  .map(|path| Json::to_s(path).split('.').next().unwrap_or("").to_string())
1130
1244
  .collect();
@@ -1134,26 +1248,33 @@ pub fn generate(
1134
1248
  arg_checks: Vec::new(),
1135
1249
  conditions: queries::query_conditions(query),
1136
1250
  reference_hop_conditions: Vec::new(),
1137
- order_by: query.get("order_by").map(|ob| queries::emit_query_order_by(ob, query.get("null_semantics"))),
1251
+ order_by: query
1252
+ .get("order_by")
1253
+ .map(|ob| queries::emit_query_order_by(ob, query.get("null_semantics"))),
1138
1254
  offset: query.get("offset").map(queries::emit_query_offset),
1139
1255
  limit: query.get("limit").map(queries::emit_query_limit),
1140
1256
  authorization: None,
1141
1257
  assignments: false,
1142
1258
  entity: Some(queries::EntityScope {
1143
1259
  list_field: crate::attr::name(list_attr).to_string(),
1144
- parent_key: crate::naming::snake(agg_name),
1260
+ parent_key: crate::hecks_naming::snake(agg_name),
1145
1261
  identity_keys,
1146
1262
  }),
1147
1263
  });
1148
1264
  }
1149
- manifest.entity_query_gaps(&format!("{aggregate_id}.{entity_name}"), entity.get("entities").map(Json::each).unwrap_or(&[]));
1265
+ manifest.entity_query_gaps(
1266
+ &format!("{aggregate_id}.{entity_name}"),
1267
+ entity.get("entities").map_or_default(Json::each),
1268
+ );
1150
1269
  }
1151
1270
  }
1152
1271
 
1153
1272
  let mut read_model_defs: Vec<read_models::ReadModelDef> = Vec::new();
1154
- for read_model in ir.get("read_models").map(Json::each).unwrap_or(&[]) {
1273
+ for read_model in ir.get("read_models").map_or_default(Json::each) {
1155
1274
  let read_model_id = format!("{domain_name}::{}", node_name(read_model));
1156
- if let Some(reason) = read_models::read_model_skip_reason(read_model, &aggregates_by_name, &unsupported_names) {
1275
+ if let Some(reason) =
1276
+ read_models::read_model_skip_reason(read_model, &aggregates_by_name, &unsupported_names)
1277
+ {
1157
1278
  manifest.skipped("read_model", read_model_id, reason);
1158
1279
  continue;
1159
1280
  }
@@ -1166,14 +1287,20 @@ pub fn generate(
1166
1287
  }
1167
1288
 
1168
1289
  // Policies and process managers have no per-instance skip condition.
1169
- for policy in ir.get("policies").map(Json::each).unwrap_or(&[]) {
1290
+ for policy in ir.get("policies").map_or_default(Json::each) {
1170
1291
  manifest.routed("policy", format!("{domain_name}::{}", node_name(policy)));
1171
1292
  }
1172
1293
  for pm in &process_managers {
1173
- manifest.routed("process_manager", format!("{domain_name}::{}", node_name(pm)));
1294
+ manifest.routed(
1295
+ "process_manager",
1296
+ format!("{domain_name}::{}", node_name(pm)),
1297
+ );
1174
1298
  }
1175
1299
  // Lineage-capable aggregates are always generated and routed; the journal path is generic.
1176
- let lineage_aggregates = ir.get("lineage").and_then(|l| l.get("capable_aggregates")).map(Json::each).unwrap_or(&[]);
1300
+ let lineage_aggregates = ir
1301
+ .get("lineage")
1302
+ .and_then(|l| l.get("capable_aggregates"))
1303
+ .map_or_default(Json::each);
1177
1304
  for lineage_aggregate in lineage_aggregates {
1178
1305
  manifest.record(
1179
1306
  "lineage_aggregate",
@@ -1189,10 +1316,10 @@ pub fn generate(
1189
1316
  );
1190
1317
  }
1191
1318
 
1192
- let policies: Vec<Json> = ir.get("policies").map(Json::each).unwrap_or(&[]).to_vec();
1319
+ let policies: Vec<Json> = ir.get("policies").map_or_default(Json::each).to_vec();
1193
1320
  // Raw aggregate JSON: a fan-out's addressing key comes from the target command's declared
1194
1321
  // `references`/`attributes`, which `AggregateEntry` does not carry.
1195
- let policy_aggregates: Vec<Json> = ir.get("aggregates").map(Json::each).unwrap_or(&[]).to_vec();
1322
+ let policy_aggregates: Vec<Json> = ir.get("aggregates").map_or_default(Json::each).to_vec();
1196
1323
 
1197
1324
  let mut registry_rs = String::new();
1198
1325
  puts_str(
@@ -1254,7 +1381,10 @@ pub fn generate(
1254
1381
  &queries::emit_query_table(exemplar, &query_defs),
1255
1382
  );
1256
1383
  puts_blank(&mut registry_rs);
1257
- puts_str(&mut registry_rs, &queries::emit_query_arg_check_table(&query_defs));
1384
+ puts_str(
1385
+ &mut registry_rs,
1386
+ &queries::emit_query_arg_check_table(&query_defs),
1387
+ );
1258
1388
  puts_blank(&mut registry_rs);
1259
1389
  for rmd in &read_model_defs {
1260
1390
  if let Some(body) = &rmd.group_by_fn_body {