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.
- checksums.yaml +4 -4
- data/examples/pizzas/adapters/fake_processor.rb +34 -0
- data/examples/pizzas/adapters/payment_signature.rb +66 -0
- data/examples/pizzas/adapters/payment_webhook.rb +87 -0
- data/examples/pizzas/bluebook/pizzas.behaviors +33 -0
- data/examples/pizzas/bluebook/pizzas.bluebook +4 -4
- data/examples/pizzas/bluebook/pizzas.hecksagon +5 -3
- data/examples/pizzas/config.ru +22 -0
- data/lib/hecks/adapters/driven/prism.rb +0 -2
- data/lib/hecks/adapters/driven.rb +0 -2
- data/lib/hecks/adapters/driving/json.rb +1 -7
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +15 -5
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +2 -2
- data/lib/hecks/bluebook/dsl/derivation_words.rb +58 -0
- data/lib/hecks/bluebook/dsl/translation_builder.rb +6 -37
- data/lib/hecks/bluebook/expression/ast_json.rb +0 -9
- data/lib/hecks/bluebook/hecksagon.rb +1 -1
- data/lib/hecks/bluebook/meta_validator/translation_judge/rules.rb +7 -10
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +4 -8
- data/lib/hecks/bluebook/meta_validator.rb +0 -11
- data/lib/hecks/bluebook/named_pattern.rb +33 -0
- data/lib/hecks/bluebook/translation.rb +18 -10
- data/lib/hecks/bluebook/translation_expression/evaluator.rb +63 -0
- data/lib/hecks/bluebook/translation_expression/parser.rb +127 -0
- data/lib/hecks/bluebook/translation_expression.rb +39 -0
- data/lib/hecks/bluebook/translation_plan.rb +70 -0
- data/lib/hecks/bluebook.rb +3 -0
- data/lib/hecks/chapters.rb +3 -3
- data/lib/hecks/cli/domain_stub.rb +1 -1
- data/lib/hecks/cli/interview_aggregate.rb +4 -4
- data/lib/hecks/composer/adapters/claude_composer.adapter +3 -0
- data/lib/hecks/composer/adapters/claude_composer.rb +83 -0
- data/lib/hecks/composer/adapters/fake_agent.adapter +3 -0
- data/lib/hecks/composer/adapters/fake_agent.rb +55 -0
- data/lib/hecks/composer/adapters/jev.adapter +3 -0
- data/lib/hecks/composer/adapters/jev.rb +66 -0
- data/lib/hecks/composer/agent.rb +113 -0
- data/lib/hecks/composer/assistant.rb +110 -0
- data/lib/hecks/composer/behavior_run.rb +53 -0
- data/lib/hecks/composer/bluebook/composer.bluebook +178 -0
- data/lib/hecks/composer/bluebook/composer.hecksagon +16 -0
- data/lib/hecks/composer/board.rb +65 -0
- data/lib/hecks/composer/board_edit/command_text.rb +39 -0
- data/lib/hecks/composer/board_edit/source.rb +84 -0
- data/lib/hecks/composer/board_edit.rb +144 -0
- data/lib/hecks/composer/check.rb +89 -0
- data/lib/hecks/composer/domains.rb +81 -0
- data/lib/hecks/composer/jobs.rb +134 -0
- data/lib/hecks/composer/layout.rb +37 -0
- data/lib/hecks/composer/live.rb +150 -0
- data/lib/hecks/composer/outline.rb +48 -0
- data/lib/hecks/composer/page.html +989 -0
- data/lib/hecks/composer/panels.rb +142 -0
- data/lib/hecks/composer/parse.rb +83 -0
- data/lib/hecks/composer/plain.rb +28 -0
- data/lib/hecks/composer/ports/composer_agent.port +7 -0
- data/lib/hecks/composer/session.rb +141 -0
- data/lib/hecks/composer/toolbox.rb +166 -0
- data/lib/hecks/composer/web.rb +156 -0
- data/lib/hecks/composer/workbench.rb +51 -0
- data/lib/hecks/composer/workspace.rb +81 -0
- data/lib/hecks/composer.rb +17 -0
- data/lib/hecks/corpus/adapters.rb +22 -0
- data/lib/hecks/corpus/rust.rb +1 -1
- data/lib/hecks/corpus/worlds.rb +19 -0
- data/lib/hecks/corpus.rb +5 -0
- data/lib/hecks/deploy/bluebook/deploy.bluebook +34 -34
- data/lib/hecks/forms/app/commands.rb +2 -3
- data/lib/hecks/forms/app/queries.rb +2 -3
- data/lib/hecks/forms/app/records.rb +17 -5
- data/lib/hecks/forms/command_form_renderer.rb +42 -16
- data/lib/hecks/forms/field_controls.rb +2 -2
- data/lib/hecks/forms/field_renderer.rb +1 -1
- data/lib/hecks/forms/field_shape.rb +36 -17
- data/lib/hecks/forms/index_renderer.rb +2 -1
- data/lib/hecks/forms/page.rb +1 -1
- data/lib/hecks/forms/params.rb +0 -13
- data/lib/hecks/forms/query_form_renderer.rb +7 -6
- data/lib/hecks/forms/record_renderer.rb +11 -7
- data/lib/hecks/forms/rule_words.rb +100 -0
- data/lib/hecks/forms/value_object_shape.rb +2 -1
- data/lib/hecks/framework/bluebook/change.bluebook +2 -2
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +0 -3
- data/lib/hecks/fuzzing/domain_generator/block_rendering.rb +1 -1
- data/lib/hecks/fuzzing/isolated_boot/worlds.rb +3 -6
- data/lib/hecks/fuzzing/replay/filters.rb +2 -6
- data/lib/hecks/gate/stages.yml +25 -0
- data/lib/hecks/grammar/evolve/seeds.rb +0 -6
- data/lib/hecks/grammar/evolve.rb +0 -3
- data/lib/hecks/grammar/translation.bluebook +1 -1
- data/lib/hecks/hecks/adapters/codebase/composing.rb +56 -0
- data/lib/hecks/hecks/adapters/codebase/source_tree.rb +3 -1
- data/lib/hecks/hecks/adapters/journal_store/changes.rb +0 -26
- data/lib/hecks/hecks/adapters/journal_store/examination.rb +2 -23
- data/lib/hecks/hecks/adapters/journal_store/readings.rb +3 -11
- data/lib/hecks/hecks/adapters/journal_store.rb +0 -11
- data/lib/hecks/hecks/adapters/rehearsal/inquiry.rb +4 -11
- data/lib/hecks/hecks/adapters/rehearsal/memory_store.rb +0 -9
- data/lib/hecks/hecks/adapters/rehearsal/postgres_reading.rb +0 -4
- data/lib/hecks/hecks/codebase.behaviors +6 -0
- data/lib/hecks/hecks/codebase.bluebook +58 -37
- data/lib/hecks/hecks/composer.behaviors +68 -0
- data/lib/hecks/hecks/context_map.hecksagon +1 -1
- data/lib/hecks/hecks/custodian.behaviors +0 -6
- data/lib/hecks/hecks/custodian.bluebook +15 -92
- data/lib/hecks/hecks/hecks.bluebook +2 -2
- data/lib/hecks/hecks/hecks.hecksagon +2 -2
- data/lib/hecks/hecks/hecks.world +1 -1
- data/lib/hecks/hecks/rehearsal.bluebook +10 -16
- data/lib/hecks/hecks/tooling.bluebook +22 -22
- data/lib/hecks/kernel_capabilities/templates.rb +4 -4
- data/lib/hecks/kernel_capabilities.rb +1 -1
- data/lib/hecks/language/bluebook/aggregate.bluebook +1 -0
- data/lib/hecks/language/bluebook/command.bluebook +1 -0
- data/lib/hecks/language/bluebook/entity.bluebook +1 -0
- data/lib/hecks/language/bluebook/query.bluebook +1 -0
- data/lib/hecks/language/bluebook/shape.bluebook +8 -7
- data/lib/hecks/language/bluebook/vocabulary.bluebook +2 -3
- data/lib/hecks/language/hecksagon/port_operation.bluebook +1 -0
- data/lib/hecks/language/translation/translation_aggregate.bluebook +21 -24
- data/lib/hecks/ports/access_control.rb +2 -2
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +3 -41
- data/lib/hecks/ports/persistence/plugins/era/lineage/coverage.rb +7 -7
- data/lib/hecks/ports/persistence/plugins/era/lineage/rewrite.rb +25 -2
- data/lib/hecks/ports/persistence/plugins/era/lineage/rules.rb +4 -4
- data/lib/hecks/ports/persistence/plugins/era/lineage.rb +17 -25
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/base_sql.rb +0 -12
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/domain_rename.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +2 -22
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +0 -1
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +9 -3
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +3 -29
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/refusals.rb +2 -26
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +6 -33
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +3 -3
- data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +2 -4
- data/lib/hecks/ports/persistence/plugins/era/translation/expression_sql.rb +52 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +23 -29
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +1 -1
- data/lib/hecks/ports/persistence/plugins/era/translation.rb +0 -1
- data/lib/hecks/ports/persistence/plugins/era.rb +3 -6
- data/lib/hecks/ports.rb +0 -1
- data/lib/hecks/projection_files.rb +3 -1
- data/lib/hecks/projections/deploy/templates/lambda/nat_comment_oauth.tmpl +1 -1
- data/lib/hecks/projections/glossary/entries.rb +10 -4
- data/lib/hecks/projections/glossary/groups.rb +42 -0
- data/lib/hecks/projections/glossary/html/page.rb +7 -2
- data/lib/hecks/projections/glossary/html/parser.rb +1 -1
- data/lib/hecks/projections/glossary/html/sections.rb +31 -11
- data/lib/hecks/projections/glossary/html.rb +1 -2
- data/lib/hecks/projections/glossary/markdown.rb +31 -28
- data/lib/hecks/projections/glossary/mermaid.rb +3 -0
- data/lib/hecks/projections/glossary/page.css +143 -153
- data/lib/hecks/projections/glossary/page.js +63 -3
- data/lib/hecks/projections/glossary/sentences/actions.rb +88 -0
- data/lib/hecks/projections/glossary/sentences/paths.rb +77 -0
- data/lib/hecks/projections/glossary/sentences/queries.rb +90 -0
- data/lib/hecks/projections/glossary/sentences/value_objects.rb +32 -5
- data/lib/hecks/projections/glossary/sentences.rb +13 -3
- data/lib/hecks/projections/glossary/slugs.rb +4 -1
- data/lib/hecks/projections/glossary.rb +2 -1
- data/lib/hecks/projections/plain_english.rb +97 -0
- data/lib/hecks/projections/rust_vocabulary/arguments.rb +2 -2
- data/lib/hecks/projections/rust_vocabulary/enum_body.rb +20 -25
- data/lib/hecks/projections/rust_vocabulary/tests.rb +2 -2
- data/lib/hecks/projections/rust_vocabulary.rb +14 -6
- data/lib/hecks/projections/site/cms_editor/color.rb +0 -6
- data/lib/hecks/projections/statements/actions.rb +99 -0
- data/lib/hecks/projections/statements/relationships.rb +86 -0
- data/lib/hecks/projections/statements.rb +15 -24
- data/lib/hecks/projector/exporter/adapters.rb +112 -0
- data/lib/hecks/projector/exporter/translations.rb +18 -35
- data/lib/hecks/projector/exporter/worlds.rb +103 -0
- data/lib/hecks/projector/exporter.rb +5 -1
- data/lib/hecks/quality_control/adapters/agent.rb +6 -7
- data/lib/hecks/quality_control/adapters/agent_profile.rb +16 -114
- data/lib/hecks/quality_control/cli/qa_mine_combinations.rb +1 -1
- data/lib/hecks/quality_control/quality_control.bluebook +51 -51
- data/lib/hecks/runtime/loader/boot_steps.rb +0 -20
- data/lib/hecks/runtime/outbox.rb +2 -9
- data/lib/hecks/runtime/port_operation_interpreter.rb +1 -9
- data/lib/hecks/runtime/remote_dispatcher.rb +2 -2
- data/lib/hecks/runtime/value.rb +13 -0
- data/lib/hecks/rust_build/project_rust/target_ir.rb +23 -4
- data/lib/hecks/rust_build/wasm.rb +0 -12
- data/lib/hecks/rust_build/write_if_changed.rb +12 -12
- data/lib/hecks/rust_format.rb +77 -0
- data/lib/hecks/site/bluebook/site.bluebook +5 -5
- data/lib/hecks/sme/bluebook/sme.bluebook +12 -12
- data/lib/hecks/tickets/bluebook/tickets.bluebook +3 -3
- data/lib/hecks/tools/fuzz_sweep/findings.rb +3 -9
- data/lib/hecks/tools/fuzz_sweep.rb +1 -3
- data/lib/hecks/tools/translation_audit/verdicts.rb +3 -28
- data/lib/hecks/tools/translation_audit.rb +8 -10
- data/lib/hecks/tools/translation_scaffold/reporting.rb +1 -1
- data/lib/hecks/version.rb +1 -1
- data/lib/hecks/vocabulary.rb +2 -1
- data/lib/hecks.rb +3 -0
- data/prebuilt/{58208399bada10b0db99928c48e38789288fc58f7b71a72b21bfa386680e32ed.marshal → 02c09c73b272c1fb5a9ae6d87bb5e5e529208e00f6b4b597dc2c0fd70a9c0964.marshal} +0 -0
- data/prebuilt/{2b59737fbdbd5f44edda0fddce2611f45d76087b3a7c782d1f1a17ea58c77948.marshal → bb84a835cf6a15136bad5ca03aa5bf93a5b92f5f72444618d3ef2412b987fb32.marshal} +0 -0
- data/prebuilt/verdicts-f1f10da14c8e8f01b4c9b7e3e2d74be8cd2bf4676364ed17fa16975d2a076d75.json +1 -0
- data/rust/Cargo.toml +40 -0
- data/rust/build/Cargo.toml +36 -0
- data/rust/build/clippy.toml +4 -0
- data/rust/build/src/adapters_pass.rs +196 -0
- data/rust/build/src/binding_pass.rs +54 -13
- data/rust/build/src/build_artifact.rs +23 -5
- data/rust/build/src/cargo_sync.rs +69 -26
- data/rust/build/src/lineage_pass.rs +101 -87
- data/rust/build/src/main.rs +11 -2
- data/rust/build/src/pipeline.rs +80 -19
- data/rust/build/src/reserved_names.rs +6 -50
- data/rust/build/src/resolve.rs +82 -35
- data/rust/build/src/rustfmt.rs +100 -0
- data/rust/build/src/seams_pass.rs +85 -16
- data/rust/build/src/subprocess.rs +30 -6
- data/rust/build/src/tmp.rs +5 -2
- data/rust/build/src/translation_pass.rs +72 -22
- data/rust/build/src/world_pass.rs +109 -0
- data/rust/clippy.toml +4 -0
- data/rust/codegen/Cargo.toml +36 -0
- data/rust/codegen/clippy.toml +4 -0
- data/rust/codegen/src/asks.rs +40 -14
- data/rust/codegen/src/attr.rs +2 -2
- data/rust/codegen/src/bridging.rs +676 -117
- data/rust/codegen/src/commands.rs +979 -373
- data/rust/codegen/src/constraints.rs +88 -25
- data/rust/codegen/src/dependency_planning.rs +128 -34
- data/rust/codegen/src/domain_generator.rs +300 -170
- data/rust/codegen/src/exemplar.rs +87 -32
- data/rust/codegen/src/expr_emitter.rs +54 -6
- data/rust/codegen/src/fielded.rs +193 -41
- data/rust/codegen/src/hecks_naming.rs +124 -16
- data/rust/codegen/src/hecks_naming_tests.rs +81 -0
- data/rust/codegen/src/json.rs +80 -44
- data/rust/codegen/src/json_codec.rs +585 -149
- data/rust/codegen/src/literal.rs +104 -138
- data/rust/codegen/src/main.rs +145 -52
- data/rust/codegen/src/manifest.rs +76 -14
- data/rust/codegen/src/mutations.rs +1212 -239
- data/rust/codegen/src/naming.rs +111 -60
- data/rust/codegen/src/optional_pass.rs +90 -28
- data/rust/codegen/src/ports.rs +5 -4
- data/rust/codegen/src/prelude.rs +139 -49
- data/rust/codegen/src/queries.rs +601 -226
- data/rust/codegen/src/reactions.rs +268 -74
- data/rust/codegen/src/read_models.rs +606 -205
- data/rust/codegen/src/reference_specs.rs +16 -3
- data/rust/codegen/src/registry.rs +128 -79
- data/rust/codegen/src/reserved_names.rs +6 -50
- data/rust/codegen/src/shared.rs +71 -22
- data/rust/codegen/src/sidecars.rs +15 -5
- data/rust/codegen/src/skip_reason.rs +8 -2
- data/rust/codegen/src/types.rs +306 -108
- data/rust/host/Cargo.lock +1 -0
- data/rust/host/Cargo.toml +40 -4
- data/rust/host/HECKS_RELEASE +1 -1
- data/rust/host/clippy.toml +4 -0
- data/rust/host/src/api.rs +698 -218
- data/rust/host/src/auth.rs +491 -214
- data/rust/host/src/b64.rs +91 -0
- data/rust/host/src/bin/expr_harness.rs +6 -2
- data/rust/host/src/bin/lineage_harness.rs +47 -11
- data/rust/host/src/bin/mint_harness.rs +70 -37
- data/rust/host/src/bin/validate_harness.rs +16 -8
- data/rust/host/src/boot.rs +144 -68
- data/rust/host/src/boundary_fuzz/api.rs +130 -32
- data/rust/host/src/boundary_fuzz/auth.rs +108 -23
- data/rust/host/src/boundary_fuzz/expr_json.rs +85 -11
- data/rust/host/src/boundary_fuzz/ir.rs +164 -12
- data/rust/host/src/boundary_fuzz/server.rs +283 -36
- data/rust/host/src/boundary_fuzz/web.rs +56 -8
- data/rust/host/src/checkout.rs +78 -32
- data/rust/host/src/clock.rs +8 -0
- data/rust/host/src/commerce_ir.rs +333 -95
- data/rust/host/src/crypto.rs +33 -0
- data/rust/host/src/dispatch.rs +990 -331
- data/rust/host/src/expr_json.rs +1021 -273
- data/rust/host/src/extension.rs +24 -4
- data/rust/host/src/field_hints.rs +11 -7
- data/rust/host/src/fuzz_support.rs +85 -13
- data/rust/host/src/host.rs +100 -0
- data/rust/host/src/http.rs +22 -0
- data/rust/host/src/ir.rs +326 -16
- data/rust/host/src/journal.rs +277 -176
- data/rust/host/src/lambda_client.rs +219 -53
- data/rust/host/src/lib.rs +16 -4
- data/rust/host/src/log.rs +62 -11
- data/rust/host/src/mint.rs +1153 -326
- data/rust/host/src/needs.rs +185 -44
- data/rust/host/src/payments/keystore.rs +197 -45
- data/rust/host/src/payments/roles.rs +191 -0
- data/rust/host/src/payments/tests.rs +1445 -275
- data/rust/host/src/payments.rs +409 -121
- data/rust/host/src/platform_signin/attack_tests.rs +5 -5
- data/rust/host/src/platform_signin/config.rs +11 -11
- data/rust/host/src/platform_signin/cookie.rs +2 -2
- data/rust/host/src/platform_signin/extension.rs +2 -1
- data/rust/host/src/platform_signin/handler.rs +9 -8
- data/rust/host/src/platform_signin/jti.rs +4 -2
- data/rust/host/src/platform_signin/jwks.rs +2 -1
- data/rust/host/src/platform_signin/jws.rs +2 -37
- data/rust/host/src/platform_signin/known_answer_tests.rs +5 -1
- data/rust/host/src/platform_signin/mode_tests.rs +5 -3
- data/rust/host/src/platform_signin/pages.rs +20 -20
- data/rust/host/src/platform_signin/session.rs +8 -1
- data/rust/host/src/platform_signin/settings.rs +6 -6
- data/rust/host/src/platform_signin/strict_json.rs +12 -9
- data/rust/host/src/platform_signin/verify.rs +41 -41
- data/rust/host/src/platform_signin/wiring_support.rs +13 -18
- data/rust/host/src/presentation.rs +207 -63
- data/rust/host/src/presentation_write.rs +502 -187
- data/rust/host/src/query_step.rs +69 -18
- data/rust/host/src/rate_limit.rs +541 -142
- data/rust/host/src/reference_transform.rs +77 -25
- data/rust/host/src/reference_validate.rs +443 -104
- data/rust/host/src/resend.rs +190 -55
- data/rust/host/src/secrets.rs +116 -21
- data/rust/host/src/server.rs +483 -104
- data/rust/host/src/storage_shape.rs +88 -21
- data/rust/host/src/test_pg.rs +17 -7
- data/rust/host/src/ui_schema.rs +495 -207
- data/rust/host/src/wasm_runner.rs +21 -6
- data/rust/host/src/web/commerce.rs +101 -23
- data/rust/host/src/web/newsletter/cooldown.rs +10 -3
- data/rust/host/src/web/newsletter/template.rs +26 -7
- data/rust/host/src/web/newsletter/tests.rs +112 -23
- data/rust/host/src/web/newsletter.rs +209 -59
- data/rust/host/src/web/newsletter_send.rs +251 -79
- data/rust/host/src/web/registration_receipt/tests.rs +16 -4
- data/rust/host/src/web/registration_receipt.rs +100 -24
- data/rust/host/src/web/registrations.rs +1384 -332
- data/rust/host/src/web/resend_webhook.rs +138 -80
- data/rust/host/src/web.rs +2416 -508
- data/rust/lsp/Cargo.toml +36 -0
- data/rust/lsp/clippy.toml +4 -0
- data/rust/lsp/src/json.rs +29 -22
- data/rust/lsp/src/main.rs +81 -31
- data/rust/lsp/src/outline.rs +23 -7
- data/rust/lsp/src/rpc.rs +17 -4
- data/rust/parser/Cargo.toml +36 -0
- data/rust/parser/clippy.toml +4 -0
- data/rust/parser/src/build/closed_sets.rs +6 -1
- data/rust/parser/src/build/identity.rs +4 -3
- data/rust/parser/src/build/mod.rs +1 -0
- data/rust/parser/src/build/named_pattern.rs +26 -0
- data/rust/parser/src/build/naming.rs +2 -80
- data/rust/parser/src/build/pattern_subset.rs +6 -8
- data/rust/parser/src/build/query_derive.rs +3 -1
- data/rust/parser/src/build/query_inference.rs +14 -5
- data/rust/parser/src/build/read_model.rs +4 -1
- data/rust/parser/src/build/references.rs +4 -3
- data/rust/parser/src/canonical.rs +34 -15
- data/rust/parser/src/emit.rs +187 -105
- data/rust/parser/src/expr/ast_json.rs +134 -42
- data/rust/parser/src/expr/evaluator.rs +27 -9
- data/rust/parser/src/expr/mod.rs +54 -13
- data/rust/parser/src/expr/resolver.rs +299 -92
- data/rust/parser/src/ir.rs +35 -3
- data/rust/parser/src/keywords.rs +7168 -510
- data/rust/parser/src/lex.rs +11 -25
- data/rust/parser/src/lib.rs +1 -0
- data/rust/parser/src/main.rs +65 -6
- data/rust/parser/src/parse/adapter.rs +157 -0
- data/rust/parser/src/parse/aggregate.rs +19 -10
- data/rust/parser/src/parse/chapter.rs +16 -17
- data/rust/parser/src/parse/command.rs +35 -16
- data/rust/parser/src/parse/domain_port.rs +4 -7
- data/rust/parser/src/parse/entity.rs +21 -11
- data/rust/parser/src/parse/hecksagon.rs +10 -4
- data/rust/parser/src/parse/lifecycle.rs +9 -5
- data/rust/parser/src/parse/mod.rs +43 -91
- data/rust/parser/src/parse/needs.rs +21 -12
- data/rust/parser/src/parse/policy.rs +2 -2
- data/rust/parser/src/parse/process_manager.rs +9 -11
- data/rust/parser/src/parse/query.rs +8 -4
- data/rust/parser/src/parse/read_model.rs +57 -16
- data/rust/parser/src/parse/value_object.rs +7 -2
- data/rust/parser/src/parse/world.rs +322 -0
- data/rust/parser/src/ruby_value.rs +7 -6
- data/rust/src/exemplar/json.rs +4 -4
- data/rust/src/exemplar/mutations.rs +18 -0
- data/rust/src/exemplar/read_models.rs +1 -10
- data/rust/src/kernel/attribute_shapes/composite.rs +54 -14
- data/rust/src/kernel/attribute_shapes/list.rs +2 -2
- data/rust/src/kernel/attribute_shapes/mod.rs +8 -8
- data/rust/src/kernel/attribute_shapes/scalar.rs +2 -2
- data/rust/src/kernel/cli.rs +229 -112
- data/rust/src/kernel/dispatch.rs +323 -115
- data/rust/src/kernel/dispatch_guard_tests.rs +327 -65
- data/rust/src/kernel/expr.rs +203 -86
- data/rust/src/kernel/expression_operators/arithmetic.rs +138 -25
- data/rust/src/kernel/expression_operators/comparison.rs +87 -2
- data/rust/src/kernel/expression_operators/enumeration.rs +106 -22
- data/rust/src/kernel/expression_operators/logical.rs +9 -3
- data/rust/src/kernel/expression_operators/membership.rs +3 -1
- data/rust/src/kernel/expression_operators/mod.rs +34 -21
- data/rust/src/kernel/expression_operators/pattern_match.rs +46 -11
- data/rust/src/kernel/expression_operators/positional.rs +84 -30
- data/rust/src/kernel/expression_operators/presence.rs +52 -13
- data/rust/src/kernel/expression_operators/sign_test.rs +3 -1
- data/rust/src/kernel/expression_operators/sized.rs +24 -8
- data/rust/src/kernel/expression_operators/text.rs +120 -27
- data/rust/src/kernel/expression_operators/to_string.rs +10 -4
- data/rust/src/kernel/json.rs +230 -148
- data/rust/src/kernel/mod.rs +46 -33
- data/rust/src/kernel/named_query.rs +63 -15
- data/rust/src/kernel/needs.rs +112 -25
- data/rust/src/kernel/orchestrate.rs +980 -581
- data/rust/src/kernel/orchestrate_guard_tests.rs +538 -140
- data/rust/src/kernel/pattern.rs +107 -34
- data/rust/src/kernel/query_comparators.rs +118 -41
- data/rust/src/kernel/query_ordering.rs +13 -5
- data/rust/src/kernel/read_model.rs +479 -181
- data/rust/src/kernel/reference_lookup.rs +122 -26
- data/rust/src/kernel/repository.rs +293 -66
- data/rust/src/kernel/routing.rs +58 -42
- data/rust/src/kernel/ruby_float.rs +139 -0
- data/rust/src/kernel/vocab/aggregate_dispatch_order.rs +57 -57
- data/rust/src/kernel/vocab/entity_dispatch_order.rs +54 -54
- data/rust/src/kernel/vocab/field_hint.rs +19 -25
- data/rust/src/kernel/vocab/mod.rs +6 -6
- data/rust/src/kernel/vocab/query_comparator.rs +23 -24
- data/rust/src/kernel/vocab/refusal_template.rs +501 -297
- data/rust/src/lib.rs +50 -0
- data/rust/src/main.rs +4 -1
- data/rust/web/Cargo.toml +36 -0
- data/rust/web/clippy.toml +4 -0
- metadata +85 -15
- data/examples/pizzas/bluebook/hecksagon/mock_stripe_payment_adapter.rb +0 -36
- data/lib/hecks/adapters/driven/google_authentication.adapter +0 -3
- data/lib/hecks/adapters/driven/google_authentication.rb +0 -99
- data/lib/hecks/adapters/driven/mock_stripe_adapter.adapter +0 -3
- data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +0 -32
- data/lib/hecks/ports/authentication.port +0 -6
- data/lib/hecks/ports/authentication.rb +0 -67
- data/lib/hecks/ports/persistence/plugins/era/translation/approval_file.rb +0 -255
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +0 -22
- data/prebuilt/verdicts-48318ca172edd21443b1ad02801c697fff100b746e828f09db987647641a5df2.json +0 -1
- data/rust/host/src/approval.rs +0 -652
|
@@ -8,7 +8,7 @@ use crate::registry::AggregateEntry;
|
|
|
8
8
|
|
|
9
9
|
pub fn policy_event_qualifier(on_event: &str) -> Option<String> {
|
|
10
10
|
if on_event.contains('.') {
|
|
11
|
-
Some(on_event.
|
|
11
|
+
Some(on_event.split('.').next().unwrap_or("").to_string())
|
|
12
12
|
} else {
|
|
13
13
|
None
|
|
14
14
|
}
|
|
@@ -16,13 +16,18 @@ pub fn policy_event_qualifier(on_event: &str) -> Option<String> {
|
|
|
16
16
|
|
|
17
17
|
pub fn policy_event_name(on_event: &str) -> String {
|
|
18
18
|
if on_event.contains('.') {
|
|
19
|
-
on_event.
|
|
19
|
+
on_event.split_once('.').map_or("", |x| x.1).to_string()
|
|
20
20
|
} else {
|
|
21
21
|
on_event.to_string()
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
pub fn emit_policy_table(
|
|
25
|
+
pub fn emit_policy_table(
|
|
26
|
+
exemplar: &Exemplar,
|
|
27
|
+
domain_name: &str,
|
|
28
|
+
policies: &[Json],
|
|
29
|
+
aggregates: &[Json],
|
|
30
|
+
) -> String {
|
|
26
31
|
let fns = where_fns(policies);
|
|
27
32
|
let rows = local_policy_rows(domain_name, policies, aggregates);
|
|
28
33
|
let table = exemplar.render(
|
|
@@ -38,7 +43,12 @@ pub fn emit_policy_table(exemplar: &Exemplar, domain_name: &str, policies: &[Jso
|
|
|
38
43
|
|
|
39
44
|
// A policy's `where { … }` becomes a generated function the kernel calls.
|
|
40
45
|
fn where_fn_name(policy: &Json) -> String {
|
|
41
|
-
format!(
|
|
46
|
+
format!(
|
|
47
|
+
"where_{}",
|
|
48
|
+
naming::dispatch_fn_name(&naming::rust_ident(
|
|
49
|
+
&policy.get("name").map(Json::to_s).unwrap_or_default()
|
|
50
|
+
))
|
|
51
|
+
)
|
|
42
52
|
}
|
|
43
53
|
|
|
44
54
|
fn where_expr(policy: &Json) -> String {
|
|
@@ -48,13 +58,28 @@ fn where_expr(policy: &Json) -> String {
|
|
|
48
58
|
}
|
|
49
59
|
}
|
|
50
60
|
|
|
61
|
+
#[allow(
|
|
62
|
+
clippy::panic,
|
|
63
|
+
reason = "a drifted exemplar or invalid IR aborts generation on purpose"
|
|
64
|
+
)]
|
|
51
65
|
fn where_fns(policies: &[Json]) -> Vec<String> {
|
|
52
66
|
policies
|
|
53
67
|
.iter()
|
|
54
|
-
.filter(|policy|
|
|
68
|
+
.filter(|policy| {
|
|
69
|
+
policy
|
|
70
|
+
.get("where")
|
|
71
|
+
.map(Json::to_s)
|
|
72
|
+
.is_some_and(|w| !w.is_empty())
|
|
73
|
+
})
|
|
55
74
|
.map(|policy| {
|
|
56
|
-
let ast = policy
|
|
57
|
-
|
|
75
|
+
let ast = policy
|
|
76
|
+
.get("where_ast")
|
|
77
|
+
.unwrap_or_else(|| panic!("policy with a where has no where_ast: {policy:?}"));
|
|
78
|
+
format!(
|
|
79
|
+
"fn {}() -> crate::kernel::Expr {{\n use crate::kernel::Expr;\n {}\n}}",
|
|
80
|
+
where_fn_name(policy),
|
|
81
|
+
crate::expr_emitter::emit_ast(ast)
|
|
82
|
+
)
|
|
58
83
|
})
|
|
59
84
|
.collect()
|
|
60
85
|
}
|
|
@@ -63,7 +88,7 @@ fn local_policy_rows(domain_name: &str, policies: &[Json], aggregates: &[Json])
|
|
|
63
88
|
crate::asks::resolve_asks(policies, aggregates)
|
|
64
89
|
.iter()
|
|
65
90
|
.filter_map(|policy| {
|
|
66
|
-
let target_domain = policy.get("target_domain").
|
|
91
|
+
let target_domain = policy.get("target_domain").map_or_else(|| domain_name.to_string(), Json::to_s);
|
|
67
92
|
if target_domain != domain_name {
|
|
68
93
|
return None;
|
|
69
94
|
}
|
|
@@ -71,10 +96,7 @@ fn local_policy_rows(domain_name: &str, policies: &[Json], aggregates: &[Json])
|
|
|
71
96
|
let on_event = policy.get("on_event").map(Json::to_s).unwrap_or_default();
|
|
72
97
|
let event_name = policy_event_name(&on_event);
|
|
73
98
|
let qualifier = policy_event_qualifier(&on_event);
|
|
74
|
-
let qualifier_expr =
|
|
75
|
-
Some(q) => format!("Some({})", naming::ruby_inspect_string(&q)),
|
|
76
|
-
None => "None".to_string(),
|
|
77
|
-
};
|
|
99
|
+
let qualifier_expr = qualifier.map_or_else(|| "None".to_string(), |q| format!("Some({})", naming::ruby_inspect_string(&q)));
|
|
78
100
|
let target_verb = format!("{target_domain}::{}", policy.get("trigger_command").map(Json::to_s).unwrap_or_default());
|
|
79
101
|
let name = policy.get("name").map(Json::to_s).unwrap_or_default();
|
|
80
102
|
|
|
@@ -97,7 +119,7 @@ fn cross_domain_policy_rows(domain_name: &str, policies: &[Json]) -> Vec<String>
|
|
|
97
119
|
policies
|
|
98
120
|
.iter()
|
|
99
121
|
.filter_map(|policy| {
|
|
100
|
-
let target_domain = policy.get("target_domain").
|
|
122
|
+
let target_domain = policy.get("target_domain").map_or_else(|| domain_name.to_string(), Json::to_s);
|
|
101
123
|
if target_domain == domain_name {
|
|
102
124
|
return None;
|
|
103
125
|
}
|
|
@@ -105,10 +127,7 @@ fn cross_domain_policy_rows(domain_name: &str, policies: &[Json]) -> Vec<String>
|
|
|
105
127
|
let on_event = policy.get("on_event").map(Json::to_s).unwrap_or_default();
|
|
106
128
|
let event_name = policy_event_name(&on_event);
|
|
107
129
|
let qualifier = policy_event_qualifier(&on_event);
|
|
108
|
-
let qualifier_expr =
|
|
109
|
-
Some(q) => format!("Some({})", naming::ruby_inspect_string(&q)),
|
|
110
|
-
None => "None".to_string(),
|
|
111
|
-
};
|
|
130
|
+
let qualifier_expr = qualifier.map_or_else(|| "None".to_string(), |q| format!("Some({})", naming::ruby_inspect_string(&q)));
|
|
112
131
|
let target_verb = format!("{target_domain}::{}", policy.get("trigger_command").map(Json::to_s).unwrap_or_default());
|
|
113
132
|
let name = policy.get("name").map(Json::to_s).unwrap_or_default();
|
|
114
133
|
|
|
@@ -124,7 +143,11 @@ fn cross_domain_policy_rows(domain_name: &str, policies: &[Json]) -> Vec<String>
|
|
|
124
143
|
.collect()
|
|
125
144
|
}
|
|
126
145
|
|
|
127
|
-
pub fn emit_cross_domain_policy_table(
|
|
146
|
+
pub fn emit_cross_domain_policy_table(
|
|
147
|
+
exemplar: &Exemplar,
|
|
148
|
+
domain_name: &str,
|
|
149
|
+
policies: &[Json],
|
|
150
|
+
) -> String {
|
|
128
151
|
let rows = cross_domain_policy_rows(domain_name, policies);
|
|
129
152
|
|
|
130
153
|
if !rows.is_empty() {
|
|
@@ -153,8 +176,16 @@ pub struct PolicySource<'a> {
|
|
|
153
176
|
/// Each source's `target_verb` is qualified against its own domain, never the target's;
|
|
154
177
|
/// omitting a chapter's policies would leave them out of the table `kernel::orchestrate` reads.
|
|
155
178
|
pub fn emit_merged_policy_table(exemplar: &Exemplar, sources: &[PolicySource]) -> String {
|
|
156
|
-
let rows: Vec<String> = sources
|
|
157
|
-
|
|
179
|
+
let rows: Vec<String> = sources
|
|
180
|
+
.iter()
|
|
181
|
+
.flat_map(|source| {
|
|
182
|
+
local_policy_rows(source.domain_name, source.policies, source.aggregates)
|
|
183
|
+
})
|
|
184
|
+
.collect();
|
|
185
|
+
let fns: Vec<String> = sources
|
|
186
|
+
.iter()
|
|
187
|
+
.flat_map(|source| where_fns(source.policies))
|
|
188
|
+
.collect();
|
|
158
189
|
|
|
159
190
|
let table = exemplar.render(
|
|
160
191
|
"policy_table",
|
|
@@ -168,8 +199,14 @@ pub fn emit_merged_policy_table(exemplar: &Exemplar, sources: &[PolicySource]) -
|
|
|
168
199
|
}
|
|
169
200
|
|
|
170
201
|
/// The cross-domain policy table for `merged.rs`, folding in every attached chapter.
|
|
171
|
-
pub fn emit_merged_cross_domain_policy_table(
|
|
172
|
-
|
|
202
|
+
pub fn emit_merged_cross_domain_policy_table(
|
|
203
|
+
exemplar: &Exemplar,
|
|
204
|
+
sources: &[PolicySource],
|
|
205
|
+
) -> String {
|
|
206
|
+
let rows: Vec<String> = sources
|
|
207
|
+
.iter()
|
|
208
|
+
.flat_map(|source| cross_domain_policy_rows(source.domain_name, source.policies))
|
|
209
|
+
.collect();
|
|
173
210
|
|
|
174
211
|
if !rows.is_empty() {
|
|
175
212
|
println!("cross-domain policy table: {} row(s) — delivered by rust/host's lambda_client.rs, not locally dispatched", rows.len());
|
|
@@ -189,18 +226,36 @@ fn with_value_parsed(raw: &str) -> Literal {
|
|
|
189
226
|
}
|
|
190
227
|
|
|
191
228
|
// Renders a parsed `with:` literal as a Rust expression building the equivalent `Json`.
|
|
229
|
+
#[allow(
|
|
230
|
+
clippy::panic,
|
|
231
|
+
reason = "a drifted exemplar or invalid IR aborts generation on purpose"
|
|
232
|
+
)]
|
|
192
233
|
fn json_literal_expr(value: &Literal) -> String {
|
|
193
234
|
match value {
|
|
194
235
|
Literal::Hash(pairs) => {
|
|
195
|
-
let fields: Vec<String> = pairs
|
|
236
|
+
let fields: Vec<String> = pairs
|
|
237
|
+
.iter()
|
|
238
|
+
.map(|(k, v)| {
|
|
239
|
+
format!(
|
|
240
|
+
"({}.to_string(), {})",
|
|
241
|
+
naming::ruby_inspect_string(k),
|
|
242
|
+
json_literal_expr(v)
|
|
243
|
+
)
|
|
244
|
+
})
|
|
245
|
+
.collect();
|
|
196
246
|
format!("crate::kernel::Json::Object(vec![{}])", fields.join(", "))
|
|
197
247
|
}
|
|
198
|
-
Literal::Str(s) => format!(
|
|
248
|
+
Literal::Str(s) => format!(
|
|
249
|
+
"crate::kernel::Json::Str({}.to_string())",
|
|
250
|
+
naming::ruby_inspect_string(s)
|
|
251
|
+
),
|
|
199
252
|
Literal::Int(n) => format!("crate::kernel::Json::int({n})"),
|
|
200
253
|
Literal::Float(n) => format!("crate::kernel::Json::Num({}f64, None)", ruby_float_text(*n)),
|
|
201
254
|
Literal::Bool(b) => format!("crate::kernel::Json::Bool({b})"),
|
|
202
255
|
Literal::Nil => "crate::kernel::Json::Null".to_string(),
|
|
203
|
-
other => panic!(
|
|
256
|
+
other => panic!(
|
|
257
|
+
"unsupported with: literal {other:?} — json_literal_expr doesn't cover this shape"
|
|
258
|
+
),
|
|
204
259
|
}
|
|
205
260
|
}
|
|
206
261
|
|
|
@@ -216,20 +271,29 @@ fn ruby_float_text(n: f64) -> String {
|
|
|
216
271
|
// `compensates` (saga compensation) recurses one level; a compensation is not itself
|
|
217
272
|
// compensable, so the recursion ends after one extra call.
|
|
218
273
|
fn emit_dispatch_spec(exemplar: &Exemplar, spec: &Json, literal_fns: &mut Vec<String>) -> String {
|
|
219
|
-
let with_spec = spec.get("with_spec").
|
|
274
|
+
let with_spec = spec.get("with_spec").map_or_default(Json::each);
|
|
220
275
|
let with_pairs: Vec<String> = with_spec
|
|
221
276
|
.iter()
|
|
222
277
|
.map(|pair| {
|
|
223
278
|
let kv = pair.as_array().unwrap_or(&[]);
|
|
224
279
|
let key = kv.first().map(Json::to_s).unwrap_or_default();
|
|
225
280
|
let raw = kv.get(1).map(Json::to_s).unwrap_or_default();
|
|
226
|
-
format!(
|
|
281
|
+
format!(
|
|
282
|
+
"({}, {})",
|
|
283
|
+
naming::ruby_inspect_string(&key),
|
|
284
|
+
emit_with_value(exemplar, &raw, literal_fns)
|
|
285
|
+
)
|
|
227
286
|
})
|
|
228
287
|
.collect();
|
|
229
|
-
let compensates =
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
288
|
+
let compensates = spec.get("compensates").map_or_else(
|
|
289
|
+
|| "None".to_string(),
|
|
290
|
+
|nested| {
|
|
291
|
+
format!(
|
|
292
|
+
"Some(&{})",
|
|
293
|
+
emit_dispatch_spec(exemplar, nested, literal_fns)
|
|
294
|
+
)
|
|
295
|
+
},
|
|
296
|
+
);
|
|
233
297
|
format!(
|
|
234
298
|
"crate::kernel::DispatchSpec {{ command_name: {}, with: &[{}], compensates: {} }}",
|
|
235
299
|
naming::ruby_inspect_string(&spec.get("command_name").map(Json::to_s).unwrap_or_default()),
|
|
@@ -243,17 +307,29 @@ fn emit_dispatch_spec(exemplar: &Exemplar, spec: &Json, literal_fns: &mut Vec<St
|
|
|
243
307
|
fn emit_with_value(exemplar: &Exemplar, raw: &str, literal_fns: &mut Vec<String>) -> String {
|
|
244
308
|
let parsed = with_value_parsed(raw);
|
|
245
309
|
if let Literal::Symbol(name) = &parsed {
|
|
246
|
-
return format!(
|
|
310
|
+
return format!(
|
|
311
|
+
"crate::kernel::WithValue::Ref({})",
|
|
312
|
+
naming::ruby_inspect_string(name)
|
|
313
|
+
);
|
|
247
314
|
}
|
|
248
315
|
|
|
249
316
|
let fn_name = format!("pm_literal_{}", literal_fns.len());
|
|
250
|
-
literal_fns.push(exemplar.render(
|
|
317
|
+
literal_fns.push(exemplar.render(
|
|
318
|
+
"with_value_literal_fn",
|
|
319
|
+
&[
|
|
320
|
+
("tmpl_literal_fn", fn_name.clone()),
|
|
321
|
+
("tmpl_body_placeholder()", json_literal_expr(&parsed)),
|
|
322
|
+
],
|
|
323
|
+
));
|
|
251
324
|
format!("crate::kernel::WithValue::Literal({fn_name})")
|
|
252
325
|
}
|
|
253
326
|
|
|
254
327
|
fn emit_handler(exemplar: &Exemplar, handler: &Json, literal_fns: &mut Vec<String>) -> String {
|
|
255
|
-
let dispatches = handler.get("dispatches").
|
|
256
|
-
let dispatch_strs: Vec<String> = dispatches
|
|
328
|
+
let dispatches = handler.get("dispatches").map_or_default(Json::each);
|
|
329
|
+
let dispatch_strs: Vec<String> = dispatches
|
|
330
|
+
.iter()
|
|
331
|
+
.map(|d| emit_dispatch_spec(exemplar, d, literal_fns))
|
|
332
|
+
.collect();
|
|
257
333
|
format!(
|
|
258
334
|
"crate::kernel::Handler {{ event_type: {}, from_state: {}, to_state: {}, dispatches: &[{}] }}",
|
|
259
335
|
naming::ruby_inspect_string(&handler.get("event_type").map(Json::to_s).unwrap_or_default()),
|
|
@@ -268,9 +344,9 @@ pub fn emit_process_manager_table(exemplar: &Exemplar, process_managers: &[Json]
|
|
|
268
344
|
let pm_exprs: Vec<String> = process_managers
|
|
269
345
|
.iter()
|
|
270
346
|
.map(|pm| {
|
|
271
|
-
let handlers = pm.get("handlers").
|
|
347
|
+
let handlers = pm.get("handlers").map_or_default(Json::each);
|
|
272
348
|
let handler_strs: Vec<String> = handlers.iter().map(|h| emit_handler(exemplar, h, &mut literal_fns)).collect();
|
|
273
|
-
let states = pm.get("states").
|
|
349
|
+
let states = pm.get("states").map_or_default(Json::each);
|
|
274
350
|
let initial_state = states.first().map(Json::to_s).unwrap_or_default();
|
|
275
351
|
format!(
|
|
276
352
|
"crate::kernel::ProcessManagerDef {{ name: {}, correlates_by: {}, starts_on: {}, ends_on: {}, initial_state: {}, handlers: &[{}] }}",
|
|
@@ -303,12 +379,19 @@ pub fn emit_reference_key_table(exemplar: &Exemplar, chapters: &[(String, Vec<St
|
|
|
303
379
|
aggregate_names.iter().map(move |name| {
|
|
304
380
|
let qualified = format!("{domain_name}::{name}");
|
|
305
381
|
let key = crate::hecks_naming::snake(name);
|
|
306
|
-
format!(
|
|
382
|
+
format!(
|
|
383
|
+
" {} => Some({}),",
|
|
384
|
+
naming::ruby_inspect_string(&qualified),
|
|
385
|
+
naming::ruby_inspect_string(&key)
|
|
386
|
+
)
|
|
307
387
|
})
|
|
308
388
|
})
|
|
309
389
|
.collect();
|
|
310
390
|
|
|
311
|
-
exemplar.render(
|
|
391
|
+
exemplar.render(
|
|
392
|
+
"reference_key_table",
|
|
393
|
+
&[("\"tmpl_qualified\" => Some(\"tmpl_key\"),", arms.join("\n"))],
|
|
394
|
+
)
|
|
312
395
|
}
|
|
313
396
|
|
|
314
397
|
/// Whether each verb creates the record it addresses; `split_routed_args` in
|
|
@@ -318,14 +401,24 @@ pub fn emit_creates_table(exemplar: &Exemplar, aggregates: &[AggregateEntry]) ->
|
|
|
318
401
|
let mut arms: Vec<String> = Vec::new();
|
|
319
402
|
for a in aggregates {
|
|
320
403
|
for c in &a.commands {
|
|
321
|
-
arms.push(format!(
|
|
404
|
+
arms.push(format!(
|
|
405
|
+
" {} => {},",
|
|
406
|
+
naming::ruby_inspect_string(&c.verb),
|
|
407
|
+
c.creates
|
|
408
|
+
));
|
|
322
409
|
}
|
|
323
410
|
for c in &a.entity_commands {
|
|
324
|
-
arms.push(format!(
|
|
411
|
+
arms.push(format!(
|
|
412
|
+
" {} => false,",
|
|
413
|
+
naming::ruby_inspect_string(&c.verb)
|
|
414
|
+
));
|
|
325
415
|
}
|
|
326
416
|
}
|
|
327
417
|
|
|
328
|
-
exemplar.render(
|
|
418
|
+
exemplar.render(
|
|
419
|
+
"creates_table",
|
|
420
|
+
&[("\"tmpl_verb\" => true,", arms.join("\n"))],
|
|
421
|
+
)
|
|
329
422
|
}
|
|
330
423
|
|
|
331
424
|
/// The single-component identity head that `orchestrate.rs` routes by first.
|
|
@@ -337,18 +430,34 @@ pub fn emit_identity_head_table(exemplar: &Exemplar, aggregates: &[AggregateEntr
|
|
|
337
430
|
if a.identified_by.len() != 1 {
|
|
338
431
|
return None;
|
|
339
432
|
}
|
|
340
|
-
let head = a.identified_by[0]
|
|
433
|
+
let head = a.identified_by[0]
|
|
434
|
+
.split('.')
|
|
435
|
+
.next()
|
|
436
|
+
.unwrap_or(&a.identified_by[0]);
|
|
341
437
|
let qualified = format!("{}::{}", a.domain_name, a.name);
|
|
342
|
-
Some(format!(
|
|
438
|
+
Some(format!(
|
|
439
|
+
" {} => Some({}),",
|
|
440
|
+
naming::ruby_inspect_string(&qualified),
|
|
441
|
+
naming::ruby_inspect_string(head)
|
|
442
|
+
))
|
|
343
443
|
})
|
|
344
444
|
.collect();
|
|
345
445
|
|
|
346
|
-
exemplar.render(
|
|
446
|
+
exemplar.render(
|
|
447
|
+
"identity_head_table",
|
|
448
|
+
&[(
|
|
449
|
+
"\"tmpl_qualified\" => Some(\"tmpl_head\"),",
|
|
450
|
+
arms.join("\n"),
|
|
451
|
+
)],
|
|
452
|
+
)
|
|
347
453
|
}
|
|
348
454
|
|
|
349
455
|
/// Like `emit_identity_head_table`, for an entity's own identity, keyed by
|
|
350
456
|
/// "Domain::Aggregate.Entity". Two-level-deep entity commands deliberately never resolve here.
|
|
351
|
-
pub fn emit_entity_identity_head_table(
|
|
457
|
+
pub fn emit_entity_identity_head_table(
|
|
458
|
+
exemplar: &Exemplar,
|
|
459
|
+
aggregates: &[AggregateEntry],
|
|
460
|
+
) -> String {
|
|
352
461
|
let arms: Vec<String> = aggregates
|
|
353
462
|
.iter()
|
|
354
463
|
.flat_map(|a| {
|
|
@@ -356,30 +465,64 @@ pub fn emit_entity_identity_head_table(exemplar: &Exemplar, aggregates: &[Aggreg
|
|
|
356
465
|
if e.identified_by.len() != 1 {
|
|
357
466
|
return None;
|
|
358
467
|
}
|
|
359
|
-
let head = e.identified_by[0]
|
|
468
|
+
let head = e.identified_by[0]
|
|
469
|
+
.split('.')
|
|
470
|
+
.next()
|
|
471
|
+
.unwrap_or(&e.identified_by[0]);
|
|
360
472
|
let qualified = format!("{}::{}.{}", a.domain_name, a.name, e.name);
|
|
361
|
-
Some(format!(
|
|
473
|
+
Some(format!(
|
|
474
|
+
" {} => Some({}),",
|
|
475
|
+
naming::ruby_inspect_string(&qualified),
|
|
476
|
+
naming::ruby_inspect_string(head)
|
|
477
|
+
))
|
|
362
478
|
})
|
|
363
479
|
})
|
|
364
480
|
.collect();
|
|
365
481
|
|
|
366
|
-
exemplar.render(
|
|
482
|
+
exemplar.render(
|
|
483
|
+
"entity_identity_head_table",
|
|
484
|
+
&[(
|
|
485
|
+
"\"tmpl_qualified\" => Some(\"tmpl_head\"),",
|
|
486
|
+
arms.join("\n"),
|
|
487
|
+
)],
|
|
488
|
+
)
|
|
367
489
|
}
|
|
368
490
|
|
|
369
491
|
pub fn emit_command_attributes_table(exemplar: &Exemplar, aggregates: &[AggregateEntry]) -> String {
|
|
370
492
|
let mut arms: Vec<String> = Vec::new();
|
|
371
493
|
for a in aggregates {
|
|
372
494
|
for c in &a.commands {
|
|
373
|
-
let names = c
|
|
374
|
-
|
|
495
|
+
let names = c
|
|
496
|
+
.attributes
|
|
497
|
+
.iter()
|
|
498
|
+
.map(|n| naming::ruby_inspect_string(n))
|
|
499
|
+
.collect::<Vec<_>>()
|
|
500
|
+
.join(", ");
|
|
501
|
+
arms.push(format!(
|
|
502
|
+
" {} => &[{}],",
|
|
503
|
+
naming::ruby_inspect_string(&c.verb),
|
|
504
|
+
names
|
|
505
|
+
));
|
|
375
506
|
}
|
|
376
507
|
for c in &a.entity_commands {
|
|
377
|
-
let names = c
|
|
378
|
-
|
|
508
|
+
let names = c
|
|
509
|
+
.attributes
|
|
510
|
+
.iter()
|
|
511
|
+
.map(|n| naming::ruby_inspect_string(n))
|
|
512
|
+
.collect::<Vec<_>>()
|
|
513
|
+
.join(", ");
|
|
514
|
+
arms.push(format!(
|
|
515
|
+
" {} => &[{}],",
|
|
516
|
+
naming::ruby_inspect_string(&c.verb),
|
|
517
|
+
names
|
|
518
|
+
));
|
|
379
519
|
}
|
|
380
520
|
}
|
|
381
521
|
|
|
382
|
-
exemplar.render(
|
|
522
|
+
exemplar.render(
|
|
523
|
+
"command_attributes_table",
|
|
524
|
+
&[("\"tmpl_verb\" => &[\"tmpl_attr\"],", arms.join("\n"))],
|
|
525
|
+
)
|
|
383
526
|
}
|
|
384
527
|
|
|
385
528
|
// Qualifies the bare "Aggregate.query" `for_each` spelling against the policy's own domain
|
|
@@ -389,7 +532,11 @@ fn fan_out_verb_expr(domain_name: &str, policy: &Json) -> String {
|
|
|
389
532
|
if for_each.is_empty() {
|
|
390
533
|
return "None".to_string();
|
|
391
534
|
}
|
|
392
|
-
let qualified = if for_each.contains("::") {
|
|
535
|
+
let qualified = if for_each.contains("::") {
|
|
536
|
+
for_each
|
|
537
|
+
} else {
|
|
538
|
+
format!("{domain_name}::{for_each}")
|
|
539
|
+
};
|
|
393
540
|
format!("Some({})", naming::ruby_inspect_string(&qualified))
|
|
394
541
|
}
|
|
395
542
|
|
|
@@ -403,7 +550,10 @@ fn fan_out_key_expr(policy: &Json, aggregates: &[Json]) -> String {
|
|
|
403
550
|
let path = for_each.split('.').next().unwrap_or_default().to_string();
|
|
404
551
|
let row_aggregate = path.rsplit("::").next().unwrap_or(&path).to_string();
|
|
405
552
|
|
|
406
|
-
let trigger = policy
|
|
553
|
+
let trigger = policy
|
|
554
|
+
.get("trigger_command")
|
|
555
|
+
.map(Json::to_s)
|
|
556
|
+
.unwrap_or_default();
|
|
407
557
|
let mut parts = trigger.splitn(2, '.');
|
|
408
558
|
let target_aggregate = parts.next().unwrap_or_default().to_string();
|
|
409
559
|
let target_command = parts.next().unwrap_or_default().to_string();
|
|
@@ -421,14 +571,19 @@ fn fan_out_key_expr(policy: &Json, aggregates: &[Json]) -> String {
|
|
|
421
571
|
})
|
|
422
572
|
.and_then(|command| addressing_key_for(&command, &row_aggregate));
|
|
423
573
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
574
|
+
key.map_or_else(
|
|
575
|
+
|| "None".to_string(),
|
|
576
|
+
|name| format!("Some({})", naming::ruby_inspect_string(&name)),
|
|
577
|
+
)
|
|
428
578
|
}
|
|
429
579
|
|
|
430
580
|
fn addressing_key_for(command: &Json, aggregate_name: &str) -> Option<String> {
|
|
431
|
-
if command
|
|
581
|
+
if command
|
|
582
|
+
.get("references")
|
|
583
|
+
.map(Json::to_s)
|
|
584
|
+
.unwrap_or_default()
|
|
585
|
+
== aggregate_name
|
|
586
|
+
{
|
|
432
587
|
return Some(crate::hecks_naming::snake(aggregate_name));
|
|
433
588
|
}
|
|
434
589
|
|
|
@@ -471,11 +626,14 @@ mod tests {
|
|
|
471
626
|
|
|
472
627
|
// Mirrors the fixtures in `spec/rust_project/reactions_merge_spec.rb`; no real corpus
|
|
473
628
|
// domain exercises this merged-chapter shape.
|
|
474
|
-
fn policy(
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
629
|
+
fn policy(
|
|
630
|
+
name: &str,
|
|
631
|
+
on_event: &str,
|
|
632
|
+
trigger_command: &str,
|
|
633
|
+
target_domain: Option<&str>,
|
|
634
|
+
) -> Json {
|
|
635
|
+
let target_domain_json =
|
|
636
|
+
target_domain.map_or_else(|| "null".to_string(), |domain| format!("\"{domain}\""));
|
|
479
637
|
Json::parse(&format!(
|
|
480
638
|
"{{\"name\":\"{name}\",\"on_event\":\"{on_event}\",\"trigger_command\":\"{trigger_command}\",\
|
|
481
639
|
\"target_domain\":{target_domain_json},\"for_each\":null,\"with_spec\":[]}}"
|
|
@@ -487,12 +645,30 @@ mod tests {
|
|
|
487
645
|
fn merged_policy_table_carries_the_target_and_a_vendored_chapters_own_same_domain_policy() {
|
|
488
646
|
let orders_policies = vec![policy("OnOrderPlaced", "OrderPlaced", "Invoice.Open", None)];
|
|
489
647
|
let payments_policies = vec![
|
|
490
|
-
policy(
|
|
491
|
-
|
|
648
|
+
policy(
|
|
649
|
+
"OnPaymentConfirmedByProcessor",
|
|
650
|
+
"PaymentConfirmedByProcessor",
|
|
651
|
+
"Payment.Succeed",
|
|
652
|
+
None,
|
|
653
|
+
),
|
|
654
|
+
policy(
|
|
655
|
+
"OnPaymentFailed",
|
|
656
|
+
"PaymentFailed",
|
|
657
|
+
"Ledger.Reverse",
|
|
658
|
+
Some("Ledger"),
|
|
659
|
+
),
|
|
492
660
|
];
|
|
493
661
|
let sources = vec![
|
|
494
|
-
PolicySource {
|
|
495
|
-
|
|
662
|
+
PolicySource {
|
|
663
|
+
domain_name: "Orders",
|
|
664
|
+
policies: &orders_policies,
|
|
665
|
+
aggregates: &[],
|
|
666
|
+
},
|
|
667
|
+
PolicySource {
|
|
668
|
+
domain_name: "Payments",
|
|
669
|
+
policies: &payments_policies,
|
|
670
|
+
aggregates: &[],
|
|
671
|
+
},
|
|
496
672
|
];
|
|
497
673
|
|
|
498
674
|
let table = emit_merged_policy_table(&Exemplar::load(), &sources);
|
|
@@ -510,12 +686,30 @@ mod tests {
|
|
|
510
686
|
fn merged_cross_domain_policy_table_carries_only_a_vendored_chapters_own_cross_domain_policy() {
|
|
511
687
|
let orders_policies = vec![policy("OnOrderPlaced", "OrderPlaced", "Invoice.Open", None)];
|
|
512
688
|
let payments_policies = vec![
|
|
513
|
-
policy(
|
|
514
|
-
|
|
689
|
+
policy(
|
|
690
|
+
"OnPaymentConfirmedByProcessor",
|
|
691
|
+
"PaymentConfirmedByProcessor",
|
|
692
|
+
"Payment.Succeed",
|
|
693
|
+
None,
|
|
694
|
+
),
|
|
695
|
+
policy(
|
|
696
|
+
"OnPaymentFailed",
|
|
697
|
+
"PaymentFailed",
|
|
698
|
+
"Ledger.Reverse",
|
|
699
|
+
Some("Ledger"),
|
|
700
|
+
),
|
|
515
701
|
];
|
|
516
702
|
let sources = vec![
|
|
517
|
-
PolicySource {
|
|
518
|
-
|
|
703
|
+
PolicySource {
|
|
704
|
+
domain_name: "Orders",
|
|
705
|
+
policies: &orders_policies,
|
|
706
|
+
aggregates: &[],
|
|
707
|
+
},
|
|
708
|
+
PolicySource {
|
|
709
|
+
domain_name: "Payments",
|
|
710
|
+
policies: &payments_policies,
|
|
711
|
+
aggregates: &[],
|
|
712
|
+
},
|
|
519
713
|
];
|
|
520
714
|
|
|
521
715
|
let table = emit_merged_cross_domain_policy_table(&Exemplar::load(), &sources);
|