hecks 3.9.1 → 3.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/examples/pizzas/bluebook/pizzas.bluebook +29 -0
- data/examples/pizzas/bluebook/pizzas.hecksagon +7 -0
- data/exe/hecks +4 -4
- data/lib/hecks/adapters/driven/d1.rb +2 -10
- data/lib/hecks/adapters/driven/heki.adapter +1 -1
- data/lib/hecks/adapters/driven/heki.rb +2 -12
- data/lib/hecks/adapters/driven/lambda.adapter +1 -1
- data/lib/hecks/adapters/driven/lambda.rb +3 -18
- data/lib/hecks/adapters/driven/postgres.rb +4 -11
- data/lib/hecks/adapters/driven/sqlite.adapter +1 -1
- data/lib/hecks/adapters/driven/sqlite.rb +2 -10
- data/lib/hecks/adapters/driving/admission.rb +46 -0
- data/lib/hecks/adapters/driving/cli/nesting.rb +36 -0
- data/lib/hecks/adapters/driving/cli/shorthand.rb +88 -0
- data/lib/hecks/adapters/driving/cli.rb +127 -0
- data/lib/hecks/adapters/driving/cli_runner/answers.rb +160 -0
- data/lib/hecks/adapters/driving/cli_runner/resolution.rb +155 -0
- data/lib/hecks/adapters/driving/cli_runner/settling.rb +120 -0
- data/lib/hecks/adapters/driving/cli_runner/streaming.rb +93 -0
- data/lib/hecks/adapters/driving/cli_runner/suggestions.rb +47 -0
- data/lib/hecks/adapters/driving/cli_runner.rb +69 -0
- data/lib/hecks/adapters/driving/command_request.rb +121 -0
- data/lib/hecks/adapters/driving/handle.rb +214 -0
- data/lib/hecks/adapters/driving/json.rb +136 -0
- data/lib/hecks/adapters/driving/launcher_options.rb +267 -0
- data/lib/hecks/adapters/driving/mcp/properties.rb +49 -0
- data/lib/hecks/adapters/driving/mcp/tool_calls.rb +116 -0
- data/lib/hecks/adapters/driving/mcp/tool_definitions/auditing.rb +53 -0
- data/lib/hecks/adapters/driving/mcp/tool_definitions/calling.rb +71 -0
- data/lib/hecks/adapters/driving/mcp/tool_definitions/reading.rb +99 -0
- data/lib/hecks/adapters/driving/mcp/tool_definitions.rb +18 -0
- data/lib/hecks/adapters/driving/mcp.rb +159 -0
- data/lib/hecks/adapters/driving/mcp_guide_cache.rb +78 -0
- data/lib/hecks/adapters/driving/mcp_scope/argument_policy.rb +97 -0
- data/lib/hecks/adapters/driving/mcp_scope/env_problems.rb +69 -0
- data/lib/hecks/adapters/driving/mcp_scope/presenter.rb +83 -0
- data/lib/hecks/adapters/driving/mcp_scope.rb +213 -0
- data/lib/hecks/adapters/driving/ruby/aggregate_module.rb +171 -0
- data/lib/hecks/adapters/driving/ruby/chapter.rb +91 -0
- data/lib/hecks/adapters/driving/ruby.rb +83 -0
- data/lib/hecks/adapters/driving/usage_cache.rb +144 -0
- data/lib/hecks/{doors.rb → adapters/driving.rb} +10 -6
- data/lib/hecks/behaviors/expectations/boot.rb +1 -1
- data/lib/hecks/bench/ruby_runner.rb +1 -1
- data/lib/hecks/bluebook/ask_resolution.rb +130 -0
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +8 -2
- data/lib/hecks/bluebook/assembly/contracts/rules.rb +4 -2
- data/lib/hecks/bluebook/assembly/contracts/structure.rb +3 -1
- data/lib/hecks/bluebook/assembly/marks.rb +1 -0
- data/lib/hecks/bluebook/attribute.rb +1 -1
- data/lib/hecks/bluebook/behaviour/command.rb +13 -8
- data/lib/hecks/bluebook/behaviour/policy.rb +30 -0
- data/lib/hecks/bluebook/capabilities/attribute_values.rb +72 -0
- data/lib/hecks/bluebook/capabilities.rb +91 -9
- data/lib/hecks/bluebook/domain_port.rb +16 -4
- data/lib/hecks/bluebook/dsl/adapter_builder.rb +18 -6
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +13 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/computed_sources.rb +98 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/fan_out_rows.rb +42 -0
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/projected_fields.rb +14 -2
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/provisions.rb +69 -3
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation/with_projections.rb +17 -10
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +5 -0
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +2 -0
- data/lib/hecks/bluebook/dsl/command_builder/mutations.rb +8 -1
- data/lib/hecks/bluebook/dsl/command_builder/operands.rb +121 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +2 -0
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +10 -1
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +45 -2
- data/lib/hecks/bluebook/dsl/policy_builder.rb +47 -10
- data/lib/hecks/bluebook/dsl/rule_reference.rb +7 -4
- data/lib/hecks/bluebook/dsl/world_builder.rb +1 -1
- data/lib/hecks/bluebook/expression/ast_json/emitters.rb +6 -0
- data/lib/hecks/bluebook/expression/ast_json.rb +9 -6
- data/lib/hecks/bluebook/expression/ast_reader.rb +14 -9
- data/lib/hecks/bluebook/expression/projection.json +36 -0
- data/lib/hecks/bluebook/expression/resolver/operations.rb +31 -0
- data/lib/hecks/bluebook/expression/resolver/parsing.rb +38 -5
- data/lib/hecks/bluebook/expression/resolver/scanning.rb +22 -5
- data/lib/hecks/bluebook/expression/resolver/values.rb +10 -0
- data/lib/hecks/bluebook/expression/resolver.rb +20 -1
- data/lib/hecks/bluebook/hecksagon.rb +23 -3
- data/lib/hecks/bluebook/lifecycle.rb +22 -3
- data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +13 -1
- data/lib/hecks/bluebook/meta_validator/modes.rb +4 -1
- data/lib/hecks/bluebook/meta_validator/readings.rb +18 -1
- data/lib/hecks/bluebook/meta_validator/reconstruction/heads.rb +2 -1
- data/lib/hecks/bluebook/meta_validator/shapes.rb +5 -0
- data/lib/hecks/bluebook/meta_validator/verdict_cache.rb +1 -1
- data/lib/hecks/bluebook/meta_validator.rb +12 -12
- data/lib/hecks/bluebook/model_check/ask_checks.rb +71 -0
- data/lib/hecks/bluebook/model_check/policy_checks.rb +2 -1
- data/lib/hecks/bluebook/model_check/reference_checks.rb +70 -0
- data/lib/hecks/bluebook/model_check.rb +8 -2
- data/lib/hecks/bluebook/policy.rb +4 -2
- data/lib/hecks/bluebook/smoke_test.rb +1 -1
- data/lib/hecks/bluebook/synthesizer.rb +2 -0
- data/lib/hecks/bluebook.rb +1 -0
- data/lib/hecks/cli/command_table.rb +1 -1
- data/lib/hecks/cli/console.rb +2 -1
- data/lib/hecks/cli/document.rb +1 -1
- data/lib/hecks/cli/launcher_words.rb +4 -4
- data/lib/hecks/cli/mcp.rb +4 -4
- data/lib/hecks/cli/project_cli/launcher_source.rb +2 -2
- data/lib/hecks/cli/project_cli/templates.rb +5 -5
- data/lib/hecks/cli/project_cli.rb +9 -6
- data/lib/hecks/cli/run.rb +2 -2
- data/lib/hecks/cli/smoke_http/checks.rb +4 -1
- data/lib/hecks/cli/smoke_http/transport.rb +3 -3
- data/lib/hecks/cli/smoke_http.rb +3 -0
- data/lib/hecks/codemod.rb +5 -2
- data/lib/hecks/corpus/routes.rb +7 -0
- data/lib/hecks/corpus/rust.rb +3 -2
- data/lib/hecks/deploy/bluebook/deploy.bluebook +124 -2
- data/lib/hecks/deploy/bluebook/deploy.hecksagon +8 -0
- data/lib/hecks/deploy/oidc.json +16 -3
- data/lib/hecks/doc/reference/rendering.rb +6 -3
- data/lib/hecks/forms/app/commands.rb +8 -7
- data/lib/hecks/forms/app/queries.rb +2 -1
- data/lib/hecks/forms/app.rb +1 -1
- data/lib/hecks/forms/record_renderer.rb +1 -1
- data/lib/hecks/framework/bluebook/privacy.bluebook +11 -0
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +4 -1
- data/lib/hecks/fuzzing/failure_triage.rb +2 -1
- data/lib/hecks/fuzzing/mutation/run.rb +11 -4
- data/lib/hecks/fuzzing/properties/catalog.rb +6 -4
- data/lib/hecks/fuzzing/properties/guaranteed_by_construction.rb +18 -11
- data/lib/hecks/fuzzing/properties/guards.rb +1 -1
- data/lib/hecks/fuzzing/self_consistency/saga_redelivery.rb +1 -1
- data/lib/hecks/fuzzing/self_consistency.rb +6 -2
- data/lib/hecks/fuzzing/shrinker.rb +3 -1
- data/lib/hecks/fuzzing/value_generator.rb +19 -5
- data/lib/hecks/gate/stages.yml +4 -10
- data/lib/hecks/grammar/evolve.rb +1 -1
- data/lib/hecks/grammar/expression_operators.json +372 -0
- data/lib/hecks/grammar/operators.rb +3 -1
- data/lib/hecks/hecks/adapters/codebase/corpus_tasks.rb +10 -10
- data/lib/hecks/hecks/adapters/codebase/inspection/rubycritic.rb +35 -0
- data/lib/hecks/hecks/adapters/codebase/inspection.rb +104 -0
- data/lib/hecks/hecks/adapters/codebase/publishing.rb +2 -1
- data/lib/hecks/hecks/adapters/codebase/release_facts.rb +12 -2
- data/lib/hecks/hecks/adapters/codebase/source_tree.rb +2 -1
- data/lib/hecks/hecks/adapters/codebase/test_runner.rb +1 -1
- data/lib/hecks/hecks/adapters/cost_explorer.rb +8 -5
- data/lib/hecks/hecks/adapters/deploy_toolchain/clearing.rb +51 -0
- data/lib/hecks/hecks/adapters/deploy_toolchain/statuses.rb +2 -1
- data/lib/hecks/hecks/adapters/deploy_toolchain.rb +2 -0
- data/lib/hecks/hecks/adapters/finding_github.rb +13 -6
- data/lib/hecks/hecks/adapters/first_admin.rb +2 -2
- data/lib/hecks/hecks/adapters/github_rulesets.rb +6 -3
- data/lib/hecks/hecks/adapters/in_process_boot.rb +1 -1
- data/lib/hecks/hecks/adapters/journal_store/compaction.rb +1 -1
- data/lib/hecks/hecks/adapters/journal_store/edge_audit.rb +10 -20
- data/lib/hecks/hecks/adapters/journal_store/held_domain.rb +28 -5
- data/lib/hecks/hecks/adapters/local_files.rb +2 -2
- data/lib/hecks/hecks/adapters/rehearsal/audit_report.rb +107 -0
- data/lib/hecks/hecks/adapters/rehearsal/census.rb +71 -0
- data/lib/hecks/hecks/adapters/rehearsal/declaration.rb +133 -0
- data/lib/hecks/hecks/adapters/rehearsal/environment.rb +83 -0
- data/lib/hecks/hecks/adapters/rehearsal/inquiry.rb +142 -0
- data/lib/hecks/hecks/adapters/rehearsal/memory_store.rb +96 -0
- data/lib/hecks/hecks/adapters/rehearsal/postgres_census.rb +100 -0
- data/lib/hecks/hecks/adapters/rehearsal/postgres_reading.rb +69 -0
- data/lib/hecks/hecks/adapters/rehearsal/postgres_store.rb +129 -0
- data/lib/hecks/hecks/adapters/rehearsal/rows.rb +41 -0
- data/lib/hecks/hecks/adapters/rehearsal/rust_audit.rb +83 -0
- data/lib/hecks/hecks/adapters/rehearsal/subject.rb +104 -0
- data/lib/hecks/hecks/adapters/rehearsal.rb +54 -0
- data/lib/hecks/hecks/adapters/rehearsal_store.adapter +7 -0
- data/lib/hecks/hecks/adapters/rehearsal_store.rb +81 -0
- data/lib/hecks/hecks/adapters/site_toolchain/role_prober.rb +78 -0
- data/lib/hecks/hecks/adapters/site_toolchain.rb +29 -4
- data/lib/hecks/hecks/adapters/terminal.rb +13 -11
- data/lib/hecks/hecks/adapters/world_clearing.rb +65 -0
- data/lib/hecks/hecks/codebase.behaviors +13 -1
- data/lib/hecks/hecks/codebase.bluebook +239 -5
- data/lib/hecks/hecks/custodian.behaviors +24 -6
- data/lib/hecks/hecks/custodian.bluebook +6 -1227
- data/lib/hecks/hecks/deploy.behaviors +1 -1
- data/lib/hecks/hecks/deploy.world +1 -3
- data/lib/hecks/hecks/hecks.behaviors +1 -1
- data/lib/hecks/hecks/hecks.hecksagon +61 -18
- data/lib/hecks/hecks/hecks.world +11 -10
- data/lib/hecks/hecks/rehearsal.bluebook +477 -0
- data/lib/hecks/hecks/site.behaviors +1 -1
- data/lib/hecks/hecks/site.world +0 -1
- data/lib/hecks/hecks/tooling.bluebook +1238 -0
- data/lib/hecks/indifferent_key.rb +20 -0
- data/lib/hecks/language/adapter.bluebook +13 -3
- data/lib/hecks/language/bluebook/aggregate.bluebook +23 -0
- data/lib/hecks/language/bluebook/bluebook.bluebook +15 -0
- data/lib/hecks/language/bluebook/entity.bluebook +18 -0
- data/lib/hecks/language/bluebook/policy.bluebook +9 -1
- data/lib/hecks/language/bluebook/query.bluebook +1 -1
- data/lib/hecks/language/bluebook/vocabulary.bluebook +11 -4
- data/lib/hecks/language/hecksagon/domain_port.bluebook +1 -1
- data/lib/hecks/language/hecksagon/hecksagon.bluebook +22 -0
- data/lib/hecks/language/oidc.json +10 -0
- data/lib/hecks/language/port.bluebook +4 -4
- data/lib/hecks/literal.rb +12 -3
- data/lib/hecks/ports/key_vault.rb +7 -2
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +21 -10
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/boot.rb +4 -2
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +2 -1
- data/lib/hecks/ports/persistence/repository_factory.rb +6 -3
- data/lib/hecks/projections/deploy/box/templates/deploy-box.sh.tmpl +29 -0
- data/lib/hecks/projections/deploy/box/templates/deploy-service.sh.tmpl +1 -1
- data/lib/hecks/projections/deploy/fargate/settings/tuning.rb +15 -0
- data/lib/hecks/projections/deploy/fargate/settings.rb +3 -1
- data/lib/hecks/projections/deploy/fargate/stack/readers.rb +1 -0
- data/lib/hecks/projections/deploy/preview/preview.sh.erb +1 -1
- data/lib/hecks/projections/deploy/shared.rb +5 -2
- data/lib/hecks/projections/deploy/templates/fargate/Makefile.tmpl +7 -4
- data/lib/hecks/projections/model/deviations.rb +2 -2
- data/lib/hecks/projections/model.rb +2 -2
- data/lib/hecks/projections/oidc.rb +13 -1
- data/lib/hecks/projections/shape.rb +5 -2
- data/lib/hecks/projections/site/cms_editor/attributes.rb +95 -0
- data/lib/hecks/projections/site/cms_editor/blocks.rb +157 -0
- data/lib/hecks/projections/site/cms_editor/checks.rb +77 -0
- data/lib/hecks/projections/site/cms_editor/clearing.rb +70 -0
- data/lib/hecks/projections/site/cms_editor/color.rb +124 -0
- data/lib/hecks/projections/site/cms_editor/composition.rb +42 -0
- data/lib/hecks/projections/site/cms_editor/destructive.rb +61 -0
- data/lib/hecks/projections/site/cms_editor/drafts.rb +102 -0
- data/lib/hecks/projections/site/cms_editor/hints.rb +74 -0
- data/lib/hecks/projections/site/cms_editor/icons.rb +86 -0
- data/lib/hecks/projections/site/cms_editor/key_kinds.rb +31 -0
- data/lib/hecks/projections/site/cms_editor/limits.rb +72 -0
- data/lib/hecks/projections/site/cms_editor/media.rb +85 -0
- data/lib/hecks/projections/site/cms_editor/moment.rb +34 -0
- data/lib/hecks/projections/site/cms_editor/palette.rb +115 -0
- data/lib/hecks/projections/site/cms_editor/pickers.rb +85 -0
- data/lib/hecks/projections/site/cms_editor/pretty.rb +40 -0
- data/lib/hecks/projections/site/cms_editor/preview.rb +91 -0
- data/lib/hecks/projections/site/cms_editor/relations.rb +92 -0
- data/lib/hecks/projections/site/cms_editor/scale_checks.rb +66 -0
- data/lib/hecks/projections/site/cms_editor/scheduling.rb +150 -0
- data/lib/hecks/projections/site/cms_editor/schema.rb +161 -0
- data/lib/hecks/projections/site/cms_editor/setting.rb +130 -0
- data/lib/hecks/projections/site/cms_editor/targets.rb +86 -0
- data/lib/hecks/projections/site/cms_editor/templates/package.json.tmpl +36 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/app.ts.tmpl +370 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/assets.ts.tmpl +98 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/auth/membership.ts.tmpl +87 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/auth/session.ts.tmpl +36 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/auth/sso.ts.tmpl +20 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/app.css.tmpl +412 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/autosave.js.tmpl +144 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/blocks.js.tmpl +500 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/body_doc.js.tmpl +175 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/body_editor.js.tmpl +418 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/epoch.js.tmpl +61 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/forms.js.tmpl +210 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/lists.js.tmpl +40 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/main.js.tmpl +26 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/media_picker.js.tmpl +232 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/moments.js.tmpl +73 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/pickers.js.tmpl +152 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/preview.js.tmpl +98 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/shell.js.tmpl +140 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/browser/toast.js.tmpl +66 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/choices.ts.tmpl +99 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/commands.ts.tmpl +133 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/config.ts.tmpl +29 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/flash.ts.tmpl +52 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/host.ts.tmpl +43 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/media/handler.ts.tmpl +177 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/media/multipart.ts.tmpl +53 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/media/sniff.ts.tmpl +94 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/media/storage.ts.tmpl +50 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/names.ts.tmpl +36 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/schema.ts.tmpl +214 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/server.ts.tmpl +65 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/availability.ts.tmpl +15 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/block_list.js.tmpl +213 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/blocks.ts.tmpl +275 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/body_model.js.tmpl +123 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/body_parse.js.tmpl +320 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/detail.ts.tmpl +88 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/dialogs.ts.tmpl +43 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/fields.ts.tmpl +275 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/html.ts.tmpl +61 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/icons.ts.tmpl +15 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/input.ts.tmpl +92 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/links.ts.tmpl +100 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/moments.ts.tmpl +44 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/outline.ts.tmpl +63 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/pages.ts.tmpl +213 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/paging.ts.tmpl +82 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/pickers.ts.tmpl +110 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/preview.ts.tmpl +87 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/related.ts.tmpl +97 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/schedule.ts.tmpl +160 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/shell.ts.tmpl +211 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/table.ts.tmpl +151 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/theme.js.tmpl +16 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/values.ts.tmpl +69 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/words.ts.tmpl +97 -0
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/world.ts.tmpl +35 -0
- data/lib/hecks/projections/site/cms_editor/templates/tsconfig.json.tmpl +17 -0
- data/lib/hecks/projections/site/cms_editor/theme.rb +29 -0
- data/lib/hecks/projections/site/cms_editor/theme_checks.rb +57 -0
- data/lib/hecks/projections/site/cms_editor.rb +133 -0
- data/lib/hecks/projections/site/role_probe.rb +74 -0
- data/lib/hecks/projector/cli_audience.rb +2 -1
- data/lib/hecks/projector/cli_projector/listing.rb +1 -1
- data/lib/hecks/projector/cli_projector/option_specs.rb +1 -1
- data/lib/hecks/projector/docs_projector/closing.rb +1 -1
- data/lib/hecks/projector/docs_projector.rb +1 -1
- data/lib/hecks/projector/exporter/bindings.rb +40 -10
- data/lib/hecks/projector/exporter/capability_values.rb +55 -0
- data/lib/hecks/projector/narrate_projector/reactions.rb +1 -1
- data/lib/hecks/projector/target.rb +11 -0
- data/lib/hecks/projector.rb +32 -5
- data/lib/hecks/quality_control/adapters/github_checks.rb +12 -8
- data/lib/hecks/quality_control/adapters/github_issues.rb +8 -4
- data/lib/hecks/quality_control/cli/qa_open_pr.rb +2 -2
- data/lib/hecks/quality_control/cli/qa_sweep/checks/shrinking.rb +1 -1
- data/lib/hecks/quality_control/cli/qa_sweep/finding_report.rb +1 -1
- data/lib/hecks/quality_control/cli/qa_sweep.rb +1 -1
- data/lib/hecks/quality_control/quality_control.bluebook +6 -2
- data/lib/hecks/release/approval.rb +64 -0
- data/lib/hecks/router/{door.rb → aggregate_reader.rb} +5 -4
- data/lib/hecks/router/namespace_installer.rb +16 -16
- data/lib/hecks/router.rb +1 -1
- data/lib/hecks/runtime/best_effort.rb +22 -0
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +12 -2
- data/lib/hecks/runtime/command_interpreter.rb +3 -2
- data/lib/hecks/runtime/command_rules/emission.rb +1 -1
- data/lib/hecks/runtime/dispatcher.rb +4 -4
- data/lib/hecks/runtime/entity_element/location.rb +1 -1
- data/lib/hecks/runtime/event.rb +5 -0
- data/lib/hecks/runtime/identity.rb +7 -6
- data/lib/hecks/runtime/interpreting.rb +2 -1
- data/lib/hecks/runtime/invocation_builder.rb +1 -1
- data/lib/hecks/runtime/loader/boot_steps.rb +8 -5
- data/lib/hecks/runtime/loader.rb +10 -10
- data/lib/hecks/runtime/policy_interpreter/arguments.rb +7 -4
- data/lib/hecks/runtime/policy_interpreter/fan_out.rb +3 -3
- data/lib/hecks/runtime/policy_interpreter.rb +6 -6
- data/lib/hecks/runtime/port_operation_interpreter.rb +1 -1
- data/lib/hecks/runtime/reaction_invocation.rb +1 -1
- data/lib/hecks/runtime/rebuild_sweep.rb +11 -1
- data/lib/hecks/runtime/registry/ask_verification.rb +35 -0
- data/lib/hecks/runtime/registry/hecksagon_rules.rb +10 -0
- data/lib/hecks/runtime/registry/merging.rb +1 -1
- data/lib/hecks/runtime/registry/providers.rb +16 -0
- data/lib/hecks/runtime/registry/read_repository.rb +6 -4
- data/lib/hecks/runtime/registry/verification.rb +4 -1
- data/lib/hecks/runtime/registry/world_defaults.rb +29 -0
- data/lib/hecks/runtime/registry.rb +1 -1
- data/lib/hecks/runtime/saga_interpreter/compensation.rb +1 -1
- data/lib/hecks/runtime/saga_interpreter/delivery.rb +4 -4
- data/lib/hecks/runtime/saga_interpreter/transitions.rb +1 -1
- data/lib/hecks/runtime/saga_interpreter.rb +3 -3
- data/lib/hecks/runtime/tenant_check.rb +5 -4
- data/lib/hecks/runtime/value/coercion.rb +2 -2
- data/lib/hecks/runtime/value/validation.rb +16 -4
- data/lib/hecks/runtime.rb +9 -9
- data/lib/hecks/rust_build/project_rust/target_ir.rb +1 -1
- data/lib/hecks/rust_build/wasm.rb +1 -1
- data/lib/hecks/rust_build/wasm_browser.rb +1 -1
- data/lib/hecks/rust_build.rb +11 -0
- data/lib/hecks/served_options.rb +53 -0
- data/lib/hecks/site/bluebook/site.bluebook +29 -1
- data/lib/hecks/site/bluebook/site.ports.hecksagon +6 -0
- data/lib/hecks/storehouse/audit.rb +1 -1
- data/lib/hecks/storehouse/dispatching.rb +8 -6
- data/lib/hecks/storehouse/introspection.rb +2 -2
- data/lib/hecks/storehouse/querying.rb +6 -4
- data/lib/hecks/storehouse.rb +4 -4
- data/lib/hecks/tools/comment_style/source_file.rb +4 -1
- data/lib/hecks/tools/deploy_recipe_lint/fixtures.rb +4 -1
- data/lib/hecks/tools/lanes/rows.rb +6 -0
- data/lib/hecks/tools/oidc_manifests.rb +4 -5
- data/lib/hecks/tools/regeneration_run.rb +11 -4
- data/lib/hecks/tools/site_routes/cli.rb +1 -1
- data/lib/hecks/tools/site_routes/editor_files.rb +45 -0
- data/lib/hecks/tools/site_routes.rb +14 -7
- data/lib/hecks/tools/tenant_provisioning.rb +2 -2
- data/lib/hecks/tools/tools_doc.rb +4 -4
- data/lib/hecks/version.rb +1 -1
- data/lib/hecks/vocabulary.rb +4 -4
- data/lib/hecks.rb +15 -15
- data/lib/rubocop/cop/hecks/env_dump.rb +69 -0
- data/lib/rubocop/cop/hecks/monotonic_duration.rb +53 -0
- data/lib/rubocop/cop/hecks/no_wall_clock_in_runtime.rb +34 -0
- data/lib/rubocop/cop/hecks/raw_shell_interpolation.rb +79 -0
- data/lib/rubocop/cop/hecks/sleep_in_spec.rb +34 -0
- data/lib/rubocop/cop/hecks/swallowed_rescue.rb +37 -0
- data/lib/rubocop/cop/hecks/symbol_string_key_mix.rb +50 -0
- data/lib/rubocop/cop/hecks/untyped_raise.rb +37 -0
- data/prebuilt/05c358d38d661a3774f813d49c66f5b68939af94432d66257a56f49ee2598994.marshal +0 -0
- data/prebuilt/26c40c61f09b09b11651c64668eda3ceb180f83cf2a3802d3033d2fd99ac841b.marshal +0 -0
- data/prebuilt/verdicts-230ac18c25abfd3d92ede032bee2661a4c2cd2773ab0cf0e2ae52546ba2f7af9.json +1 -0
- data/rust/.gitignore +6 -0
- data/rust/Cargo.toml +9 -1
- data/rust/build/src/binding_pass.rs +103 -0
- data/rust/build/src/cargo_sync.rs +6 -0
- data/rust/build/src/lineage_pass.rs +3 -3
- data/rust/build/src/main.rs +17 -5
- data/rust/build/src/pipeline.rs +48 -5
- data/rust/build/src/seams_pass.rs +123 -0
- data/rust/build/src/translation_pass.rs +167 -0
- data/rust/codegen/src/asks.rs +103 -0
- data/rust/codegen/src/bridging.rs +1 -1
- data/rust/codegen/src/commands.rs +13 -8
- data/rust/codegen/src/constraints.rs +25 -0
- data/rust/codegen/src/domain_generator.rs +11 -9
- data/rust/codegen/src/expr_emitter.rs +13 -0
- data/rust/codegen/src/json_codec.rs +54 -15
- data/rust/codegen/src/main.rs +2 -1
- data/rust/codegen/src/mutations.rs +174 -4
- data/rust/codegen/src/naming.rs +30 -0
- data/rust/codegen/src/queries.rs +11 -2
- data/rust/codegen/src/reactions.rs +1 -1
- data/rust/codegen/src/types.rs +166 -8
- data/rust/host/HECKS_RELEASE +1 -1
- data/rust/host/src/api.rs +4 -4
- data/rust/host/src/bin/validate_harness.rs +43 -0
- data/rust/host/src/boundary_fuzz/expr_json.rs +2 -2
- data/rust/host/src/boundary_fuzz/ir.rs +1 -0
- data/rust/host/src/boundary_fuzz/server.rs +1 -1
- data/rust/host/src/checkout.rs +35 -19
- data/rust/host/src/commerce_ir.rs +408 -2
- data/rust/host/src/expr_json.rs +118 -0
- data/rust/host/src/mint.rs +1 -1
- data/rust/host/src/payments/tests.rs +27 -1
- data/rust/host/src/payments.rs +12 -4
- data/rust/host/src/query_step.rs +22 -4
- data/rust/host/src/reference_validate.rs +653 -108
- data/rust/host/src/resend.rs +2 -0
- data/rust/host/src/server.rs +19 -6
- data/rust/host/src/ui_schema.rs +132 -5
- data/rust/host/src/web/newsletter.rs +7 -8
- data/rust/host/src/web/newsletter_send.rs +38 -13
- data/rust/host/src/web/registrations.rs +229 -26
- data/rust/host/src/web.rs +3 -3
- data/rust/parser/src/emit.rs +38 -6
- data/rust/parser/src/expr/ast_json.rs +7 -1
- data/rust/parser/src/expr/resolver.rs +171 -6
- data/rust/parser/src/ir.rs +7 -0
- data/rust/parser/src/keywords.rs +24 -0
- data/rust/parser/src/main.rs +3 -0
- data/rust/parser/src/parse/aggregate.rs +2 -1
- data/rust/parser/src/parse/chapter.rs +2 -2
- data/rust/parser/src/parse/command.rs +2 -0
- data/rust/parser/src/parse/hecksagon.rs +5 -2
- data/rust/parser/src/parse/lifecycle.rs +81 -0
- data/rust/parser/src/parse/mod.rs +15 -1
- data/rust/parser/src/parse/policy.rs +13 -2
- data/rust/parser/src/parse/value_object.rs +13 -8
- data/rust/parser/src/ruby_value.rs +1 -1
- data/rust/src/exemplar/commands.rs +4 -4
- data/rust/src/exemplar/constraints.rs +1 -1
- data/rust/src/exemplar/json.rs +43 -1
- data/rust/src/kernel/cli.rs +7 -5
- data/rust/src/kernel/dispatch.rs +2 -2
- data/rust/src/kernel/dispatch_guard_tests.rs +1 -1
- data/rust/src/kernel/expr.rs +73 -4
- data/rust/src/kernel/expression_operators/arithmetic.rs +130 -5
- data/rust/src/kernel/expression_operators/presence.rs +41 -3
- data/rust/src/kernel/expression_operators/text.rs +26 -2
- data/rust/src/kernel/json.rs +15 -0
- data/rust/src/kernel/mod.rs +1 -1
- data/rust/src/kernel/orchestrate.rs +54 -5
- data/rust/src/kernel/orchestrate_guard_tests.rs +67 -0
- data/rust/src/kernel/pattern.rs +60 -0
- data/rust/src/kernel/reference_lookup.rs +90 -7
- metadata +174 -36
- data/lib/hecks/doors/cli_door/nesting.rb +0 -34
- data/lib/hecks/doors/cli_door/shorthand.rb +0 -85
- data/lib/hecks/doors/cli_door.rb +0 -124
- data/lib/hecks/doors/cli_runner/answers.rb +0 -138
- data/lib/hecks/doors/cli_runner/resolution.rb +0 -146
- data/lib/hecks/doors/cli_runner/settling.rb +0 -115
- data/lib/hecks/doors/cli_runner/streaming.rb +0 -90
- data/lib/hecks/doors/cli_runner/suggestions.rb +0 -43
- data/lib/hecks/doors/cli_runner.rb +0 -66
- data/lib/hecks/doors/command_request.rb +0 -119
- data/lib/hecks/doors/handle.rb +0 -208
- data/lib/hecks/doors/json_door.rb +0 -132
- data/lib/hecks/doors/launcher_options.rb +0 -247
- data/lib/hecks/doors/mcp_door/properties.rb +0 -47
- data/lib/hecks/doors/mcp_door/tool_calls.rb +0 -113
- data/lib/hecks/doors/mcp_door/tool_definitions/auditing.rb +0 -51
- data/lib/hecks/doors/mcp_door/tool_definitions/calling.rb +0 -69
- data/lib/hecks/doors/mcp_door/tool_definitions/reading.rb +0 -97
- data/lib/hecks/doors/mcp_door/tool_definitions.rb +0 -15
- data/lib/hecks/doors/mcp_door.rb +0 -156
- data/lib/hecks/doors/mcp_door_scope/argument_policy.rb +0 -92
- data/lib/hecks/doors/mcp_door_scope/env_problems.rb +0 -55
- data/lib/hecks/doors/mcp_door_scope/presenter.rb +0 -78
- data/lib/hecks/doors/mcp_door_scope.rb +0 -201
- data/lib/hecks/doors/mcp_guide_cache.rb +0 -75
- data/lib/hecks/doors/ruby_door/aggregate_door.rb +0 -162
- data/lib/hecks/doors/ruby_door/chapter.rb +0 -89
- data/lib/hecks/doors/ruby_door.rb +0 -80
- data/lib/hecks/doors/usage_cache.rb +0 -139
- data/prebuilt/0ee7f83cba59ce7d1c45c65ba166b071779f70143449f584f33ff7989f64eccb.marshal +0 -0
- data/prebuilt/6e4a6bcf0aa880e2e6b056e1846b70e5a768090b9dc998bbadeaf5d6bcfd3db8.marshal +0 -0
- data/prebuilt/verdicts-91aaf93ce8981bd9a754948f075d95650dc2ec6435015376f5c60992b36a24b1.json +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//! Parses value expressions into a `Resolver` tree (port of `resolver.rb#parse`).
|
|
2
2
|
|
|
3
3
|
use super::evaluator::Evaluator;
|
|
4
|
-
use super::{find_operator,
|
|
4
|
+
use super::{find_operator, Operator};
|
|
5
5
|
|
|
6
6
|
/// Which of `all?`, `any?` or `none?` a block predicate uses.
|
|
7
7
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
@@ -39,6 +39,10 @@ pub enum Resolver {
|
|
|
39
39
|
BoolLiteral(bool),
|
|
40
40
|
NilLiteral,
|
|
41
41
|
Addition(Box<Resolver>, Box<Resolver>),
|
|
42
|
+
Subtraction(Box<Resolver>, Box<Resolver>),
|
|
43
|
+
Multiplication(Box<Resolver>, Box<Resolver>),
|
|
44
|
+
/// Integer operands floor toward negative infinity; a zero divisor is an evaluation fault.
|
|
45
|
+
Division(Box<Resolver>, Box<Resolver>),
|
|
42
46
|
SignTest { operator: Operator, receiver: Box<Resolver> },
|
|
43
47
|
Empty(Box<Resolver>),
|
|
44
48
|
ToS(Box<Resolver>),
|
|
@@ -57,6 +61,8 @@ pub enum Resolver {
|
|
|
57
61
|
Assignment { receiver: Box<Resolver>, negated: bool },
|
|
58
62
|
/// `receiver.split("sep")`: the separator is sliced verbatim between the quotes.
|
|
59
63
|
Split { receiver: Box<Resolver>, separator: String },
|
|
64
|
+
/// `receiver.strip` / `.lstrip` / `.rstrip`; `side` is `both`, `left` or `right`.
|
|
65
|
+
Strip { receiver: Box<Resolver>, side: &'static str },
|
|
60
66
|
/// `receiver.first`.
|
|
61
67
|
First(Box<Resolver>),
|
|
62
68
|
/// `receiver.last`.
|
|
@@ -100,8 +106,16 @@ pub fn parse(expr: &str) -> Resolver {
|
|
|
100
106
|
return Resolver::ArrayLiteral(elements.iter().map(|element| parse(element)).collect());
|
|
101
107
|
}
|
|
102
108
|
|
|
103
|
-
if let Some((left, right)) =
|
|
104
|
-
|
|
109
|
+
if let Some((operator, left, right)) = split_last_binary(expr, b"+-") {
|
|
110
|
+
let (left, right) = (Box::new(parse(left)), Box::new(parse(right)));
|
|
111
|
+
return if operator == b'+' { Resolver::Addition(left, right) } else { Resolver::Subtraction(left, right) };
|
|
112
|
+
}
|
|
113
|
+
if let Some((operator, left, right)) = split_last_binary(expr, b"*/") {
|
|
114
|
+
let (left, right) = (Box::new(parse(left)), Box::new(parse(right)));
|
|
115
|
+
return if operator == b'*' { Resolver::Multiplication(left, right) } else { Resolver::Division(left, right) };
|
|
116
|
+
}
|
|
117
|
+
if grouped(expr) {
|
|
118
|
+
return parse(&expr[1..expr.len() - 1]);
|
|
105
119
|
}
|
|
106
120
|
|
|
107
121
|
if let Some((receiver, test)) = match_suffix(expr, &SIGN_TESTS.map(|(s, _)| s)) {
|
|
@@ -139,6 +153,12 @@ pub fn parse(expr: &str) -> Resolver {
|
|
|
139
153
|
}
|
|
140
154
|
}
|
|
141
155
|
|
|
156
|
+
for (suffix, side) in [("strip", "both"), ("lstrip", "left"), ("rstrip", "right")] {
|
|
157
|
+
if let Some(inner) = strip_suffix_dotted(expr, suffix) {
|
|
158
|
+
return Resolver::Strip { receiver: Box::new(parse(inner)), side };
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
142
162
|
if let Some((receiver, separator)) = match_string_call(expr, "split") {
|
|
143
163
|
return Resolver::Split { receiver: Box::new(parse(receiver)), separator: separator.to_string() };
|
|
144
164
|
}
|
|
@@ -351,9 +371,118 @@ fn array_elements(expr: &str) -> Option<Vec<String>> {
|
|
|
351
371
|
Some(elements.into_iter().filter(|element| !element.is_empty()).collect())
|
|
352
372
|
}
|
|
353
373
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
374
|
+
/// The canonical text of an arithmetic expression over names and numbers, as the Ruby DSL prints
|
|
375
|
+
/// it: one space around each operator, parentheses only where the grouping needs them. `None` when
|
|
376
|
+
/// `expr` is not arithmetic, or holds anything but names and numbers.
|
|
377
|
+
pub fn arithmetic_text(expr: &str) -> Option<String> {
|
|
378
|
+
let node = parse(expr);
|
|
379
|
+
match node {
|
|
380
|
+
Resolver::Addition(..) | Resolver::Subtraction(..) | Resolver::Multiplication(..) | Resolver::Division(..) => render_arithmetic(&node),
|
|
381
|
+
_ => None,
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
fn render_arithmetic(node: &Resolver) -> Option<String> {
|
|
386
|
+
match node {
|
|
387
|
+
Resolver::Addition(l, r) => render_binary(l, '+', r),
|
|
388
|
+
Resolver::Subtraction(l, r) => render_binary(l, '-', r),
|
|
389
|
+
Resolver::Multiplication(l, r) => render_binary(l, '*', r),
|
|
390
|
+
Resolver::Division(l, r) => render_binary(l, '/', r),
|
|
391
|
+
Resolver::Lookup(path) => Some(path.clone()),
|
|
392
|
+
Resolver::IntegerLiteral(n) => Some(n.to_string()),
|
|
393
|
+
Resolver::FloatLiteral(f) => Some(crate::ruby_value::format_ruby_float(*f)),
|
|
394
|
+
_ => None,
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
fn binding_strength(operator: char) -> u8 {
|
|
399
|
+
if matches!(operator, '*' | '/') { 2 } else { 1 }
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
fn node_strength(node: &Resolver) -> u8 {
|
|
403
|
+
match node {
|
|
404
|
+
Resolver::Addition(..) | Resolver::Subtraction(..) => 1,
|
|
405
|
+
Resolver::Multiplication(..) | Resolver::Division(..) => 2,
|
|
406
|
+
_ => 0,
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// A joined side is parenthesised when it binds looser than the operator, or equally on the right,
|
|
411
|
+
// so the printed text parses back to the same grouping.
|
|
412
|
+
fn render_binary(left: &Resolver, operator: char, right: &Resolver) -> Option<String> {
|
|
413
|
+
let strength = binding_strength(operator);
|
|
414
|
+
let side = |node: &Resolver, on_right: bool| -> Option<String> {
|
|
415
|
+
let text = render_arithmetic(node)?;
|
|
416
|
+
let held = node_strength(node);
|
|
417
|
+
Some(if held != 0 && (held < strength || (on_right && held == strength)) { format!("({text})") } else { text })
|
|
418
|
+
};
|
|
419
|
+
Some(format!("{} {operator} {}", side(left, false)?, side(right, true)?))
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/// The operator and the texts either side of the LAST top-level binary operator in `operators`, so
|
|
423
|
+
/// a chain splits left-associatively. A `-` is binary only after an operand (`a - b`, not `a - -b`
|
|
424
|
+
/// or a leading `-5`). Brackets of every kind count toward depth, quotes hide their contents.
|
|
425
|
+
fn split_last_binary<'a>(expr: &'a str, operators: &[u8]) -> Option<(u8, &'a str, &'a str)> {
|
|
426
|
+
let bytes = expr.as_bytes();
|
|
427
|
+
let mut depth: i32 = 0;
|
|
428
|
+
let mut quote: Option<u8> = None;
|
|
429
|
+
let mut found: Option<usize> = None;
|
|
430
|
+
|
|
431
|
+
for (index, &byte) in bytes.iter().enumerate() {
|
|
432
|
+
if let Some(open) = quote {
|
|
433
|
+
if byte == open {
|
|
434
|
+
quote = None;
|
|
435
|
+
}
|
|
436
|
+
continue;
|
|
437
|
+
}
|
|
438
|
+
match byte {
|
|
439
|
+
b'"' | b'\'' => quote = Some(byte),
|
|
440
|
+
b'(' | b'{' | b'[' => depth += 1,
|
|
441
|
+
b')' | b'}' | b']' => depth -= 1,
|
|
442
|
+
_ if depth == 0 && operators.contains(&byte) && binary_position(bytes, index) => found = Some(index),
|
|
443
|
+
_ => {}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
found.map(|index| (bytes[index], expr[..index].trim(), expr[index + 1..].trim()))
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// Only `-` can also be a sign, so it needs an operand ending on its left.
|
|
450
|
+
fn binary_position(bytes: &[u8], index: usize) -> bool {
|
|
451
|
+
if bytes[index] != b'-' {
|
|
452
|
+
return true;
|
|
453
|
+
}
|
|
454
|
+
let before = bytes[..index].iter().rev().find(|b| !b.is_ascii_whitespace());
|
|
455
|
+
matches!(before, Some(b) if b.is_ascii_alphanumeric() || matches!(b, b'_' | b')' | b']' | b'"' | b'\''))
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/// Whether `expr` is one parenthesised group: its first `(` closes at its last character.
|
|
459
|
+
fn grouped(expr: &str) -> bool {
|
|
460
|
+
let bytes = expr.as_bytes();
|
|
461
|
+
if bytes.first() != Some(&b'(') || bytes.last() != Some(&b')') {
|
|
462
|
+
return false;
|
|
463
|
+
}
|
|
464
|
+
let mut depth: i32 = 0;
|
|
465
|
+
let mut quote: Option<u8> = None;
|
|
466
|
+
for (index, &byte) in bytes.iter().enumerate() {
|
|
467
|
+
if let Some(open) = quote {
|
|
468
|
+
if byte == open {
|
|
469
|
+
quote = None;
|
|
470
|
+
}
|
|
471
|
+
continue;
|
|
472
|
+
}
|
|
473
|
+
match byte {
|
|
474
|
+
b'"' | b'\'' => quote = Some(byte),
|
|
475
|
+
b'(' => depth += 1,
|
|
476
|
+
b')' => {
|
|
477
|
+
depth -= 1;
|
|
478
|
+
if depth == 0 {
|
|
479
|
+
return index == bytes.len() - 1;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
_ => {}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
false
|
|
357
486
|
}
|
|
358
487
|
|
|
359
488
|
fn match_suffix<'a>(expr: &'a str, suffixes: &[&'a str]) -> Option<(&'a str, &'a str)> {
|
|
@@ -485,6 +614,9 @@ mod tests {
|
|
|
485
614
|
("a.set?", format!(r#"{{"op":"assignment","receiver":{a},"negated":false}}"#)),
|
|
486
615
|
("a.unset?", format!(r#"{{"op":"assignment","receiver":{a},"negated":true}}"#)),
|
|
487
616
|
("a.split(\"/\")", format!(r#"{{"op":"split","receiver":{a},"separator":"/"}}"#)),
|
|
617
|
+
("a.strip", format!(r#"{{"op":"strip","receiver":{a},"side":"both"}}"#)),
|
|
618
|
+
("a.lstrip", format!(r#"{{"op":"strip","receiver":{a},"side":"left"}}"#)),
|
|
619
|
+
("a.rstrip", format!(r#"{{"op":"strip","receiver":{a},"side":"right"}}"#)),
|
|
488
620
|
("a.first", format!(r#"{{"op":"first","receiver":{a}}}"#)),
|
|
489
621
|
("a.last", format!(r#"{{"op":"last","receiver":{a}}}"#)),
|
|
490
622
|
("a.start_with?(\"x\")", format!(r#"{{"op":"starts_with","receiver":{a},"substring":"x"}}"#)),
|
|
@@ -494,4 +626,37 @@ mod tests {
|
|
|
494
626
|
assert_eq!(compact(text), expected, "{text}");
|
|
495
627
|
}
|
|
496
628
|
}
|
|
629
|
+
|
|
630
|
+
#[test]
|
|
631
|
+
fn splits_arithmetic_by_level_and_left_to_right() {
|
|
632
|
+
assert!(matches!(parse("a + b * c"), Resolver::Addition(..)));
|
|
633
|
+
assert!(matches!(parse("a - b - c"), Resolver::Subtraction(left, _) if matches!(*left, Resolver::Subtraction(..))));
|
|
634
|
+
assert!(matches!(parse("a * b / c"), Resolver::Division(left, _) if matches!(*left, Resolver::Multiplication(..))));
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
#[test]
|
|
638
|
+
fn a_minus_is_binary_only_after_an_operand() {
|
|
639
|
+
assert!(matches!(parse("a - -5"), Resolver::Subtraction(_, right) if matches!(*right, Resolver::IntegerLiteral(-5))));
|
|
640
|
+
assert!(matches!(parse("-5"), Resolver::IntegerLiteral(-5)));
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
#[test]
|
|
644
|
+
fn a_parenthesised_group_reads_as_what_it_wraps() {
|
|
645
|
+
assert!(matches!(parse("(a + b) * c"), Resolver::Multiplication(left, _) if matches!(*left, Resolver::Addition(..))));
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
#[test]
|
|
649
|
+
fn prints_arithmetic_with_parentheses_only_where_the_grouping_needs_them() {
|
|
650
|
+
assert_eq!(arithmetic_text("a*b/100").as_deref(), Some("a * b / 100"));
|
|
651
|
+
assert_eq!(arithmetic_text("(a+b)*2").as_deref(), Some("(a + b) * 2"));
|
|
652
|
+
assert_eq!(arithmetic_text("a-(b-c)").as_deref(), Some("a - (b - c)"));
|
|
653
|
+
assert_eq!(arithmetic_text("(a*b)+c").as_deref(), Some("a * b + c"));
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
#[test]
|
|
657
|
+
fn text_that_is_not_arithmetic_over_names_and_numbers_prints_nothing() {
|
|
658
|
+
assert_eq!(arithmetic_text("paid"), None);
|
|
659
|
+
assert_eq!(arithmetic_text("a.size + 1"), None);
|
|
660
|
+
assert_eq!(arithmetic_text("\"x\""), None);
|
|
661
|
+
}
|
|
497
662
|
}
|
data/rust/parser/src/ir.rs
CHANGED
|
@@ -60,6 +60,8 @@ pub enum MutationSource {
|
|
|
60
60
|
Literal(crate::ruby_value::Value),
|
|
61
61
|
/// `state(:field)`: the record's own field, read from the pre-dispatch state.
|
|
62
62
|
State(String),
|
|
63
|
+
/// Arithmetic over argument names, record fields and numbers: its canonical text.
|
|
64
|
+
Expression(String),
|
|
63
65
|
}
|
|
64
66
|
|
|
65
67
|
#[derive(Debug, Clone)]
|
|
@@ -120,6 +122,8 @@ pub struct Lifecycle {
|
|
|
120
122
|
pub field: String,
|
|
121
123
|
pub default: String,
|
|
122
124
|
pub transitions: Vec<StateTransitionRow>,
|
|
125
|
+
// `mark :name, "state", ...`: each meaning and its states, in declared order.
|
|
126
|
+
pub marks: Vec<(String, Vec<String>)>,
|
|
123
127
|
}
|
|
124
128
|
|
|
125
129
|
#[derive(Debug, Clone, Default)]
|
|
@@ -285,6 +289,9 @@ pub struct Policy {
|
|
|
285
289
|
pub name: String,
|
|
286
290
|
pub on_event: Option<String>,
|
|
287
291
|
pub trigger_command: Option<String>,
|
|
292
|
+
// `ask :name`: the need, in the domain's words. Emitted in place of `trigger_command`; the
|
|
293
|
+
// hecksagon's declared asks say which port operation answers.
|
|
294
|
+
pub ask: Option<String>,
|
|
288
295
|
pub target_domain: Option<String>,
|
|
289
296
|
// `across "X", expect_undelivered: true`; emitted as a boolean, `false` when not declared.
|
|
290
297
|
pub expect_undelivered: bool,
|
data/rust/parser/src/keywords.rs
CHANGED
|
@@ -82,6 +82,7 @@ pub static KEYWORDS: &[KeywordRow] = &[
|
|
|
82
82
|
KeywordRow { word: "given", context: "Aggregate", body: "source", inner: "", opens: "", fills: "preconditions", status: "admitted", was: "", resolves_via: "owner_keyed", disambiguator: "declared_by" },
|
|
83
83
|
KeywordRow { word: "projects", context: "Aggregate", body: "none", inner: "", opens: "", fills: "projected_fields", status: "admitted", was: "", resolves_via: "", disambiguator: "" },
|
|
84
84
|
KeywordRow { word: "transition", context: "Lifecycle", body: "none", inner: "", opens: "", fills: "transitions", status: "admitted", was: "", resolves_via: "", disambiguator: "" },
|
|
85
|
+
KeywordRow { word: "mark", context: "Lifecycle", body: "none", inner: "", opens: "", fills: "marks", status: "admitted", was: "", resolves_via: "", disambiguator: "" },
|
|
85
86
|
KeywordRow { word: "bluebook", context: "File", body: "keywords", inner: "Bluebook", opens: "Bluebook", fills: "", status: "admitted", was: "", resolves_via: "", disambiguator: "" },
|
|
86
87
|
KeywordRow { word: "vision", context: "Bluebook", body: "none", inner: "", opens: "", fills: "vision", status: "admitted", was: "", resolves_via: "", disambiguator: "" },
|
|
87
88
|
KeywordRow { word: "formerly_known_as", context: "Bluebook", body: "none", inner: "", opens: "", fills: "formerly_known_as", status: "admitted", was: "", resolves_via: "", disambiguator: "" },
|
|
@@ -125,6 +126,7 @@ pub static KEYWORDS: &[KeywordRow] = &[
|
|
|
125
126
|
KeywordRow { word: "entity", context: "Entity", body: "keywords", inner: "Entity", opens: "Entity", fills: "", status: "admitted", was: "", resolves_via: "", disambiguator: "" },
|
|
126
127
|
KeywordRow { word: "on", context: "Policy", body: "none", inner: "", opens: "", fills: "on_event", status: "admitted", was: "", resolves_via: "", disambiguator: "" },
|
|
127
128
|
KeywordRow { word: "trigger", context: "Policy", body: "none", inner: "", opens: "", fills: "trigger_command", status: "admitted", was: "", resolves_via: "", disambiguator: "" },
|
|
129
|
+
KeywordRow { word: "ask", context: "Policy", body: "none", inner: "", opens: "", fills: "ask", status: "admitted", was: "", resolves_via: "", disambiguator: "" },
|
|
128
130
|
KeywordRow { word: "across", context: "Policy", body: "none", inner: "", opens: "", fills: "target_domain", status: "admitted", was: "", resolves_via: "", disambiguator: "" },
|
|
129
131
|
KeywordRow { word: "where", context: "Policy", body: "source", inner: "", opens: "", fills: "where", status: "admitted", was: "", resolves_via: "", disambiguator: "" },
|
|
130
132
|
KeywordRow { word: "for_each", context: "Policy", body: "none", inner: "", opens: "", fills: "for_each", status: "admitted", was: "", resolves_via: "", disambiguator: "" },
|
|
@@ -184,6 +186,7 @@ pub static KEYWORDS: &[KeywordRow] = &[
|
|
|
184
186
|
KeywordRow { word: "hecksagon", context: "File", body: "keywords", inner: "Hecksagon", opens: "Hecksagon", fills: "", status: "admitted", was: "", resolves_via: "", disambiguator: "" },
|
|
185
187
|
KeywordRow { word: "subscribe", context: "Hecksagon", body: "none", inner: "", opens: "", fills: "subscriptions", status: "admitted", was: "", resolves_via: "", disambiguator: "" },
|
|
186
188
|
KeywordRow { word: "attaches", context: "Hecksagon", body: "none", inner: "", opens: "", fills: "attachments", status: "admitted", was: "", resolves_via: "", disambiguator: "" },
|
|
189
|
+
KeywordRow { word: "driven_by", context: "Hecksagon", body: "none", inner: "", opens: "", fills: "driving", status: "admitted", was: "", resolves_via: "", disambiguator: "" },
|
|
187
190
|
KeywordRow { word: "port", context: "Hecksagon", body: "keywords", inner: "DomainPort", opens: "DomainPort", fills: "", status: "admitted", was: "", resolves_via: "", disambiguator: "" },
|
|
188
191
|
KeywordRow { word: "translates", context: "Hecksagon", body: "keywords", inner: "Policy", opens: "Policy", fills: "", status: "admitted", was: "", resolves_via: "", disambiguator: "" },
|
|
189
192
|
KeywordRow { word: "bounded", context: "Hecksagon", body: "none", inner: "", opens: "", fills: "", status: "admitted", was: "", resolves_via: "", disambiguator: "" },
|
|
@@ -263,6 +266,8 @@ pub static ARGUMENTS: &[ArgumentRow] = &[
|
|
|
263
266
|
ArgumentRow { keyword: "transition", context: "Lifecycle", at: "1", named: "", kind: "pairs", required: "true", fills: "", selects: "", pair_key_fills: "command", pair_value_fills: "to_state", pairs_shape: "fields", status: "admitted", variadic: "", minimum: "" },
|
|
264
267
|
ArgumentRow { keyword: "transition", context: "Lifecycle", at: "", named: "from", kind: "text", required: "false", fills: "from_state", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
265
268
|
ArgumentRow { keyword: "transition", context: "Lifecycle", at: "", named: "from", kind: "list", required: "false", fills: "from_state", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
269
|
+
ArgumentRow { keyword: "mark", context: "Lifecycle", at: "1", named: "", kind: "symbol", required: "true", fills: "name", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
270
|
+
ArgumentRow { keyword: "mark", context: "Lifecycle", at: "2", named: "", kind: "text", required: "true", fills: "state", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "true", minimum: "" },
|
|
266
271
|
ArgumentRow { keyword: "bluebook", context: "File", at: "1", named: "", kind: "text", required: "true", fills: "name", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
267
272
|
ArgumentRow { keyword: "bluebook", context: "File", at: "", named: "version", kind: "text", required: "false", fills: "version", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
268
273
|
ArgumentRow { keyword: "vision", context: "Bluebook", at: "1", named: "", kind: "text", required: "true", fills: "vision", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
@@ -282,13 +287,24 @@ pub static ARGUMENTS: &[ArgumentRow] = &[
|
|
|
282
287
|
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "add_name", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
283
288
|
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "confirm", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
284
289
|
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "unsubscribe", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
290
|
+
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "awaiting_confirmation", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
291
|
+
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "receives_issues", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
292
|
+
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "left", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
293
|
+
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "confirm_window", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
294
|
+
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "unsubscribe_window", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
295
|
+
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "webhook_tolerance", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
296
|
+
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "session_hold", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
285
297
|
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "initiate", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
286
298
|
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "succeeded", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
287
299
|
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "failed", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
300
|
+
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "lapse_reason", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
301
|
+
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "holds_seat", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
288
302
|
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "send_issue", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
289
303
|
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "record_delivery", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
290
304
|
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "schedule", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
291
305
|
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "request", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
306
|
+
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "registered_at", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
307
|
+
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "frees_seat", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
292
308
|
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "connect", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
293
309
|
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "reconnect", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
294
310
|
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "disconnect", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
@@ -296,6 +312,10 @@ pub static ARGUMENTS: &[ArgumentRow] = &[
|
|
|
296
312
|
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "resume", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
297
313
|
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "enable", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
298
314
|
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "disable", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
315
|
+
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "mark_sensitive", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
316
|
+
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "markings_for", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
317
|
+
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "key_for", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
318
|
+
ArgumentRow { keyword: "provides", context: "Bluebook", at: "", named: "shred", kind: "text", required: "false", fills: "provides", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
299
319
|
ArgumentRow { keyword: "aggregate", context: "Bluebook", at: "1", named: "", kind: "text", required: "true", fills: "name", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
300
320
|
ArgumentRow { keyword: "read_model", context: "Bluebook", at: "1", named: "", kind: "text", required: "true", fills: "name", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
301
321
|
ArgumentRow { keyword: "policy", context: "Bluebook", at: "1", named: "", kind: "text", required: "true", fills: "name", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
@@ -377,10 +397,12 @@ pub static ARGUMENTS: &[ArgumentRow] = &[
|
|
|
377
397
|
ArgumentRow { keyword: "on", context: "Policy", at: "1", named: "", kind: "text", required: "true", fills: "on_event", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
378
398
|
ArgumentRow { keyword: "trigger", context: "Policy", at: "1", named: "", kind: "constant", required: "true", fills: "trigger_command", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
379
399
|
ArgumentRow { keyword: "trigger", context: "Policy", at: "1", named: "", kind: "text", required: "true", fills: "trigger_command", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
400
|
+
ArgumentRow { keyword: "ask", context: "Policy", at: "1", named: "", kind: "symbol", required: "true", fills: "ask", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
380
401
|
ArgumentRow { keyword: "across", context: "Policy", at: "1", named: "", kind: "text", required: "true", fills: "target_domain", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
381
402
|
ArgumentRow { keyword: "across", context: "Policy", at: "", named: "expect_undelivered", kind: "flag", required: "false", fills: "expect_undelivered", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
382
403
|
ArgumentRow { keyword: "for_each", context: "Policy", at: "1", named: "", kind: "text", required: "true", fills: "for_each", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
383
404
|
ArgumentRow { keyword: "trigger", context: "Policy", at: "", named: "with", kind: "pairs", required: "false", fills: "with_spec", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "verbatim", status: "admitted", variadic: "", minimum: "" },
|
|
405
|
+
ArgumentRow { keyword: "ask", context: "Policy", at: "", named: "with", kind: "pairs", required: "false", fills: "with_spec", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "verbatim", status: "admitted", variadic: "", minimum: "" },
|
|
384
406
|
ArgumentRow { keyword: "correlates_by", context: "ProcessManager", at: "1", named: "", kind: "symbol", required: "true", fills: "correlates_by", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
385
407
|
ArgumentRow { keyword: "starts_on", context: "ProcessManager", at: "1", named: "", kind: "constant", required: "true", fills: "starts_on", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
386
408
|
ArgumentRow { keyword: "starts_on", context: "ProcessManager", at: "1", named: "", kind: "text", required: "true", fills: "starts_on", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
@@ -468,6 +490,7 @@ pub static ARGUMENTS: &[ArgumentRow] = &[
|
|
|
468
490
|
ArgumentRow { keyword: "subscribe", context: "Hecksagon", at: "1", named: "", kind: "text", required: "true", fills: "subscriptions", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
469
491
|
ArgumentRow { keyword: "attaches", context: "Hecksagon", at: "1", named: "", kind: "text", required: "true", fills: "attachments", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
470
492
|
ArgumentRow { keyword: "attaches", context: "Hecksagon", at: "", named: "from", kind: "symbol", required: "false", fills: "source", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
493
|
+
ArgumentRow { keyword: "driven_by", context: "Hecksagon", at: "1", named: "", kind: "text", required: "true", fills: "driving", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
471
494
|
ArgumentRow { keyword: "port", context: "Hecksagon", at: "1", named: "", kind: "text", required: "true", fills: "name", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
472
495
|
ArgumentRow { keyword: "translates", context: "Hecksagon", at: "1", named: "", kind: "text", required: "true", fills: "name", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
473
496
|
ArgumentRow { keyword: "reference_to", context: "PortOperation", at: "1", named: "", kind: "constant", required: "true", fills: "type", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
@@ -489,6 +512,7 @@ pub static ARGUMENTS: &[ArgumentRow] = &[
|
|
|
489
512
|
ArgumentRow { keyword: "adapter", context: "File", at: "1", named: "", kind: "text", required: "true", fills: "name", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
490
513
|
ArgumentRow { keyword: "port", context: "Adapter", at: "1", named: "", kind: "text", required: "true", fills: "port", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
491
514
|
ArgumentRow { keyword: "field", context: "Adapter", at: "1", named: "", kind: "symbol", required: "true", fills: "fields", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
515
|
+
ArgumentRow { keyword: "field", context: "Adapter", at: "", named: "default", kind: "literal", required: "false", fills: "default", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
492
516
|
ArgumentRow { keyword: "secret", context: "Adapter", at: "1", named: "", kind: "symbol", required: "true", fills: "secrets", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
493
517
|
ArgumentRow { keyword: "data_translation", context: "File", at: "1", named: "", kind: "text", required: "true", fills: "name", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
|
494
518
|
ArgumentRow { keyword: "data_translation", context: "File", at: "", named: "from", kind: "text", required: "true", fills: "from", selects: "", pair_key_fills: "", pair_value_fills: "", pairs_shape: "", status: "admitted", variadic: "", minimum: "" },
|
data/rust/parser/src/main.rs
CHANGED
|
@@ -198,6 +198,7 @@ const COVERED_PAIRS: &[(&str, &str)] = &[
|
|
|
198
198
|
("invariant", "ValueObject"),
|
|
199
199
|
("member", "OneOf"),
|
|
200
200
|
("transition", "Lifecycle"),
|
|
201
|
+
("mark", "Lifecycle"),
|
|
201
202
|
("description", "Query"),
|
|
202
203
|
("attribute", "Query"),
|
|
203
204
|
("where", "Query"),
|
|
@@ -208,6 +209,7 @@ const COVERED_PAIRS: &[(&str, &str)] = &[
|
|
|
208
209
|
("needs", "Query"),
|
|
209
210
|
("on", "Policy"),
|
|
210
211
|
("trigger", "Policy"),
|
|
212
|
+
("ask", "Policy"),
|
|
211
213
|
("across", "Policy"),
|
|
212
214
|
("where", "Policy"),
|
|
213
215
|
("for_each", "Policy"),
|
|
@@ -220,6 +222,7 @@ const COVERED_PAIRS: &[(&str, &str)] = &[
|
|
|
220
222
|
("translates", "Hecksagon"),
|
|
221
223
|
("bounded", "Hecksagon"),
|
|
222
224
|
("attaches", "Hecksagon"),
|
|
225
|
+
("driven_by", "Hecksagon"),
|
|
223
226
|
("operation", "DomainPort"),
|
|
224
227
|
("reference_to", "PortOperation"),
|
|
225
228
|
("attribute", "PortOperation"),
|
|
@@ -425,7 +425,7 @@ pub fn parse_body(
|
|
|
425
425
|
.chain(closed_sets.iter())
|
|
426
426
|
.cloned()
|
|
427
427
|
.collect();
|
|
428
|
-
let vo = super::parse_nested_body(
|
|
428
|
+
let (vo, nested_sets) = super::parse_nested_body(
|
|
429
429
|
file,
|
|
430
430
|
lines,
|
|
431
431
|
pos,
|
|
@@ -434,6 +434,7 @@ pub fn parse_body(
|
|
|
434
434
|
|f, l, p| value_object::parse_body(f, l, p, &vo_name, &owner_value_objects),
|
|
435
435
|
)?;
|
|
436
436
|
aggregate.value_objects.push(vo);
|
|
437
|
+
aggregate.value_objects.extend(nested_sets);
|
|
437
438
|
}
|
|
438
439
|
}
|
|
439
440
|
"lifecycle" => {
|
|
@@ -297,7 +297,7 @@ pub fn parse_chapter(chapter_name: &str, files: &[(String, String)]) -> ParseRes
|
|
|
297
297
|
&mut discarded,
|
|
298
298
|
&mut Vec::new(),
|
|
299
299
|
&mut Vec::new(),
|
|
300
|
-
|
|
300
|
+
false,
|
|
301
301
|
)?;
|
|
302
302
|
}
|
|
303
303
|
}
|
|
@@ -355,7 +355,7 @@ pub fn resolve_hecksagon_dependencies(
|
|
|
355
355
|
&mut discarded,
|
|
356
356
|
&mut Vec::new(),
|
|
357
357
|
&mut Vec::new(),
|
|
358
|
-
|
|
358
|
+
false,
|
|
359
359
|
)?;
|
|
360
360
|
}
|
|
361
361
|
}
|
|
@@ -544,8 +544,10 @@ fn build_mutation(
|
|
|
544
544
|
}
|
|
545
545
|
// `state(:field)` is the record's own field, neither argument nor literal; classified
|
|
546
546
|
// before the Symbol/literal split.
|
|
547
|
+
let computed = if op == "set" { crate::expr::resolver::arithmetic_text(raw.trim()) } else { None };
|
|
547
548
|
let source = match state_ref(raw.trim()) {
|
|
548
549
|
Some(name) => ir::MutationSource::State(name),
|
|
550
|
+
None if computed.is_some() => ir::MutationSource::Expression(computed.unwrap_or_default()),
|
|
549
551
|
None => match value {
|
|
550
552
|
ruby_value::Value::Symbol(name) => ir::MutationSource::Argument(name),
|
|
551
553
|
other => ir::MutationSource::Literal(other),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
//! The `Hecksagon` construct: a `.hecksagon` file's `port` blocks and `attaches` words.
|
|
2
|
-
//! Adapter binds (`persisted_by`, `projected_by`, `subscribe`) are shape-matched and
|
|
2
|
+
//! Adapter binds (`persisted_by`, `projected_by`, `subscribe`, `driven_by`) are shape-matched and
|
|
3
|
+
//! dropped.
|
|
3
4
|
|
|
4
5
|
use super::domain_port;
|
|
5
6
|
use super::policy;
|
|
@@ -64,7 +65,7 @@ pub fn apply(
|
|
|
64
65
|
if let LineShape::Call(call) = lex::classify(file, &line)? {
|
|
65
66
|
if !matches!(
|
|
66
67
|
call.word.as_str(),
|
|
67
|
-
"port" | "subscribe" | "attaches" | "translates" | "bounded" | "end"
|
|
68
|
+
"port" | "subscribe" | "attaches" | "translates" | "bounded" | "driven_by" | "end"
|
|
68
69
|
) {
|
|
69
70
|
let instead = match call.word.as_str() {
|
|
70
71
|
"uses_framework" => Some("attaches \"Name\""),
|
|
@@ -130,6 +131,8 @@ pub fn apply(
|
|
|
130
131
|
}
|
|
131
132
|
// Consumer-owned bounded-context mark; a wiring fact, dropped like `subscribe`.
|
|
132
133
|
"bounded" => {}
|
|
134
|
+
// A driving adapter the domain admits; Ruby's boot enforces it, `ir.json` carries none.
|
|
135
|
+
"driven_by" => {}
|
|
133
136
|
_ => {
|
|
134
137
|
return Err(super::not_built_yet(
|
|
135
138
|
"Hecksagon",
|
|
@@ -22,11 +22,13 @@ pub fn parse_body(
|
|
|
22
22
|
field: field.to_string(),
|
|
23
23
|
default: default.to_string(),
|
|
24
24
|
transitions: Vec::new(),
|
|
25
|
+
marks: Vec::new(),
|
|
25
26
|
};
|
|
26
27
|
|
|
27
28
|
loop {
|
|
28
29
|
let Some(gated) = super::next_line(file, lines, pos, "Lifecycle")? else {
|
|
29
30
|
refuse_ambiguity(file, *pos, &lifecycle)?;
|
|
31
|
+
refuse_unknown_mark_states(file, *pos, &lifecycle)?;
|
|
30
32
|
return Ok(lifecycle);
|
|
31
33
|
};
|
|
32
34
|
|
|
@@ -52,6 +54,47 @@ pub fn parse_body(
|
|
|
52
54
|
});
|
|
53
55
|
}
|
|
54
56
|
}
|
|
57
|
+
"mark" => {
|
|
58
|
+
let line = gated.line.number;
|
|
59
|
+
let name = super::positional_symbol_raw(file, line, "mark", &gated.args, 1)?;
|
|
60
|
+
if !is_lowercase_word(&name) {
|
|
61
|
+
return Err(Diagnostic::new(
|
|
62
|
+
file,
|
|
63
|
+
line,
|
|
64
|
+
format!(
|
|
65
|
+
"lifecycle :{field} mark {:?} is not a lowercase word (such as :holds_seat)",
|
|
66
|
+
format!(":{name}")
|
|
67
|
+
),
|
|
68
|
+
));
|
|
69
|
+
}
|
|
70
|
+
if lifecycle.marks.iter().any(|(held, _)| *held == name) {
|
|
71
|
+
return Err(Diagnostic::new(
|
|
72
|
+
file,
|
|
73
|
+
line,
|
|
74
|
+
format!("lifecycle :{field} declares mark :{name} twice"),
|
|
75
|
+
));
|
|
76
|
+
}
|
|
77
|
+
let mut states: Vec<String> = Vec::new();
|
|
78
|
+
for (_, raw) in gated.args.positional.iter().filter(|(idx, _)| *idx > 1) {
|
|
79
|
+
let state = text_value(raw);
|
|
80
|
+
if states.contains(&state) {
|
|
81
|
+
return Err(Diagnostic::new(
|
|
82
|
+
file,
|
|
83
|
+
line,
|
|
84
|
+
format!("lifecycle :{field} mark :{name} names state {state:?} twice"),
|
|
85
|
+
));
|
|
86
|
+
}
|
|
87
|
+
states.push(state);
|
|
88
|
+
}
|
|
89
|
+
if states.is_empty() {
|
|
90
|
+
return Err(Diagnostic::new(
|
|
91
|
+
file,
|
|
92
|
+
line,
|
|
93
|
+
format!("lifecycle :{field} mark :{name} names no states"),
|
|
94
|
+
));
|
|
95
|
+
}
|
|
96
|
+
lifecycle.marks.push((name, states));
|
|
97
|
+
}
|
|
55
98
|
_ => {
|
|
56
99
|
return Err(super::not_built_yet(
|
|
57
100
|
"Lifecycle",
|
|
@@ -65,6 +108,44 @@ pub fn parse_body(
|
|
|
65
108
|
}
|
|
66
109
|
}
|
|
67
110
|
|
|
111
|
+
// A lowercase word: a letter a-z, then lowercase letters, digits and underscores.
|
|
112
|
+
fn is_lowercase_word(name: &str) -> bool {
|
|
113
|
+
let mut chars = name.chars();
|
|
114
|
+
matches!(chars.next(), Some('a'..='z'))
|
|
115
|
+
&& chars.all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_')
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Refuses a mark naming a state that is neither the default nor a transition target. Wording
|
|
119
|
+
// matches Ruby's.
|
|
120
|
+
fn refuse_unknown_mark_states(file: &str, line: usize, lifecycle: &ir::Lifecycle) -> ParseResult<()> {
|
|
121
|
+
let mut known: Vec<&str> = vec![lifecycle.default.as_str()];
|
|
122
|
+
for row in &lifecycle.transitions {
|
|
123
|
+
if !known.contains(&row.to_state.as_str()) {
|
|
124
|
+
known.push(row.to_state.as_str());
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
for (name, states) in &lifecycle.marks {
|
|
128
|
+
let unknown: Vec<String> = states
|
|
129
|
+
.iter()
|
|
130
|
+
.filter(|s| !known.contains(&s.as_str()))
|
|
131
|
+
.map(|s| format!("{s:?}"))
|
|
132
|
+
.collect();
|
|
133
|
+
if !unknown.is_empty() {
|
|
134
|
+
return Err(Diagnostic::new(
|
|
135
|
+
file,
|
|
136
|
+
line,
|
|
137
|
+
format!(
|
|
138
|
+
"lifecycle :{} mark :{name} names {}, which is not a state of the lifecycle (states: {})",
|
|
139
|
+
lifecycle.field,
|
|
140
|
+
unknown.join(", "),
|
|
141
|
+
known.join(", ")
|
|
142
|
+
),
|
|
143
|
+
));
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
Ok(())
|
|
147
|
+
}
|
|
148
|
+
|
|
68
149
|
// Refuses one command reaching two targets from overlapping `from:` states (`None` overlaps all).
|
|
69
150
|
// Rows are already expanded one per `from:` state. A `from:` naming an undeclared state is left
|
|
70
151
|
// to `hecks model_check`, since a bluebook may exhibit it on purpose. Wording matches Ruby's.
|
|
@@ -1070,7 +1070,9 @@ pub(crate) fn parse_identified_by(
|
|
|
1070
1070
|
"'identified_by' cannot combine a value-object type with a block",
|
|
1071
1071
|
));
|
|
1072
1072
|
}
|
|
1073
|
-
|
|
1073
|
+
// An identity block's own `one_of(...)` sets are not installed (its builder is not
|
|
1074
|
+
// the aggregate's `value_object` verb).
|
|
1075
|
+
let (value_object, _) = parse_nested_body(file, lines, pos, opener, line, |f, l, p| {
|
|
1074
1076
|
value_object::parse_body(f, l, p, inline_type_name, owner_value_objects)
|
|
1075
1077
|
})?;
|
|
1076
1078
|
if value_object.attributes.is_empty() {
|
|
@@ -1090,6 +1092,18 @@ pub(crate) fn parse_identified_by(
|
|
|
1090
1092
|
}
|
|
1091
1093
|
}
|
|
1092
1094
|
|
|
1095
|
+
/// The N'th positional as a symbol name (`:holds_seat` gives `holds_seat`).
|
|
1096
|
+
pub(crate) fn positional_symbol_raw(
|
|
1097
|
+
file: &str,
|
|
1098
|
+
line: usize,
|
|
1099
|
+
word: &str,
|
|
1100
|
+
args: &ArgumentGateResult,
|
|
1101
|
+
at: usize,
|
|
1102
|
+
) -> ParseResult<String> {
|
|
1103
|
+
let raw = positional_raw(file, line, word, args, at)?;
|
|
1104
|
+
positional_symbol_text(file, line, word, raw)
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1093
1107
|
/// Symbol name for one raw positional token, for variadic callers such as `identified_by`.
|
|
1094
1108
|
fn positional_symbol_text(file: &str, line: usize, word: &str, raw: &str) -> ParseResult<String> {
|
|
1095
1109
|
let trimmed = raw.trim();
|