hecks 3.2.0 → 3.3.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/bluebook/assembly/contracts.rb +2 -1
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +1 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +2 -39
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +3 -3
- data/lib/hecks/bluebook/dsl/need_word.rb +50 -0
- data/lib/hecks/bluebook/dsl/query_builder.rb +6 -1
- data/lib/hecks/bluebook/query.rb +8 -5
- data/lib/hecks/cli/check_era.rb +3 -39
- data/lib/hecks/cli/interview_draft.rb +86 -31
- data/lib/hecks/cli/interview_session.rb +77 -26
- data/lib/hecks/cli/interview_shape.rb +179 -0
- data/lib/hecks/doors/cli_runner.rb +14 -1
- data/lib/hecks/doors/launcher_options.rb +13 -3
- data/lib/hecks/doors/mcp_door.rb +16 -2
- data/lib/hecks/doors/mcp_door_scope.rb +45 -5
- data/lib/hecks/doors/mcp_guide_cache.rb +75 -0
- data/lib/hecks/doors.rb +1 -1
- data/lib/hecks/embryonaut_bluebook/manifest.rb +117 -0
- data/lib/hecks/embryonaut_bluebook/registry.rb +209 -0
- data/lib/hecks/embryonaut_bluebook/vendor.rb +1 -1
- data/lib/hecks/embryonaut_bluebook.rb +2 -0
- data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +17 -1
- data/lib/hecks/fuzzing/qa_settings.rb +15 -34
- data/lib/hecks/gate/stages.yml +113 -8
- data/lib/hecks/hecks/adapters/codebase/regeneration.rb +10 -1
- data/lib/hecks/hecks/adapters/codebase/test_runner.rb +10 -2
- data/lib/hecks/hecks/adapters/first_admin.rb +108 -0
- data/lib/hecks/hecks/adapters/git.rb +59 -0
- data/lib/hecks/hecks/adapters/in_process_access.rb +25 -0
- data/lib/hecks/hecks/adapters/in_process_boot.rb +2 -0
- data/lib/hecks/hecks/adapters/rust_toolchain.rb +18 -3
- data/lib/hecks/hecks/adapters/rust_workspace.rb +1 -1
- data/lib/hecks/hecks/adapters/site_toolchain.rb +88 -11
- data/lib/hecks/hecks/codebase.behaviors +6 -0
- data/lib/hecks/hecks/codebase.bluebook +21 -0
- data/lib/hecks/hecks/custodian.behaviors +6 -0
- data/lib/hecks/hecks/custodian.bluebook +217 -0
- data/lib/hecks/hecks/hecks.hecksagon +24 -0
- data/lib/hecks/hecks/hecks.world +8 -3
- data/lib/hecks/hecks/site.world +5 -2
- data/lib/hecks/language/bluebook/query.bluebook +25 -0
- data/lib/hecks/language/bluebook/vocabulary.bluebook +220 -7
- data/lib/hecks/language/hecksagon/hecksagon.bluebook +1 -1
- data/lib/hecks/language/oidc.json +5 -0
- data/lib/hecks/ports/persistence/plugins/era/expected_era.rb +3 -3
- data/lib/hecks/projections/deploy/box/hosting.rb +170 -0
- data/lib/hecks/projections/deploy/box/hosting_settings.rb +123 -0
- data/lib/hecks/projections/deploy/box/settings.rb +40 -6
- data/lib/hecks/projections/deploy/box/templates/deploy-box.sh.tmpl +2 -0
- data/lib/hecks/projections/deploy/box/templates/deploy-service.services-roll.part +33 -0
- data/lib/hecks/projections/deploy/box/templates/deploy-service.sh.tmpl +79 -0
- data/lib/hecks/projections/deploy/box/templates/deploy-service.taskdef-roll.part +77 -0
- data/lib/hecks/projections/deploy/box/templates/deploy-service.taskdef.part +12 -0
- data/lib/hecks/projections/deploy/box/templates/hosting.mk.tmpl +24 -0
- data/lib/hecks/projections/deploy/box/templates/render-compose-taskdef.sh.tmpl +17 -0
- data/lib/hecks/projections/deploy/box/templates/smoke-after-deploy.sh.tmpl +271 -0
- data/lib/hecks/projections/deploy/box.rb +28 -4
- data/lib/hecks/projections/deploy/fargate.rb +3 -3
- data/lib/hecks/projections/deploy/lambda.rb +8 -8
- data/lib/hecks/projections/model/deviations.rb +1 -1
- data/lib/hecks/projections/site/edge/behaviours.rb +5 -3
- data/lib/hecks/projections/site/edge/checks.rb +31 -5
- data/lib/hecks/projections/site/edge.rb +25 -11
- data/lib/hecks/projections/site/live_edge.rb +162 -0
- data/lib/hecks/projections/site/routes_ts.rb +50 -27
- data/lib/hecks/projections/site/site_cdn.rb +7 -4
- data/lib/hecks/projections/site/table/checks.rb +53 -7
- data/lib/hecks/projections/site/table/link_builder.rb +64 -0
- data/lib/hecks/projections/site/table/row_builder.rb +21 -6
- data/lib/hecks/projections/site/table.rb +16 -5
- data/lib/hecks/quality_control/adapters/git_pr.rb +0 -14
- data/lib/hecks/quality_control/cli/qa_discover_external_domains.rb +1 -1
- data/lib/hecks/quality_control/cli/qa_open_pr.rb +32 -16
- data/lib/hecks/quality_control/cli/qa_seed_angles.rb +2 -2
- data/lib/hecks/quality_control/cli/qa_seed_targets.rb +1 -2
- data/lib/hecks/quality_control/quality_control.bluebook +76 -124
- data/lib/hecks/runtime/interpreting.rb +3 -22
- data/lib/hecks/runtime/needs.rb +48 -0
- data/lib/hecks/runtime/query_interpreter.rb +3 -0
- data/lib/hecks/runtime/registry/verification.rb +3 -3
- data/lib/hecks/rust_build/host.rb +147 -0
- data/lib/hecks/rust_build/kernel_input.rb +51 -17
- data/lib/hecks/rust_build/project_rust/codegen_run.rb +0 -18
- data/lib/hecks/rust_build/project_rust.rb +7 -140
- data/lib/hecks/rust_build.rb +1 -0
- data/lib/hecks/site/bluebook/site.bluebook +80 -14
- data/lib/hecks/site/bluebook/site.ports.hecksagon +6 -0
- data/lib/hecks/sme/bluebook/sme.bluebook +128 -1
- data/lib/hecks/storehouse.rb +35 -1
- data/lib/hecks/tools/comment_style.rb +4 -2
- data/lib/hecks/tools/gate.rb +1 -1
- data/lib/hecks/tools/rust_comment_style.rb +2 -4
- data/lib/hecks/tools/site_routes.rb +69 -28
- data/lib/hecks/tools/tools_doc.rb +204 -0
- data/lib/hecks/tools.rb +1 -0
- data/lib/hecks/version.rb +1 -1
- data/lib/hecks/vocabulary.rb +152 -1
- data/lib/hecks.rb +1 -0
- data/qa/settings.yml +1 -2
- data/rust/build/src/lineage_pass.rs +31 -16
- data/rust/build/src/main.rs +4 -2
- data/rust/build/src/pipeline.rs +9 -20
- data/rust/codegen/src/attr.rs +1 -1
- data/rust/codegen/src/bridging.rs +8 -8
- data/rust/codegen/src/commands.rs +1 -1
- data/rust/codegen/src/constraints.rs +1 -1
- data/rust/codegen/src/dependency_planning.rs +1 -1
- data/rust/codegen/src/domain_generator.rs +2 -2
- data/rust/codegen/src/exemplar.rs +1 -1
- data/rust/codegen/src/expr_emitter.rs +1 -1
- data/rust/codegen/src/fielded.rs +1 -1
- data/rust/codegen/src/json.rs +214 -23
- data/rust/codegen/src/json_codec.rs +1 -1
- data/rust/codegen/src/literal.rs +6 -3
- data/rust/codegen/src/main.rs +23 -13
- data/rust/codegen/src/mutations.rs +1 -1
- data/rust/codegen/src/naming.rs +5 -3
- data/rust/codegen/src/optional_pass.rs +226 -0
- data/rust/codegen/src/ports.rs +1 -1
- data/rust/codegen/src/queries.rs +3 -3
- data/rust/codegen/src/reactions.rs +1 -1
- data/rust/codegen/src/read_models.rs +2 -2
- data/rust/codegen/src/reference_specs.rs +1 -1
- data/rust/codegen/src/registry.rs +4 -4
- data/rust/codegen/src/shared.rs +1 -1
- data/rust/{build → codegen}/src/sidecars.rs +9 -5
- data/rust/codegen/src/skip_reason.rs +1 -1
- data/rust/codegen/src/types.rs +4 -4
- data/rust/host/HECKS_RELEASE +1 -1
- data/rust/host/src/api.rs +1 -1
- data/rust/host/src/dispatch.rs +5 -0
- data/rust/host/src/needs.rs +193 -29
- data/rust/host/src/resend.rs +4 -4
- data/rust/host/src/ui_schema.rs +1 -1
- data/rust/parser/src/emit.rs +12 -0
- data/rust/parser/src/ir.rs +2 -0
- data/rust/parser/src/keywords.rs +2 -0
- data/rust/parser/src/main.rs +1 -0
- data/rust/parser/src/parse/command.rs +2 -44
- data/rust/parser/src/parse/mod.rs +1 -0
- data/rust/parser/src/parse/needs.rs +60 -0
- data/rust/parser/src/parse/query.rs +3 -0
- data/rust/src/exemplar/commands.rs +1 -1
- data/rust/src/exemplar/constraints.rs +1 -1
- data/rust/src/exemplar/fielded.rs +1 -1
- data/rust/src/exemplar/json.rs +1 -1
- data/rust/src/exemplar/mod.rs +1 -1
- data/rust/src/exemplar/mutations.rs +1 -1
- data/rust/src/exemplar/queries.rs +1 -1
- data/rust/src/exemplar/reactions.rs +1 -1
- data/rust/src/exemplar/read_models.rs +1 -1
- data/rust/src/exemplar/registry.rs +1 -1
- data/rust/src/exemplar/types.rs +1 -1
- data/rust/src/kernel/cli.rs +18 -8
- data/rust/src/kernel/needs.rs +104 -9
- data/rust/src/kernel/read_model.rs +1 -1
- data/rust/src/lib.rs +1 -1
- metadata +24 -30
- data/lib/hecks/rust_build/append_optionals.rb +0 -79
- data/lib/hecks/rust_build/rust_literal.rb +0 -33
- data/lib/hecks/three_zero/forms.yml +0 -127
- data/lib/hecks/three_zero.rb +0 -12
- data/rust/build/src/json.rs +0 -421
- data/rust/build/src/optional_pass.rs +0 -150
- data/rust/project/bridging.rb +0 -257
- data/rust/project/commands.rb +0 -877
- data/rust/project/constraints.rb +0 -86
- data/rust/project/dependency_planning.rb +0 -178
- data/rust/project/domain_generator.rb +0 -983
- data/rust/project/exemplar.rb +0 -148
- data/rust/project/expr_emitter.rb +0 -72
- data/rust/project/fielded.rb +0 -141
- data/rust/project/json_codec.rb +0 -641
- data/rust/project/mutations.rb +0 -695
- data/rust/project/naming.rb +0 -223
- data/rust/project/ports.rb +0 -65
- data/rust/project/queries.rb +0 -493
- data/rust/project/reactions.rb +0 -317
- data/rust/project/read_models.rb +0 -690
- data/rust/project/reference_specs.rb +0 -27
- data/rust/project/registry.rb +0 -396
- data/rust/project/skip_reason.rb +0 -29
- data/rust/project/types.rb +0 -225
- data/rust/project/write_if_changed.rb +0 -7
- data/rust/project.rb +0 -30
- data/rust/project_rust_pipeline.rb +0 -391
data/rust/project/naming.rb
DELETED
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
require "hecks/vocabulary"
|
|
2
|
-
require "hecks/bluebook/model_check"
|
|
3
|
-
require "hecks/rust_build/domain_name"
|
|
4
|
-
require "hecks/rust_build/rust_literal"
|
|
5
|
-
|
|
6
|
-
module RustProjection
|
|
7
|
-
# Domain-to-Rust codegen support: type mapping, reserved-name checks, and
|
|
8
|
-
# literal escaping shared by the Rust code generator.
|
|
9
|
-
module Projector
|
|
10
|
-
module_function
|
|
11
|
-
|
|
12
|
-
# Ruby has no single Boolean class, so a boolean attribute is declared
|
|
13
|
-
# TrueClass or FalseClass; both keys must map here.
|
|
14
|
-
SCALAR = { "String" => "String", "Integer" => "i64", "Float" => "f64",
|
|
15
|
-
"TrueClass" => "bool", "FalseClass" => "bool" }.freeze
|
|
16
|
-
SCALAR_KIND = { "String" => :string, "Integer" => :int, "Float" => :float,
|
|
17
|
-
"TrueClass" => :bool, "FalseClass" => :bool }.freeze
|
|
18
|
-
|
|
19
|
-
# A `Reference<X>` is represented as a plain `String` at the
|
|
20
|
-
# struct-field level — it's a bare id, not a nested object (see
|
|
21
|
-
# aggregates-and-value-objects.md's "Pointing at another aggregate").
|
|
22
|
-
def reference_type?(type_name) = type_name.to_s.start_with?("Reference<")
|
|
23
|
-
|
|
24
|
-
# Returns nil when `type_name` isn't a `Reference<...>` at all.
|
|
25
|
-
def reference_target(type_name)
|
|
26
|
-
match = type_name.to_s.match(/\AReference<(.+)>\z/)
|
|
27
|
-
match && match[1]
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def effective_scalar_type(type_name)
|
|
31
|
-
return "String" if reference_type?(type_name)
|
|
32
|
-
|
|
33
|
-
type_name if SCALAR.key?(type_name)
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def rust_type(type_name, list:)
|
|
37
|
-
scalar = effective_scalar_type(type_name)
|
|
38
|
-
inner = scalar ? SCALAR.fetch(scalar) : rust_ident(type_name)
|
|
39
|
-
list ? "Vec<#{inner}>" : inner
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def rust_ident(name) = name.to_s.gsub(/[^A-Za-z0-9]/, "")
|
|
43
|
-
def dispatch_fn_name(cmd) = cmd.gsub(/(?<=.)([A-Z])/, '_\1').downcase
|
|
44
|
-
|
|
45
|
-
# A field name plays two different roles in generated code: a
|
|
46
|
-
# string-literal match-arm/payload key (plain text) and a struct-field
|
|
47
|
-
# identifier (must be raw-escaped when it collides with a Rust
|
|
48
|
-
# keyword) — kept as separate functions so escaping only ever applies
|
|
49
|
-
# to the identifier role.
|
|
50
|
-
#
|
|
51
|
-
# Declared once as the `RustReservedWord` vocabulary;
|
|
52
|
-
# `hecks project_reserved_names` projects the same table into
|
|
53
|
-
# hecks-codegen's `reserved_names.rs`.
|
|
54
|
-
RUST_KEYWORDS = Hecks::Vocabulary.fetch("RustReservedWord")
|
|
55
|
-
|
|
56
|
-
# A domain's own name doubles as a directory, a bare Rust module
|
|
57
|
-
# identifier (module names get no raw-identifier escape hatch), and a
|
|
58
|
-
# Cargo `[features]` key. This list rules out the third: every key
|
|
59
|
-
# already used elsewhere in `rust/Cargo.toml` outside `[features]`,
|
|
60
|
-
# plus `default`, which Cargo itself reserves for the auto-enabled
|
|
61
|
-
# feature set.
|
|
62
|
-
#
|
|
63
|
-
# Declared once as the `CargoReservedName` vocabulary.
|
|
64
|
-
CARGO_RESERVED_DOMAIN_NAMES = Hecks::RustBuild::DomainName::CARGO_RESERVED
|
|
65
|
-
|
|
66
|
-
# Moved to `Hecks::RustBuild::DomainName`, which the codegen-backed `hecks project_rust` uses.
|
|
67
|
-
def valid_domain_mod_name?(name) = Hecks::RustBuild::DomainName.valid?(name)
|
|
68
|
-
|
|
69
|
-
# Identifier-shape check only (a PascalCase name always passes); whether
|
|
70
|
-
# the downcased name is a Rust keyword is `reserved_name_refusal`'s job,
|
|
71
|
-
# below. An aggregate name never doubles as a Cargo feature key.
|
|
72
|
-
def legal_aggregate_mod_identifier?(name)
|
|
73
|
-
name.to_s.downcase.match?(/\A[a-z_][a-z0-9_]*\z/)
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
# Returns nil when every name is usable, else the message
|
|
77
|
-
# `DomainGenerator.call` raises. Must return the identical string as
|
|
78
|
-
# hecks-codegen's `naming::reserved_name_refusal`
|
|
79
|
-
# (rust/codegen/src/naming.rs) for the same input.
|
|
80
|
-
def reserved_name_refusal(source_label, mod_name, aggregate_names)
|
|
81
|
-
names = aggregate_names.map(&:to_s)
|
|
82
|
-
reserved = Hecks::Bluebook::ModelCheck.rust_reserved_name_findings(aggregate_names: names, rust_target: true)
|
|
83
|
-
.map(&:subject)
|
|
84
|
-
refused = names.select { |name| reserved.include?(name) || !legal_aggregate_mod_identifier?(name) }
|
|
85
|
-
if refused.any?
|
|
86
|
-
return "#{source_label}: aggregate name(s) #{refused.map(&:inspect).join(', ')} can't be used as-is — " \
|
|
87
|
-
"downcased, each becomes a bare Rust module identifier (`pub mod #{refused.first.downcase};`) and a " \
|
|
88
|
-
"generated file name, and at least one is not a plain identifier or is a Rust keyword " \
|
|
89
|
-
"(RustReservedWord). Module names get no raw-identifier (r#name) escape hatch — rename the aggregate."
|
|
90
|
-
end
|
|
91
|
-
return nil if valid_domain_mod_name?(mod_name)
|
|
92
|
-
|
|
93
|
-
"#{source_label}: domain module name #{mod_name.to_s.inspect} can't be used as-is — it has to double as a Rust " \
|
|
94
|
-
"module identifier and a Cargo feature name, and this one is either not a plain lowercase identifier, is a " \
|
|
95
|
-
"Rust keyword (RustReservedWord), or is a reserved Cargo.toml key (CargoReservedName). Rename the domain."
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
# Every declared `name` in the IR, in document order. The `fields` maps under
|
|
99
|
-
# `mutations` are skipped: their keys are attribute names and their values
|
|
100
|
-
# are source text, not declarations. So is `translations`: an era edge names
|
|
101
|
-
# data paths (`attendee.first_name`, a backfill into a nested value object)
|
|
102
|
-
# that the host applies to stored rows and never writes into Rust.
|
|
103
|
-
def declared_names(node, out = [])
|
|
104
|
-
case node
|
|
105
|
-
when Hash
|
|
106
|
-
node.each do |key, value|
|
|
107
|
-
if %w[fields translations].include?(key.to_s)
|
|
108
|
-
next
|
|
109
|
-
elsif key.to_s == "name" && value.is_a?(String)
|
|
110
|
-
out << value
|
|
111
|
-
else
|
|
112
|
-
declared_names(value, out)
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
when Array
|
|
116
|
-
node.each { |item| declared_names(item, out) }
|
|
117
|
-
end
|
|
118
|
-
out
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
# Returns nil when every declared name is a plain identifier, else the
|
|
122
|
-
# message `DomainGenerator.call` raises. Attribute, command, event, query
|
|
123
|
-
# and port names are written into the generated crate as field, struct and
|
|
124
|
-
# function names, so a name like "a: String, pub evil: u8" would otherwise
|
|
125
|
-
# inject code into it. Must return the identical string as hecks-codegen's
|
|
126
|
-
# `naming::unsafe_name_refusal` (rust/codegen/src/naming.rs).
|
|
127
|
-
def unsafe_name_refusal(source_label, ir)
|
|
128
|
-
refused = declared_names(ir).uniq.reject { |name| name.match?(/\A[A-Za-z_][A-Za-z0-9_]*\z/) }
|
|
129
|
-
return nil if refused.empty?
|
|
130
|
-
|
|
131
|
-
"#{source_label}: declared name(s) #{refused.map(&:inspect).join(', ')} can't be used as-is — each is " \
|
|
132
|
-
"written into the generated Rust as an identifier, and at least one is not a plain identifier (letters, " \
|
|
133
|
-
"digits and underscores, not starting with a digit). Rename it in the bluebook."
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
# `r#crate`/`r#self`/`r#super`/`r#Self` are not valid raw-identifier
|
|
137
|
-
# syntax in Rust at all, so these four can't be escaped the way
|
|
138
|
-
# `rust_ident_field` escapes every other `RUST_KEYWORDS` entry.
|
|
139
|
-
RUST_UNESCAPABLE_KEYWORDS = %w[crate self super Self].freeze
|
|
140
|
-
|
|
141
|
-
def rust_field(name) = name.to_s
|
|
142
|
-
|
|
143
|
-
def rust_ident_field(name)
|
|
144
|
-
field = rust_field(name)
|
|
145
|
-
if RUST_UNESCAPABLE_KEYWORDS.include?(field)
|
|
146
|
-
raise "rust_ident_field(#{field.inspect}): #{field.inspect} is a Rust keyword that cannot be rescued by a raw " \
|
|
147
|
-
"identifier (r##{field} is not valid Rust syntax for crate/self/super/Self in any position) — rename " \
|
|
148
|
-
"the attribute/field in the bluebook."
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
RUST_KEYWORDS.include?(field) ? "r##{field}" : field
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
# Splits on any run of non-alphanumeric characters, since closed-set
|
|
155
|
-
# members can be glob patterns like `*.port`. `Self`, the one
|
|
156
|
-
# capitalized Rust keyword, is renamed by original casing (SelfType/
|
|
157
|
-
# SelfValue) so two different values can't collide into it.
|
|
158
|
-
def closed_set_variant(row)
|
|
159
|
-
_, value = row.first
|
|
160
|
-
variant = value.to_s.split(/[^A-Za-z0-9]+/).reject(&:empty?).map(&:capitalize).join
|
|
161
|
-
return variant unless variant == "Self"
|
|
162
|
-
|
|
163
|
-
value.to_s.start_with?("S") ? "SelfType" : "SelfValue"
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
def screaming_snake(name)
|
|
167
|
-
name.to_s.gsub(/([a-z0-9])([A-Z])/, '\1_\2').upcase
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
def scalar_to_value(type_name, rust_expr)
|
|
171
|
-
case type_name
|
|
172
|
-
when "String" then "Value::Str(#{rust_expr}.clone())"
|
|
173
|
-
when "Integer" then "Value::Int(#{rust_expr})"
|
|
174
|
-
when "Float" then "Value::Float(#{rust_expr})"
|
|
175
|
-
when "TrueClass", "FalseClass" then "Value::Bool(#{rust_expr})"
|
|
176
|
-
end
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
# True when `vo` can emit `Field::Nested(&self.x)`: any ordinary value
|
|
180
|
-
# object, or a single-field closed set (which has its own `Fielded`
|
|
181
|
-
# impl). False for a multi-field closed set, which has no `Fielded`
|
|
182
|
-
# impl to emit against.
|
|
183
|
-
def fielded_capable_nested?(vo)
|
|
184
|
-
!vo[:closed_set] || vo[:attributes].size == 1
|
|
185
|
-
end
|
|
186
|
-
|
|
187
|
-
# `Fielded` impl for a single-field closed set: answers "value" as its
|
|
188
|
-
# one field, matching the same arms the enum's own generated `to_json`
|
|
189
|
-
# already builds (reproduced here rather than shared, so it never
|
|
190
|
-
# touches the enum's existing to_json/from_json generation).
|
|
191
|
-
def emit_closed_set_fielded_impl(vo)
|
|
192
|
-
name = rust_ident(vo[:name])
|
|
193
|
-
arms = vo[:members].map do |row|
|
|
194
|
-
_, raw = row.first
|
|
195
|
-
"#{name}::#{closed_set_variant(row)} => #{rust_string_literal(raw.to_s)}.to_string(),"
|
|
196
|
-
end.join(" ")
|
|
197
|
-
|
|
198
|
-
"impl crate::kernel::Fielded for #{name} {\n " \
|
|
199
|
-
"fn field(&self, name: &str) -> Option<crate::kernel::Field<'_>> {\n " \
|
|
200
|
-
"use crate::kernel::{Field, Value};\n " \
|
|
201
|
-
"match name {\n " \
|
|
202
|
-
"\"value\" => Some(Field::Value(Value::Str(match self { #{arms} }))),\n " \
|
|
203
|
-
"_ => None,\n " \
|
|
204
|
-
"}\n " \
|
|
205
|
-
"}\n " \
|
|
206
|
-
"fn as_scalar(&self) -> Option<crate::kernel::Value> {\n " \
|
|
207
|
-
"match self.field(\"value\") { Some(crate::kernel::Field::Value(v)) => Some(v), _ => None }\n " \
|
|
208
|
-
"}\n" \
|
|
209
|
-
"}"
|
|
210
|
-
end
|
|
211
|
-
|
|
212
|
-
def literal_rhs(literal)
|
|
213
|
-
case literal
|
|
214
|
-
when String then "#{rust_string_literal(literal)}.to_string()"
|
|
215
|
-
when Integer, Float, true, false then literal.to_s
|
|
216
|
-
else raise "unsupported literal mutation source #{literal.inspect} — not one of String/Integer/Float/Boolean"
|
|
217
|
-
end
|
|
218
|
-
end
|
|
219
|
-
|
|
220
|
-
# Moved to `Hecks::RustBuild::RustLiteral`, which the codegen-backed `hecks project_rust` uses.
|
|
221
|
-
def rust_string_literal(str) = Hecks::RustBuild::RustLiteral.string(str)
|
|
222
|
-
end
|
|
223
|
-
end
|
data/rust/project/ports.rb
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
require_relative "skip_reason"
|
|
2
|
-
|
|
3
|
-
module RustProjection
|
|
4
|
-
module Projector
|
|
5
|
-
module_function
|
|
6
|
-
|
|
7
|
-
# A port operation has no givens or mutations, so the only ungenerable shape left is an
|
|
8
|
-
# attribute type with no resolved Rust type.
|
|
9
|
-
def port_operation_skip_reason(operation, _owner_name, value_objects_by_name)
|
|
10
|
-
unresolved = operation[:attributes].reject do |attr|
|
|
11
|
-
next true if attr[:list] # a list attribute's element type is checked below
|
|
12
|
-
next true if reference_type?(attr[:type])
|
|
13
|
-
next true if SCALAR.key?(attr[:type])
|
|
14
|
-
|
|
15
|
-
value_objects_by_name.key?(attr[:type])
|
|
16
|
-
end
|
|
17
|
-
return skip("port_attribute_type", "attribute type(s) #{unresolved.map { |a| a[:type] }.uniq.join(', ')} not generated yet " \
|
|
18
|
-
"(a value object this aggregate's own attributes never resolved a Rust type for)") if unresolved.any?
|
|
19
|
-
|
|
20
|
-
nil
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
# Emits the args struct and a pure dispatch function that builds the events the operation
|
|
24
|
-
# `emits`, addressed by `receiver_id`. Payloads are `Json::Null` placeholders; the registry's
|
|
25
|
-
# `stamp_payload` replaces them. A self-reference to the owner is left out of the args.
|
|
26
|
-
def emit_port_operation(operation, port_name, owner_name, domain_name, value_objects_by_name, aggregates_by_name)
|
|
27
|
-
args_struct = "#{rust_ident(port_name)}#{rust_ident(operation[:name])}Args"
|
|
28
|
-
qualified = "#{domain_name}::#{owner_name}"
|
|
29
|
-
fact_attrs = operation[:attributes].reject { |attr| reference_target(attr[:type]) == owner_name }
|
|
30
|
-
|
|
31
|
-
struct_lines = ["pub struct #{args_struct} {"]
|
|
32
|
-
fact_attrs.each do |attr|
|
|
33
|
-
type = rust_type(attr[:type], list: attr[:list])
|
|
34
|
-
type = "Option<#{type}>" if attr[:optional]
|
|
35
|
-
struct_lines << " #{Exemplar.render('struct_field', 'TmplFieldType' => type, 'tmpl_field' => rust_ident_field(attr[:name]))}"
|
|
36
|
-
end
|
|
37
|
-
struct_lines << "}"
|
|
38
|
-
|
|
39
|
-
invariant_checks = invariant_checks_for(operation, aggregates_by_name, value_objects_by_name)
|
|
40
|
-
fn = "#{port_name.downcase}_#{dispatch_fn_name(rust_ident(operation[:name]))}"
|
|
41
|
-
|
|
42
|
-
events = operation[:emits].map do |event_name|
|
|
43
|
-
" crate::kernel::Event { name: #{event_name.inspect}.to_string(), aggregate: #{qualified.inspect}.to_string(), " \
|
|
44
|
-
"id: receiver_id.to_string(), payload: crate::kernel::Json::Null, occurred_at: None, correlation: None },"
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
dispatch_fn = <<~RUST.rstrip
|
|
48
|
-
pub fn dispatch_operation_#{fn}(receiver_id: &str, args: #{args_struct}) -> Result<Vec<crate::kernel::Event>, crate::kernel::Refusal> {
|
|
49
|
-
#{invariant_checks.join("\n")}
|
|
50
|
-
Ok(vec![
|
|
51
|
-
#{events.join("\n")}
|
|
52
|
-
])
|
|
53
|
-
}
|
|
54
|
-
RUST
|
|
55
|
-
|
|
56
|
-
[
|
|
57
|
-
"#[derive(Debug, Clone)]\n#{struct_lines.join("\n")}",
|
|
58
|
-
emit_to_json_flat(args_struct, fact_attrs, value_objects_by_name),
|
|
59
|
-
emit_from_json_flat(args_struct, fact_attrs, value_objects_by_name, command_name: "#{port_name}.#{operation[:name]}",
|
|
60
|
-
interleave_checks: true, aggregates_by_name: aggregates_by_name),
|
|
61
|
-
dispatch_fn,
|
|
62
|
-
].join("\n\n")
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|