hecks 1.3.0 → 1.5.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/lib/hecks/adapters/driven/claude_code.rb +72 -7
- data/lib/hecks/adapters/driven/d1.rb +187 -23
- data/lib/hecks/adapters/driven/folder.rb +83 -10
- data/lib/hecks/adapters/driven/google_authentication.rb +33 -12
- data/lib/hecks/adapters/driven/governance_authorization.rb +87 -18
- data/lib/hecks/adapters/driven/heki/journal.rb +13 -4
- data/lib/hecks/adapters/driven/heki/saga_store.rb +56 -10
- data/lib/hecks/adapters/driven/heki/snapshot.rb +1 -1
- data/lib/hecks/adapters/driven/heki.rb +106 -9
- data/lib/hecks/adapters/driven/identity_registry.rb +12 -2
- data/lib/hecks/adapters/driven/in_memory_ordering.rb +25 -3
- data/lib/hecks/adapters/driven/in_process_key_vault.adapter +3 -0
- data/lib/hecks/adapters/driven/in_process_key_vault.rb +53 -0
- data/lib/hecks/adapters/driven/lambda/client.rb +67 -14
- data/lib/hecks/adapters/driven/lambda.rb +82 -35
- data/lib/hecks/adapters/driven/local_storage.rb +83 -10
- data/lib/hecks/adapters/driven/memory.rb +205 -9
- data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +21 -1
- data/lib/hecks/adapters/driven/postgres/codec.rb +27 -11
- data/lib/hecks/adapters/driven/postgres/outbox.rb +40 -2
- data/lib/hecks/adapters/driven/postgres/reconnect.rb +23 -7
- data/lib/hecks/adapters/driven/postgres/schema_builder.rb +14 -14
- data/lib/hecks/adapters/driven/postgres.rb +175 -28
- data/lib/hecks/adapters/driven/prism.rb +50 -11
- data/lib/hecks/adapters/driven/secure_random_identity.rb +3 -0
- data/lib/hecks/adapters/driven/sql_query_builder.rb +34 -22
- data/lib/hecks/adapters/driven/sqlite/codec.rb +38 -10
- data/lib/hecks/adapters/driven/sqlite/projection.rb +60 -32
- data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +12 -12
- data/lib/hecks/adapters/driven/sqlite.rb +181 -21
- data/lib/hecks/adapters/driven/system_clock.rb +3 -0
- data/lib/hecks/adapters/driven/tenant_provisioner.adapter +3 -0
- data/lib/hecks/adapters/driven/tenant_provisioner.rb +66 -0
- data/lib/hecks/adapters/driven.rb +6 -4
- data/lib/hecks/adapters/driving/github_webhook.rb +31 -18
- data/lib/hecks/behaviors/dsl.rb +60 -2
- data/lib/hecks/behaviors/expectations.rb +190 -29
- data/lib/hecks/behaviors/ir.rb +12 -1
- data/lib/hecks/behaviors/rspec.rb +9 -1
- data/lib/hecks/behaviors/runner.rb +21 -2
- data/lib/hecks/behaviors.rb +9 -1
- data/lib/hecks/bluebook/aggregate.rb +43 -13
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +17 -10
- data/lib/hecks/bluebook/assembly/build.rb +26 -5
- data/lib/hecks/bluebook/assembly/contract.rb +98 -23
- data/lib/hecks/bluebook/assembly/contracts.rb +59 -52
- data/lib/hecks/bluebook/assembly/marks.rb +159 -30
- data/lib/hecks/bluebook/assembly/specializer.rb +38 -21
- data/lib/hecks/bluebook/assembly.rb +32 -14
- data/lib/hecks/bluebook/attribute.rb +26 -12
- data/lib/hecks/bluebook/behaviour/aggregate.rb +43 -11
- data/lib/hecks/bluebook/behaviour/attribute.rb +18 -5
- data/lib/hecks/bluebook/behaviour/chapter.rb +76 -5
- data/lib/hecks/bluebook/behaviour/command.rb +55 -25
- data/lib/hecks/bluebook/behaviour/domain_port.rb +27 -7
- data/lib/hecks/bluebook/behaviour/entity.rb +20 -8
- data/lib/hecks/bluebook/behaviour/hexagon.rb +30 -4
- data/lib/hecks/bluebook/behaviour/lifecycle.rb +27 -6
- data/lib/hecks/bluebook/behaviour/policy.rb +42 -17
- data/lib/hecks/bluebook/behaviour/process_manager.rb +39 -8
- data/lib/hecks/bluebook/behaviour/query.rb +6 -1
- data/lib/hecks/bluebook/behaviour/read_model.rb +29 -8
- data/lib/hecks/bluebook/behaviour/traits.rb +48 -12
- data/lib/hecks/bluebook/behaviour/value_object.rb +21 -9
- data/lib/hecks/bluebook/capabilities.rb +27 -0
- data/lib/hecks/bluebook/chapter.rb +51 -9
- data/lib/hecks/bluebook/command.rb +62 -17
- data/lib/hecks/bluebook/domain_port.rb +34 -9
- data/lib/hecks/bluebook/dsl/adapter_builder.rb +24 -0
- data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +49 -49
- data/lib/hecks/bluebook/dsl/aggregate_builder.rb +282 -123
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +112 -75
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +81 -2
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +486 -117
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +179 -47
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +116 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +284 -122
- data/lib/hecks/bluebook/dsl/const_shim.rb +46 -15
- data/lib/hecks/bluebook/dsl/domain_port_builder.rb +90 -25
- data/lib/hecks/bluebook/dsl/entity_builder.rb +191 -61
- data/lib/hecks/bluebook/dsl/generic_dispatch.rb +148 -132
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +130 -30
- data/lib/hecks/bluebook/dsl/identity_declaration.rb +38 -21
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +27 -4
- data/lib/hecks/bluebook/dsl/policy_builder.rb +86 -36
- data/lib/hecks/bluebook/dsl/port_builder.rb +38 -7
- data/lib/hecks/bluebook/dsl/port_operation_builder.rb +56 -22
- data/lib/hecks/bluebook/dsl/process_manager_builder.rb +111 -47
- data/lib/hecks/bluebook/dsl/query_builder.rb +37 -8
- data/lib/hecks/bluebook/dsl/read_model_builder.rb +127 -52
- data/lib/hecks/bluebook/dsl/rule_reference.rb +97 -43
- data/lib/hecks/bluebook/dsl/translation_builder.rb +150 -44
- data/lib/hecks/bluebook/dsl/value_object_builder.rb +68 -20
- data/lib/hecks/bluebook/dsl/word_gate.rb +59 -53
- data/lib/hecks/bluebook/dsl/world_builder.rb +51 -8
- data/lib/hecks/bluebook/entity.rb +40 -11
- data/lib/hecks/bluebook/expression/ast_json.rb +128 -36
- data/lib/hecks/bluebook/expression/ast_reader.rb +32 -3
- data/lib/hecks/bluebook/expression/canonical_form.rb +55 -16
- data/lib/hecks/bluebook/expression/evaluator.rb +221 -43
- data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +54 -18
- data/lib/hecks/bluebook/expression/resolver.rb +369 -128
- data/lib/hecks/bluebook/hexagon.rb +35 -1
- data/lib/hecks/bluebook/lifecycle.rb +12 -1
- data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +2 -1
- data/lib/hecks/bluebook/meta_validator/judge.rb +126 -108
- data/lib/hecks/bluebook/meta_validator/plan.rb +81 -46
- data/lib/hecks/bluebook/meta_validator/port_judge.rb +3 -2
- data/lib/hecks/bluebook/meta_validator/readings.rb +200 -50
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +68 -41
- data/lib/hecks/bluebook/meta_validator/shapes.rb +166 -21
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +286 -46
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +11 -10
- data/lib/hecks/bluebook/meta_validator/world_judge.rb +6 -5
- data/lib/hecks/bluebook/meta_validator.rb +235 -139
- data/lib/hecks/bluebook/model_check.rb +434 -104
- data/lib/hecks/bluebook/pattern_subset.rb +32 -10
- data/lib/hecks/bluebook/policy.rb +15 -13
- data/lib/hecks/bluebook/process_manager.rb +27 -14
- data/lib/hecks/bluebook/project_discovery.rb +5 -0
- data/lib/hecks/bluebook/project_loader.rb +40 -0
- data/lib/hecks/bluebook/project_register.rb +50 -6
- data/lib/hecks/bluebook/query.rb +31 -4
- data/lib/hecks/bluebook/read_model.rb +35 -15
- data/lib/hecks/bluebook/reference.rb +26 -13
- data/lib/hecks/bluebook/smoke_test.rb +46 -23
- data/lib/hecks/bluebook/synthesizer.rb +46 -12
- data/lib/hecks/bluebook/translation.rb +34 -5
- data/lib/hecks/bluebook/value_object.rb +29 -11
- data/lib/hecks/bluebook.rb +5 -6
- data/lib/hecks/codemod.rb +138 -50
- data/lib/hecks/construct.rb +21 -7
- data/lib/hecks/corpus.rb +438 -0
- data/lib/hecks/deploy/bluebook/deploy.hecksagon +19 -0
- data/lib/hecks/doc/reference.rb +200 -31
- data/lib/hecks/embryonaut_bluebook.rb +38 -15
- data/lib/hecks/facade/cli_door.rb +69 -10
- data/lib/hecks/facade/cli_runner.rb +105 -24
- data/lib/hecks/facade/command_request.rb +23 -0
- data/lib/hecks/facade/handle.rb +155 -35
- data/lib/hecks/facade/json_door.rb +106 -25
- data/lib/hecks/facade/surface/aggregate_door.rb +50 -27
- data/lib/hecks/facade/surface/chapter.rb +26 -17
- data/lib/hecks/facade/surface.rb +16 -3
- data/lib/hecks/facade.rb +15 -4
- data/lib/hecks/forms/app.rb +46 -30
- data/lib/hecks/forms/command_form_renderer.rb +70 -9
- data/lib/hecks/forms/field_renderer.rb +142 -6
- data/lib/hecks/forms/field_shape.rb +183 -19
- data/lib/hecks/forms/html.rb +51 -7
- data/lib/hecks/forms/index_renderer.rb +14 -2
- data/lib/hecks/forms/page.rb +14 -0
- data/lib/hecks/forms/params.rb +120 -23
- data/lib/hecks/forms/port_argument.rb +14 -2
- data/lib/hecks/forms/query_form_renderer.rb +65 -2
- data/lib/hecks/forms/record_renderer.rb +60 -2
- data/lib/hecks/forms/record_table.rb +28 -1
- data/lib/hecks/forms/reference_options.rb +24 -0
- data/lib/hecks/forms/value_object_shape.rb +13 -3
- data/lib/hecks/forms.rb +24 -4
- data/lib/hecks/fqn.rb +59 -1
- data/lib/hecks/framework/bluebook/governance.bluebook +9 -0
- data/lib/hecks/framework/bluebook/privacy.bluebook +155 -0
- data/lib/hecks/framework/oidc.json +15 -0
- data/lib/hecks/framework.rb +79 -25
- data/lib/hecks/freezer.rb +27 -11
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +241 -106
- data/lib/hecks/fuzzing/combination_miner.rb +178 -0
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +241 -45
- data/lib/hecks/fuzzing/coverage_campaign.rb +161 -0
- data/lib/hecks/fuzzing/differential.rb +192 -0
- data/lib/hecks/fuzzing/domain_generator.rb +871 -0
- data/lib/hecks/fuzzing/era_boundary.rb +68 -19
- data/lib/hecks/fuzzing/form_census.rb +121 -20
- data/lib/hecks/fuzzing/generated_domain_check.rb +171 -0
- data/lib/hecks/fuzzing/invalid_value_generator.rb +45 -6
- data/lib/hecks/fuzzing/isolated_boot.rb +137 -80
- data/lib/hecks/fuzzing/nondeterministic.rb +79 -0
- data/lib/hecks/fuzzing/persistence_parity.rb +111 -21
- data/lib/hecks/fuzzing/properties/corrections.rb +34 -9
- data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +300 -51
- data/lib/hecks/fuzzing/properties/guards.rb +86 -42
- data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +80 -32
- data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +40 -35
- data/lib/hecks/fuzzing/properties/outbox.rb +70 -32
- data/lib/hecks/fuzzing/properties/querying.rb +82 -28
- data/lib/hecks/fuzzing/properties.rb +84 -51
- data/lib/hecks/fuzzing/qa_settings.rb +164 -0
- data/lib/hecks/fuzzing/replay.rb +241 -133
- data/lib/hecks/fuzzing/rotation_priority.rb +48 -28
- data/lib/hecks/fuzzing/rust_gap_manifest.rb +139 -0
- data/lib/hecks/fuzzing/self_consistency.rb +315 -137
- data/lib/hecks/fuzzing/sequence_generator/adversary.rb +46 -40
- data/lib/hecks/fuzzing/sequence_generator/catalog.rb +18 -11
- data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +13 -12
- data/lib/hecks/fuzzing/sequence_generator/picker.rb +21 -12
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +59 -32
- data/lib/hecks/fuzzing/sequence_generator.rb +158 -23
- data/lib/hecks/fuzzing/shrinker.rb +309 -0
- data/lib/hecks/fuzzing/structural_skips.rb +37 -130
- data/lib/hecks/fuzzing/sweep_depth.rb +12 -4
- data/lib/hecks/fuzzing/target_capabilities.rb +107 -29
- data/lib/hecks/fuzzing/value_generator.rb +110 -22
- data/lib/hecks/fuzzing.rb +5 -0
- data/lib/hecks/grammar/evolve.rb +188 -12
- data/lib/hecks/grammar.rb +53 -7
- data/lib/hecks/ir.rb +51 -20
- data/lib/hecks/language/bluebook/bluebook.bluebook +41 -0
- data/lib/hecks/language/bluebook/policy.bluebook +11 -1
- data/lib/hecks/language/bluebook/vocabulary.bluebook +348 -13
- data/lib/hecks/language/hecksagon/hecksagon.bluebook +11 -0
- data/lib/hecks/language/oidc.json +5 -0
- data/lib/hecks/literal.rb +41 -9
- data/lib/hecks/naming.rb +112 -31
- data/lib/hecks/ports/access_control.rb +53 -2
- data/lib/hecks/ports/agent/answers.rb +83 -6
- data/lib/hecks/ports/agent.rb +119 -35
- data/lib/hecks/ports/authentication.rb +44 -4
- data/lib/hecks/ports/authorization.rb +50 -11
- data/lib/hecks/ports/clock.rb +42 -23
- data/lib/hecks/ports/extraction.rb +16 -0
- data/lib/hecks/ports/identity_assignment.rb +23 -2
- data/lib/hecks/ports/identity_generation.rb +17 -3
- data/lib/hecks/ports/identity_resolution.rb +17 -1
- data/lib/hecks/ports/key_vault.port +6 -0
- data/lib/hecks/ports/key_vault.rb +58 -0
- data/lib/hecks/ports/loading.rb +4 -0
- data/lib/hecks/ports/persistence/append_only.rb +172 -8
- data/lib/hecks/ports/persistence/binding_policy.rb +34 -0
- data/lib/hecks/ports/persistence/codec_boundary.rb +178 -0
- data/lib/hecks/ports/persistence/execution.rb +4 -0
- data/lib/hecks/ports/persistence/null_saga_store.rb +12 -1
- data/lib/hecks/ports/persistence/plugin.rb +42 -4
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +218 -25
- data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +77 -9
- data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +81 -24
- data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +29 -18
- data/lib/hecks/ports/persistence/plugins/era/lineage.rb +144 -60
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +103 -8
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +98 -23
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +282 -109
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +63 -25
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +118 -66
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +51 -28
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +34 -5
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +25 -12
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +129 -34
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +51 -6
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +33 -9
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +16 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +95 -6
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +25 -2
- data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +314 -90
- data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +68 -10
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +9 -3
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +9 -2
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +48 -8
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +16 -1
- data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +36 -5
- data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +23 -3
- data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +58 -19
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +96 -5
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +15 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +9 -1
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -2
- data/lib/hecks/ports/persistence/plugins/era.rb +12 -2
- data/lib/hecks/ports/persistence/remote_runtime.rb +9 -2
- data/lib/hecks/ports/persistence/repository_factory.rb +23 -3
- data/lib/hecks/ports/persistence/state_codec.rb +319 -0
- data/lib/hecks/ports/persistence.rb +36 -1
- data/lib/hecks/ports/projection.rb +61 -7
- data/lib/hecks/ports/query/in_memory.rb +41 -8
- data/lib/hecks/ports/query/ordering.rb +21 -6
- data/lib/hecks/ports/query.rb +35 -0
- data/lib/hecks/ports.rb +1 -0
- data/lib/hecks/projections/bootstrap_table.rb +147 -0
- data/lib/hecks/projections/diagrams.rb +315 -79
- data/lib/hecks/projections/glossary/html.rb +91 -3
- data/lib/hecks/projections/glossary/markdown.rb +50 -3
- data/lib/hecks/projections/glossary/mermaid.rb +49 -1
- data/lib/hecks/projections/glossary/sections.rb +1 -1
- data/lib/hecks/projections/glossary/sentences.rb +110 -5
- data/lib/hecks/projections/glossary.rb +173 -31
- data/lib/hecks/projections/ir.rb +1 -1
- data/lib/hecks/projections/model/deviations.rb +62 -17
- data/lib/hecks/projections/model.rb +75 -21
- data/lib/hecks/projections/oidc.rb +45 -8
- data/lib/hecks/projections/parser_table.rb +53 -12
- data/lib/hecks/projections/reference.rb +15 -3
- data/lib/hecks/projections/rust_vocabulary.rb +646 -0
- data/lib/hecks/projections/shape.rb +10 -2
- data/lib/hecks/projections/statements.rb +69 -22
- data/lib/hecks/projections/vocabulary.rb +26 -9
- data/lib/hecks/projections.rb +5 -3
- data/lib/hecks/projector/cli_projector.rb +245 -37
- data/lib/hecks/projector/docs_projector.rb +154 -28
- data/lib/hecks/projector/exporter.rb +104 -29
- data/lib/hecks/projector/ir_projector.rb +7 -1
- data/lib/hecks/projector/narrate_projector.rb +144 -23
- data/lib/hecks/projector/target.rb +42 -18
- data/lib/hecks/projector.rb +86 -18
- data/lib/hecks/query_ir.rb +94 -47
- data/lib/hecks/query_specification/common/comparators.rb +19 -3
- data/lib/hecks/query_specification/common/comparison.rb +109 -27
- data/lib/hecks/query_specification/common/dsl.rb +65 -9
- data/lib/hecks/query_specification/common/null_policy.rb +61 -15
- data/lib/hecks/query_specification/common/null_semantics.rb +4 -0
- data/lib/hecks/query_specification/common/options.rb +25 -0
- data/lib/hecks/query_specification/field_path.rb +69 -15
- data/lib/hecks/query_specification/hop_path.rb +57 -20
- data/lib/hecks/query_specification/read_model/specification.rb +4 -0
- data/lib/hecks/rendering.rb +9 -3
- data/lib/hecks/router/namespace_installer.rb +16 -3
- data/lib/hecks/router.rb +56 -1
- data/lib/hecks/runtime/aggregate_lock.rb +20 -11
- data/lib/hecks/runtime/boot_gates.rb +21 -3
- data/lib/hecks/runtime/caller.rb +40 -8
- data/lib/hecks/runtime/capability_graph.rb +13 -2
- data/lib/hecks/runtime/command_interpreter/argument_gate.rb +40 -41
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +45 -67
- data/lib/hecks/runtime/command_interpreter.rb +195 -113
- data/lib/hecks/runtime/command_rules/admissibility.rb +231 -80
- data/lib/hecks/runtime/command_rules/arithmetic.rb +154 -96
- data/lib/hecks/runtime/command_rules/authorization.rb +38 -17
- data/lib/hecks/runtime/command_rules/emission.rb +18 -1
- data/lib/hecks/runtime/command_rules/references.rb +145 -55
- data/lib/hecks/runtime/command_rules.rb +3 -0
- data/lib/hecks/runtime/dependency_planning.rb +56 -11
- data/lib/hecks/runtime/dispatcher.rb +263 -92
- data/lib/hecks/runtime/entity_element.rb +304 -67
- data/lib/hecks/runtime/entity_interpreter.rb +149 -88
- data/lib/hecks/runtime/errors.rb +37 -23
- data/lib/hecks/runtime/event.rb +15 -10
- data/lib/hecks/runtime/identity.rb +91 -23
- data/lib/hecks/runtime/instance.rb +103 -18
- data/lib/hecks/runtime/interpreting.rb +24 -16
- data/lib/hecks/runtime/invocation.rb +358 -0
- data/lib/hecks/runtime/loader.rb +105 -19
- data/lib/hecks/runtime/outbox.rb +164 -26
- data/lib/hecks/runtime/policy_interpreter.rb +73 -60
- data/lib/hecks/runtime/port_operation_interpreter.rb +42 -19
- data/lib/hecks/runtime/query_interpreter.rb +93 -74
- data/lib/hecks/runtime/reaction_invocation.rb +73 -28
- data/lib/hecks/runtime/read_model_interpreter.rb +60 -44
- data/lib/hecks/runtime/rebuild_sweep.rb +32 -4
- data/lib/hecks/runtime/reference_hop.rb +48 -6
- data/lib/hecks/runtime/refusal_wording.rb +142 -115
- data/lib/hecks/runtime/registry/saga_persistence.rb +32 -21
- data/lib/hecks/runtime/registry/verification.rb +153 -28
- data/lib/hecks/runtime/registry.rb +202 -32
- data/lib/hecks/runtime/remote_dispatcher.rb +125 -24
- data/lib/hecks/runtime/routing.rb +36 -154
- data/lib/hecks/runtime/saga_interpreter/correlation.rb +25 -27
- data/lib/hecks/runtime/saga_interpreter.rb +90 -76
- data/lib/hecks/runtime/saga_pending_dispatch.rb +12 -12
- data/lib/hecks/runtime/tenant_check.rb +33 -13
- data/lib/hecks/runtime/tenant_scope.rb +23 -5
- data/lib/hecks/runtime/value/admission.rb +75 -30
- data/lib/hecks/runtime/value/coercion.rb +555 -142
- data/lib/hecks/runtime/value/entity_list_coercion.rb +132 -60
- data/lib/hecks/runtime/value.rb +71 -21
- data/lib/hecks/runtime.rb +39 -7
- data/lib/hecks/storehouse.rb +368 -72
- data/lib/hecks/tenancy/bluebook/tenancy.bluebook +130 -0
- data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +32 -0
- data/lib/hecks/version.rb +3 -3
- data/lib/hecks/vocabulary.rb +205 -4
- data/lib/hecks.rb +91 -11
- data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +19 -11
- data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +24 -12
- data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +38 -14
- metadata +28 -2
|
@@ -3,14 +3,14 @@ require_relative "../../forms/html"
|
|
|
3
3
|
module Hecks
|
|
4
4
|
module Projections
|
|
5
5
|
module Glossary
|
|
6
|
-
#
|
|
6
|
+
# **The page, rendered from the markdown** — `html/index.html` is
|
|
7
7
|
# `glossary.md` read back and dressed: a navigation rail built from
|
|
8
8
|
# its `##` headings, each `###` a term entry, every ```mermaid fence
|
|
9
9
|
# a diagram, every `[x](#y)` an in-page link. Nothing here reads
|
|
10
10
|
# the bluebook; if the page shows it, the Markdown says it, so the
|
|
11
11
|
# two cannot drift.
|
|
12
12
|
#
|
|
13
|
-
# A
|
|
13
|
+
# A subset renderer, not a markdown library — the projector emits
|
|
14
14
|
# a fixed handful of constructs (`Markdown`'s own header lists
|
|
15
15
|
# them), and this reads exactly those. The Gemfile keeps every
|
|
16
16
|
# dependency justified in its own comment; a full Markdown engine
|
|
@@ -30,6 +30,10 @@ module Hecks
|
|
|
30
30
|
|
|
31
31
|
module_function
|
|
32
32
|
|
|
33
|
+
# Renders `glossary.md`'s Markdown source as a self-contained HTML page.
|
|
34
|
+
#
|
|
35
|
+
# @param markdown [String] `glossary.md`'s own rendered Markdown source
|
|
36
|
+
# @return [String] the complete `html/index.html` source
|
|
33
37
|
def render(markdown)
|
|
34
38
|
blocks = parse(markdown)
|
|
35
39
|
slugs = heading_slugs(blocks)
|
|
@@ -40,6 +44,12 @@ module Hecks
|
|
|
40
44
|
|
|
41
45
|
# ── reading the Markdown ─────────────────────────────────────────
|
|
42
46
|
|
|
47
|
+
# Parses the subset of Markdown the glossary projector emits into
|
|
48
|
+
# structured blocks.
|
|
49
|
+
#
|
|
50
|
+
# @param markdown [String] the Markdown source to parse
|
|
51
|
+
# @return [Array<Block>] one block per heading, quote, list, mermaid
|
|
52
|
+
# fence, or paragraph, in document order
|
|
43
53
|
def parse(markdown)
|
|
44
54
|
lines = markdown.lines.map(&:chomp)
|
|
45
55
|
blocks = []
|
|
@@ -70,6 +80,11 @@ module Hecks
|
|
|
70
80
|
|
|
71
81
|
# The mermaid source between the opening fence at `index` and its
|
|
72
82
|
# closing one, and the index just past that.
|
|
83
|
+
#
|
|
84
|
+
# @param lines [Array<String>] the document's lines
|
|
85
|
+
# @param index [Integer] the opening ` ```mermaid ` fence's line index
|
|
86
|
+
# @return [Array(Block, Integer)] the parsed `:mermaid` block, and the line
|
|
87
|
+
# index just past its closing fence
|
|
73
88
|
def fence(lines, index)
|
|
74
89
|
close = ((index + 1)...lines.size).find { |at| lines[at] == "```" } || lines.size
|
|
75
90
|
[Block.new(type: :mermaid, text: lines[(index + 1)...close].join("\n")), close + 1]
|
|
@@ -77,6 +92,13 @@ module Hecks
|
|
|
77
92
|
|
|
78
93
|
# The consecutive lines from `index` that satisfy the block, and
|
|
79
94
|
# the index just past them.
|
|
95
|
+
#
|
|
96
|
+
# @param lines [Array<String>] the document's lines
|
|
97
|
+
# @param index [Integer] the line index to start scanning from
|
|
98
|
+
# @yieldparam text [String] one candidate line
|
|
99
|
+
# @yieldreturn [Boolean] whether that line belongs to the run
|
|
100
|
+
# @return [Array(Array<String>, Integer)] the consecutive matching lines, and
|
|
101
|
+
# the line index just past them
|
|
80
102
|
def run(lines, index)
|
|
81
103
|
taken = []
|
|
82
104
|
while index < lines.size && yield(lines[index])
|
|
@@ -89,10 +111,14 @@ module Hecks
|
|
|
89
111
|
# The same slugs GitHub would give these headings, in the same
|
|
90
112
|
# order — so the links the Markdown carries land here too.
|
|
91
113
|
#
|
|
92
|
-
#
|
|
114
|
+
# Keyed by the block itself, not its value — a Struct compares by
|
|
93
115
|
# members, so two "### Open" headings in different sections would
|
|
94
116
|
# otherwise be one key, and the first would answer with the
|
|
95
117
|
# second's "-1" slug, leaving `#open` with nothing to land on.
|
|
118
|
+
#
|
|
119
|
+
# @param blocks [Array<Block>] every parsed block, in document order
|
|
120
|
+
# @return [Hash{Block => String}] each heading block, mapped to its GitHub-style
|
|
121
|
+
# slug, keyed by object identity
|
|
96
122
|
def heading_slugs(blocks)
|
|
97
123
|
seen = Hash.new(0)
|
|
98
124
|
slugs = {}.compare_by_identity
|
|
@@ -106,6 +132,11 @@ module Hecks
|
|
|
106
132
|
|
|
107
133
|
# Everything before the first `##` is the front matter; each `##`
|
|
108
134
|
# opens a section that runs to the next.
|
|
135
|
+
#
|
|
136
|
+
# @param blocks [Array<Block>] every parsed block, in document order
|
|
137
|
+
# @return [Array<Hash{Symbol => Object}>] one Hash per section: `:heading`
|
|
138
|
+
# (the `Block`, or nil for the leading front matter) and `:blocks` (its
|
|
139
|
+
# own `Array<Block>`)
|
|
109
140
|
def split_sections(blocks)
|
|
110
141
|
sections = [{ heading: nil, blocks: [] }]
|
|
111
142
|
blocks.each do |block|
|
|
@@ -117,6 +148,13 @@ module Hecks
|
|
|
117
148
|
|
|
118
149
|
# ── writing the page ─────────────────────────────────────────────
|
|
119
150
|
|
|
151
|
+
# Renders the full HTML page shell around the navigation rail and content.
|
|
152
|
+
#
|
|
153
|
+
# @param title [String] the document's `#` heading text
|
|
154
|
+
# @param sections [Array<Hash{Symbol => Object}>] every `##` section, as
|
|
155
|
+
# `split_sections` builds (the front matter excluded by the caller)
|
|
156
|
+
# @param slugs [Hash{Block => String}] every heading block's own slug
|
|
157
|
+
# @return [String] the complete HTML page source
|
|
120
158
|
def page(title, sections, slugs)
|
|
121
159
|
front, *rest = sections
|
|
122
160
|
<<~HTML
|
|
@@ -148,6 +186,14 @@ module Hecks
|
|
|
148
186
|
HTML
|
|
149
187
|
end
|
|
150
188
|
|
|
189
|
+
# Renders the navigation rail: the domain name, a search box, and one
|
|
190
|
+
# link per section.
|
|
191
|
+
#
|
|
192
|
+
# @param title [String] the document's `#` heading text, `"Domain — Glossary"`
|
|
193
|
+
# @param sections [Array<Hash{Symbol => Object}>] every `##` section (the
|
|
194
|
+
# front matter excluded)
|
|
195
|
+
# @param slugs [Hash{Block => String}] every heading block's own slug
|
|
196
|
+
# @return [String] the rail's HTML source
|
|
151
197
|
def rail(title, sections, slugs)
|
|
152
198
|
domain = title.split(" — ").first
|
|
153
199
|
items = sections.map do |section|
|
|
@@ -167,6 +213,10 @@ module Hecks
|
|
|
167
213
|
HTML
|
|
168
214
|
end
|
|
169
215
|
|
|
216
|
+
# Renders the page's `<header>`: the title, vision, lede, and overview diagram.
|
|
217
|
+
#
|
|
218
|
+
# @param blocks [Array<Block>] the front matter's own blocks
|
|
219
|
+
# @return [String] the header's HTML source
|
|
170
220
|
def front_matter(blocks)
|
|
171
221
|
parts = ["<header>"]
|
|
172
222
|
blocks.each do |block|
|
|
@@ -185,6 +235,11 @@ module Hecks
|
|
|
185
235
|
# rules list), then its terms — each `###` opens an article that
|
|
186
236
|
# runs to the next. A bold-only paragraph is the caption of
|
|
187
237
|
# whatever figure or list follows it.
|
|
238
|
+
#
|
|
239
|
+
# @param section [Hash{Symbol => Object}] one `##` section, as `split_sections`
|
|
240
|
+
# builds
|
|
241
|
+
# @param slugs [Hash{Block => String}] every heading block's own slug
|
|
242
|
+
# @return [String] the section's `<section>` HTML source
|
|
188
243
|
def section_html(section, slugs)
|
|
189
244
|
heading = section[:heading]
|
|
190
245
|
state = { parts: [%(<section id="#{slugs[heading]}">), "<h2>#{inline(heading.text)}</h2>"],
|
|
@@ -195,6 +250,15 @@ module Hecks
|
|
|
195
250
|
state[:parts].join("\n")
|
|
196
251
|
end
|
|
197
252
|
|
|
253
|
+
# Renders one block into `state[:parts]`, mutating `state` as it goes.
|
|
254
|
+
#
|
|
255
|
+
# @param block [Block] the block to render
|
|
256
|
+
# @param state [Hash{Symbol => Object}] the section's own render state:
|
|
257
|
+
# `:parts` (the growing `Array<String>` of HTML), `:caption` (a pending
|
|
258
|
+
# bold-only paragraph's text, or nil), `:in_terms` (whether a `###` term
|
|
259
|
+
# article is currently open)
|
|
260
|
+
# @param slugs [Hash{Block => String}] every heading block's own slug
|
|
261
|
+
# @return [void]
|
|
198
262
|
def section_block(block, state, slugs)
|
|
199
263
|
parts = state[:parts]
|
|
200
264
|
case block.type
|
|
@@ -214,6 +278,13 @@ module Hecks
|
|
|
214
278
|
end
|
|
215
279
|
end
|
|
216
280
|
|
|
281
|
+
# Renders one paragraph, either capturing it as a pending caption (a
|
|
282
|
+
# bold-only line) or appending it to `state[:parts]`.
|
|
283
|
+
#
|
|
284
|
+
# @param text [String] the paragraph's own text
|
|
285
|
+
# @param state [Hash{Symbol => Object}] the section's own render state (see
|
|
286
|
+
# `section_block`); `:caption` and `:parts` may be mutated
|
|
287
|
+
# @return [void]
|
|
217
288
|
def paragraph(text, state)
|
|
218
289
|
if text.match?(/\A\*\*[^*]+\*\*\z/)
|
|
219
290
|
state[:caption] = text.delete("*")
|
|
@@ -223,6 +294,11 @@ module Hecks
|
|
|
223
294
|
end
|
|
224
295
|
end
|
|
225
296
|
|
|
297
|
+
# Renders a mermaid block as a `<figure>`, with an optional caption.
|
|
298
|
+
#
|
|
299
|
+
# @param block [Block] the `:mermaid` block to render
|
|
300
|
+
# @param caption [String, nil] the figure's caption text, or nil for none
|
|
301
|
+
# @return [String] the `<figure>`'s HTML source
|
|
226
302
|
def figure(block, caption)
|
|
227
303
|
parts = ["<figure>"]
|
|
228
304
|
parts << "<figcaption>#{escape(caption)}</figcaption>" if caption
|
|
@@ -232,10 +308,18 @@ module Hecks
|
|
|
232
308
|
|
|
233
309
|
# ── inline text ──────────────────────────────────────────────────
|
|
234
310
|
|
|
311
|
+
# Escapes text for HTML.
|
|
312
|
+
#
|
|
313
|
+
# @param text [Object, nil] the value to escape, rendered with `to_s`
|
|
314
|
+
# @return [String] `text`, HTML-escaped
|
|
235
315
|
def escape(text) = Forms::Escape.html(text)
|
|
236
316
|
|
|
237
317
|
# Escape first, so nothing in the prose ever becomes a tag; then
|
|
238
318
|
# the three inline forms the Markdown uses, on the escaped text.
|
|
319
|
+
#
|
|
320
|
+
# @param text [String] the inline text to render
|
|
321
|
+
# @return [String] `text`, HTML-escaped, with `[x](#y)` links, `**bold**` and
|
|
322
|
+
# `*italic*` spans converted to their HTML equivalents
|
|
239
323
|
def inline(text)
|
|
240
324
|
escape(text)
|
|
241
325
|
.gsub(/\[([^\]]+)\]\(#([^)]+)\)/) { %(<a href="##{Regexp.last_match(2)}">#{Regexp.last_match(1)}</a>) }
|
|
@@ -243,6 +327,10 @@ module Hecks
|
|
|
243
327
|
.gsub(/\*(.+?)\*/) { "<em>#{Regexp.last_match(1)}</em>" }
|
|
244
328
|
end
|
|
245
329
|
|
|
330
|
+
# Reads one static asset file from beside this file.
|
|
331
|
+
#
|
|
332
|
+
# @param name [String] the asset's filename, such as `"page.css"`
|
|
333
|
+
# @return [String] the asset file's contents, read from beside this file
|
|
246
334
|
def asset(name) = File.read(File.join(__dir__, name))
|
|
247
335
|
end
|
|
248
336
|
end
|
|
@@ -6,7 +6,7 @@ require_relative "../statements"
|
|
|
6
6
|
module Hecks
|
|
7
7
|
module Projections
|
|
8
8
|
module Glossary
|
|
9
|
-
#
|
|
9
|
+
# **The document itself** — `glossary.md`, the one source the page is
|
|
10
10
|
# rendered from. Written in the handful of Markdown constructs
|
|
11
11
|
# GitHub renders as-is (headings, blockquotes, ```mermaid fences,
|
|
12
12
|
# lists, in-page links), so the file is a complete, readable
|
|
@@ -39,14 +39,27 @@ module Hecks
|
|
|
39
39
|
|
|
40
40
|
module_function
|
|
41
41
|
|
|
42
|
+
# Titles the document after its chapter.
|
|
43
|
+
#
|
|
44
|
+
# @param bluebook [Bluebook::Behaviour::Chapter] the chapter to title after
|
|
45
|
+
# @return [String] the document's `#` heading text
|
|
42
46
|
def title(bluebook) = "#{bluebook.name} — Glossary"
|
|
43
47
|
|
|
48
|
+
# Renders the full `glossary.md` document.
|
|
49
|
+
#
|
|
50
|
+
# @param document [Glossary::Document] the assembled document to render
|
|
51
|
+
# @return [String] the complete Markdown source, ending in a newline
|
|
44
52
|
def render(document)
|
|
45
53
|
parts = [header(document.bluebook)]
|
|
46
54
|
parts += document.sections.map { |section| section_text(section, document) }
|
|
47
55
|
"#{parts.join("\n\n")}\n"
|
|
48
56
|
end
|
|
49
57
|
|
|
58
|
+
# Renders the document's title, vision blockquote, lede, and overview map.
|
|
59
|
+
#
|
|
60
|
+
# @param bluebook [Bluebook::Behaviour::Chapter] the chapter to render a
|
|
61
|
+
# header for
|
|
62
|
+
# @return [String] the header's Markdown source
|
|
50
63
|
def header(bluebook)
|
|
51
64
|
parts = ["# #{title(bluebook)}"]
|
|
52
65
|
parts << "> #{bluebook.vision}" if bluebook.vision
|
|
@@ -55,6 +68,13 @@ module Hecks
|
|
|
55
68
|
parts.join("\n\n")
|
|
56
69
|
end
|
|
57
70
|
|
|
71
|
+
# Renders one `##` section: its opening (an aggregate's, or a standing
|
|
72
|
+
# group's blurb), followed by every term inside it.
|
|
73
|
+
#
|
|
74
|
+
# @param section [Glossary::Section] the section to render
|
|
75
|
+
# @param document [Glossary::Document] the document `section` belongs to,
|
|
76
|
+
# for its bluebook and link index
|
|
77
|
+
# @return [String] the section's Markdown source
|
|
58
78
|
def section_text(section, document)
|
|
59
79
|
parts = ["## #{section.title}"]
|
|
60
80
|
parts += section.aggregate ? opening(section.aggregate, document.bluebook) : ["> #{STANDING[section.name]}"]
|
|
@@ -62,8 +82,14 @@ module Hecks
|
|
|
62
82
|
parts.join("\n\n")
|
|
63
83
|
end
|
|
64
84
|
|
|
65
|
-
# What an aggregate
|
|
85
|
+
# What an aggregate is, what it can be, how it fits and moves,
|
|
66
86
|
# and what is always true of it — before a single term.
|
|
87
|
+
#
|
|
88
|
+
# @param aggregate [Bluebook::Aggregate] the aggregate to render an opening for
|
|
89
|
+
# @param bluebook [Bluebook::Behaviour::Chapter] the chapter `aggregate` belongs
|
|
90
|
+
# to, for drawing its context diagram
|
|
91
|
+
# @return [Array<String>] the opening's Markdown blocks, one per paragraph or
|
|
92
|
+
# diagram, not yet joined
|
|
67
93
|
def opening(aggregate, bluebook)
|
|
68
94
|
parts = []
|
|
69
95
|
parts << "> #{aggregate.description}" if aggregate.description
|
|
@@ -75,13 +101,19 @@ module Hecks
|
|
|
75
101
|
parts
|
|
76
102
|
end
|
|
77
103
|
|
|
78
|
-
#
|
|
104
|
+
# The statements projection's own sentences, spoken. An invariant
|
|
79
105
|
# is the author's words and stays exactly so. A relationship
|
|
80
106
|
# sentence is built mechanically from construct names ("An
|
|
81
107
|
# ATMCard references an Account."), and a construct name is the
|
|
82
108
|
# one thing this page never shows as an identifier — so each is
|
|
83
109
|
# replaced with how it is said, whole-word, and nothing else in
|
|
84
110
|
# the sentence is touched.
|
|
111
|
+
#
|
|
112
|
+
# @param aggregate [Bluebook::Aggregate] the aggregate to gather rules for
|
|
113
|
+
# @param bluebook [Bluebook::Behaviour::Chapter] the chapter to read every
|
|
114
|
+
# construct name from, for de-identifying relationship sentences
|
|
115
|
+
# @return [Array<String>] `aggregate`'s (and its entities') attribute and
|
|
116
|
+
# invariant statements, spoken and deduplicated
|
|
85
117
|
def always_true(aggregate, bluebook)
|
|
86
118
|
names = bluebook.aggregates.flat_map { |other| [other.hecks_name, *other.entities.map(&:hecks_name)] }
|
|
87
119
|
[aggregate, *aggregate.entities].flat_map do |holder|
|
|
@@ -90,14 +122,29 @@ module Hecks
|
|
|
90
122
|
end.uniq
|
|
91
123
|
end
|
|
92
124
|
|
|
125
|
+
# Replaces every whole-word construct name in `sentence` with how it is said.
|
|
126
|
+
#
|
|
127
|
+
# @param sentence [String] the sentence to de-identify
|
|
128
|
+
# @param names [Array<String>] every construct name to replace, whole-word
|
|
129
|
+
# @return [String] `sentence` with each name in `names` replaced by
|
|
130
|
+
# `Naming.words(name)`
|
|
93
131
|
def spoken(sentence, names)
|
|
94
132
|
names.reduce(sentence) { |text, name| text.gsub(/\b#{Regexp.escape(name)}\b/, Naming.words(name)) }
|
|
95
133
|
end
|
|
96
134
|
|
|
135
|
+
# Renders one term's `###` heading and its paragraphs.
|
|
136
|
+
#
|
|
137
|
+
# @param entry [Glossary::Entry] the term to render
|
|
138
|
+
# @param index [Glossary::Index] the document's link index
|
|
139
|
+
# @return [String] the term's Markdown source
|
|
97
140
|
def term_text(entry, index)
|
|
98
141
|
["### #{entry.headword}", *Sentences.paragraphs(entry, index)].join("\n\n")
|
|
99
142
|
end
|
|
100
143
|
|
|
144
|
+
# Wraps a Mermaid diagram's source in a fenced code block.
|
|
145
|
+
#
|
|
146
|
+
# @param source [String] a Mermaid diagram's own source
|
|
147
|
+
# @return [String] `source` wrapped in a ` ```mermaid ` fence
|
|
101
148
|
def fence(source) = "```mermaid\n#{source}\n```"
|
|
102
149
|
end
|
|
103
150
|
end
|
|
@@ -3,7 +3,7 @@ require_relative "../../naming"
|
|
|
3
3
|
module Hecks
|
|
4
4
|
module Projections
|
|
5
5
|
module Glossary
|
|
6
|
-
#
|
|
6
|
+
# The three pictures the glossary draws, each kept to the handful of
|
|
7
7
|
# things that matter — Evans' "three to five objects central to the
|
|
8
8
|
# issue at hand", never the whole model at once.
|
|
9
9
|
#
|
|
@@ -25,6 +25,10 @@ module Hecks
|
|
|
25
25
|
module Mermaid
|
|
26
26
|
module_function
|
|
27
27
|
|
|
28
|
+
# Draws the whole chapter's aggregates and which points at which.
|
|
29
|
+
#
|
|
30
|
+
# @param bluebook [Bluebook::Behaviour::Chapter] the chapter to draw
|
|
31
|
+
# @return [String] a Mermaid `flowchart LR` source
|
|
28
32
|
def map(bluebook)
|
|
29
33
|
names = bluebook.aggregates.map(&:hecks_name)
|
|
30
34
|
lines = ["flowchart LR"]
|
|
@@ -39,6 +43,12 @@ module Hecks
|
|
|
39
43
|
lines.join("\n")
|
|
40
44
|
end
|
|
41
45
|
|
|
46
|
+
# Draws one aggregate, its entities, and its neighbours.
|
|
47
|
+
#
|
|
48
|
+
# @param aggregate [Bluebook::Aggregate] the aggregate to focus on
|
|
49
|
+
# @param bluebook [Bluebook::Behaviour::Chapter] the chapter to find
|
|
50
|
+
# neighbouring aggregates in
|
|
51
|
+
# @return [String] a Mermaid `flowchart LR` source
|
|
42
52
|
def context(aggregate, bluebook)
|
|
43
53
|
focus = aggregate.hecks_name
|
|
44
54
|
lines = ["flowchart LR", node(focus, focus: true)]
|
|
@@ -58,6 +68,11 @@ module Hecks
|
|
|
58
68
|
lines.uniq.join("\n")
|
|
59
69
|
end
|
|
60
70
|
|
|
71
|
+
# Draws the states a holder can be in and what moves it between them.
|
|
72
|
+
#
|
|
73
|
+
# @param holder [Bluebook::Aggregate, Bluebook::Entity] the holder whose
|
|
74
|
+
# lifecycle to draw
|
|
75
|
+
# @return [String] a Mermaid `stateDiagram-v2` source
|
|
61
76
|
def lifecycle(holder)
|
|
62
77
|
lifecycle = holder.lifecycle
|
|
63
78
|
lines = ["stateDiagram-v2"]
|
|
@@ -74,15 +89,33 @@ module Hecks
|
|
|
74
89
|
|
|
75
90
|
# ── the facts drawn ──────────────────────────────────────────────
|
|
76
91
|
|
|
92
|
+
# Names a holder's own reference attributes.
|
|
93
|
+
#
|
|
94
|
+
# @param holder [Bluebook::Aggregate, Bluebook::Entity] the holder to
|
|
95
|
+
# read reference attributes from
|
|
96
|
+
# @return [Array<Bluebook::Attribute>] `holder`'s own reference attributes
|
|
77
97
|
def references(holder) = holder.attributes.select(&:reference?)
|
|
78
98
|
|
|
79
99
|
# An entity is held as `list_of(LedgerEntry)` — the attribute
|
|
80
100
|
# whose element type names one of the aggregate's own entities.
|
|
101
|
+
#
|
|
102
|
+
# @param aggregate [Bluebook::Aggregate] the aggregate to read entity
|
|
103
|
+
# attributes from
|
|
104
|
+
# @return [Array<Bluebook::Attribute>] attributes whose element type is one
|
|
105
|
+
# of `aggregate`'s own entities
|
|
81
106
|
def entities(aggregate)
|
|
82
107
|
names = aggregate.entities.map(&:hecks_name)
|
|
83
108
|
aggregate.attributes.select { |attribute| !attribute.reference? && names.include?(attribute.type.to_s) }
|
|
84
109
|
end
|
|
85
110
|
|
|
111
|
+
# Finds every other aggregate that references `aggregate`.
|
|
112
|
+
#
|
|
113
|
+
# @param aggregate [Bluebook::Aggregate] the aggregate to find pointers to
|
|
114
|
+
# @param bluebook [Bluebook::Behaviour::Chapter] the chapter to search other
|
|
115
|
+
# aggregates in
|
|
116
|
+
# @return [Array<Array(Bluebook::Aggregate, Bluebook::Attribute)>] every other
|
|
117
|
+
# aggregate's own reference attribute that targets `aggregate`, paired
|
|
118
|
+
# with its holder
|
|
86
119
|
def pointing_at(aggregate, bluebook)
|
|
87
120
|
bluebook.aggregates.reject { |other| other.equal?(aggregate) }.flat_map do |other|
|
|
88
121
|
references(other).select { |attribute| attribute.type.target_name == aggregate.hecks_name }
|
|
@@ -94,13 +127,28 @@ module Hecks
|
|
|
94
127
|
|
|
95
128
|
# A node id the page source can carry without an identifier in
|
|
96
129
|
# it — `n_atm_card`, never `n_ATMCard`.
|
|
130
|
+
#
|
|
131
|
+
# @param name [String, Symbol] the construct name to derive an id from
|
|
132
|
+
# @return [String] a Mermaid-safe node id, such as `"n_atm_card"`
|
|
97
133
|
def id(name) = "n_#{Naming.snake(name).gsub(/[^a-z0-9_]/, '_')}"
|
|
98
134
|
|
|
135
|
+
# Renders one Mermaid node declaration.
|
|
136
|
+
#
|
|
137
|
+
# @param name [String, Symbol] the node's construct name
|
|
138
|
+
# @param focus [Boolean] whether to mark this node with the `focus` CSS class
|
|
139
|
+
# @return [String] a Mermaid node declaration line
|
|
99
140
|
def node(name, focus: false)
|
|
100
141
|
line = " #{id(name)}[\"#{Naming.words(name)}\"]"
|
|
101
142
|
focus ? "#{line}:::focus" : line
|
|
102
143
|
end
|
|
103
144
|
|
|
145
|
+
# Renders one Mermaid edge declaration.
|
|
146
|
+
#
|
|
147
|
+
# @param from [String, Symbol] the source node's construct name
|
|
148
|
+
# @param attribute [Bluebook::Attribute] the attribute the edge is labelled after
|
|
149
|
+
# @param to [String, Symbol] the target node's construct name
|
|
150
|
+
# @return [String] a Mermaid edge declaration line, labelled with the
|
|
151
|
+
# attribute's spoken name
|
|
104
152
|
def edge(from, attribute, to)
|
|
105
153
|
" #{id(from)} -->|\"#{Naming.words(attribute.name).downcase}\"| #{id(to)}"
|
|
106
154
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module Hecks
|
|
2
2
|
module Projections
|
|
3
3
|
module Glossary
|
|
4
|
-
#
|
|
4
|
+
# The three sections nothing homes to one aggregate. In their own
|
|
5
5
|
# file because `Markdown` reads them and loads before the
|
|
6
6
|
# projector's own body does.
|
|
7
7
|
ROLES = "Roles".freeze
|