hecks 1.4.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 +65 -0
- data/lib/hecks/adapters/driven/folder.rb +73 -0
- data/lib/hecks/adapters/driven/google_authentication.rb +25 -4
- data/lib/hecks/adapters/driven/governance_authorization.rb +57 -6
- data/lib/hecks/adapters/driven/heki/journal.rb +8 -0
- data/lib/hecks/adapters/driven/heki/saga_store.rb +53 -7
- data/lib/hecks/adapters/driven/heki/snapshot.rb +1 -1
- data/lib/hecks/adapters/driven/heki.rb +93 -2
- data/lib/hecks/adapters/driven/identity_registry.rb +10 -0
- data/lib/hecks/adapters/driven/in_memory_ordering.rb +22 -0
- 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 +35 -7
- data/lib/hecks/adapters/driven/lambda.rb +43 -2
- data/lib/hecks/adapters/driven/local_storage.rb +67 -1
- data/lib/hecks/adapters/driven/memory.rb +13 -13
- data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +20 -0
- data/lib/hecks/adapters/driven/prism.rb +46 -7
- data/lib/hecks/adapters/driven/secure_random_identity.rb +3 -0
- 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 +2 -0
- data/lib/hecks/adapters/driving/github_webhook.rb +14 -1
- data/lib/hecks/behaviors/dsl.rb +58 -0
- data/lib/hecks/behaviors/expectations.rb +168 -7
- data/lib/hecks/behaviors/ir.rb +11 -0
- data/lib/hecks/behaviors/rspec.rb +8 -0
- data/lib/hecks/behaviors/runner.rb +19 -0
- data/lib/hecks/behaviors.rb +8 -0
- data/lib/hecks/bluebook/aggregate.rb +30 -0
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +7 -0
- data/lib/hecks/bluebook/assembly/build.rb +25 -4
- data/lib/hecks/bluebook/assembly/contract.rb +66 -14
- data/lib/hecks/bluebook/assembly/contracts.rb +24 -19
- data/lib/hecks/bluebook/assembly/marks.rb +143 -14
- data/lib/hecks/bluebook/assembly/specializer.rb +19 -0
- data/lib/hecks/bluebook/assembly.rb +25 -7
- data/lib/hecks/bluebook/attribute.rb +17 -3
- data/lib/hecks/bluebook/behaviour/aggregate.rb +32 -0
- data/lib/hecks/bluebook/behaviour/attribute.rb +13 -0
- data/lib/hecks/bluebook/behaviour/chapter.rb +55 -2
- data/lib/hecks/bluebook/behaviour/command.rb +33 -3
- data/lib/hecks/bluebook/behaviour/domain_port.rb +20 -0
- data/lib/hecks/bluebook/behaviour/entity.rb +12 -0
- data/lib/hecks/bluebook/behaviour/hexagon.rb +26 -0
- data/lib/hecks/bluebook/behaviour/lifecycle.rb +23 -2
- data/lib/hecks/bluebook/behaviour/policy.rb +34 -9
- data/lib/hecks/bluebook/behaviour/process_manager.rb +32 -1
- data/lib/hecks/bluebook/behaviour/query.rb +5 -0
- data/lib/hecks/bluebook/behaviour/read_model.rb +21 -0
- data/lib/hecks/bluebook/behaviour/traits.rb +36 -0
- data/lib/hecks/bluebook/behaviour/value_object.rb +17 -5
- data/lib/hecks/bluebook/chapter.rb +23 -0
- data/lib/hecks/bluebook/command.rb +53 -8
- data/lib/hecks/bluebook/domain_port.rb +25 -0
- data/lib/hecks/bluebook/dsl/aggregate_builder.rb +196 -37
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +79 -42
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +59 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +385 -53
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +135 -21
- data/lib/hecks/bluebook/dsl/command_builder.rb +189 -27
- data/lib/hecks/bluebook/dsl/entity_builder.rb +139 -9
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +41 -0
- data/lib/hecks/bluebook/dsl/identity_declaration.rb +23 -6
- data/lib/hecks/bluebook/dsl/policy_builder.rb +60 -19
- data/lib/hecks/bluebook/dsl/process_manager_builder.rb +79 -15
- data/lib/hecks/bluebook/dsl/query_builder.rb +33 -4
- data/lib/hecks/bluebook/dsl/read_model_builder.rb +102 -27
- data/lib/hecks/bluebook/dsl/rule_reference.rb +60 -8
- data/lib/hecks/bluebook/dsl/translation_builder.rb +146 -40
- data/lib/hecks/bluebook/dsl/value_object_builder.rb +55 -7
- data/lib/hecks/bluebook/entity.rb +29 -0
- data/lib/hecks/bluebook/expression/ast_json.rb +115 -23
- data/lib/hecks/bluebook/expression/ast_reader.rb +29 -0
- data/lib/hecks/bluebook/expression/canonical_form.rb +48 -9
- data/lib/hecks/bluebook/expression/evaluator.rb +207 -29
- data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +36 -0
- data/lib/hecks/bluebook/expression/resolver.rb +320 -77
- data/lib/hecks/bluebook/hexagon.rb +34 -0
- data/lib/hecks/bluebook/lifecycle.rb +11 -0
- data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -0
- data/lib/hecks/bluebook/meta_validator/judge.rb +30 -26
- data/lib/hecks/bluebook/meta_validator/plan.rb +43 -8
- data/lib/hecks/bluebook/meta_validator/port_judge.rb +1 -0
- data/lib/hecks/bluebook/meta_validator/readings.rb +157 -7
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +24 -4
- data/lib/hecks/bluebook/meta_validator/shapes.rb +141 -0
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +149 -23
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +5 -4
- data/lib/hecks/bluebook/meta_validator/world_judge.rb +1 -0
- data/lib/hecks/bluebook/meta_validator.rb +180 -84
- data/lib/hecks/bluebook/model_check.rb +268 -24
- data/lib/hecks/bluebook/pattern_subset.rb +23 -1
- data/lib/hecks/bluebook/process_manager.rb +13 -0
- 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 +44 -0
- data/lib/hecks/bluebook/query.rb +27 -0
- data/lib/hecks/bluebook/read_model.rb +21 -1
- data/lib/hecks/bluebook/reference.rb +21 -8
- data/lib/hecks/bluebook/smoke_test.rb +29 -6
- data/lib/hecks/bluebook/synthesizer.rb +34 -0
- data/lib/hecks/bluebook/translation.rb +30 -1
- data/lib/hecks/bluebook/value_object.rb +23 -5
- data/lib/hecks/bluebook.rb +3 -4
- data/lib/hecks/codemod.rb +107 -20
- data/lib/hecks/construct.rb +15 -1
- data/lib/hecks/corpus.rb +146 -25
- data/lib/hecks/deploy/bluebook/deploy.hecksagon +19 -0
- data/lib/hecks/doc/reference.rb +185 -16
- data/lib/hecks/embryonaut_bluebook.rb +32 -9
- data/lib/hecks/facade/handle.rb +76 -3
- data/lib/hecks/facade/surface/aggregate_door.rb +8 -0
- data/lib/hecks/forms/field_shape.rb +3 -0
- data/lib/hecks/forms/page.rb +14 -0
- data/lib/hecks/forms/port_argument.rb +12 -0
- data/lib/hecks/forms/query_form_renderer.rb +63 -0
- data/lib/hecks/forms/record_renderer.rb +58 -0
- data/lib/hecks/forms/record_table.rb +27 -0
- data/lib/hecks/forms/reference_options.rb +24 -0
- data/lib/hecks/forms/value_object_shape.rb +10 -0
- data/lib/hecks/fqn.rb +58 -0
- data/lib/hecks/framework/bluebook/privacy.bluebook +155 -0
- data/lib/hecks/framework/oidc.json +15 -0
- data/lib/hecks/framework.rb +43 -20
- data/lib/hecks/freezer.rb +17 -1
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +159 -24
- data/lib/hecks/fuzzing/combination_miner.rb +59 -0
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +109 -8
- data/lib/hecks/fuzzing/coverage_campaign.rb +56 -13
- data/lib/hecks/fuzzing/differential.rb +34 -0
- data/lib/hecks/fuzzing/domain_generator.rb +188 -11
- data/lib/hecks/fuzzing/era_boundary.rb +45 -15
- data/lib/hecks/fuzzing/form_census.rb +86 -0
- data/lib/hecks/fuzzing/generated_domain_check.rb +76 -0
- data/lib/hecks/fuzzing/invalid_value_generator.rb +39 -0
- data/lib/hecks/fuzzing/isolated_boot.rb +79 -22
- data/lib/hecks/fuzzing/nondeterministic.rb +13 -1
- data/lib/hecks/fuzzing/persistence_parity.rb +95 -3
- data/lib/hecks/fuzzing/properties/corrections.rb +25 -0
- data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +158 -14
- data/lib/hecks/fuzzing/properties/guards.rb +44 -0
- data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +48 -0
- data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +18 -0
- data/lib/hecks/fuzzing/properties/outbox.rb +49 -11
- data/lib/hecks/fuzzing/properties/querying.rb +68 -14
- data/lib/hecks/fuzzing/properties.rb +24 -15
- data/lib/hecks/fuzzing/qa_settings.rb +12 -0
- data/lib/hecks/fuzzing/replay.rb +137 -29
- data/lib/hecks/fuzzing/rotation_priority.rb +41 -21
- data/lib/hecks/fuzzing/rust_gap_manifest.rb +46 -20
- data/lib/hecks/fuzzing/self_consistency.rb +189 -40
- data/lib/hecks/fuzzing/sequence_generator/adversary.rb +12 -6
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +1 -1
- data/lib/hecks/fuzzing/sequence_generator.rb +47 -0
- data/lib/hecks/fuzzing/shrinker.rb +114 -2
- data/lib/hecks/fuzzing/structural_skips.rb +18 -4
- data/lib/hecks/fuzzing/sweep_depth.rb +8 -0
- data/lib/hecks/fuzzing/target_capabilities.rb +61 -14
- data/lib/hecks/fuzzing/value_generator.rb +98 -10
- data/lib/hecks/grammar/evolve.rb +178 -2
- data/lib/hecks/grammar.rb +46 -0
- data/lib/hecks/ir.rb +38 -7
- data/lib/hecks/language/hecksagon/hecksagon.bluebook +11 -0
- data/lib/hecks/literal.rb +32 -0
- data/lib/hecks/naming.rb +88 -7
- data/lib/hecks/ports/access_control.rb +5 -10
- data/lib/hecks/ports/authorization.rb +3 -6
- data/lib/hecks/ports/identity_assignment.rb +1 -2
- data/lib/hecks/ports/identity_resolution.rb +1 -2
- data/lib/hecks/ports/key_vault.port +6 -0
- data/lib/hecks/ports/key_vault.rb +58 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +6 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +38 -2
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +6 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +40 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +92 -1
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +15 -0
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +8 -0
- data/lib/hecks/ports/query/in_memory.rb +39 -6
- data/lib/hecks/ports/query/ordering.rb +15 -0
- data/lib/hecks/ports.rb +1 -0
- data/lib/hecks/projections/bootstrap_table.rb +43 -8
- data/lib/hecks/projections/diagrams.rb +243 -7
- data/lib/hecks/projections/glossary/html.rb +88 -0
- data/lib/hecks/projections/glossary/markdown.rb +47 -0
- data/lib/hecks/projections/glossary/mermaid.rb +48 -0
- data/lib/hecks/projections/glossary/sentences.rb +105 -0
- data/lib/hecks/projections/glossary.rb +161 -19
- data/lib/hecks/projections/model/deviations.rb +44 -0
- data/lib/hecks/projections/model.rb +51 -1
- data/lib/hecks/projections/oidc.rb +40 -3
- data/lib/hecks/projections/parser_table.rb +49 -8
- data/lib/hecks/projections/reference.rb +12 -0
- data/lib/hecks/projections/rust_vocabulary.rb +219 -16
- data/lib/hecks/projections/shape.rb +8 -0
- data/lib/hecks/projections/statements.rb +63 -16
- data/lib/hecks/projections/vocabulary.rb +17 -0
- data/lib/hecks/projector/cli_projector.rb +218 -10
- data/lib/hecks/projector/docs_projector.rb +145 -19
- data/lib/hecks/projector/exporter.rb +65 -11
- data/lib/hecks/projector/ir_projector.rb +6 -0
- data/lib/hecks/projector/narrate_projector.rb +136 -15
- data/lib/hecks/projector/target.rb +29 -5
- data/lib/hecks/projector.rb +74 -6
- data/lib/hecks/query_ir.rb +47 -0
- data/lib/hecks/query_specification/common/null_policy.rb +5 -3
- data/lib/hecks/rendering.rb +6 -0
- data/lib/hecks/router/namespace_installer.rb +13 -0
- data/lib/hecks/router.rb +55 -0
- data/lib/hecks/runtime/aggregate_lock.rb +9 -0
- data/lib/hecks/runtime/boot_gates.rb +18 -0
- data/lib/hecks/runtime/caller.rb +32 -0
- data/lib/hecks/runtime/capability_graph.rb +11 -0
- data/lib/hecks/runtime/command_interpreter/argument_gate.rb +23 -21
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +14 -15
- data/lib/hecks/runtime/command_interpreter.rb +42 -17
- data/lib/hecks/runtime/command_rules/admissibility.rb +165 -14
- data/lib/hecks/runtime/command_rules/arithmetic.rb +17 -5
- data/lib/hecks/runtime/command_rules/references.rb +118 -28
- data/lib/hecks/runtime/dependency_planning.rb +45 -0
- data/lib/hecks/runtime/dispatcher.rb +28 -50
- data/lib/hecks/runtime/entity_element.rb +161 -8
- data/lib/hecks/runtime/entity_interpreter.rb +44 -9
- data/lib/hecks/runtime/errors.rb +18 -4
- data/lib/hecks/runtime/event.rb +10 -5
- data/lib/hecks/runtime/identity.rb +71 -3
- data/lib/hecks/runtime/instance.rb +67 -7
- data/lib/hecks/runtime/interpreting.rb +13 -5
- data/lib/hecks/runtime/invocation.rb +118 -36
- data/lib/hecks/runtime/loader.rb +94 -8
- data/lib/hecks/runtime/outbox.rb +145 -7
- data/lib/hecks/runtime/policy_interpreter.rb +22 -9
- data/lib/hecks/runtime/port_operation_interpreter.rb +20 -0
- data/lib/hecks/runtime/query_interpreter.rb +40 -12
- data/lib/hecks/runtime/reaction_invocation.rb +53 -8
- data/lib/hecks/runtime/read_model_interpreter.rb +23 -7
- data/lib/hecks/runtime/rebuild_sweep.rb +28 -0
- data/lib/hecks/runtime/reference_hop.rb +42 -0
- data/lib/hecks/runtime/refusal_wording.rb +50 -0
- data/lib/hecks/runtime/registry/saga_persistence.rb +11 -0
- data/lib/hecks/runtime/registry/verification.rb +119 -4
- data/lib/hecks/runtime/registry.rb +157 -4
- data/lib/hecks/runtime/remote_dispatcher.rb +92 -6
- data/lib/hecks/runtime/routing.rb +27 -2
- data/lib/hecks/runtime/saga_interpreter/correlation.rb +10 -12
- data/lib/hecks/runtime/saga_interpreter.rb +27 -13
- data/lib/hecks/runtime/tenant_check.rb +26 -6
- data/lib/hecks/runtime/tenant_scope.rb +18 -0
- data/lib/hecks/runtime/value/coercion.rb +255 -33
- data/lib/hecks/runtime/value/entity_list_coercion.rb +102 -30
- data/lib/hecks/runtime/value.rb +50 -0
- data/lib/hecks/runtime.rb +32 -0
- data/lib/hecks/storehouse.rb +305 -9
- data/lib/hecks/tenancy/bluebook/tenancy.bluebook +130 -0
- data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +32 -0
- data/lib/hecks/version.rb +1 -1
- data/lib/hecks.rb +79 -1
- data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +8 -0
- data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +12 -2
- data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +29 -5
- metadata +11 -5
- data/lib/hecks/codemod/legacy_dispatch_args.rb +0 -299
- data/lib/hecks/codemod/legacy_dispatch_recorder.rb +0 -186
- data/lib/hecks/deprecation.rb +0 -95
|
@@ -4,14 +4,16 @@ module Hecks
|
|
|
4
4
|
module Projector
|
|
5
5
|
# A bluebook, projected as its own usage documentation.
|
|
6
6
|
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
7
|
+
# ## What this is for
|
|
8
|
+
#
|
|
9
|
+
# A chapter in this corpus already contains everything a user of it
|
|
10
|
+
# needs: what each aggregate is (`description`), what each verb is
|
|
11
|
+
# for (`goal`) and who issues it (`role`), which states it moves
|
|
10
12
|
# between, what it refuses and in whose words (`given`, `invariant`,
|
|
11
|
-
# `ensures`), and what each list is worth reading (`description` on
|
|
12
|
-
# query). None of that reaches the person who has to call the
|
|
13
|
-
# They read the source, or they read a document somebody
|
|
14
|
-
# source and stopped updating.
|
|
13
|
+
# `ensures`), and what each list is worth reading (`description` on
|
|
14
|
+
# a query). None of that reaches the person who has to call the
|
|
15
|
+
# domain. They read the source, or they read a document somebody
|
|
16
|
+
# wrote beside the source and stopped updating.
|
|
15
17
|
#
|
|
16
18
|
# `docs/implemented/reference/` is the precedent and the contrast. `bin/reference`
|
|
17
19
|
# generates it from the language's own Syntax chapter, so the reference
|
|
@@ -19,12 +21,14 @@ module Hecks
|
|
|
19
21
|
# down: the usage document for a domain, generated from that domain, so it
|
|
20
22
|
# cannot drift from the domain either.
|
|
21
23
|
#
|
|
22
|
-
# Why
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
24
|
+
# ## Why a projection, not a generator script
|
|
25
|
+
#
|
|
26
|
+
# `Projector` is the repository's registry of "canonical IR in,
|
|
27
|
+
# external artifact out" (§30 of the implementation plan), and this
|
|
28
|
+
# is exactly that shape: one bluebook's IR in, markdown out, no
|
|
29
|
+
# runtime needed and no store touched. Registered as `:docs` beside
|
|
30
|
+
# `:ir`, and reachable the way every projector is —
|
|
31
|
+
# `Projector.call(:docs, bluebook: ...)`.
|
|
28
32
|
#
|
|
29
33
|
# And as a method, which is the half that makes it get used.
|
|
30
34
|
# `Facade::Surface` already installs a module per chapter carrying
|
|
@@ -33,17 +37,30 @@ module Hecks
|
|
|
33
37
|
# `QualityControl::Bug.docs`. A document you have to remember a script for
|
|
34
38
|
# is a document nobody reads.
|
|
35
39
|
#
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
#
|
|
41
|
-
#
|
|
40
|
+
# ## What it deliberately does not do
|
|
41
|
+
#
|
|
42
|
+
# Invent. Every sentence below comes out of the chapter. Where a
|
|
43
|
+
# chapter says nothing — an aggregate with no `description`, a
|
|
44
|
+
# command with no `goal` — the document says nothing rather than
|
|
45
|
+
# filling the gap with a restatement of the name, because a
|
|
46
|
+
# generated paragraph that only rephrases an identifier teaches a
|
|
47
|
+
# reader to skim the ones that do not.
|
|
42
48
|
module DocsProjector
|
|
43
49
|
module_function
|
|
44
50
|
|
|
51
|
+
# Projects `bluebook` as its own usage documentation.
|
|
52
|
+
#
|
|
45
53
|
# `options[:heading]` sets the top heading level (default 1), so a
|
|
46
54
|
# caller splicing this into a larger document can push it down.
|
|
55
|
+
#
|
|
56
|
+
# @param bluebook [Bluebook::Behaviour::Chapter] the chapter to document
|
|
57
|
+
# @param options [Hash] optional inputs
|
|
58
|
+
# @option options [Integer, String] :heading the top heading level; defaults to 1
|
|
59
|
+
# @option options [String, Symbol, nil] :aggregate narrows the document to one
|
|
60
|
+
# aggregate, omitting the chapter header and closing sections
|
|
61
|
+
# @return [String] the document, as Markdown, ending in a newline
|
|
62
|
+
# @raise [Runtime::NotFound] if `options[:aggregate]` names no aggregate `bluebook`
|
|
63
|
+
# declares
|
|
47
64
|
def call(bluebook:, options: {})
|
|
48
65
|
depth = (options[:heading] || 1).to_i
|
|
49
66
|
only = options[:aggregate]
|
|
@@ -60,6 +77,13 @@ module Hecks
|
|
|
60
77
|
# matched no head returned "" and exit 0, which is the silent-wrong-
|
|
61
78
|
# answer shape this repository has already been bitten by twice in the
|
|
62
79
|
# query engine. A misspelling should cost a sentence, not a puzzle.
|
|
80
|
+
#
|
|
81
|
+
# @param bluebook [Bluebook::Behaviour::Chapter] the chapter to look in
|
|
82
|
+
# @param only [String, Symbol, nil] narrows the result to the one aggregate
|
|
83
|
+
# named; nil answers every aggregate
|
|
84
|
+
# @return [Array<Bluebook::Aggregate>, Bluebook::Aggregate] every declared
|
|
85
|
+
# aggregate, or the single aggregate `only` names
|
|
86
|
+
# @raise [Runtime::NotFound] if `only` names no aggregate `bluebook` declares
|
|
63
87
|
def aggregates(bluebook, only)
|
|
64
88
|
return bluebook.aggregates unless only
|
|
65
89
|
|
|
@@ -69,10 +93,21 @@ module Hecks
|
|
|
69
93
|
"it declares #{bluebook.aggregates.map(&:hecks_name).sort.join(', ')}")
|
|
70
94
|
end
|
|
71
95
|
|
|
96
|
+
# Renders a Markdown heading line.
|
|
97
|
+
#
|
|
98
|
+
# @param depth [Integer] the heading level
|
|
99
|
+
# @param text [String] the heading text
|
|
100
|
+
# @return [String] a Markdown `#`-prefixed heading line
|
|
72
101
|
def h(depth, text) = "#{'#' * depth} #{text}"
|
|
73
102
|
|
|
74
103
|
# ── the chapter ───────────────────────────────────────────────────
|
|
75
104
|
|
|
105
|
+
# Renders the chapter-level header: its title, vision, classification,
|
|
106
|
+
# former name, and aggregate list.
|
|
107
|
+
#
|
|
108
|
+
# @param bluebook [Bluebook::Behaviour::Chapter] the chapter to document
|
|
109
|
+
# @param depth [Integer] the heading level for the chapter's own title
|
|
110
|
+
# @return [String] the header's Markdown source
|
|
76
111
|
def chapter_header(bluebook, depth)
|
|
77
112
|
out = [h(depth, bluebook.name), ""]
|
|
78
113
|
# The vision first and as a quote. It is the one sentence in a chapter
|
|
@@ -86,6 +121,10 @@ module Hecks
|
|
|
86
121
|
out.join("\n")
|
|
87
122
|
end
|
|
88
123
|
|
|
124
|
+
# Builds a construct's own GitHub-style heading anchor.
|
|
125
|
+
#
|
|
126
|
+
# @param name [String, Symbol] the construct name to anchor
|
|
127
|
+
# @return [String] the construct's own GitHub-style heading anchor
|
|
89
128
|
def anchor(name) = Naming.snake(name).tr("_", "-")
|
|
90
129
|
|
|
91
130
|
# What happens without anybody asking — the part of a domain a caller
|
|
@@ -93,6 +132,11 @@ module Hecks
|
|
|
93
132
|
# them. A policy means one dispatch causes another, sometimes into a
|
|
94
133
|
# different domain entirely; a saga means a sequence is being driven on
|
|
95
134
|
# their behalf and can end in more than one place.
|
|
135
|
+
#
|
|
136
|
+
# @param bluebook [Bluebook::Behaviour::Chapter] the chapter to document
|
|
137
|
+
# @param depth [Integer] the heading level for the "Reactions"/saga sections
|
|
138
|
+
# @return [String, nil] the closing's Markdown source, or nil if `bluebook`
|
|
139
|
+
# declares no policy and no process manager
|
|
96
140
|
def closing(bluebook, depth)
|
|
97
141
|
out = []
|
|
98
142
|
|
|
@@ -123,6 +167,12 @@ module Hecks
|
|
|
123
167
|
|
|
124
168
|
# ── one aggregate ─────────────────────────────────────────────────
|
|
125
169
|
|
|
170
|
+
# Documents one aggregate: its description, identity, references,
|
|
171
|
+
# attributes, lifecycle, verbs, queries, and nested entities.
|
|
172
|
+
#
|
|
173
|
+
# @param aggregate [Bluebook::Aggregate] the aggregate to document
|
|
174
|
+
# @param depth [Integer] the heading level for the aggregate's own title
|
|
175
|
+
# @return [String] the aggregate's Markdown section
|
|
126
176
|
def aggregate_section(aggregate, depth)
|
|
127
177
|
out = [h(depth, aggregate.hecks_name), ""]
|
|
128
178
|
out += [aggregate.description, ""] if aggregate.description
|
|
@@ -142,6 +192,12 @@ module Hecks
|
|
|
142
192
|
out.compact.join("\n")
|
|
143
193
|
end
|
|
144
194
|
|
|
195
|
+
# Documents one entity nested under `aggregate`.
|
|
196
|
+
#
|
|
197
|
+
# @param aggregate [Bluebook::Aggregate] the entity's own owning aggregate
|
|
198
|
+
# @param entity [Bluebook::Entity] the entity to document
|
|
199
|
+
# @param depth [Integer] the heading level for the entity's own title
|
|
200
|
+
# @return [String] the entity's Markdown section
|
|
145
201
|
def entity_section(aggregate, entity, depth)
|
|
146
202
|
out = [h(depth, "#{entity.hecks_name} (within #{aggregate.hecks_name})"), ""]
|
|
147
203
|
out += [entity.description, ""] if entity.description
|
|
@@ -161,6 +217,12 @@ module Hecks
|
|
|
161
217
|
|
|
162
218
|
# ── the shape ─────────────────────────────────────────────────────
|
|
163
219
|
|
|
220
|
+
# Renders a holder's own non-reference attributes as a Markdown table.
|
|
221
|
+
#
|
|
222
|
+
# @param holder [Bluebook::Aggregate, Bluebook::Entity] the holder whose
|
|
223
|
+
# attributes to render
|
|
224
|
+
# @return [String, nil] the attribute/shape/rules table, or nil if `holder`
|
|
225
|
+
# declares no non-reference attribute
|
|
164
226
|
def attributes_table(holder)
|
|
165
227
|
attributes = holder.attributes.reject(&:reference?)
|
|
166
228
|
return nil if attributes.empty?
|
|
@@ -175,6 +237,11 @@ module Hecks
|
|
|
175
237
|
# a caller nothing; `{ value: String }` tells them what to send, which is
|
|
176
238
|
# the single most common thing to get wrong at this boundary — a bare
|
|
177
239
|
# scalar where an object is wanted.
|
|
240
|
+
#
|
|
241
|
+
# @param attribute [Bluebook::Attribute] the attribute to describe
|
|
242
|
+
# @param holder [Bluebook::Aggregate, Bluebook::Entity] `attribute`'s own holder
|
|
243
|
+
# @return [String] the attribute's shape: its value object's own fields, or its
|
|
244
|
+
# scalar type, with "list of" and "*(optional)*" applied as declared
|
|
178
245
|
def shape_of(attribute, holder)
|
|
179
246
|
value_object = value_object_for(attribute, holder)
|
|
180
247
|
inner =
|
|
@@ -187,6 +254,12 @@ module Hecks
|
|
|
187
254
|
attribute.optional? ? "#{shape} *(optional)*" : shape
|
|
188
255
|
end
|
|
189
256
|
|
|
257
|
+
# Lists an attribute's own rules: closed-set members, field patterns and
|
|
258
|
+
# defaults, invariants, and its own default.
|
|
259
|
+
#
|
|
260
|
+
# @param attribute [Bluebook::Attribute] the attribute to describe
|
|
261
|
+
# @param holder [Bluebook::Aggregate, Bluebook::Entity] `attribute`'s own holder
|
|
262
|
+
# @return [String] the attribute's rules, joined with "; "; `""` if it has none
|
|
190
263
|
def rules_of(attribute, holder)
|
|
191
264
|
value_object = value_object_for(attribute, holder)
|
|
192
265
|
rules = []
|
|
@@ -200,6 +273,11 @@ module Hecks
|
|
|
200
273
|
rules.empty? ? "" : rules.join("; ")
|
|
201
274
|
end
|
|
202
275
|
|
|
276
|
+
# Names a closed set's own members.
|
|
277
|
+
#
|
|
278
|
+
# @param value_object [Bluebook::ValueObject, nil] the value object to check
|
|
279
|
+
# @return [Array<Object>] every unique value across `value_object`'s own member
|
|
280
|
+
# rows, or `[]` if `value_object` is nil or not a closed set
|
|
203
281
|
def closed_members(value_object)
|
|
204
282
|
return [] unless value_object&.closed_set?
|
|
205
283
|
|
|
@@ -208,6 +286,12 @@ module Hecks
|
|
|
208
286
|
|
|
209
287
|
# An entity holds no value objects of its own — its argument types are
|
|
210
288
|
# declared on the aggregate above it.
|
|
289
|
+
#
|
|
290
|
+
# @param attribute [Bluebook::Attribute] the attribute whose type to resolve
|
|
291
|
+
# @param holder [Bluebook::Aggregate, Bluebook::Entity] `attribute`'s own holder
|
|
292
|
+
# @return [Bluebook::ValueObject, nil] the value object class `attribute`'s type
|
|
293
|
+
# names, found on `holder` or its own owning aggregate; nil if `attribute`'s
|
|
294
|
+
# type is not a value object
|
|
211
295
|
def value_object_for(attribute, holder)
|
|
212
296
|
scopes = [holder, holder.respond_to?(:hecks_owner) ? holder.hecks_owner : nil].compact
|
|
213
297
|
scopes.each do |scope|
|
|
@@ -221,6 +305,13 @@ module Hecks
|
|
|
221
305
|
|
|
222
306
|
# ── the machine ───────────────────────────────────────────────────
|
|
223
307
|
|
|
308
|
+
# Renders a holder's own lifecycle as a "starting state" sentence and a
|
|
309
|
+
# verb/from/to table.
|
|
310
|
+
#
|
|
311
|
+
# @param holder [Bluebook::Aggregate, Bluebook::Entity] the holder to document
|
|
312
|
+
# @param depth [Integer] the heading level for the "Lifecycle" section
|
|
313
|
+
# @return [String, nil] the section's Markdown source, or nil if `holder`
|
|
314
|
+
# declares no lifecycle
|
|
224
315
|
def lifecycle_section(holder, depth)
|
|
225
316
|
lifecycle = holder.lifecycle or return nil
|
|
226
317
|
|
|
@@ -234,6 +325,13 @@ module Hecks
|
|
|
234
325
|
|
|
235
326
|
# ── the verbs ─────────────────────────────────────────────────────
|
|
236
327
|
|
|
328
|
+
# Documents every command a holder declares.
|
|
329
|
+
#
|
|
330
|
+
# @param holder [Bluebook::Aggregate, Bluebook::Entity] the holder whose
|
|
331
|
+
# commands to document
|
|
332
|
+
# @param depth [Integer] the heading level for the "Verbs" section
|
|
333
|
+
# @return [String, nil] the section's Markdown source, or nil if `holder`
|
|
334
|
+
# declares no command
|
|
237
335
|
def verbs_section(holder, depth)
|
|
238
336
|
commands = holder.commands
|
|
239
337
|
return nil if commands.empty?
|
|
@@ -243,6 +341,13 @@ module Hecks
|
|
|
243
341
|
out.join("\n")
|
|
244
342
|
end
|
|
245
343
|
|
|
344
|
+
# Documents one command: its goal, role, arguments, refusals,
|
|
345
|
+
# guarantees, and emitted events.
|
|
346
|
+
#
|
|
347
|
+
# @param command [Bluebook::Command] the command to document
|
|
348
|
+
# @param holder [Bluebook::Aggregate, Bluebook::Entity] `command`'s own holder
|
|
349
|
+
# @param depth [Integer] the heading level for the command's own title
|
|
350
|
+
# @return [String] the command's Markdown section
|
|
246
351
|
def command_entry(command, holder, depth)
|
|
247
352
|
out = [h(depth, "#{command.hecks_name}#{' *(creates)*' if command.creates?}"), ""]
|
|
248
353
|
out += [command.goal, ""] if command.goal
|
|
@@ -270,6 +375,11 @@ module Hecks
|
|
|
270
375
|
# nothing to share with `command_entry`'s other sections, extracted
|
|
271
376
|
# only to keep that method to the one shape every section there
|
|
272
377
|
# follows: build a chunk, append it if non-empty.
|
|
378
|
+
#
|
|
379
|
+
# @param arguments [Array<Bluebook::Attribute>] the command's own arguments
|
|
380
|
+
# @param holder [Bluebook::Aggregate, Bluebook::Entity] the arguments' own holder
|
|
381
|
+
# @return [Array<Array(String, String, String)>] one `[argument, shape, needed]`
|
|
382
|
+
# row per argument
|
|
273
383
|
def command_argument_rows(arguments, holder)
|
|
274
384
|
arguments.map do |attribute|
|
|
275
385
|
shape = attribute.reference? ? "id of a `#{attribute.type.target_name}`" : shape_of(attribute, holder)
|
|
@@ -282,6 +392,10 @@ module Hecks
|
|
|
282
392
|
# `given`s, and the fact that a reference has to resolve. A caller
|
|
283
393
|
# reading only the argument list learns none of these, and they are
|
|
284
394
|
# most of what a domain is.
|
|
395
|
+
#
|
|
396
|
+
# @param command [Bluebook::Command] the command to gather refusals for
|
|
397
|
+
# @param holder [Bluebook::Aggregate, Bluebook::Entity] `command`'s own holder
|
|
398
|
+
# @return [Array<String>] every way `command` can refuse, stated as sentences
|
|
285
399
|
def refusals_of(command, holder)
|
|
286
400
|
refusals = []
|
|
287
401
|
|
|
@@ -304,6 +418,12 @@ module Hecks
|
|
|
304
418
|
|
|
305
419
|
# ── the reads ─────────────────────────────────────────────────────
|
|
306
420
|
|
|
421
|
+
# Renders a list of queries as one Markdown paragraph per query.
|
|
422
|
+
#
|
|
423
|
+
# @param queries [Array<Bluebook::Query>] the queries to document
|
|
424
|
+
# @param depth [Integer] the heading level for `title`
|
|
425
|
+
# @param title [String] the section's own heading text
|
|
426
|
+
# @return [String, nil] the section's Markdown source, or nil if `queries` is empty
|
|
307
427
|
def queries_section(queries, depth, title)
|
|
308
428
|
return nil if queries.empty?
|
|
309
429
|
|
|
@@ -320,6 +440,12 @@ module Hecks
|
|
|
320
440
|
out.join("\n")
|
|
321
441
|
end
|
|
322
442
|
|
|
443
|
+
# Renders a Markdown pipe table.
|
|
444
|
+
#
|
|
445
|
+
# @param headers [Array<String>] the column headers
|
|
446
|
+
# @param rows [Array<Array<String>>] each row's own cell values, matching
|
|
447
|
+
# `headers`' width
|
|
448
|
+
# @return [String] the rendered table, ending in a blank line
|
|
323
449
|
def table(headers, rows)
|
|
324
450
|
lines = ["| #{headers.join(' | ')} |", "|#{headers.map { '---' }.join('|')}|"]
|
|
325
451
|
rows.each { |row| lines << "| #{row.join(' | ')} |" }
|
|
@@ -13,10 +13,18 @@ module Hecks
|
|
|
13
13
|
module Exporter
|
|
14
14
|
module_function
|
|
15
15
|
|
|
16
|
+
# Exports every booted bluebook's own canonical IR.
|
|
17
|
+
#
|
|
18
|
+
# @param registry [Runtime::Registry] the booted registry to export
|
|
19
|
+
# @return [Hash{String => Hash}] each domain name, mapped to its bluebook's `to_h`
|
|
16
20
|
def call(registry)
|
|
17
21
|
registry.bluebooks.transform_values(&:to_h)
|
|
18
22
|
end
|
|
19
23
|
|
|
24
|
+
# Exports every booted bluebook's own canonical IR as JSON.
|
|
25
|
+
#
|
|
26
|
+
# @param registry [Runtime::Registry] the booted registry to export
|
|
27
|
+
# @return [String] `call`'s output, as pretty-printed JSON
|
|
20
28
|
def json(registry)
|
|
21
29
|
JSON.pretty_generate(call(registry))
|
|
22
30
|
end
|
|
@@ -42,6 +50,12 @@ module Hecks
|
|
|
42
50
|
# already answers for a domain with nothing lineage-capable bound —
|
|
43
51
|
# `capable_aggregates: []` — rather than raising on an undefined
|
|
44
52
|
# constant.
|
|
53
|
+
# @param registry [Runtime::Registry] the booted registry `domain_name` is loaded in
|
|
54
|
+
# @param domain_name [String] the domain to check era-adapter lineage capability for
|
|
55
|
+
# @return [Hash{Symbol => Array<Hash{Symbol => String}>}] `:capable_aggregates`,
|
|
56
|
+
# each a `:name`/`:storage_name` Hash; empty when the era plugin is unloaded or
|
|
57
|
+
# nothing this domain binds is lineage-capable
|
|
58
|
+
# @raise [KeyError] if `domain_name` is not a loaded domain
|
|
45
59
|
def lineage(registry, domain_name)
|
|
46
60
|
return { capable_aggregates: [] } unless Ports::Persistence.plugin?(:era)
|
|
47
61
|
|
|
@@ -68,6 +82,13 @@ module Hecks
|
|
|
68
82
|
# today), rather than silently building up a second, disjoint
|
|
69
83
|
# history nothing but Rust ever reads while the real state stays
|
|
70
84
|
# wherever its own adapter actually wrote it.
|
|
85
|
+
# @param registry [Runtime::Registry] the booted registry `domain_name` is loaded in
|
|
86
|
+
# @param domain_name [String] the domain to export persistence bindings for
|
|
87
|
+
# @return [Hash{Symbol => Array<Hash{Symbol => Object}>}] `:aggregates`, each a
|
|
88
|
+
# `:name`/`:storage_name`/`:adapter` Hash
|
|
89
|
+
# @raise [KeyError] if `domain_name` is not a loaded domain
|
|
90
|
+
# @raise [Runtime::WiringError] if an aggregate has no authoritative bind, more
|
|
91
|
+
# than one, or a bind with a role this port does not support
|
|
71
92
|
def persistence(registry, domain_name)
|
|
72
93
|
bluebook = registry.bluebooks.fetch(domain_name)
|
|
73
94
|
aggregates = bluebook.aggregates.map do |aggregate|
|
|
@@ -85,6 +106,12 @@ module Hecks
|
|
|
85
106
|
# "authorization"`), with that chapter's declared verbs qualified.
|
|
86
107
|
# `rust/host` (auth.rs) reads this instead of naming Governance.
|
|
87
108
|
# `{}` when nothing this domain attaches provides authorization.
|
|
109
|
+
# @param registry [Runtime::Registry] the booted registry `domain_name` is loaded in
|
|
110
|
+
# @param domain_name [String] the domain to export the authorization binding for
|
|
111
|
+
# @return [Hash{Symbol => String, nil}] `:provider` (name), `:grant`, `:assignments`
|
|
112
|
+
# (both provided-verb names), and `:assignment_aggregate` (`:assignments`' own
|
|
113
|
+
# leading aggregate name); `{}` if nothing this domain attaches provides
|
|
114
|
+
# authorization
|
|
88
115
|
def authorization(registry, domain_name)
|
|
89
116
|
provider = registry.authorization_provider_for(domain_name)
|
|
90
117
|
return {} unless provider
|
|
@@ -107,10 +134,19 @@ module Hecks
|
|
|
107
134
|
# separate). `values:` tables serialize as `[key, value]` pairs,
|
|
108
135
|
# never an object, because JSON object keys are always strings and
|
|
109
136
|
# a convert's keys are typed.
|
|
137
|
+
# @param registry [Runtime::Registry] the booted registry to export translations from
|
|
138
|
+
# @return [Array<Hash>] every registered translation, as `compiled_translation_hash`
|
|
139
|
+
# builds
|
|
110
140
|
def translations(registry)
|
|
111
141
|
registry.translations.map { |translation| compiled_translation_hash(translation) }
|
|
112
142
|
end
|
|
113
143
|
|
|
144
|
+
# Exports one translation, its aggregates' compiled SQL included.
|
|
145
|
+
#
|
|
146
|
+
# @param translation [Bluebook::Translation] the translation to export
|
|
147
|
+
# @return [Hash{Symbol => Object}] `:domain` (String), `:from`/`:to` (the era
|
|
148
|
+
# identifiers as declared), `:retired` (`Array<String>`), and `:aggregates`
|
|
149
|
+
# (each `compiled_translation_aggregate`'s own Hash)
|
|
114
150
|
def compiled_translation_hash(translation)
|
|
115
151
|
{
|
|
116
152
|
domain: translation.domain,
|
|
@@ -121,6 +157,10 @@ module Hecks
|
|
|
121
157
|
}
|
|
122
158
|
end
|
|
123
159
|
|
|
160
|
+
# Exports every registered translation as JSON.
|
|
161
|
+
#
|
|
162
|
+
# @param registry [Runtime::Registry] the booted registry to export translations from
|
|
163
|
+
# @return [String] `translations`' output, as pretty-printed JSON
|
|
124
164
|
def translations_json(registry)
|
|
125
165
|
JSON.pretty_generate(translations(registry))
|
|
126
166
|
end
|
|
@@ -136,6 +176,10 @@ module Hecks
|
|
|
136
176
|
# reviewed never changed at all. The approval binds to what was
|
|
137
177
|
# declared, not to what a particular compiler build happened to
|
|
138
178
|
# emit from it.
|
|
179
|
+
# @param translation [Bluebook::Translation] the translation to digest
|
|
180
|
+
# @return [Hash{Symbol => Object}] `:domain` (String), `:from`/`:to` (the era
|
|
181
|
+
# identifiers as declared), `:retired` (`Array<String>`), and `:aggregates`
|
|
182
|
+
# (each `translation_aggregate`'s own Hash)
|
|
139
183
|
def translation_hash(translation)
|
|
140
184
|
{
|
|
141
185
|
domain: translation.domain,
|
|
@@ -146,6 +190,14 @@ module Hecks
|
|
|
146
190
|
}
|
|
147
191
|
end
|
|
148
192
|
|
|
193
|
+
# Digests one aggregate's own declared translation rules.
|
|
194
|
+
#
|
|
195
|
+
# @param aggregate [Bluebook::TranslationAggregate] the aggregate's own
|
|
196
|
+
# translation rules to digest
|
|
197
|
+
# @return [Hash{Symbol => Object}] `:name` (String), `:was` (String, nil),
|
|
198
|
+
# `:renames` (`Hash{String => String}`), `:moves`/`:converts`/`:retypes`/
|
|
199
|
+
# `:computes`/`:rekeys`/`:backfills` (each an `Array<Hash>`), `:drops`
|
|
200
|
+
# (`Array<String>`)
|
|
149
201
|
def translation_aggregate(aggregate)
|
|
150
202
|
{
|
|
151
203
|
name: aggregate.name,
|
|
@@ -158,17 +210,14 @@ module Hecks
|
|
|
158
210
|
drops: aggregate.drops.map(&:to_s),
|
|
159
211
|
retypes: aggregate.retypes.map { |retype| { from: retype.from, to: retype.to } },
|
|
160
212
|
computes: aggregate.computes.map { |compute| { from: compute.from, to: compute.to, sql: compute.sql } },
|
|
161
|
-
#
|
|
162
|
-
#
|
|
163
|
-
#
|
|
164
|
-
#
|
|
165
|
-
#
|
|
166
|
-
#
|
|
167
|
-
#
|
|
168
|
-
#
|
|
169
|
-
# exported). Fixing this changes every existing rekey/
|
|
170
|
-
# backfill edge's digest — any approval already recorded for
|
|
171
|
-
# one is invalidated by this fix and must be re-reviewed.
|
|
213
|
+
# **`rekeys`/`backfills` are digest-relevant too.** Without them, an
|
|
214
|
+
# edge carrying only a rekey (no compute) would bind its approval
|
|
215
|
+
# to nothing rekey-specific: any two rekey edges with otherwise-
|
|
216
|
+
# identical renames/moves/converts/drops/retypes/computes would
|
|
217
|
+
# produce the same digest regardless of what their `rekey sql:`
|
|
218
|
+
# actually said, letting a rekey's own SQL change without
|
|
219
|
+
# invalidating an existing approval. Same reasoning covers
|
|
220
|
+
# `backfills`.
|
|
172
221
|
rekeys: aggregate.rekeys.map { |rekey| { sql: rekey.sql } },
|
|
173
222
|
backfills: aggregate.backfills.map { |backfill| { name: backfill.name.to_s, default: backfill.default } }
|
|
174
223
|
}
|
|
@@ -197,6 +246,11 @@ module Hecks
|
|
|
197
246
|
# declared-rules shape, just without precompiled SQL to execute —
|
|
198
247
|
# consistent with there being no mint/audit machinery to run it
|
|
199
248
|
# against either.
|
|
249
|
+
# @param aggregate [Bluebook::TranslationAggregate] the aggregate's own
|
|
250
|
+
# translation rules to compile and export
|
|
251
|
+
# @return [Hash{Symbol => Object}] `translation_aggregate`'s own Hash, plus
|
|
252
|
+
# `:compiled_state_expression` (String) and `:compiled_id_expression`
|
|
253
|
+
# (String, nil) when the era persistence plugin is loaded
|
|
200
254
|
def compiled_translation_aggregate(aggregate)
|
|
201
255
|
return translation_aggregate(aggregate) unless Ports::Persistence.plugin?(:era)
|
|
202
256
|
|
|
@@ -12,6 +12,12 @@ module Hecks
|
|
|
12
12
|
module IRProjector
|
|
13
13
|
module_function
|
|
14
14
|
|
|
15
|
+
# Projects `bluebook` as its own canonical IR.
|
|
16
|
+
#
|
|
17
|
+
# @param bluebook [Hecks::IR] the IR-emitting construct to project
|
|
18
|
+
# @param options [Hash] unused; accepted to satisfy the registry's call shape
|
|
19
|
+
# @return [Hash] `bluebook`'s canonical IR, as built by `Hecks::IR::Emits#to_h`
|
|
20
|
+
# @raise [Hecks::IR::Undeclared] if `bluebook` never declared its shape with `emits_ir`
|
|
15
21
|
def call(bluebook:, options: {}) = bluebook.to_h
|
|
16
22
|
end
|
|
17
23
|
end
|