hecks 3.14.0 → 5.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/exe/hecks +1 -1
- data/lib/hecks/adapters/driven/prism.rb +0 -2
- data/lib/hecks/adapters/driven.rb +0 -2
- data/lib/hecks/adapters/driving/json.rb +9 -16
- 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/cli/project_cli/launcher_source.rb +1 -1
- 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/app/responses.rb +3 -1
- 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/first_admin.rb +3 -3
- 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/site/cms_editor/templates/src/host.ts.tmpl +7 -2
- 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/unwrapping.rb +60 -0
- data/lib/hecks/runtime/value.rb +10 -21
- 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/{1a6f596be124228be93eba1d86dbc9d2933190fa389b284331241cb9f27115a0.marshal → ad68f9e06c8068c2a4176b57abf3083d591d5d8980c2b3e897b97331f965b643.marshal} +0 -0
- data/prebuilt/{a883a7e568667aa5ac904c82daff356bdf9e996252a36af6def4a4a43efb967e.marshal → ee22ec8642c4006717ba2b80f46e5efb81de459eef9dfec043e838c0ad4fd720.marshal} +0 -0
- data/prebuilt/{verdicts-872993b1aa26d73fe48f28251374b8585fed145d02aab42be0f00de386b6ff80.json → verdicts-b69f5dcbba79c20daa0493476fa7c317004a30aa2bc3d3dc6a722ea70ae2b43b.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 +306 -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 +151 -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/presenters.rs +335 -0
- data/rust/codegen/src/queries.rs +601 -226
- data/rust/codegen/src/reactions.rs +268 -74
- data/rust/codegen/src/read_models.rs +574 -229
- 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 +1037 -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 +555 -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 +244 -114
- 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 +244 -148
- data/rust/src/kernel/mod.rs +47 -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/present.rs +261 -0
- 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/rust/host/src/approval.rs +0 -652
data/rust/build/src/resolve.rs
CHANGED
|
@@ -8,8 +8,12 @@ use crate::subprocess;
|
|
|
8
8
|
|
|
9
9
|
pub fn bluebook_files(directory: &Path) -> Result<Vec<PathBuf>, String> {
|
|
10
10
|
let mut files = Vec::new();
|
|
11
|
-
for entry in
|
|
12
|
-
|
|
11
|
+
for entry in
|
|
12
|
+
std::fs::read_dir(directory).map_err(|e| format!("reading {}: {e}", directory.display()))?
|
|
13
|
+
{
|
|
14
|
+
let path = entry
|
|
15
|
+
.map_err(|e| format!("reading {}: {e}", directory.display()))?
|
|
16
|
+
.path();
|
|
13
17
|
if path.extension().and_then(|extension| extension.to_str()) == Some("bluebook") {
|
|
14
18
|
files.push(path);
|
|
15
19
|
}
|
|
@@ -20,7 +24,8 @@ pub fn bluebook_files(directory: &Path) -> Result<Vec<PathBuf>, String> {
|
|
|
20
24
|
|
|
21
25
|
// Plain text scan of the `Hecks.bluebook "Name"` line; the file is never executed.
|
|
22
26
|
pub fn header_chapter_name(path: &Path) -> Result<String, String> {
|
|
23
|
-
let text =
|
|
27
|
+
let text =
|
|
28
|
+
std::fs::read_to_string(path).map_err(|e| format!("reading {}: {e}", path.display()))?;
|
|
24
29
|
for line in text.lines() {
|
|
25
30
|
let trimmed = line.trim_start();
|
|
26
31
|
if let Some(rest) = trimmed.strip_prefix("Hecks.bluebook") {
|
|
@@ -29,7 +34,10 @@ pub fn header_chapter_name(path: &Path) -> Result<String, String> {
|
|
|
29
34
|
}
|
|
30
35
|
}
|
|
31
36
|
}
|
|
32
|
-
Err(format!(
|
|
37
|
+
Err(format!(
|
|
38
|
+
"{} has no 'Hecks.bluebook \"Name\"' header",
|
|
39
|
+
path.display()
|
|
40
|
+
))
|
|
33
41
|
}
|
|
34
42
|
|
|
35
43
|
fn extract_quoted(rest: &str) -> Option<String> {
|
|
@@ -52,25 +60,17 @@ pub fn framework_members(root: &Path) -> Result<Vec<(String, PathBuf)>, String>
|
|
|
52
60
|
if path.extension().and_then(|e| e.to_str()) != Some("bluebook") {
|
|
53
61
|
continue;
|
|
54
62
|
}
|
|
55
|
-
let stem = path
|
|
56
|
-
|
|
63
|
+
let stem = path
|
|
64
|
+
.file_stem()
|
|
65
|
+
.and_then(|s| s.to_str())
|
|
66
|
+
.unwrap_or("")
|
|
67
|
+
.to_string();
|
|
68
|
+
members.push((crate::hecks_naming::pascal(&stem), path));
|
|
57
69
|
}
|
|
58
70
|
members.sort();
|
|
59
71
|
Ok(members)
|
|
60
72
|
}
|
|
61
73
|
|
|
62
|
-
pub fn pascal(text: &str) -> String {
|
|
63
|
-
text.split('_')
|
|
64
|
-
.map(|part| {
|
|
65
|
-
let mut chars = part.chars();
|
|
66
|
-
match chars.next() {
|
|
67
|
-
Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
|
|
68
|
-
None => String::new(),
|
|
69
|
-
}
|
|
70
|
-
})
|
|
71
|
-
.collect()
|
|
72
|
-
}
|
|
73
|
-
|
|
74
74
|
// Discovery, not a mirrored filename list, so a new concept cannot drift from this pipeline.
|
|
75
75
|
pub fn grammar_files(root: &Path) -> Result<Vec<PathBuf>, String> {
|
|
76
76
|
let dir = root.join("lib/hecks/language/bluebook");
|
|
@@ -78,27 +78,50 @@ pub fn grammar_files(root: &Path) -> Result<Vec<PathBuf>, String> {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
// The names `attaches "Name"` gave, for a chapter the gem carries.
|
|
81
|
-
pub fn resolve_gem_chapters(
|
|
81
|
+
pub fn resolve_gem_chapters(
|
|
82
|
+
parser_bin: &Path,
|
|
83
|
+
chapter_name: &str,
|
|
84
|
+
hecksagon_path: &Path,
|
|
85
|
+
) -> Result<Vec<String>, String> {
|
|
82
86
|
resolve_json(parser_bin, chapter_name, hecksagon_path, "gem_chapters")
|
|
83
87
|
}
|
|
84
88
|
|
|
85
89
|
// The names `attaches "name", from: :vendor` gave, for a vendored package.
|
|
86
|
-
pub fn resolve_vendored_packages(
|
|
87
|
-
|
|
90
|
+
pub fn resolve_vendored_packages(
|
|
91
|
+
parser_bin: &Path,
|
|
92
|
+
chapter_name: &str,
|
|
93
|
+
hecksagon_path: &Path,
|
|
94
|
+
) -> Result<Vec<String>, String> {
|
|
95
|
+
resolve_json(
|
|
96
|
+
parser_bin,
|
|
97
|
+
chapter_name,
|
|
98
|
+
hecksagon_path,
|
|
99
|
+
"vendored_packages",
|
|
100
|
+
)
|
|
88
101
|
}
|
|
89
102
|
|
|
90
103
|
// Where the gem keeps the chapters other than framework members, relative to `lib/hecks`; the
|
|
91
104
|
// same places `Hecks::Chapters::GLOBS` lists.
|
|
92
|
-
const OTHER_GEM_CHAPTER_DIRS: &[&str] = &[
|
|
105
|
+
const OTHER_GEM_CHAPTER_DIRS: &[&str] = &[
|
|
106
|
+
"language",
|
|
107
|
+
"grammar",
|
|
108
|
+
"tenancy/bluebook",
|
|
109
|
+
"deploy/bluebook",
|
|
110
|
+
"quality_control",
|
|
111
|
+
];
|
|
93
112
|
|
|
94
113
|
// The names of the chapters the gem carries beside the framework members, found by reading each
|
|
95
114
|
// file's header. Only the Ruby runtime loads them, so the build uses this list to tell a real
|
|
96
115
|
// gem chapter from a misspelt name.
|
|
97
116
|
pub fn other_gem_chapter_names(root: &Path) -> Result<Vec<String>, String> {
|
|
98
117
|
fn walk(directory: &Path, names: &mut Vec<String>) -> Result<(), String> {
|
|
99
|
-
let Ok(entries) = std::fs::read_dir(directory) else {
|
|
118
|
+
let Ok(entries) = std::fs::read_dir(directory) else {
|
|
119
|
+
return Ok(());
|
|
120
|
+
};
|
|
100
121
|
for entry in entries {
|
|
101
|
-
let path = entry
|
|
122
|
+
let path = entry
|
|
123
|
+
.map_err(|e| format!("reading {}: {e}", directory.display()))?
|
|
124
|
+
.path();
|
|
102
125
|
if path.is_dir() {
|
|
103
126
|
walk(&path, names)?;
|
|
104
127
|
} else if path.extension().and_then(|e| e.to_str()) == Some("bluebook") {
|
|
@@ -118,13 +141,26 @@ pub fn other_gem_chapter_names(root: &Path) -> Result<Vec<String>, String> {
|
|
|
118
141
|
Ok(names)
|
|
119
142
|
}
|
|
120
143
|
|
|
121
|
-
fn resolve_json(
|
|
144
|
+
fn resolve_json(
|
|
145
|
+
parser_bin: &Path,
|
|
146
|
+
chapter_name: &str,
|
|
147
|
+
hecksagon_path: &Path,
|
|
148
|
+
key: &str,
|
|
149
|
+
) -> Result<Vec<String>, String> {
|
|
122
150
|
let parser_bin_str = parser_bin.to_string_lossy().to_string();
|
|
123
151
|
let hecksagon_str = hecksagon_path.to_string_lossy().to_string();
|
|
124
|
-
let out = subprocess::run_capture(
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
152
|
+
let out = subprocess::run_capture(
|
|
153
|
+
&parser_bin_str,
|
|
154
|
+
&["resolve", "--chapter", chapter_name, &hecksagon_str],
|
|
155
|
+
)?;
|
|
156
|
+
let json = Json::parse(&out)
|
|
157
|
+
.map_err(|e| format!("parsing 'hecks-parse resolve' output: {e}\n{out}"))?;
|
|
158
|
+
let names = json.get(key).map_or(&[][..], Json::each);
|
|
159
|
+
Ok(names
|
|
160
|
+
.iter()
|
|
161
|
+
.filter_map(Json::as_str)
|
|
162
|
+
.map(str::to_string)
|
|
163
|
+
.collect())
|
|
128
164
|
}
|
|
129
165
|
|
|
130
166
|
/// `/\A[a-z][a-z0-9_]*\z/` — the shape `hecks vendor` accepts for a package directory name.
|
|
@@ -132,7 +168,8 @@ fn resolve_json(parser_bin: &Path, chapter_name: &str, hecksagon_path: &Path, ke
|
|
|
132
168
|
/// so `../x` or an absolute path must never reach either.
|
|
133
169
|
pub fn valid_package_name(name: &str) -> bool {
|
|
134
170
|
let mut chars = name.chars();
|
|
135
|
-
matches!(chars.next(), Some(c) if c.is_ascii_lowercase())
|
|
171
|
+
matches!(chars.next(), Some(c) if c.is_ascii_lowercase())
|
|
172
|
+
&& chars.all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_')
|
|
136
173
|
}
|
|
137
174
|
|
|
138
175
|
pub fn vendored_bluebook_files(domain: &Path, pkg_name: &str) -> Result<Vec<PathBuf>, String> {
|
|
@@ -141,7 +178,11 @@ pub fn vendored_bluebook_files(domain: &Path, pkg_name: &str) -> Result<Vec<Path
|
|
|
141
178
|
"attaches {pkg_name:?}, from: :vendor is not a package name — it must match [a-z][a-z0-9_]* (the name `hecks vendor` accepts)"
|
|
142
179
|
));
|
|
143
180
|
}
|
|
144
|
-
let dir = domain
|
|
181
|
+
let dir = domain
|
|
182
|
+
.join("vendor")
|
|
183
|
+
.join("embryonaut_bluebooks")
|
|
184
|
+
.join(pkg_name)
|
|
185
|
+
.join("bluebook");
|
|
145
186
|
if !dir.is_dir() {
|
|
146
187
|
return Err(format!(
|
|
147
188
|
"attaches {pkg_name:?}, from: :vendor names no vendored bluebook at {} — run hecks vendor {pkg_name}",
|
|
@@ -169,14 +210,20 @@ mod tests {
|
|
|
169
210
|
|
|
170
211
|
#[test]
|
|
171
212
|
fn pascal_cases_snake_case_stems() {
|
|
172
|
-
assert_eq!(pascal("governance"), "Governance");
|
|
173
|
-
assert_eq!(
|
|
174
|
-
|
|
213
|
+
assert_eq!(crate::hecks_naming::pascal("governance"), "Governance");
|
|
214
|
+
assert_eq!(
|
|
215
|
+
crate::hecks_naming::pascal("console_settings"),
|
|
216
|
+
"ConsoleSettings"
|
|
217
|
+
);
|
|
218
|
+
assert_eq!(crate::hecks_naming::pascal("identity"), "Identity");
|
|
175
219
|
}
|
|
176
220
|
|
|
177
221
|
#[test]
|
|
178
222
|
fn extracts_the_quoted_chapter_name() {
|
|
179
223
|
assert_eq!(extract_quoted(r#" "Pizzas""#), Some("Pizzas".to_string()));
|
|
180
|
-
assert_eq!(
|
|
224
|
+
assert_eq!(
|
|
225
|
+
extract_quoted(r#" "Console Settings" do"#),
|
|
226
|
+
Some("Console Settings".to_string())
|
|
227
|
+
);
|
|
181
228
|
}
|
|
182
229
|
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
//! Lays generated Rust out with rustfmt, as `Hecks::RustFormat` does for `hecks project_rust`, so
|
|
2
|
+
//! the tree `hecks-build` writes matches the one `hecks project_rust` writes, byte for byte.
|
|
3
|
+
|
|
4
|
+
use std::io::Write as _;
|
|
5
|
+
use std::path::{Path, PathBuf};
|
|
6
|
+
use std::process::{Command, Stdio};
|
|
7
|
+
|
|
8
|
+
const EDITION: &str = "2021";
|
|
9
|
+
|
|
10
|
+
// The most passes made; a text still changing after them keeps the last result, as in Ruby.
|
|
11
|
+
const PASSES: usize = 3;
|
|
12
|
+
|
|
13
|
+
/// Formats every `.rs` file of this run's own output: the `mod.rs` at `out_root` and each of
|
|
14
|
+
/// `dirs` beneath it, skipping a directory that is not there. A file is rewritten only when its
|
|
15
|
+
/// layout changes, so mtimes stay put and Cargo does not rebuild what did not change.
|
|
16
|
+
pub fn format_generated(out_root: &Path, dirs: &[String]) -> Result<(), String> {
|
|
17
|
+
let mut files = vec![out_root.join("mod.rs")];
|
|
18
|
+
for dir in dirs {
|
|
19
|
+
collect_rust_files(&out_root.join(dir), &mut files)?;
|
|
20
|
+
}
|
|
21
|
+
for file in files.iter().filter(|f| f.is_file()) {
|
|
22
|
+
format_file(file)?;
|
|
23
|
+
}
|
|
24
|
+
Ok(())
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
fn collect_rust_files(dir: &Path, into: &mut Vec<PathBuf>) -> Result<(), String> {
|
|
28
|
+
let Ok(entries) = std::fs::read_dir(dir) else {
|
|
29
|
+
return Ok(());
|
|
30
|
+
};
|
|
31
|
+
let mut paths: Vec<PathBuf> = entries.filter_map(|e| e.ok().map(|e| e.path())).collect();
|
|
32
|
+
paths.sort();
|
|
33
|
+
for path in paths {
|
|
34
|
+
if path.is_dir() {
|
|
35
|
+
collect_rust_files(&path, into)?;
|
|
36
|
+
} else if path.extension().is_some_and(|ext| ext == "rs") {
|
|
37
|
+
into.push(path);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
Ok(())
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
fn format_file(path: &Path) -> Result<(), String> {
|
|
44
|
+
let text =
|
|
45
|
+
std::fs::read_to_string(path).map_err(|e| format!("reading {}: {e}", path.display()))?;
|
|
46
|
+
let formatted = format_source(&text)?;
|
|
47
|
+
if formatted != text {
|
|
48
|
+
std::fs::write(path, formatted).map_err(|e| format!("writing {}: {e}", path.display()))?;
|
|
49
|
+
}
|
|
50
|
+
Ok(())
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
fn format_source(text: &str) -> Result<String, String> {
|
|
54
|
+
let mut current = text.to_string();
|
|
55
|
+
for _ in 0..PASSES {
|
|
56
|
+
let formatted = pass(¤t)?;
|
|
57
|
+
if formatted == current {
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
current = formatted;
|
|
61
|
+
}
|
|
62
|
+
Ok(current)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// One rustfmt run over stdin. Text rustfmt cannot parse is returned as it came, with a warning:
|
|
66
|
+
// the compiler will name the real fault. Any other failure of rustfmt is an error.
|
|
67
|
+
fn pass(text: &str) -> Result<String, String> {
|
|
68
|
+
let mut child = Command::new("rustfmt")
|
|
69
|
+
.args(["--edition", EDITION, "--emit", "stdout"])
|
|
70
|
+
.stdin(Stdio::piped())
|
|
71
|
+
.stdout(Stdio::piped())
|
|
72
|
+
.stderr(Stdio::piped())
|
|
73
|
+
.spawn()
|
|
74
|
+
.map_err(|e| {
|
|
75
|
+
format!("running rustfmt: {e} (generated Rust is formatted with it; run `rustup component add rustfmt`)")
|
|
76
|
+
})?;
|
|
77
|
+
let mut stdin = child.stdin.take().ok_or("rustfmt gave no stdin")?;
|
|
78
|
+
let input = text.to_string();
|
|
79
|
+
// Written from a thread: a large file fills the pipe before rustfmt starts reading its output.
|
|
80
|
+
let writer = std::thread::spawn(move || stdin.write_all(input.as_bytes()));
|
|
81
|
+
let output = child
|
|
82
|
+
.wait_with_output()
|
|
83
|
+
.map_err(|e| format!("waiting for rustfmt: {e}"))?;
|
|
84
|
+
let _ = writer.join();
|
|
85
|
+
if output.status.success() {
|
|
86
|
+
return String::from_utf8(output.stdout)
|
|
87
|
+
.map_err(|e| format!("rustfmt output was not UTF-8: {e}"));
|
|
88
|
+
}
|
|
89
|
+
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
90
|
+
let first = stderr.lines().next().unwrap_or_default().to_string();
|
|
91
|
+
// A parse error names `<stdin>`; anything else is rustfmt itself failing, and falling back to
|
|
92
|
+
// the unformatted text would write the wrong bytes without a word.
|
|
93
|
+
if !stderr.contains("<stdin>") {
|
|
94
|
+
return Err(format!("rustfmt failed: {first}"));
|
|
95
|
+
}
|
|
96
|
+
eprintln!(
|
|
97
|
+
"hecks-build: rustfmt could not format generated Rust, leaving it as generated: {first}"
|
|
98
|
+
);
|
|
99
|
+
Ok(text.to_string())
|
|
100
|
+
}
|
|
@@ -16,9 +16,27 @@ struct Seam {
|
|
|
16
16
|
|
|
17
17
|
// In `TargetIr::SEAMS` order, which is the order the keys land in `ir.json`.
|
|
18
18
|
const SEAMS: &[Seam] = &[
|
|
19
|
-
Seam {
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
Seam {
|
|
20
|
+
capability: "authorization",
|
|
21
|
+
export_as: "authorization",
|
|
22
|
+
verbs: &["grant", "assignments"],
|
|
23
|
+
aggregates: &[("assignment_aggregate", "assignments")],
|
|
24
|
+
marks: &[],
|
|
25
|
+
},
|
|
26
|
+
Seam {
|
|
27
|
+
capability: "membership",
|
|
28
|
+
export_as: "membership",
|
|
29
|
+
verbs: &["admit", "grant", "people"],
|
|
30
|
+
aggregates: &[("aggregate", "admit")],
|
|
31
|
+
marks: &[],
|
|
32
|
+
},
|
|
33
|
+
Seam {
|
|
34
|
+
capability: "identity",
|
|
35
|
+
export_as: "identity",
|
|
36
|
+
verbs: &["register", "link", "resolve"],
|
|
37
|
+
aggregates: &[],
|
|
38
|
+
marks: &[],
|
|
39
|
+
},
|
|
22
40
|
Seam {
|
|
23
41
|
capability: "newsletter",
|
|
24
42
|
export_as: "newsletter",
|
|
@@ -30,21 +48,41 @@ const SEAMS: &[Seam] = &[
|
|
|
30
48
|
capability: "newsletter_issues",
|
|
31
49
|
export_as: "newsletter_issues",
|
|
32
50
|
verbs: &["send_issue", "record_delivery"],
|
|
33
|
-
aggregates: &[
|
|
51
|
+
aggregates: &[
|
|
52
|
+
("issue_aggregate", "send_issue"),
|
|
53
|
+
("delivery_aggregate", "record_delivery"),
|
|
54
|
+
],
|
|
34
55
|
marks: &[],
|
|
35
56
|
},
|
|
36
|
-
Seam {
|
|
57
|
+
Seam {
|
|
58
|
+
capability: "payments",
|
|
59
|
+
export_as: "payments",
|
|
60
|
+
verbs: &["initiate", "succeeded", "failed"],
|
|
61
|
+
aggregates: &[("aggregate", "initiate")],
|
|
62
|
+
marks: &["holds_seat"],
|
|
63
|
+
},
|
|
37
64
|
Seam {
|
|
38
65
|
capability: "registrations",
|
|
39
66
|
export_as: "registrations",
|
|
40
67
|
verbs: &["schedule", "request"],
|
|
41
|
-
aggregates: &[
|
|
68
|
+
aggregates: &[
|
|
69
|
+
("event_aggregate", "schedule"),
|
|
70
|
+
("registration_aggregate", "request"),
|
|
71
|
+
],
|
|
42
72
|
marks: &["frees_seat"],
|
|
43
73
|
},
|
|
44
74
|
Seam {
|
|
45
75
|
capability: "payment_connection",
|
|
46
76
|
export_as: "payment_connection",
|
|
47
|
-
verbs: &[
|
|
77
|
+
verbs: &[
|
|
78
|
+
"connect",
|
|
79
|
+
"reconnect",
|
|
80
|
+
"disconnect",
|
|
81
|
+
"suspend",
|
|
82
|
+
"resume",
|
|
83
|
+
"enable",
|
|
84
|
+
"disable",
|
|
85
|
+
],
|
|
48
86
|
aggregates: &[("aggregate", "connect")],
|
|
49
87
|
marks: &[],
|
|
50
88
|
},
|
|
@@ -60,7 +98,12 @@ pub fn run(target: &mut Json, members: &[Json]) -> Result<(), String> {
|
|
|
60
98
|
let mut membership = false;
|
|
61
99
|
let mut identity = false;
|
|
62
100
|
for seam in SEAMS {
|
|
63
|
-
let Some(provider) = chapters
|
|
101
|
+
let Some(provider) = chapters
|
|
102
|
+
.iter()
|
|
103
|
+
.find(|chapter| provision(chapter, seam.capability).is_some())
|
|
104
|
+
else {
|
|
105
|
+
continue;
|
|
106
|
+
};
|
|
64
107
|
let exported = export(seam, provider);
|
|
65
108
|
membership |= seam.capability == "membership";
|
|
66
109
|
identity |= seam.capability == "identity";
|
|
@@ -79,7 +122,12 @@ pub fn run(target: &mut Json, members: &[Json]) -> Result<(), String> {
|
|
|
79
122
|
fn export(seam: &Seam, provider: &Json) -> Json {
|
|
80
123
|
let name = name_of(provider);
|
|
81
124
|
let entries = provision(provider, seam.capability).unwrap_or_default();
|
|
82
|
-
let verb = |key: &str|
|
|
125
|
+
let verb = |key: &str| {
|
|
126
|
+
entries
|
|
127
|
+
.iter()
|
|
128
|
+
.find(|(k, _)| k == key)
|
|
129
|
+
.map(|(_, v)| format!("{name}::{v}"))
|
|
130
|
+
};
|
|
83
131
|
|
|
84
132
|
let mut out = vec![("provider".to_string(), Json::String(name.clone()))];
|
|
85
133
|
for key in seam.verbs {
|
|
@@ -87,10 +135,19 @@ fn export(seam: &Seam, provider: &Json) -> Json {
|
|
|
87
135
|
}
|
|
88
136
|
for (exported, key) in seam.aggregates {
|
|
89
137
|
let aggregate = verb(key).map(|v| v.split('.').next().unwrap_or_default().to_string());
|
|
90
|
-
out.push((
|
|
138
|
+
out.push((
|
|
139
|
+
exported.to_string(),
|
|
140
|
+
aggregate.map_or(Json::Null, Json::String),
|
|
141
|
+
));
|
|
91
142
|
}
|
|
92
143
|
for key in seam.marks {
|
|
93
|
-
if let Some(states) = marked_states(
|
|
144
|
+
if let Some(states) = marked_states(
|
|
145
|
+
provider,
|
|
146
|
+
entries
|
|
147
|
+
.iter()
|
|
148
|
+
.find(|(k, _)| k == key)
|
|
149
|
+
.map(|(_, v)| v.as_str()),
|
|
150
|
+
) {
|
|
94
151
|
out.push((key.to_string(), states));
|
|
95
152
|
}
|
|
96
153
|
}
|
|
@@ -101,11 +158,15 @@ fn export(seam: &Seam, provider: &Json) -> Json {
|
|
|
101
158
|
fn provision(chapter: &Json, capability: &str) -> Option<Vec<(String, String)>> {
|
|
102
159
|
let entries: Vec<(String, String)> = chapter
|
|
103
160
|
.get("provides")
|
|
104
|
-
.
|
|
105
|
-
.unwrap_or(&[])
|
|
161
|
+
.map_or(&[][..], Json::each)
|
|
106
162
|
.iter()
|
|
107
163
|
.filter(|entry| entry.get("capability").and_then(Json::as_str) == Some(capability))
|
|
108
|
-
.filter_map(|entry|
|
|
164
|
+
.filter_map(|entry| {
|
|
165
|
+
Some((
|
|
166
|
+
entry.get("key")?.as_str()?.to_string(),
|
|
167
|
+
entry.get("verb")?.as_str()?.to_string(),
|
|
168
|
+
))
|
|
169
|
+
})
|
|
109
170
|
.collect();
|
|
110
171
|
(!entries.is_empty()).then_some(entries)
|
|
111
172
|
}
|
|
@@ -114,10 +175,18 @@ fn provision(chapter: &Json, capability: &str) -> Option<Vec<(String, String)>>
|
|
|
114
175
|
// entry is not declared or the mark is.
|
|
115
176
|
fn marked_states(provider: &Json, entry: Option<&str>) -> Option<Json> {
|
|
116
177
|
let (aggregate_name, mark) = entry?.split_once('.')?;
|
|
117
|
-
let aggregate = provider
|
|
178
|
+
let aggregate = provider
|
|
179
|
+
.get("aggregates")
|
|
180
|
+
.map(Json::each)?
|
|
181
|
+
.iter()
|
|
182
|
+
.find(|a| a.get("name").and_then(Json::as_str) == Some(aggregate_name))?;
|
|
118
183
|
aggregate.get("lifecycle")?.get("marks")?.get(mark).cloned()
|
|
119
184
|
}
|
|
120
185
|
|
|
121
186
|
fn name_of(chapter: &Json) -> String {
|
|
122
|
-
chapter
|
|
187
|
+
chapter
|
|
188
|
+
.get("name")
|
|
189
|
+
.and_then(Json::as_str)
|
|
190
|
+
.unwrap_or_default()
|
|
191
|
+
.to_string()
|
|
123
192
|
}
|
|
@@ -5,7 +5,10 @@ use std::path::Path;
|
|
|
5
5
|
use std::process::{Command, Stdio};
|
|
6
6
|
|
|
7
7
|
pub fn run_capture(program: &str, args: &[&str]) -> Result<String, String> {
|
|
8
|
-
let output = Command::new(program)
|
|
8
|
+
let output = Command::new(program)
|
|
9
|
+
.args(args)
|
|
10
|
+
.output()
|
|
11
|
+
.map_err(|e| format!("running {program} {}: {e}", args.join(" ")))?;
|
|
9
12
|
if !output.status.success() {
|
|
10
13
|
return Err(format!(
|
|
11
14
|
"{program} {} failed:\n{}",
|
|
@@ -13,11 +16,19 @@ pub fn run_capture(program: &str, args: &[&str]) -> Result<String, String> {
|
|
|
13
16
|
String::from_utf8_lossy(&output.stderr)
|
|
14
17
|
));
|
|
15
18
|
}
|
|
16
|
-
String::from_utf8(output.stdout).map_err(|e|
|
|
19
|
+
String::from_utf8(output.stdout).map_err(|e| {
|
|
20
|
+
format!(
|
|
21
|
+
"{program} {}: stdout was not valid UTF-8: {e}",
|
|
22
|
+
args.join(" ")
|
|
23
|
+
)
|
|
24
|
+
})
|
|
17
25
|
}
|
|
18
26
|
|
|
19
27
|
pub fn run(program: &str, args: &[&str]) -> Result<(), String> {
|
|
20
|
-
let status = Command::new(program)
|
|
28
|
+
let status = Command::new(program)
|
|
29
|
+
.args(args)
|
|
30
|
+
.status()
|
|
31
|
+
.map_err(|e| format!("running {program} {}: {e}", args.join(" ")))?;
|
|
21
32
|
if !status.success() {
|
|
22
33
|
return Err(format!("{program} {} failed", args.join(" ")));
|
|
23
34
|
}
|
|
@@ -29,9 +40,19 @@ pub fn run_in(dir: &Path, program: &str, args: &[&str]) -> Result<(), String> {
|
|
|
29
40
|
.args(args)
|
|
30
41
|
.current_dir(dir)
|
|
31
42
|
.status()
|
|
32
|
-
.map_err(|e|
|
|
43
|
+
.map_err(|e| {
|
|
44
|
+
format!(
|
|
45
|
+
"running {program} {} in {}: {e}",
|
|
46
|
+
args.join(" "),
|
|
47
|
+
dir.display()
|
|
48
|
+
)
|
|
49
|
+
})?;
|
|
33
50
|
if !status.success() {
|
|
34
|
-
return Err(format!(
|
|
51
|
+
return Err(format!(
|
|
52
|
+
"{program} {} failed in {}",
|
|
53
|
+
args.join(" "),
|
|
54
|
+
dir.display()
|
|
55
|
+
));
|
|
35
56
|
}
|
|
36
57
|
Ok(())
|
|
37
58
|
}
|
|
@@ -45,7 +66,10 @@ pub fn cargo_build_quiet(dir: &Path) -> Result<(), String> {
|
|
|
45
66
|
.status()
|
|
46
67
|
.map_err(|e| format!("running cargo build in {}: {e}", dir.display()))?;
|
|
47
68
|
if !status.success() {
|
|
48
|
-
return Err(format!(
|
|
69
|
+
return Err(format!(
|
|
70
|
+
"cargo build failed in {} — run it there directly to see why",
|
|
71
|
+
dir.display()
|
|
72
|
+
));
|
|
49
73
|
}
|
|
50
74
|
Ok(())
|
|
51
75
|
}
|
data/rust/build/src/tmp.rs
CHANGED
|
@@ -13,9 +13,12 @@ impl TempDir {
|
|
|
13
13
|
pub fn new(prefix: &str) -> Result<Self, String> {
|
|
14
14
|
let base = std::env::temp_dir();
|
|
15
15
|
let pid = std::process::id();
|
|
16
|
-
let nanos = std::time::SystemTime::now()
|
|
16
|
+
let nanos = std::time::SystemTime::now()
|
|
17
|
+
.duration_since(std::time::UNIX_EPOCH)
|
|
18
|
+
.map_or(0, |d| d.as_nanos());
|
|
17
19
|
let path = base.join(format!("{prefix}-{pid}-{nanos}"));
|
|
18
|
-
std::fs::create_dir_all(&path)
|
|
20
|
+
std::fs::create_dir_all(&path)
|
|
21
|
+
.map_err(|e| format!("creating temp dir {}: {e}", path.display()))?;
|
|
19
22
|
Ok(Self { path })
|
|
20
23
|
}
|
|
21
24
|
|