hecks 3.10.0 → 3.12.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 +158 -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 +70 -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/newcomer.rb +50 -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/read_models.rb +1 -1
- 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 +4 -15
- data/lib/hecks/bluebook/assembly/scalars.rb +39 -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 +24 -1
- data/lib/hecks/bluebook/meta_validator/reconstruction/heads.rb +2 -1
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +6 -3
- 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 +2 -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 +34 -4
- 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 +33 -7
- 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/statuses.rb +2 -1
- 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 +133 -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/terminal.rb +13 -11
- 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 +53 -18
- data/lib/hecks/hecks/hecks.world +13 -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.behaviors +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.behaviors +19 -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 +63 -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/projection_files/expression_tables.rb +7 -2
- data/lib/hecks/projections/deploy/box/compose.rb +6 -4
- data/lib/hecks/projections/deploy/box/edge.rb +62 -0
- data/lib/hecks/projections/deploy/box/logging.rb +99 -0
- data/lib/hecks/projections/deploy/box/roll_scripts.rb +16 -8
- data/lib/hecks/projections/deploy/box/settings/cdn.rb +40 -0
- data/lib/hecks/projections/deploy/box/settings/logs.rb +40 -0
- data/lib/hecks/projections/deploy/box/settings/patterns.rb +11 -0
- data/lib/hecks/projections/deploy/box/settings/types.rb +16 -1
- data/lib/hecks/projections/deploy/box/settings.rb +6 -2
- data/lib/hecks/projections/deploy/box/stack_yaml.rb +5 -2
- data/lib/hecks/projections/deploy/box/templates/Makefile.tmpl +16 -0
- data/lib/hecks/projections/deploy/box/templates/box.yaml.tmpl +8 -4
- data/lib/hecks/projections/deploy/box/templates/deploy-box.sh.tmpl +32 -0
- data/lib/hecks/projections/deploy/box/templates/deploy-service.sh.tmpl +1 -1
- data/lib/hecks/projections/deploy/box/templates/edge.mk.tmpl +17 -0
- data/lib/hecks/projections/deploy/box/templates/edge.yaml.tmpl +65 -0
- data/lib/hecks/projections/deploy/box/templates/log-group.yaml.tmpl +12 -0
- data/lib/hecks/projections/deploy/box/templates/log-policy.yaml.tmpl +7 -0
- data/lib/hecks/projections/deploy/box/templates/render-compose-taskdef.sh.tmpl +5 -4
- data/lib/hecks/projections/deploy/box/templates/render-compose.sh.tmpl +5 -4
- data/lib/hecks/projections/deploy/box.rb +15 -3
- data/lib/hecks/projections/deploy/preview/preview.sh.erb +1 -1
- data/lib/hecks/projections/deploy/shared.rb +5 -2
- 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 +26 -6
- data/lib/hecks/projections/site/cms_editor/blocks.rb +157 -0
- data/lib/hecks/projections/site/cms_editor/checks.rb +14 -1
- 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 +1 -1
- 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/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 +96 -19
- data/lib/hecks/projections/site/cms_editor/setting.rb +52 -9
- data/lib/hecks/projections/site/cms_editor/targets.rb +86 -0
- data/lib/hecks/projections/site/cms_editor/templates/package.json.tmpl +18 -1
- data/lib/hecks/projections/site/cms_editor/templates/src/app.ts.tmpl +251 -57
- 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 +32 -24
- 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 +78 -24
- data/lib/hecks/projections/site/cms_editor/templates/src/config.ts.tmpl +6 -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 +19 -2
- data/lib/hecks/projections/site/cms_editor/templates/src/media/handler.ts.tmpl +31 -8
- 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 +131 -2
- 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 +8 -5
- 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 +229 -34
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/html.ts.tmpl +40 -81
- 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 +29 -12
- 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 +53 -17
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/pages.ts.tmpl +178 -88
- 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 +2 -1
- 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 +49 -23
- data/lib/hecks/projections/site/role_probe.rb +2 -0
- data/lib/hecks/projections/site/site_root/workflow.rb +5 -0
- data/lib/hecks/projector/cli_audience.rb +22 -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/cli_projector/usage.rb +15 -4
- 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/host.rb +11 -4
- data/lib/hecks/rust_build/prebuilt_binary.rb +101 -0
- 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 +1 -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/ci_gate_decision.rb +35 -0
- data/lib/hecks/tools/ci_gates.rb +20 -1
- 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/files.rb +8 -0
- data/lib/hecks/tools/lanes/prebuilt_workflow.rb +81 -0
- data/lib/hecks/tools/lanes/rows.rb +6 -0
- data/lib/hecks/tools/lanes.rb +1 -0
- data/lib/hecks/tools/oidc_manifests.rb +4 -5
- data/lib/hecks/tools/regeneration_run.rb +11 -4
- data/lib/hecks/tools/release_only.rb +111 -0
- data/lib/hecks/tools/site_routes/editor_files.rb +12 -5
- 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 +19 -5
- 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/9ee54e2f0d4d6d3fe046827779b221e02de665fba911a048ae5dd8b8fbfb7d90.marshal +0 -0
- data/prebuilt/d74a00e996222c1d8b676d5959092effc46b4dc59e0555f3bf9554ac58e3094a.marshal +0 -0
- data/prebuilt/verdicts-df19f35868d3284a70f55e42dcef87ef4e65e6a678e5135f72e1f6cff4c1357b.json +1 -0
- data/rust/.gitignore +6 -0
- data/rust/Cargo.toml +6 -0
- 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/commands.rs +13 -8
- data/rust/codegen/src/constraints.rs +25 -0
- data/rust/codegen/src/domain_generator.rs +2 -0
- data/rust/codegen/src/expr_emitter.rs +13 -0
- data/rust/codegen/src/json_codec.rs +54 -15
- data/rust/codegen/src/main.rs +1 -0
- data/rust/codegen/src/mutations.rs +128 -3
- 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/extension.rs +13 -1
- data/rust/host/src/lib.rs +1 -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/platform_signin/attack_tests.rs +1100 -0
- data/rust/host/src/platform_signin/config.rs +512 -0
- data/rust/host/src/platform_signin/cookie.rs +237 -0
- data/rust/host/src/platform_signin/extension.rs +190 -0
- data/rust/host/src/platform_signin/fetcher.rs +322 -0
- data/rust/host/src/platform_signin/handler.rs +251 -0
- data/rust/host/src/platform_signin/handler_tests.rs +554 -0
- data/rust/host/src/platform_signin/jti.rs +196 -0
- data/rust/host/src/platform_signin/jwks.rs +542 -0
- data/rust/host/src/platform_signin/jws.rs +249 -0
- data/rust/host/src/platform_signin/known_answer_tests.rs +237 -0
- data/rust/host/src/platform_signin/mapping_tests.rs +254 -0
- data/rust/host/src/platform_signin/mod.rs +75 -0
- data/rust/host/src/platform_signin/mode_tests.rs +382 -0
- data/rust/host/src/platform_signin/pages.rs +204 -0
- data/rust/host/src/platform_signin/query.rs +233 -0
- data/rust/host/src/platform_signin/session.rs +151 -0
- data/rust/host/src/platform_signin/settings.rs +385 -0
- data/rust/host/src/platform_signin/strict_json.rs +351 -0
- data/rust/host/src/platform_signin/test_support.rs +235 -0
- data/rust/host/src/platform_signin/ttl_tests.rs +94 -0
- data/rust/host/src/platform_signin/verify.rs +604 -0
- data/rust/host/src/platform_signin/wiring_support.rs +319 -0
- 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 +53 -9
- 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 +34 -17
- 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 +66 -3
- data/rust/src/kernel/expression_operators/arithmetic.rs +130 -5
- 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 +178 -38
- 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/lib/hecks/projections/site/cms_editor/templates/src/ui/body_widget.js.tmpl +0 -282
- data/lib/hecks/projections/site/cms_editor/templates/src/ui/media_picker.js.tmpl +0 -109
- data/prebuilt/c28d6d9db14eea3e17161e9d9c262efee30b256cf97693a7cfd552bce24b2f7f.marshal +0 -0
- data/prebuilt/cb375cba61ca0dbe8ddb9739c306510fe05e5f4b7a9b6955caff8224c63ea0e0.marshal +0 -0
- data/prebuilt/verdicts-d6d584ad43b5f3cebf88aafbbdbf024c38574acf18e06adffbc555f7786b1c2f.json +0 -1
|
@@ -30,6 +30,7 @@ module Hecks
|
|
|
30
30
|
["Aggregate", "given"] => :given_impl,
|
|
31
31
|
["Aggregate", "projects"] => :projects_impl,
|
|
32
32
|
["Lifecycle", "transition"] => :transition_impl,
|
|
33
|
+
["Lifecycle", "mark"] => :mark_impl,
|
|
33
34
|
["Bluebook", "attaches_to"] => :attaches_to_impl,
|
|
34
35
|
["Bluebook", "provides"] => :provides_impl,
|
|
35
36
|
["Bluebook", "aggregate"] => :aggregate_impl,
|
|
@@ -57,6 +58,7 @@ module Hecks
|
|
|
57
58
|
["Entity", "entity"] => :entity_impl,
|
|
58
59
|
["Policy", "on"] => :on_impl,
|
|
59
60
|
["Policy", "trigger"] => :trigger_impl,
|
|
61
|
+
["Policy", "ask"] => :ask_impl,
|
|
60
62
|
["Policy", "across"] => :across_impl,
|
|
61
63
|
["ProcessManager", "starts_on"] => :starts_on_impl,
|
|
62
64
|
["ProcessManager", "ends_on"] => :ends_on_impl,
|
|
@@ -28,7 +28,7 @@ module Hecks
|
|
|
28
28
|
# @raise [ArgumentError] on any other keyword
|
|
29
29
|
def sets_impl(target, positional_to = UNSET, **ops)
|
|
30
30
|
refuse_unknown_ops!(ops, KWARG_TO_OP.keys)
|
|
31
|
-
ops =
|
|
31
|
+
ops = source_of_to(ops, positional_to)
|
|
32
32
|
|
|
33
33
|
# Only a Symbol can repeat the target's name; a literal value (`to: false`,
|
|
34
34
|
# a String, ...) never has `.to_sym` to compare in the first place.
|
|
@@ -98,6 +98,13 @@ module Hecks
|
|
|
98
98
|
|
|
99
99
|
private
|
|
100
100
|
|
|
101
|
+
# Folds a positional source into `to:`, and reads arithmetic written there
|
|
102
|
+
# (`to: paid * rate / 100`) as the source it spells.
|
|
103
|
+
def source_of_to(ops, positional_to)
|
|
104
|
+
ops = ops.merge(to: positional_to) unless ops.key?(:to) || positional_to.equal?(UNSET)
|
|
105
|
+
ops[:to].is_a?(Operands::Computation) ? ops.merge(to: ops[:to].to_source) : ops
|
|
106
|
+
end
|
|
107
|
+
|
|
101
108
|
# A command's effects are one update set over the pre-dispatch state — a field
|
|
102
109
|
# written twice would make declaration order silently significant.
|
|
103
110
|
def refuse_duplicate_targets!
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
module Hecks
|
|
2
|
+
module Bluebook
|
|
3
|
+
module DSL
|
|
4
|
+
class CommandBuilder
|
|
5
|
+
# Lets a bluebook write arithmetic where a `sets` takes its source: inside a command, a bare
|
|
6
|
+
# name that is one of its arguments or one of its owner's fields reads as an operand, and
|
|
7
|
+
# `+ - * /` over operands and numbers build a {Hecks::Computed}.
|
|
8
|
+
#
|
|
9
|
+
# sets :refund_cents, to: paid_cents * late_percent / 100
|
|
10
|
+
module Operands
|
|
11
|
+
# One node of the arithmetic a `sets` source spells: an operand name, a number, or two
|
|
12
|
+
# nodes joined by an operator. Renders the canonical text the expression grammar reads,
|
|
13
|
+
# parenthesised only where the written grouping needs it.
|
|
14
|
+
class Computation
|
|
15
|
+
# Binding strength of each operator; `*` and `/` bind tighter than `+` and `-`.
|
|
16
|
+
PRECEDENCE = { :+ => 1, :- => 1, :* => 2, :/ => 2 }.freeze
|
|
17
|
+
|
|
18
|
+
attr_reader :operator, :left, :right
|
|
19
|
+
|
|
20
|
+
# @param operator [Symbol, nil] the joining operator, or nil for a name or number
|
|
21
|
+
# @param left [Object] the operand name or number, or the left node
|
|
22
|
+
# @param right [Object, nil] the right node of a joined pair
|
|
23
|
+
def initialize(operator, left, right = nil)
|
|
24
|
+
@operator = operator
|
|
25
|
+
@left = left
|
|
26
|
+
@right = right
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
PRECEDENCE.each_key do |operator|
|
|
30
|
+
define_method(operator) { |other| Computation.new(operator, self, Computation.wrap(other)) }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Lets `100 * paid` work: Ruby asks the right-hand operand to coerce the number.
|
|
34
|
+
#
|
|
35
|
+
# @return [Array<Computation>] the number and this node, as a left and right pair
|
|
36
|
+
def coerce(number) = [Computation.wrap(number), self]
|
|
37
|
+
|
|
38
|
+
# @return [Hecks::Computed, Symbol, Numeric] the source a `sets` records: the canonical
|
|
39
|
+
# text of joined arithmetic, or for a lone operand its argument name, or its number
|
|
40
|
+
def to_source
|
|
41
|
+
return Computed.new(to_text) if operator
|
|
42
|
+
|
|
43
|
+
return left if left.is_a?(Numeric)
|
|
44
|
+
|
|
45
|
+
path? ? Computed.new(left.to_s) : left.to_sym
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Reaches a field of the value object a name holds: `charged.cents` is the operand
|
|
49
|
+
# `charged` followed by its field `cents`, read by the same dotted path a `given` reads.
|
|
50
|
+
#
|
|
51
|
+
# @return [Computation] the operand extended by one path segment
|
|
52
|
+
def method_missing(field, *args, &block)
|
|
53
|
+
return super unless field_read?(args, block)
|
|
54
|
+
|
|
55
|
+
Computation.new(nil, "#{left}.#{field}")
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def respond_to_missing?(field, include_private = false) = field_read?([], nil) || super
|
|
59
|
+
|
|
60
|
+
# @return [Boolean] whether this operand is a dotted path into a value object
|
|
61
|
+
def path? = left.to_s.include?(".")
|
|
62
|
+
|
|
63
|
+
# @return [String] the expression text, such as `paid * rate / 100`
|
|
64
|
+
def to_text
|
|
65
|
+
return operand_text unless operator
|
|
66
|
+
|
|
67
|
+
"#{side_text(left, false)} #{operator} #{side_text(right, true)}"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# @param value [Computation, Numeric] a node or a number
|
|
71
|
+
# @return [Computation] the node, or the number wrapped as one
|
|
72
|
+
# @raise [Bluebook::DSL::Malformed] if `value` is neither
|
|
73
|
+
def self.wrap(value)
|
|
74
|
+
return value if value.is_a?(Computation)
|
|
75
|
+
return new(nil, value) if value.is_a?(Numeric)
|
|
76
|
+
|
|
77
|
+
raise Malformed, "a sets expression joins argument names and numbers, not #{value.inspect}"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
private
|
|
81
|
+
|
|
82
|
+
def operand_text = left.to_s
|
|
83
|
+
|
|
84
|
+
# Only a bare name (or an existing path) can be followed by a field.
|
|
85
|
+
def field_read?(args, block) = operator.nil? && !left.is_a?(Numeric) && args.empty? && block.nil?
|
|
86
|
+
|
|
87
|
+
# A joined side is parenthesised when it binds looser than this operator, or equally
|
|
88
|
+
# on the right, so the printed text parses back to the same grouping.
|
|
89
|
+
def side_text(side, right_side)
|
|
90
|
+
return side.to_text unless side.operator
|
|
91
|
+
|
|
92
|
+
looser = PRECEDENCE.fetch(side.operator) < PRECEDENCE.fetch(operator)
|
|
93
|
+
equal_on_right = right_side && PRECEDENCE.fetch(side.operator) == PRECEDENCE.fetch(operator)
|
|
94
|
+
looser || equal_on_right ? "(#{side.to_text})" : side.to_text
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
private
|
|
99
|
+
|
|
100
|
+
# A bare name the command declares as an argument, or its owner declares as a field,
|
|
101
|
+
# is an operand; anything else keeps the builder's own answer.
|
|
102
|
+
def method_missing(word, *args, **kwargs, &block)
|
|
103
|
+
return Computation.new(nil, word) if operand?(word, args, kwargs, block)
|
|
104
|
+
|
|
105
|
+
super
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def respond_to_missing?(word, include_private = false)
|
|
109
|
+
operand?(word, [], {}, nil) || super
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def operand?(word, args, kwargs, block)
|
|
113
|
+
return false unless args.empty? && kwargs.empty? && block.nil?
|
|
114
|
+
|
|
115
|
+
attributes.any? { |attr| attr.name == word } || @owner_attributes.any? { |attr| attr.name == word }
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -4,6 +4,7 @@ require_relative "command_builder/owner"
|
|
|
4
4
|
require_relative "command_builder/rules"
|
|
5
5
|
require_relative "command_builder/mutations"
|
|
6
6
|
require_relative "command_builder/implicit_attributes"
|
|
7
|
+
require_relative "command_builder/operands"
|
|
7
8
|
module Hecks
|
|
8
9
|
module Bluebook
|
|
9
10
|
module DSL
|
|
@@ -17,6 +18,7 @@ module Hecks
|
|
|
17
18
|
include WordGate
|
|
18
19
|
include NeedWord
|
|
19
20
|
include ImplicitAttributes
|
|
21
|
+
include Operands
|
|
20
22
|
|
|
21
23
|
# Sentinel for "this keyword was never passed" — distinct from Ruby's own
|
|
22
24
|
# nil/false, so `to: false` doesn't get treated as absent.
|
|
@@ -44,6 +44,7 @@ module Hecks
|
|
|
44
44
|
@binds = []
|
|
45
45
|
@subscriptions = []
|
|
46
46
|
@attachments = []
|
|
47
|
+
@driving = []
|
|
47
48
|
@bounded = false
|
|
48
49
|
@translates = []
|
|
49
50
|
end
|
|
@@ -57,6 +58,13 @@ module Hecks
|
|
|
57
58
|
# Subscribes to an event from outside this domain's own bluebook.
|
|
58
59
|
def subscribe(event) = @subscriptions << event.to_s
|
|
59
60
|
|
|
61
|
+
# Admits a driving adapter (`Ruby`, `Cli`, `Json` or `Mcp`) to reach this domain. Once any
|
|
62
|
+
# is declared, the adapters left out refuse the domain; none declared leaves it open.
|
|
63
|
+
#
|
|
64
|
+
# @param adapter [String, Symbol] the adapter's name
|
|
65
|
+
# @return [void]
|
|
66
|
+
def driven_by(adapter) = @driving << adapter.to_s
|
|
67
|
+
|
|
60
68
|
# Attaches a chapter by name and loads it into the current registry, marked bounded.
|
|
61
69
|
#
|
|
62
70
|
# Without `from:` the name is a chapter the gem carries (a framework member such as
|
|
@@ -111,7 +119,8 @@ module Hecks
|
|
|
111
119
|
# No ungoverned-role check here — it runs once on the merged result at verify! time.
|
|
112
120
|
def build
|
|
113
121
|
Hecksagon.new(domain: @domain, binds: @binds, subscriptions: @subscriptions,
|
|
114
|
-
attachments: @attachments, bounded: @bounded, translates: @translates
|
|
122
|
+
attachments: @attachments, bounded: @bounded, translates: @translates,
|
|
123
|
+
driving: @driving)
|
|
115
124
|
end
|
|
116
125
|
|
|
117
126
|
# Loads a chapter the gem carries and records it as attached from the gem.
|
|
@@ -14,6 +14,32 @@ module Hecks
|
|
|
14
14
|
@field = field
|
|
15
15
|
@default = default
|
|
16
16
|
@transitions = []
|
|
17
|
+
@marks = {}
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Names a meaning and the states that carry it, such as
|
|
21
|
+
# `mark :holds_seat, "pending", "succeeded"`.
|
|
22
|
+
#
|
|
23
|
+
# Listed in `BOOTSTRAP_CALLS_FALLBACK` because syntax.bluebook uses it during boot.
|
|
24
|
+
#
|
|
25
|
+
# @param name [Symbol, String] a lowercase word (`holds_seat`)
|
|
26
|
+
# @param states [Array<String, Symbol>] one or more states, each named once
|
|
27
|
+
# @return [Array<String>] the states just recorded
|
|
28
|
+
# @raise [Bluebook::DSL::Malformed] for a name that is not a lowercase word, a name
|
|
29
|
+
# declared twice, no states, or a state named twice in one mark
|
|
30
|
+
def mark_impl(name, *states)
|
|
31
|
+
mark = name.to_s
|
|
32
|
+
unless mark.match?(/\A[a-z][a-z0-9_]*\z/)
|
|
33
|
+
raise Malformed, "lifecycle :#{@field} mark #{name.inspect} is not a lowercase word (such as :holds_seat)"
|
|
34
|
+
end
|
|
35
|
+
raise Malformed, "lifecycle :#{@field} declares mark :#{mark} twice" if @marks.key?(mark)
|
|
36
|
+
raise Malformed, "lifecycle :#{@field} mark :#{mark} names no states" if states.empty?
|
|
37
|
+
|
|
38
|
+
names = states.map(&:to_s)
|
|
39
|
+
twice = names.find { |state| names.count(state) > 1 }
|
|
40
|
+
raise Malformed, "lifecycle :#{@field} mark :#{mark} names state #{twice.inspect} twice" if twice
|
|
41
|
+
|
|
42
|
+
@marks[mark] = names
|
|
17
43
|
end
|
|
18
44
|
|
|
19
45
|
# Records one transition row per command in `mapping`, all sharing its `from:` guard.
|
|
@@ -40,10 +66,12 @@ module Hecks
|
|
|
40
66
|
#
|
|
41
67
|
# @return [Bluebook::Lifecycle] the state machine: its field, default and transitions
|
|
42
68
|
# @raise [Bluebook::DSL::Malformed] if two transitions for one command could both apply
|
|
43
|
-
# from the same state (C5.3
|
|
69
|
+
# from the same state (C5.3; skipped while shadow-parsing frozen era text), or a mark
|
|
70
|
+
# names a state the lifecycle does not have
|
|
44
71
|
def build
|
|
45
72
|
refuse_ambiguity!
|
|
46
|
-
|
|
73
|
+
refuse_unknown_mark_states!
|
|
74
|
+
Lifecycle.new(field: @field, default: @default, transitions: @transitions, marks: @marks)
|
|
47
75
|
end
|
|
48
76
|
|
|
49
77
|
# Evaluates a `lifecycle` block against a fresh builder and returns what it built.
|
|
@@ -62,6 +90,21 @@ module Hecks
|
|
|
62
90
|
|
|
63
91
|
private
|
|
64
92
|
|
|
93
|
+
# A mark may name only the default or a transition target: anything else is a typo that
|
|
94
|
+
# would silently mark nothing. (A `from:` state is not enough; it is not reachable.)
|
|
95
|
+
def refuse_unknown_mark_states!
|
|
96
|
+
known = ([@default] + @transitions.map { |(_command, transition)| transition.target }).map(&:to_s)
|
|
97
|
+
|
|
98
|
+
@marks.each do |mark, states|
|
|
99
|
+
unknown = states - known
|
|
100
|
+
next if unknown.empty?
|
|
101
|
+
|
|
102
|
+
raise Malformed,
|
|
103
|
+
"lifecycle :#{@field} mark :#{mark} names #{unknown.map(&:inspect).join(", ")}, which " \
|
|
104
|
+
"is not a state of the lifecycle (states: #{known.uniq.join(", ")})"
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
65
108
|
# C5.3 (docs/semantics/bluebook-semantics.md): overlapping `from:` sets for one command
|
|
66
109
|
# are refused. Disjoint sets are legitimate. An undeclared `from:` state is left to
|
|
67
110
|
# `hecks model_check`.
|
|
@@ -39,6 +39,8 @@ module Hecks
|
|
|
39
39
|
# @return [void]
|
|
40
40
|
# @raise [Bluebook::DSL::Malformed] if `command_ref` is quoted text outside shadow-parsing
|
|
41
41
|
def trigger_impl(command_ref, with: nil)
|
|
42
|
+
raise Malformed, "#{@name} declares both a trigger and an ask — a policy does one" if @ask
|
|
43
|
+
|
|
42
44
|
if command_ref.is_a?(::String) && !MetaValidator.shadow_parsing?
|
|
43
45
|
raise Malformed,
|
|
44
46
|
"#{@name}'s trigger #{command_ref.inspect} is quoted text — give the bare command " \
|
|
@@ -50,6 +52,26 @@ module Hecks
|
|
|
50
52
|
@projection_declared = !with.nil?
|
|
51
53
|
end
|
|
52
54
|
|
|
55
|
+
# Records the need this policy puts to the outside, in the domain's own words.
|
|
56
|
+
#
|
|
57
|
+
# The runtime resolves the name against the hecksagon's declared asks (the event's
|
|
58
|
+
# aggregate and the ask's name) and dispatches the port operation the match names, as
|
|
59
|
+
# `trigger` would have. `with:` projects the event onto the operation as it does for
|
|
60
|
+
# `trigger`.
|
|
61
|
+
#
|
|
62
|
+
# @param name [Symbol, String] the need, such as `:check`
|
|
63
|
+
# @param with [Hash{Symbol => Object}, nil] event payload to operation arguments;
|
|
64
|
+
# `nil` forwards the whole payload
|
|
65
|
+
# @return [void]
|
|
66
|
+
# @raise [Bluebook::DSL::Malformed] if the policy already triggers a command
|
|
67
|
+
def ask_impl(name, with: nil)
|
|
68
|
+
raise Malformed, "#{@name} declares both a trigger and an ask — a policy does one" if @trigger_command
|
|
69
|
+
|
|
70
|
+
@ask = name.to_s
|
|
71
|
+
@with_spec = (with || {}).to_a
|
|
72
|
+
@projection_declared = !with.nil?
|
|
73
|
+
end
|
|
74
|
+
|
|
53
75
|
# Records the domain this policy's trigger reaches into.
|
|
54
76
|
#
|
|
55
77
|
# `expect_undelivered: true` declares that the target is expected never to be reached
|
|
@@ -96,16 +118,9 @@ module Hecks
|
|
|
96
118
|
# @return [Bluebook::Policy] the built policy, carrying every field set by `on`,
|
|
97
119
|
# `trigger`, `across`, `where`, `for_each`, and `with:`
|
|
98
120
|
def build
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
trigger_command: @trigger_command,
|
|
103
|
-
target_domain: @target_domain,
|
|
104
|
-
expect_undelivered: @expect_undelivered || false,
|
|
105
|
-
where: @where,
|
|
106
|
-
for_each: @for_each,
|
|
107
|
-
with_spec: @with_spec || []
|
|
108
|
-
).tap { |policy| policy.instance_variable_set(:@projection_declared, !!@projection_declared) }
|
|
121
|
+
refuse_ask_across!
|
|
122
|
+
Policy.new(**reaction_fields, **guard_fields)
|
|
123
|
+
.tap { |policy| policy.instance_variable_set(:@projection_declared, !!@projection_declared) }
|
|
109
124
|
end
|
|
110
125
|
|
|
111
126
|
# Builds a `Policy` from a `policy "Name" do ... end` block.
|
|
@@ -118,6 +133,28 @@ module Hecks
|
|
|
118
133
|
builder.instance_eval(&block) if block
|
|
119
134
|
builder.build
|
|
120
135
|
end
|
|
136
|
+
|
|
137
|
+
private
|
|
138
|
+
|
|
139
|
+
# What the policy reacts to and what it reaches.
|
|
140
|
+
def reaction_fields
|
|
141
|
+
{ name: @name, on_event: @on_event, trigger_command: @trigger_command, ask: @ask,
|
|
142
|
+
target_domain: @target_domain }
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# What decides whether it fires, and what it hands over.
|
|
146
|
+
def guard_fields
|
|
147
|
+
{ expect_undelivered: @expect_undelivered || false, where: @where, for_each: @for_each,
|
|
148
|
+
with_spec: @with_spec || [] }
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# An ask resolves against the ports of the domain it is declared in, so `across` has
|
|
152
|
+
# nothing to add to it.
|
|
153
|
+
def refuse_ask_across!
|
|
154
|
+
return unless @ask && @target_domain
|
|
155
|
+
|
|
156
|
+
raise Malformed, "#{@name} declares both an ask and across — an ask resolves in its own domain"
|
|
157
|
+
end
|
|
121
158
|
end
|
|
122
159
|
end
|
|
123
160
|
end
|
|
@@ -6,6 +6,9 @@ module Hecks
|
|
|
6
6
|
# The three "declared once, referenced by name" resolution primitives shared by
|
|
7
7
|
# every given/invariant/ensures scope in this DSL (ADR 0025).
|
|
8
8
|
module RuleReference
|
|
9
|
+
# Raised when the syntax table names a resolution this module cannot perform.
|
|
10
|
+
class Error < RuntimeError; end
|
|
11
|
+
|
|
9
12
|
module_function
|
|
10
13
|
|
|
11
14
|
# Extracts a predicate's source and builds the rule struct (Given or Invariant),
|
|
@@ -94,10 +97,10 @@ module Hecks
|
|
|
94
97
|
actual = lookup(word, context)[:resolves_via]
|
|
95
98
|
return if actual == expected_primitive
|
|
96
99
|
|
|
97
|
-
raise "internal: syntax.bluebook says #{word}/#{context} resolves via " \
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
100
|
+
raise Error, "internal: syntax.bluebook says #{word}/#{context} resolves via " \
|
|
101
|
+
"#{actual.inspect}, but #{word}'s own Ruby builder is about to use " \
|
|
102
|
+
"#{expected_primitive.inspect} — the grammar table and the " \
|
|
103
|
+
"implementation have drifted"
|
|
101
104
|
end
|
|
102
105
|
end
|
|
103
106
|
end
|
|
@@ -102,7 +102,7 @@ module Hecks
|
|
|
102
102
|
end
|
|
103
103
|
|
|
104
104
|
class << self
|
|
105
|
-
# The builder whose block is being evaluated, so an aggregate
|
|
105
|
+
# The builder whose block is being evaluated, so an aggregate module a facade already
|
|
106
106
|
# installed (a repeat boot in one process) can record a qualified bind into it.
|
|
107
107
|
#
|
|
108
108
|
# @return [Bluebook::DSL::WorldBuilder, nil] nil outside a `.world` block
|
|
@@ -55,6 +55,9 @@ module Hecks
|
|
|
55
55
|
# Segments, as `find.path` has, so a reader need not split a dotted string.
|
|
56
56
|
Resolver::Lookup => ->(node) { { "op" => "lookup", "path" => node.path.split(".") } },
|
|
57
57
|
Resolver::Addition => binary("add", :emit_resolver),
|
|
58
|
+
Resolver::Subtraction => binary("sub", :emit_resolver),
|
|
59
|
+
Resolver::Multiplication => binary("mul", :emit_resolver),
|
|
60
|
+
Resolver::Division => binary("div", :emit_resolver),
|
|
58
61
|
Resolver::SignTest => lambda { |node|
|
|
59
62
|
{ "op" => "sign_test", "cmp" => AstJson.emit_comparison(node.operator),
|
|
60
63
|
"receiver" => AstJson.emit_resolver(node.receiver) }
|
|
@@ -81,6 +84,9 @@ module Hecks
|
|
|
81
84
|
Resolver::Presence => receiver_with("presence", :negated),
|
|
82
85
|
Resolver::Assignment => receiver_with("assignment", :negated),
|
|
83
86
|
Resolver::Split => receiver_with("split", :separator),
|
|
87
|
+
Resolver::Strip => lambda { |node|
|
|
88
|
+
{ "op" => "strip", "receiver" => AstJson.emit_resolver(node.receiver), "side" => node.side.to_s }
|
|
89
|
+
},
|
|
84
90
|
Resolver::StartsWith => receiver_with("starts_with", :substring),
|
|
85
91
|
Resolver::EndsWith => receiver_with("ends_with", :substring),
|
|
86
92
|
Resolver::First => receiver_only("first"),
|
|
@@ -9,6 +9,9 @@ module Hecks
|
|
|
9
9
|
# Lives in core because rust/host cannot link the kernel crate and interprets this from
|
|
10
10
|
# ir.json.
|
|
11
11
|
module AstJson
|
|
12
|
+
# Raised for an expression node that no JSON rendering exists for.
|
|
13
|
+
class UnhandledNode < RuntimeError; end
|
|
14
|
+
|
|
12
15
|
module_function
|
|
13
16
|
|
|
14
17
|
# The closed roster of `"op"` tags. A new node kind needs an entry here and an arm in
|
|
@@ -16,9 +19,9 @@ module Hecks
|
|
|
16
19
|
OPS = %w[
|
|
17
20
|
or and not compare include
|
|
18
21
|
int float str bool nil array lookup
|
|
19
|
-
add modulo sign_test empty size to_s
|
|
22
|
+
add sub mul div modulo sign_test empty size to_s
|
|
20
23
|
block_predicate find first last
|
|
21
|
-
matches_regex presence assignment split starts_with ends_with
|
|
24
|
+
matches_regex presence assignment split strip starts_with ends_with
|
|
22
25
|
].freeze
|
|
23
26
|
|
|
24
27
|
# One rule row: description, canonical text, and the AST derived from that text.
|
|
@@ -119,8 +122,8 @@ module Hecks
|
|
|
119
122
|
_, emitter = Emitters::BOOL.find { |klass, _| node.is_a?(klass) }
|
|
120
123
|
return emitter.call(node) if emitter
|
|
121
124
|
|
|
122
|
-
raise "unhandled evaluator node #{node.class} — no JSON rendering exists for it " \
|
|
123
|
-
|
|
125
|
+
raise UnhandledNode, "unhandled evaluator node #{node.class} — no JSON rendering exists for it " \
|
|
126
|
+
"(lib/hecks/bluebook/expression/ast_json.rb#emit_bool)"
|
|
124
127
|
end
|
|
125
128
|
|
|
126
129
|
# Emits the JSON form of one comparison operator.
|
|
@@ -161,8 +164,8 @@ module Hecks
|
|
|
161
164
|
_, emitter = Emitters::RESOLVER.find { |klass, _| node.is_a?(klass) }
|
|
162
165
|
return emitter.call(node) if emitter
|
|
163
166
|
|
|
164
|
-
raise "unhandled resolver node #{node.class} — no JSON rendering exists for it " \
|
|
165
|
-
|
|
167
|
+
raise UnhandledNode, "unhandled resolver node #{node.class} — no JSON rendering exists for it " \
|
|
168
|
+
"(lib/hecks/bluebook/expression/ast_json.rb#emit_resolver)"
|
|
166
169
|
end
|
|
167
170
|
end
|
|
168
171
|
end
|
|
@@ -4,6 +4,9 @@ require_relative "resolver"
|
|
|
4
4
|
module Hecks
|
|
5
5
|
module Bluebook
|
|
6
6
|
module Expression
|
|
7
|
+
# Raised for an operator `AstReader` has no arm for.
|
|
8
|
+
class UnhandledOp < RuntimeError; end
|
|
9
|
+
|
|
7
10
|
# The inverse of `AstJson`: reads a rule row's `"op"`-tagged `ast` back into the
|
|
8
11
|
# `Evaluator`/`Resolver` nodes, so dispatch evaluates a rule without re-parsing its text.
|
|
9
12
|
module AstReader
|
|
@@ -33,9 +36,7 @@ module Hecks
|
|
|
33
36
|
# @param klass [Class] `Evaluator::Or` or `Evaluator::And`
|
|
34
37
|
# @param json [Hash] the node's `"left"` and `"right"` boolean children
|
|
35
38
|
# @return [Object] the node `klass` builds over them
|
|
36
|
-
def read_pair(klass, json)
|
|
37
|
-
klass.new(left: read_bool(json["left"]), right: read_bool(json["right"]))
|
|
38
|
-
end
|
|
39
|
+
def read_pair(klass, json) = klass.new(left: read_bool(json["left"]), right: read_bool(json["right"]))
|
|
39
40
|
|
|
40
41
|
# @param json [Hash] a `"compare"` node
|
|
41
42
|
# @return [Evaluator::Compare] its operator and both resolver sides
|
|
@@ -51,7 +52,7 @@ module Hecks
|
|
|
51
52
|
op.compares_less_than == cmp.fetch("less_than") &&
|
|
52
53
|
op.compares_equal == cmp.fetch("equal") &&
|
|
53
54
|
op.negated == cmp.fetch("negated")
|
|
54
|
-
end or raise "no comparison operator has the triple #{cmp.inspect}"
|
|
55
|
+
end or raise UnhandledOp, "no comparison operator has the triple #{cmp.inspect}"
|
|
55
56
|
end
|
|
56
57
|
|
|
57
58
|
# The readers `read_resolver` tries in turn; each answers `nil` for an op it does not own.
|
|
@@ -65,7 +66,7 @@ module Hecks
|
|
|
65
66
|
node = public_send(reader, json)
|
|
66
67
|
return node if node
|
|
67
68
|
end
|
|
68
|
-
raise "no reader handles op #{op.inspect} — add an arm before AstJson can emit it"
|
|
69
|
+
raise UnhandledOp, "no reader handles op #{op.inspect} — add an arm before AstJson can emit it"
|
|
69
70
|
end
|
|
70
71
|
|
|
71
72
|
# @param json [Hash] a resolver node
|
|
@@ -80,6 +81,8 @@ module Hecks
|
|
|
80
81
|
end
|
|
81
82
|
end
|
|
82
83
|
|
|
84
|
+
def read_binary(node_class, json) = node_class.new(left: read_resolver(json["left"]), right: read_resolver(json["right"]))
|
|
85
|
+
|
|
83
86
|
# @param json [Hash] a resolver node
|
|
84
87
|
# @return [Object, nil] the array or lookup it spells, or `nil` for any other op
|
|
85
88
|
def read_collection(json)
|
|
@@ -93,7 +96,10 @@ module Hecks
|
|
|
93
96
|
# @return [Object, nil] the sum, remainder or sign test it spells, or `nil` for any other op
|
|
94
97
|
def read_arithmetic(json)
|
|
95
98
|
case json["op"]
|
|
96
|
-
when "add" then Resolver::Addition
|
|
99
|
+
when "add" then read_binary(Resolver::Addition, json)
|
|
100
|
+
when "sub" then read_binary(Resolver::Subtraction, json)
|
|
101
|
+
when "mul" then read_binary(Resolver::Multiplication, json)
|
|
102
|
+
when "div" then read_binary(Resolver::Division, json)
|
|
97
103
|
when "modulo" then Resolver::Modulo.new(receiver: receiver(json), divisor: read_resolver(json["divisor"]))
|
|
98
104
|
when "sign_test"
|
|
99
105
|
op = operator(json["cmp"])
|
|
@@ -110,6 +116,7 @@ module Hecks
|
|
|
110
116
|
when "size" then Resolver::Size.new(receiver: receiver(json))
|
|
111
117
|
when "first" then Resolver::First.new(receiver: receiver(json))
|
|
112
118
|
when "last" then Resolver::Last.new(receiver: receiver(json))
|
|
119
|
+
when "strip" then Resolver::Strip.new(receiver: receiver(json), side: json["side"].to_sym)
|
|
113
120
|
end
|
|
114
121
|
end
|
|
115
122
|
|
|
@@ -152,9 +159,7 @@ module Hecks
|
|
|
152
159
|
|
|
153
160
|
# `SignTest#test` is only refusal wording; recovering it keeps a rebuilt node's message
|
|
154
161
|
# identical to the parsed one's.
|
|
155
|
-
def sign_test_name(operator)
|
|
156
|
-
Resolver::SIGN_TEST_OPERATORS.key(operator.symbol) || operator.symbol
|
|
157
|
-
end
|
|
162
|
+
def sign_test_name(operator) = Resolver::SIGN_TEST_OPERATORS.key(operator.symbol) || operator.symbol
|
|
158
163
|
end
|
|
159
164
|
end
|
|
160
165
|
end
|
|
@@ -209,6 +209,42 @@
|
|
|
209
209
|
"category": "presence",
|
|
210
210
|
"precedence": 7,
|
|
211
211
|
"arity": 1
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
"symbol": ".strip",
|
|
215
|
+
"category": "text",
|
|
216
|
+
"precedence": 7,
|
|
217
|
+
"arity": 1
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
"symbol": ".lstrip",
|
|
221
|
+
"category": "text",
|
|
222
|
+
"precedence": 7,
|
|
223
|
+
"arity": 1
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
"symbol": ".rstrip",
|
|
227
|
+
"category": "text",
|
|
228
|
+
"precedence": 7,
|
|
229
|
+
"arity": 1
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
"symbol": "-",
|
|
233
|
+
"category": "arithmetic",
|
|
234
|
+
"precedence": 6,
|
|
235
|
+
"arity": 2
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
"symbol": "*",
|
|
239
|
+
"category": "arithmetic",
|
|
240
|
+
"precedence": 7,
|
|
241
|
+
"arity": 2
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
"symbol": "/",
|
|
245
|
+
"category": "arithmetic",
|
|
246
|
+
"precedence": 7,
|
|
247
|
+
"arity": 2
|
|
212
248
|
}
|
|
213
249
|
],
|
|
214
250
|
"normalisations": [
|
|
@@ -24,6 +24,7 @@ module Hecks
|
|
|
24
24
|
Presence => ->(node, value, _state, _attrs) { Resolver.presence_of(node, value) },
|
|
25
25
|
Assignment => ->(node, value, _state, _attrs) { Resolver.assignment_of(node, value) },
|
|
26
26
|
Split => ->(node, value, _state, _attrs) { Resolver.split_value(value, node.separator) },
|
|
27
|
+
Strip => ->(node, value, _state, _attrs) { Resolver.strip_value(value, node.side) },
|
|
27
28
|
Last => ->(_node, value, _state, _attrs) { Resolver.last_of(value) },
|
|
28
29
|
First => ->(_node, value, _state, _attrs) { Resolver.first_of(value) },
|
|
29
30
|
Find => ->(node, value, state, attrs) { Resolver.found_of(node, value, state, attrs) },
|
|
@@ -46,6 +47,36 @@ module Hecks
|
|
|
46
47
|
raise EvaluationError, "addition overflowed: #{lhs} + #{rhs} is not a finite number"
|
|
47
48
|
end
|
|
48
49
|
|
|
50
|
+
def subtract(left, right)
|
|
51
|
+
checked_arithmetic("subtraction", "-", left, right) { |lhs, rhs| lhs - rhs }
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def multiply(left, right)
|
|
55
|
+
checked_arithmetic("multiplication", "*", left, right) { |lhs, rhs| lhs * rhs }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Integer operands floor toward negative infinity; a zero divisor faults like `.modulo`.
|
|
59
|
+
def divide(left, right)
|
|
60
|
+
raise EvaluationError, "divided by 0" if require_number(right, "division").zero?
|
|
61
|
+
|
|
62
|
+
checked_arithmetic("division", "/", left, right) { |lhs, rhs| lhs / rhs }
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Applies `operation` to two numbers, refusing an Integer outside 64 bits or a Float that
|
|
66
|
+
# is not finite, as `add` does.
|
|
67
|
+
def checked_arithmetic(name, symbol, left, right)
|
|
68
|
+
lhs = require_number(left, name)
|
|
69
|
+
rhs = require_number(right, name)
|
|
70
|
+
result = yield(lhs, rhs)
|
|
71
|
+
return result if representable?(result)
|
|
72
|
+
|
|
73
|
+
raise EvaluationError, "#{name} overflowed: #{lhs} #{symbol} #{rhs} #{overflow_reason(result)}"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def representable?(number) = number.is_a?(Integer) ? INT64_RANGE.cover?(number) : number.finite?
|
|
77
|
+
|
|
78
|
+
def overflow_reason(number) = number.is_a?(Integer) ? "does not fit in a 64-bit integer" : "is not a finite number"
|
|
79
|
+
|
|
49
80
|
def apply_sign_test(node, value)
|
|
50
81
|
number = numeric(value)
|
|
51
82
|
raise EvaluationError, "#{node.test} expects a number, got #{describe(value)}" unless number
|