hecks 3.14.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.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/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/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 +2 -0
- data/lib/hecks/chapters.rb +3 -3
- 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/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/fuzzing/bounded_exhaustive_expressions.rb +0 -3
- 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 +21 -0
- 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 +3 -80
- data/lib/hecks/hecks/hecks.hecksagon +2 -2
- data/lib/hecks/hecks/hecks.world +1 -1
- data/lib/hecks/hecks/rehearsal.bluebook +7 -13
- data/lib/hecks/kernel_capabilities/templates.rb +4 -4
- data/lib/hecks/kernel_capabilities.rb +1 -1
- data/lib/hecks/language/bluebook/vocabulary.bluebook +2 -3
- 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/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/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/{a883a7e568667aa5ac904c82daff356bdf9e996252a36af6def4a4a43efb967e.marshal → 02c09c73b272c1fb5a9ae6d87bb5e5e529208e00f6b4b597dc2c0fd70a9c0964.marshal} +0 -0
- data/prebuilt/{1a6f596be124228be93eba1d86dbc9d2933190fa389b284331241cb9f27115a0.marshal → bb84a835cf6a15136bad5ca03aa5bf93a5b92f5f72444618d3ef2412b987fb32.marshal} +0 -0
- data/prebuilt/{verdicts-872993b1aa26d73fe48f28251374b8585fed145d02aab42be0f00de386b6ff80.json → verdicts-f1f10da14c8e8f01b4c9b7e3e2d74be8cd2bf4676364ed17fa16975d2a076d75.json} +1 -1
- 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 +39 -7
- data/rust/host/src/payments/tests.rs +1427 -282
- data/rust/host/src/payments.rs +391 -112
- 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 -1
- data/rust/parser/src/build/named_pattern.rs +4 -1
- 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 -516
- 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 +22 -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 +82 -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/rust/host/src/approval.rs +0 -652
data/rust/codegen/src/literal.rs
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
//! `Literal::from_json` covers values embedded raw in ir.json, which were never rendered.
|
|
3
3
|
|
|
4
4
|
use crate::json::{Json, Number};
|
|
5
|
+
use crate::ruby_value::{self, Value};
|
|
6
|
+
use crate::shared::ruby_to_i;
|
|
5
7
|
|
|
6
8
|
#[derive(Debug, Clone, PartialEq)]
|
|
7
9
|
pub enum Literal {
|
|
@@ -12,73 +14,71 @@ pub enum Literal {
|
|
|
12
14
|
/// A Symbol, which JSON cannot represent; only `read` produces one (leading-colon strings).
|
|
13
15
|
Symbol(String),
|
|
14
16
|
Str(String),
|
|
15
|
-
Hash(Vec<(String,
|
|
16
|
-
Array(Vec<
|
|
17
|
+
Hash(Vec<(String, Self)>),
|
|
18
|
+
Array(Vec<Self>),
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
impl Literal {
|
|
20
22
|
/// Converts a raw `Json` value structurally, with no text parsing and no Symbol case.
|
|
21
|
-
pub fn from_json(value: &Json) ->
|
|
23
|
+
pub fn from_json(value: &Json) -> Self {
|
|
22
24
|
match value {
|
|
23
|
-
Json::Null =>
|
|
24
|
-
Json::Bool(b) =>
|
|
25
|
+
Json::Null => Self::Nil,
|
|
26
|
+
Json::Bool(b) => Self::Bool(*b),
|
|
25
27
|
Json::Number(_) => match value.number() {
|
|
26
|
-
Some(Number::Int(n)) =>
|
|
27
|
-
Some(Number::Float(n)) =>
|
|
28
|
-
None =>
|
|
28
|
+
Some(Number::Int(n)) => Self::Int(n),
|
|
29
|
+
Some(Number::Float(n)) => Self::Float(n),
|
|
30
|
+
None => Self::Nil,
|
|
29
31
|
},
|
|
30
|
-
Json::String(s) =>
|
|
31
|
-
Json::Array(items) =>
|
|
32
|
-
Json::Object(pairs) =>
|
|
32
|
+
Json::String(s) => Self::Str(s.clone()),
|
|
33
|
+
Json::Array(items) => Self::Array(items.iter().map(Self::from_json).collect()),
|
|
34
|
+
Json::Object(pairs) => Self::Hash(
|
|
35
|
+
pairs
|
|
36
|
+
.iter()
|
|
37
|
+
.map(|(k, v)| (k.clone(), Self::from_json(v)))
|
|
38
|
+
.collect(),
|
|
39
|
+
),
|
|
33
40
|
}
|
|
34
41
|
}
|
|
35
42
|
|
|
36
|
-
pub fn as_hash(&self) -> Option<&[(String,
|
|
43
|
+
pub const fn as_hash(&self) -> Option<&[(String, Self)]> {
|
|
37
44
|
match self {
|
|
38
|
-
|
|
45
|
+
Self::Hash(pairs) => Some(pairs.as_slice()),
|
|
39
46
|
_ => None,
|
|
40
47
|
}
|
|
41
48
|
}
|
|
42
49
|
|
|
43
|
-
pub fn get(&self, key: &str) -> Option<&
|
|
44
|
-
self.as_hash()
|
|
50
|
+
pub fn get(&self, key: &str) -> Option<&Self> {
|
|
51
|
+
self.as_hash()?
|
|
52
|
+
.iter()
|
|
53
|
+
.find(|(k, _)| k == key)
|
|
54
|
+
.map(|(_, v)| v)
|
|
45
55
|
}
|
|
46
56
|
}
|
|
47
57
|
|
|
48
58
|
/// `Literal.read`: parses a rendered wire string back to a `Literal`.
|
|
49
59
|
///
|
|
50
|
-
///
|
|
60
|
+
/// Reads through the parser's shared `ruby_value::read`. A bare word becomes a `Str`. An integer
|
|
61
|
+
/// too large for `i64` (the shared reader returns it as `Bare`) becomes `Int(0)`, as `ruby_to_i`
|
|
62
|
+
/// always did: no corpus domain holds one, and a stable `0` keeps generation total.
|
|
51
63
|
pub fn read(text: &str) -> Literal {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
return Literal::Nil;
|
|
55
|
-
}
|
|
56
|
-
if raw == "true" {
|
|
57
|
-
return Literal::Bool(true);
|
|
58
|
-
}
|
|
59
|
-
if raw == "false" {
|
|
60
|
-
return Literal::Bool(false);
|
|
61
|
-
}
|
|
62
|
-
if is_integer(raw) {
|
|
63
|
-
return Literal::Int(ruby_to_i(raw));
|
|
64
|
-
}
|
|
65
|
-
if is_float(raw) {
|
|
66
|
-
return Literal::Float(raw.parse::<f64>().unwrap_or(0.0));
|
|
67
|
-
}
|
|
68
|
-
if let Some(rest) = raw.strip_prefix(':') {
|
|
69
|
-
return Literal::Symbol(rest.to_string());
|
|
70
|
-
}
|
|
71
|
-
if is_quoted(raw) {
|
|
72
|
-
return Literal::Str(unquote(raw));
|
|
73
|
-
}
|
|
74
|
-
if raw.starts_with('{') && raw.ends_with('}') {
|
|
75
|
-
return read_hash(raw);
|
|
76
|
-
}
|
|
77
|
-
if raw.starts_with('[') && raw.ends_with(']') {
|
|
78
|
-
return read_array(raw);
|
|
79
|
-
}
|
|
64
|
+
from_value(ruby_value::read(text))
|
|
65
|
+
}
|
|
80
66
|
|
|
81
|
-
|
|
67
|
+
fn from_value(value: Value) -> Literal {
|
|
68
|
+
match value {
|
|
69
|
+
Value::Nil => Literal::Nil,
|
|
70
|
+
Value::Bool(b) => Literal::Bool(b),
|
|
71
|
+
Value::Int(n) => Literal::Int(n),
|
|
72
|
+
Value::Float(n) => Literal::Float(n),
|
|
73
|
+
Value::Str(s) => Literal::Str(s),
|
|
74
|
+
Value::Symbol(s) => Literal::Symbol(s),
|
|
75
|
+
Value::Hash(pairs) => {
|
|
76
|
+
Literal::Hash(pairs.into_iter().map(|(k, v)| (k, from_value(v))).collect())
|
|
77
|
+
}
|
|
78
|
+
Value::Array(items) => Literal::Array(items.into_iter().map(from_value).collect()),
|
|
79
|
+
Value::Bare(text) if is_integer(&text) => Literal::Int(ruby_to_i(&text)),
|
|
80
|
+
Value::Bare(text) => Literal::Str(text),
|
|
81
|
+
}
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
/// `/\A-?\d+\z/`
|
|
@@ -87,63 +87,11 @@ fn is_integer(raw: &str) -> bool {
|
|
|
87
87
|
!s.is_empty() && s.bytes().all(|b| b.is_ascii_digit())
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
/// `/\A-?\d+\.\d+\z/`
|
|
91
|
-
fn is_float(raw: &str) -> bool {
|
|
92
|
-
let s = raw.strip_prefix('-').unwrap_or(raw);
|
|
93
|
-
let Some((int_part, frac_part)) = s.split_once('.') else { return false };
|
|
94
|
-
!int_part.is_empty() && !frac_part.is_empty() && int_part.bytes().all(|b| b.is_ascii_digit()) && frac_part.bytes().all(|b| b.is_ascii_digit())
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
fn ruby_to_i(raw: &str) -> i64 {
|
|
98
|
-
raw.parse().unwrap_or(0)
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
fn is_quoted(raw: &str) -> bool {
|
|
102
|
-
raw.len() >= 2 && raw.starts_with('"') && raw.ends_with('"')
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/// Drops the surrounding quotes, then unescapes any backslash-escaped character.
|
|
106
|
-
fn unquote(raw: &str) -> String {
|
|
107
|
-
let inner = &raw[1..raw.len() - 1];
|
|
108
|
-
let mut out = String::with_capacity(inner.len());
|
|
109
|
-
let mut chars = inner.chars().peekable();
|
|
110
|
-
while let Some(c) = chars.next() {
|
|
111
|
-
if c == '\\' {
|
|
112
|
-
if let Some(next) = chars.next() {
|
|
113
|
-
out.push(next);
|
|
114
|
-
continue;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
out.push(c);
|
|
118
|
-
}
|
|
119
|
-
out
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
fn read_hash(raw: &str) -> Literal {
|
|
123
|
-
let inner = &raw[1..raw.len() - 1];
|
|
124
|
-
let pairs = split_items(inner)
|
|
125
|
-
.into_iter()
|
|
126
|
-
.map(|item| {
|
|
127
|
-
// Splits at the first ":" only, like Ruby's `partition`; field names have none.
|
|
128
|
-
match item.find(':') {
|
|
129
|
-
Some(idx) => {
|
|
130
|
-
let key = item[..idx].trim().to_string();
|
|
131
|
-
let held = &item[idx + 1..];
|
|
132
|
-
(key, read(held))
|
|
133
|
-
}
|
|
134
|
-
None => (item.trim().to_string(), read("")),
|
|
135
|
-
}
|
|
136
|
-
})
|
|
137
|
-
.collect();
|
|
138
|
-
Literal::Hash(pairs)
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
fn read_array(raw: &str) -> Literal {
|
|
142
|
-
let inner = &raw[1..raw.len() - 1];
|
|
143
|
-
Literal::Array(split_items(inner).into_iter().map(|item| read(&item)).collect())
|
|
144
|
-
}
|
|
145
|
-
|
|
146
90
|
/// `naming.rb#literal_rhs` for a `Literal`: String/Integer/Float/Boolean, else panics.
|
|
91
|
+
#[allow(
|
|
92
|
+
clippy::panic,
|
|
93
|
+
reason = "a drifted exemplar or invalid IR aborts generation on purpose"
|
|
94
|
+
)]
|
|
147
95
|
pub fn literal_rhs(literal: &Literal) -> String {
|
|
148
96
|
match literal {
|
|
149
97
|
Literal::Str(s) => format!("{}.to_string()", crate::naming::ruby_inspect_string(s)),
|
|
@@ -168,43 +116,61 @@ fn ruby_float_to_s(literal: &Literal) -> String {
|
|
|
168
116
|
}
|
|
169
117
|
}
|
|
170
118
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
let mut current = String::new();
|
|
175
|
-
let mut depth: i32 = 0;
|
|
176
|
-
let mut quoting = false;
|
|
177
|
-
let mut escaping = false;
|
|
178
|
-
|
|
179
|
-
for ch in body.chars() {
|
|
180
|
-
current.push(ch);
|
|
181
|
-
if escaping {
|
|
182
|
-
escaping = false;
|
|
183
|
-
continue;
|
|
184
|
-
}
|
|
185
|
-
if quoting && ch == '\\' {
|
|
186
|
-
escaping = true;
|
|
187
|
-
continue;
|
|
188
|
-
}
|
|
189
|
-
if ch == '"' {
|
|
190
|
-
quoting = !quoting;
|
|
191
|
-
continue;
|
|
192
|
-
}
|
|
193
|
-
if quoting {
|
|
194
|
-
continue;
|
|
195
|
-
}
|
|
119
|
+
#[cfg(test)]
|
|
120
|
+
mod tests {
|
|
121
|
+
use super::*;
|
|
196
122
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
123
|
+
fn s(text: &str) -> Literal {
|
|
124
|
+
Literal::Str(text.to_string())
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
#[test]
|
|
128
|
+
fn reads_scalars() {
|
|
129
|
+
assert_eq!(read(""), Literal::Nil);
|
|
130
|
+
assert_eq!(read("nil"), Literal::Nil);
|
|
131
|
+
assert_eq!(read("true"), Literal::Bool(true));
|
|
132
|
+
assert_eq!(read("-12"), Literal::Int(-12));
|
|
133
|
+
assert_eq!(read("1.5"), Literal::Float(1.5));
|
|
134
|
+
assert_eq!(read(":name"), Literal::Symbol("name".to_string()));
|
|
135
|
+
assert_eq!(read(r#""a\"b""#), s("a\"b"));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
#[test]
|
|
139
|
+
fn reads_collections() {
|
|
140
|
+
assert_eq!(
|
|
141
|
+
read(r#"[1, "x"]"#),
|
|
142
|
+
Literal::Array(vec![Literal::Int(1), s("x")])
|
|
143
|
+
);
|
|
144
|
+
assert_eq!(
|
|
145
|
+
read("{a: 1, b: :c}"),
|
|
146
|
+
Literal::Hash(vec![
|
|
147
|
+
("a".to_string(), Literal::Int(1)),
|
|
148
|
+
("b".to_string(), Literal::Symbol("c".to_string()))
|
|
149
|
+
])
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
#[test]
|
|
154
|
+
fn bare_word_is_a_string() {
|
|
155
|
+
assert_eq!(read("Widget"), s("Widget"));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
#[test]
|
|
159
|
+
fn overflowing_integer_is_zero_like_ruby_to_i() {
|
|
160
|
+
assert_eq!(read("99999999999999999999"), Literal::Int(0));
|
|
161
|
+
assert_eq!(read("-99999999999999999999"), Literal::Int(0));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
#[test]
|
|
165
|
+
fn adjacent_and_single_quoted_strings() {
|
|
166
|
+
assert_eq!(read(r#""a" "b""#), s("ab"));
|
|
167
|
+
assert_eq!(read(r"'it\'s'"), s("it's"));
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
#[test]
|
|
171
|
+
fn from_json_and_get() {
|
|
172
|
+
let hash = read("{a: 1}");
|
|
173
|
+
assert_eq!(hash.get("a"), Some(&Literal::Int(1)));
|
|
174
|
+
assert_eq!(Literal::from_json(&Json::Null), Literal::Nil);
|
|
207
175
|
}
|
|
208
|
-
items.push(current);
|
|
209
|
-
items.into_iter().map(|s| s.trim().to_string()).filter(|s| !s.is_empty()).collect()
|
|
210
176
|
}
|
data/rust/codegen/src/main.rs
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
//! `hecks-codegen` — the IR-to-Rust-source generator, the only one (ADR 0086).
|
|
2
2
|
//! Usage: `hecks-codegen <prelude|domain|full> ...`, one subcommand per function below.
|
|
3
|
-
// Some ported `naming.rs` helpers are not called yet.
|
|
4
|
-
#![allow(dead_code)]
|
|
5
3
|
|
|
6
4
|
mod asks;
|
|
7
5
|
mod attr;
|
|
@@ -13,7 +11,12 @@ mod domain_generator;
|
|
|
13
11
|
mod exemplar;
|
|
14
12
|
mod expr_emitter;
|
|
15
13
|
mod fielded;
|
|
14
|
+
// The one `Hecks::Naming` port, compiled by path into the other Cargo projects too; codegen uses
|
|
15
|
+
// only part of it.
|
|
16
|
+
#[allow(dead_code)]
|
|
16
17
|
mod hecks_naming;
|
|
18
|
+
#[cfg(test)]
|
|
19
|
+
mod hecks_naming_tests;
|
|
17
20
|
mod json;
|
|
18
21
|
mod json_codec;
|
|
19
22
|
mod literal;
|
|
@@ -29,12 +32,19 @@ mod read_models;
|
|
|
29
32
|
mod reference_specs;
|
|
30
33
|
mod registry;
|
|
31
34
|
mod reserved_names;
|
|
35
|
+
#[path = "../../parser/src/ruby_value.rs"]
|
|
36
|
+
#[allow(
|
|
37
|
+
dead_code,
|
|
38
|
+
reason = "shared with the parser, which uses parts codegen does not"
|
|
39
|
+
)]
|
|
40
|
+
mod ruby_value;
|
|
32
41
|
mod shared;
|
|
33
42
|
mod sidecars;
|
|
34
43
|
mod skip_reason;
|
|
35
44
|
mod types;
|
|
36
45
|
|
|
37
46
|
use json::Json;
|
|
47
|
+
use shared::{puts_blank, puts_str};
|
|
38
48
|
use std::process::ExitCode;
|
|
39
49
|
|
|
40
50
|
fn main() -> ExitCode {
|
|
@@ -69,7 +79,7 @@ fn run_prelude(args: &[String]) -> Result<(), String> {
|
|
|
69
79
|
|
|
70
80
|
let ex = exemplar::Exemplar::load();
|
|
71
81
|
|
|
72
|
-
let aggregates = ir.get("aggregates").
|
|
82
|
+
let aggregates = ir.get("aggregates").map_or_default(Json::each);
|
|
73
83
|
for aggregate in aggregates {
|
|
74
84
|
let name = aggregate.get("name").and_then(Json::as_str).unwrap_or("");
|
|
75
85
|
match prelude::aggregate_prelude(&ex, &ir, aggregate, source_label) {
|
|
@@ -92,7 +102,9 @@ fn run_prelude(args: &[String]) -> Result<(), String> {
|
|
|
92
102
|
/// sidecars into `out_dir`.
|
|
93
103
|
fn run_domain(args: &[String]) -> Result<(), String> {
|
|
94
104
|
let [ir_path, source_label, mod_name, out_dir] = args else {
|
|
95
|
-
return Err(
|
|
105
|
+
return Err(
|
|
106
|
+
"usage: hecks-codegen domain <ir.json> <source_label> <mod_name> <out_dir>".to_string(),
|
|
107
|
+
);
|
|
96
108
|
};
|
|
97
109
|
|
|
98
110
|
let ir = read_ir(ir_path)?;
|
|
@@ -123,8 +135,7 @@ fn write_domain(
|
|
|
123
135
|
// Refuse before writing anything, so a name collision is reported before any file exists.
|
|
124
136
|
let aggregate_names: Vec<&str> = ir
|
|
125
137
|
.get("aggregates")
|
|
126
|
-
.
|
|
127
|
-
.unwrap_or(&[])
|
|
138
|
+
.map_or_default(Json::each)
|
|
128
139
|
.iter()
|
|
129
140
|
.map(|a| a.get("name").and_then(Json::as_str).unwrap_or(""))
|
|
130
141
|
.collect();
|
|
@@ -146,7 +157,8 @@ fn write_domain(
|
|
|
146
157
|
}
|
|
147
158
|
|
|
148
159
|
let registry_path = format!("{out_dir}/registry.rs");
|
|
149
|
-
std::fs::write(®istry_path, &generated.registry_rs)
|
|
160
|
+
std::fs::write(®istry_path, &generated.registry_rs)
|
|
161
|
+
.map_err(|e| format!("writing {registry_path}: {e}"))?;
|
|
150
162
|
println!("wrote {registry_path}");
|
|
151
163
|
|
|
152
164
|
let mod_path = format!("{out_dir}/mod.rs");
|
|
@@ -154,34 +166,25 @@ fn write_domain(
|
|
|
154
166
|
println!("wrote {mod_path}");
|
|
155
167
|
|
|
156
168
|
let manifest_path = format!("{out_dir}/manifest.json");
|
|
157
|
-
std::fs::write(&manifest_path, &generated.manifest_json)
|
|
169
|
+
std::fs::write(&manifest_path, &generated.manifest_json)
|
|
170
|
+
.map_err(|e| format!("writing {manifest_path}: {e}"))?;
|
|
158
171
|
println!("wrote {manifest_path}");
|
|
159
172
|
|
|
160
|
-
let (ir_json_path, metadata_path) =
|
|
173
|
+
let (ir_json_path, metadata_path) =
|
|
174
|
+
sidecars::write(std::path::Path::new(out_dir), ir, source_label)?;
|
|
161
175
|
println!("wrote {}", ir_json_path.display());
|
|
162
176
|
println!("wrote {}", metadata_path.display());
|
|
163
177
|
|
|
164
178
|
Ok(generated)
|
|
165
179
|
}
|
|
166
180
|
|
|
167
|
-
fn puts_str(out: &mut String, s: &str) {
|
|
168
|
-
out.push_str(s);
|
|
169
|
-
if !s.ends_with('\n') {
|
|
170
|
-
out.push('\n');
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
fn puts_blank(out: &mut String) {
|
|
175
|
-
out.push('\n');
|
|
176
|
-
}
|
|
177
|
-
|
|
178
181
|
/// `hecks-codegen full <out_root> <target_mod_name> <target_source_label> <target_ir.json>
|
|
179
182
|
/// [<chapter_mod_name> <chapter_source_label> <chapter_ir.json>]...`
|
|
180
183
|
///
|
|
181
184
|
/// Writes the target chapter's directory, each attached chapter's own directory, and the
|
|
182
185
|
/// target's `merged.rs`: one `Store`/`dispatch_by_name` table spanning every chapter given.
|
|
183
186
|
fn run_full(args: &[String]) -> Result<(), String> {
|
|
184
|
-
if args.len() < 4 || (args.len() - 4)
|
|
187
|
+
if args.len() < 4 || !(args.len() - 4).is_multiple_of(3) {
|
|
185
188
|
return Err(
|
|
186
189
|
"usage: hecks-codegen full <out_root> <target_mod_name> <target_source_label> <target_ir.json> [<chapter_mod_name> <chapter_source_label> <chapter_ir.json>]..."
|
|
187
190
|
.to_string(),
|
|
@@ -196,19 +199,38 @@ fn run_full(args: &[String]) -> Result<(), String> {
|
|
|
196
199
|
let ex = exemplar::Exemplar::load();
|
|
197
200
|
|
|
198
201
|
let target_ir = read_ir(target_ir_path)?;
|
|
199
|
-
let target_domain_name = target_ir
|
|
202
|
+
let target_domain_name = target_ir
|
|
203
|
+
.get("name")
|
|
204
|
+
.and_then(Json::as_str)
|
|
205
|
+
.unwrap_or("")
|
|
206
|
+
.to_string();
|
|
200
207
|
|
|
201
208
|
let target_out_dir = format!("{out_root}/{target_mod_name}");
|
|
202
|
-
let target_gen = write_domain(
|
|
209
|
+
let target_gen = write_domain(
|
|
210
|
+
&ex,
|
|
211
|
+
&target_ir,
|
|
212
|
+
target_source_label,
|
|
213
|
+
target_mod_name,
|
|
214
|
+
&target_out_dir,
|
|
215
|
+
)?;
|
|
203
216
|
|
|
204
217
|
// Target first, then each attached chapter in command-line order.
|
|
205
|
-
let mut reference_key_pairs: Vec<(String, Vec<String>)> =
|
|
206
|
-
|
|
218
|
+
let mut reference_key_pairs: Vec<(String, Vec<String>)> = vec![(
|
|
219
|
+
target_domain_name.clone(),
|
|
220
|
+
target_gen
|
|
221
|
+
.registry_aggregates
|
|
222
|
+
.iter()
|
|
223
|
+
.map(|a| a.name.clone())
|
|
224
|
+
.collect(),
|
|
225
|
+
)];
|
|
207
226
|
|
|
208
227
|
let mut merged_aggregates = target_gen.registry_aggregates;
|
|
209
228
|
let mut merged_queries = target_gen.query_defs;
|
|
210
229
|
let mut merged_read_models = target_gen.read_model_defs;
|
|
211
|
-
let mut merged_process_managers: Vec<Json> = target_ir
|
|
230
|
+
let mut merged_process_managers: Vec<Json> = target_ir
|
|
231
|
+
.get("process_managers")
|
|
232
|
+
.map_or_default(Json::each)
|
|
233
|
+
.to_vec();
|
|
212
234
|
|
|
213
235
|
// Policies and process managers merge across chapters; `chapter_irs` keeps each parsed
|
|
214
236
|
// chapter alive so `policy_sources` can borrow from it.
|
|
@@ -223,60 +245,127 @@ fn run_full(args: &[String]) -> Result<(), String> {
|
|
|
223
245
|
i += 3;
|
|
224
246
|
|
|
225
247
|
let chapter_ir = read_ir(chapter_ir_path)?;
|
|
226
|
-
let chapter_domain_name = chapter_ir
|
|
248
|
+
let chapter_domain_name = chapter_ir
|
|
249
|
+
.get("name")
|
|
250
|
+
.and_then(Json::as_str)
|
|
251
|
+
.unwrap_or("")
|
|
252
|
+
.to_string();
|
|
227
253
|
|
|
228
254
|
let chapter_out_dir = format!("{out_root}/{chapter_mod_name}");
|
|
229
|
-
let chapter_gen = write_domain(
|
|
230
|
-
|
|
231
|
-
|
|
255
|
+
let chapter_gen = write_domain(
|
|
256
|
+
&ex,
|
|
257
|
+
&chapter_ir,
|
|
258
|
+
chapter_source_label,
|
|
259
|
+
chapter_mod_name,
|
|
260
|
+
&chapter_out_dir,
|
|
261
|
+
)?;
|
|
262
|
+
|
|
263
|
+
reference_key_pairs.push((
|
|
264
|
+
chapter_domain_name.clone(),
|
|
265
|
+
chapter_gen
|
|
266
|
+
.registry_aggregates
|
|
267
|
+
.iter()
|
|
268
|
+
.map(|a| a.name.clone())
|
|
269
|
+
.collect(),
|
|
270
|
+
));
|
|
232
271
|
merged_aggregates.extend(chapter_gen.registry_aggregates);
|
|
233
272
|
merged_queries.extend(chapter_gen.query_defs);
|
|
234
273
|
merged_read_models.extend(chapter_gen.read_model_defs);
|
|
235
|
-
merged_process_managers.extend(
|
|
274
|
+
merged_process_managers.extend(
|
|
275
|
+
chapter_ir
|
|
276
|
+
.get("process_managers")
|
|
277
|
+
.map_or_default(Json::each)
|
|
278
|
+
.to_vec(),
|
|
279
|
+
);
|
|
236
280
|
|
|
237
281
|
chapter_domain_names.push(chapter_domain_name);
|
|
238
282
|
chapter_irs.push(chapter_ir);
|
|
239
283
|
}
|
|
240
284
|
|
|
241
285
|
// One entry per chapter, so its policies qualify against its own domain and aggregates.
|
|
242
|
-
let policies: Vec<Json> = target_ir
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
286
|
+
let policies: Vec<Json> = target_ir
|
|
287
|
+
.get("policies")
|
|
288
|
+
.map_or_default(Json::each)
|
|
289
|
+
.to_vec();
|
|
290
|
+
let policy_aggregates: Vec<Json> = target_ir
|
|
291
|
+
.get("aggregates")
|
|
292
|
+
.map_or_default(Json::each)
|
|
293
|
+
.to_vec();
|
|
294
|
+
|
|
295
|
+
let mut policy_sources: Vec<reactions::PolicySource> = vec![reactions::PolicySource {
|
|
296
|
+
domain_name: &target_domain_name,
|
|
297
|
+
policies: &policies,
|
|
298
|
+
aggregates: &policy_aggregates,
|
|
299
|
+
}];
|
|
247
300
|
for (name, ir) in chapter_domain_names.iter().zip(chapter_irs.iter()) {
|
|
248
301
|
policy_sources.push(reactions::PolicySource {
|
|
249
302
|
domain_name: name,
|
|
250
|
-
policies: ir.get("policies").
|
|
251
|
-
aggregates: ir.get("aggregates").
|
|
303
|
+
policies: ir.get("policies").map_or_default(Json::each),
|
|
304
|
+
aggregates: ir.get("aggregates").map_or_default(Json::each),
|
|
252
305
|
});
|
|
253
306
|
}
|
|
254
307
|
|
|
255
308
|
let mut merged_rs = String::new();
|
|
256
|
-
puts_str(
|
|
309
|
+
puts_str(
|
|
310
|
+
&mut merged_rs,
|
|
311
|
+
&crate::registry::emit_registry(&ex, &merged_aggregates),
|
|
312
|
+
);
|
|
257
313
|
puts_blank(&mut merged_rs);
|
|
258
|
-
puts_str(
|
|
314
|
+
puts_str(
|
|
315
|
+
&mut merged_rs,
|
|
316
|
+
&crate::registry::emit_reference_lookup(&merged_aggregates),
|
|
317
|
+
);
|
|
259
318
|
puts_blank(&mut merged_rs);
|
|
260
|
-
puts_str(
|
|
319
|
+
puts_str(
|
|
320
|
+
&mut merged_rs,
|
|
321
|
+
&reactions::emit_merged_policy_table(&ex, &policy_sources),
|
|
322
|
+
);
|
|
261
323
|
puts_blank(&mut merged_rs);
|
|
262
|
-
puts_str(
|
|
324
|
+
puts_str(
|
|
325
|
+
&mut merged_rs,
|
|
326
|
+
&reactions::emit_merged_cross_domain_policy_table(&ex, &policy_sources),
|
|
327
|
+
);
|
|
263
328
|
puts_blank(&mut merged_rs);
|
|
264
|
-
puts_str(
|
|
329
|
+
puts_str(
|
|
330
|
+
&mut merged_rs,
|
|
331
|
+
&reactions::emit_process_manager_table(&ex, &merged_process_managers),
|
|
332
|
+
);
|
|
265
333
|
puts_blank(&mut merged_rs);
|
|
266
|
-
puts_str(
|
|
334
|
+
puts_str(
|
|
335
|
+
&mut merged_rs,
|
|
336
|
+
&reactions::emit_reference_key_table(&ex, &reference_key_pairs),
|
|
337
|
+
);
|
|
267
338
|
puts_blank(&mut merged_rs);
|
|
268
|
-
puts_str(
|
|
339
|
+
puts_str(
|
|
340
|
+
&mut merged_rs,
|
|
341
|
+
&reactions::emit_creates_table(&ex, &merged_aggregates),
|
|
342
|
+
);
|
|
269
343
|
puts_blank(&mut merged_rs);
|
|
270
|
-
puts_str(
|
|
344
|
+
puts_str(
|
|
345
|
+
&mut merged_rs,
|
|
346
|
+
&reactions::emit_identity_head_table(&ex, &merged_aggregates),
|
|
347
|
+
);
|
|
271
348
|
puts_blank(&mut merged_rs);
|
|
272
349
|
// Section order is part of the output: `hecks regenerate_corpus --check` diffs this file byte for byte.
|
|
273
|
-
puts_str(
|
|
350
|
+
puts_str(
|
|
351
|
+
&mut merged_rs,
|
|
352
|
+
&reactions::emit_entity_identity_head_table(&ex, &merged_aggregates),
|
|
353
|
+
);
|
|
274
354
|
puts_blank(&mut merged_rs);
|
|
275
|
-
puts_str(
|
|
355
|
+
puts_str(
|
|
356
|
+
&mut merged_rs,
|
|
357
|
+
&reactions::emit_command_attributes_table(&ex, &merged_aggregates),
|
|
358
|
+
);
|
|
276
359
|
puts_blank(&mut merged_rs);
|
|
277
|
-
puts_str(
|
|
360
|
+
puts_str(
|
|
361
|
+
&mut merged_rs,
|
|
362
|
+
&queries::emit_query_table(&ex, &merged_queries),
|
|
363
|
+
);
|
|
278
364
|
puts_blank(&mut merged_rs);
|
|
279
|
-
puts_str(
|
|
365
|
+
puts_str(
|
|
366
|
+
&mut merged_rs,
|
|
367
|
+
&queries::emit_query_arg_check_table(&merged_queries),
|
|
368
|
+
);
|
|
280
369
|
puts_blank(&mut merged_rs);
|
|
281
370
|
for rmd in &merged_read_models {
|
|
282
371
|
if let Some(body) = &rmd.group_by_fn_body {
|
|
@@ -284,7 +373,10 @@ fn run_full(args: &[String]) -> Result<(), String> {
|
|
|
284
373
|
puts_blank(&mut merged_rs);
|
|
285
374
|
}
|
|
286
375
|
}
|
|
287
|
-
puts_str(
|
|
376
|
+
puts_str(
|
|
377
|
+
&mut merged_rs,
|
|
378
|
+
&read_models::emit_read_model_table(&ex, &merged_read_models),
|
|
379
|
+
);
|
|
288
380
|
|
|
289
381
|
let merged_path = format!("{target_out_dir}/merged.rs");
|
|
290
382
|
std::fs::write(&merged_path, &merged_rs).map_err(|e| format!("writing {merged_path}: {e}"))?;
|
|
@@ -292,7 +384,8 @@ fn run_full(args: &[String]) -> Result<(), String> {
|
|
|
292
384
|
|
|
293
385
|
// `write_domain` already wrote `mod.rs`; only the target directory gets a `merged` module.
|
|
294
386
|
let mod_path = format!("{target_out_dir}/mod.rs");
|
|
295
|
-
let mut mod_rs =
|
|
387
|
+
let mut mod_rs =
|
|
388
|
+
std::fs::read_to_string(&mod_path).map_err(|e| format!("reading {mod_path}: {e}"))?;
|
|
296
389
|
if !mod_rs.ends_with('\n') {
|
|
297
390
|
mod_rs.push('\n');
|
|
298
391
|
}
|