hecks 3.13.0 → 4.0.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.
Files changed (440) hide show
  1. checksums.yaml +4 -4
  2. data/examples/pizzas/adapters/fake_processor.rb +34 -0
  3. data/examples/pizzas/adapters/payment_signature.rb +66 -0
  4. data/examples/pizzas/adapters/payment_webhook.rb +87 -0
  5. data/examples/pizzas/bluebook/pizzas.behaviors +33 -0
  6. data/examples/pizzas/bluebook/pizzas.bluebook +4 -4
  7. data/examples/pizzas/bluebook/pizzas.hecksagon +5 -3
  8. data/examples/pizzas/config.ru +22 -0
  9. data/lib/hecks/adapters/driven/prism.rb +0 -2
  10. data/lib/hecks/adapters/driven.rb +0 -2
  11. data/lib/hecks/adapters/driving/json.rb +1 -7
  12. data/lib/hecks/bluebook/dsl/attribute_collector.rb +15 -5
  13. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +2 -2
  14. data/lib/hecks/bluebook/dsl/derivation_words.rb +58 -0
  15. data/lib/hecks/bluebook/dsl/translation_builder.rb +6 -37
  16. data/lib/hecks/bluebook/expression/ast_json.rb +0 -9
  17. data/lib/hecks/bluebook/hecksagon.rb +1 -1
  18. data/lib/hecks/bluebook/meta_validator/translation_judge/rules.rb +7 -10
  19. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +4 -8
  20. data/lib/hecks/bluebook/meta_validator.rb +0 -11
  21. data/lib/hecks/bluebook/named_pattern.rb +33 -0
  22. data/lib/hecks/bluebook/translation.rb +18 -10
  23. data/lib/hecks/bluebook/translation_expression/evaluator.rb +63 -0
  24. data/lib/hecks/bluebook/translation_expression/parser.rb +127 -0
  25. data/lib/hecks/bluebook/translation_expression.rb +39 -0
  26. data/lib/hecks/bluebook/translation_plan.rb +70 -0
  27. data/lib/hecks/bluebook.rb +3 -0
  28. data/lib/hecks/chapters.rb +3 -3
  29. data/lib/hecks/cli/domain_stub.rb +1 -1
  30. data/lib/hecks/cli/interview_aggregate.rb +4 -4
  31. data/lib/hecks/composer/adapters/claude_composer.adapter +3 -0
  32. data/lib/hecks/composer/adapters/claude_composer.rb +83 -0
  33. data/lib/hecks/composer/adapters/fake_agent.adapter +3 -0
  34. data/lib/hecks/composer/adapters/fake_agent.rb +55 -0
  35. data/lib/hecks/composer/adapters/jev.adapter +3 -0
  36. data/lib/hecks/composer/adapters/jev.rb +66 -0
  37. data/lib/hecks/composer/agent.rb +113 -0
  38. data/lib/hecks/composer/assistant.rb +110 -0
  39. data/lib/hecks/composer/behavior_run.rb +53 -0
  40. data/lib/hecks/composer/bluebook/composer.bluebook +178 -0
  41. data/lib/hecks/composer/bluebook/composer.hecksagon +16 -0
  42. data/lib/hecks/composer/board.rb +65 -0
  43. data/lib/hecks/composer/board_edit/command_text.rb +39 -0
  44. data/lib/hecks/composer/board_edit/source.rb +84 -0
  45. data/lib/hecks/composer/board_edit.rb +144 -0
  46. data/lib/hecks/composer/check.rb +89 -0
  47. data/lib/hecks/composer/domains.rb +81 -0
  48. data/lib/hecks/composer/jobs.rb +134 -0
  49. data/lib/hecks/composer/layout.rb +37 -0
  50. data/lib/hecks/composer/live.rb +150 -0
  51. data/lib/hecks/composer/outline.rb +48 -0
  52. data/lib/hecks/composer/page.html +989 -0
  53. data/lib/hecks/composer/panels.rb +142 -0
  54. data/lib/hecks/composer/parse.rb +83 -0
  55. data/lib/hecks/composer/plain.rb +28 -0
  56. data/lib/hecks/composer/ports/composer_agent.port +7 -0
  57. data/lib/hecks/composer/session.rb +141 -0
  58. data/lib/hecks/composer/toolbox.rb +166 -0
  59. data/lib/hecks/composer/web.rb +156 -0
  60. data/lib/hecks/composer/workbench.rb +51 -0
  61. data/lib/hecks/composer/workspace.rb +81 -0
  62. data/lib/hecks/composer.rb +17 -0
  63. data/lib/hecks/corpus/adapters.rb +22 -0
  64. data/lib/hecks/corpus/rust.rb +1 -1
  65. data/lib/hecks/corpus/worlds.rb +19 -0
  66. data/lib/hecks/corpus.rb +5 -0
  67. data/lib/hecks/deploy/bluebook/deploy.bluebook +34 -34
  68. data/lib/hecks/forms/app/commands.rb +2 -3
  69. data/lib/hecks/forms/app/queries.rb +2 -3
  70. data/lib/hecks/forms/app/records.rb +17 -5
  71. data/lib/hecks/forms/command_form_renderer.rb +42 -16
  72. data/lib/hecks/forms/field_controls.rb +2 -2
  73. data/lib/hecks/forms/field_renderer.rb +1 -1
  74. data/lib/hecks/forms/field_shape.rb +36 -17
  75. data/lib/hecks/forms/index_renderer.rb +2 -1
  76. data/lib/hecks/forms/page.rb +1 -1
  77. data/lib/hecks/forms/params.rb +0 -13
  78. data/lib/hecks/forms/query_form_renderer.rb +7 -6
  79. data/lib/hecks/forms/record_renderer.rb +11 -7
  80. data/lib/hecks/forms/rule_words.rb +100 -0
  81. data/lib/hecks/forms/value_object_shape.rb +2 -1
  82. data/lib/hecks/framework/bluebook/change.bluebook +2 -2
  83. data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +0 -3
  84. data/lib/hecks/fuzzing/domain_generator/block_rendering.rb +1 -1
  85. data/lib/hecks/fuzzing/isolated_boot/worlds.rb +3 -6
  86. data/lib/hecks/fuzzing/replay/filters.rb +2 -6
  87. data/lib/hecks/gate/stages.yml +25 -0
  88. data/lib/hecks/grammar/evolve/seeds.rb +0 -6
  89. data/lib/hecks/grammar/evolve.rb +0 -3
  90. data/lib/hecks/grammar/translation.bluebook +1 -1
  91. data/lib/hecks/hecks/adapters/codebase/composing.rb +56 -0
  92. data/lib/hecks/hecks/adapters/codebase/source_tree.rb +3 -1
  93. data/lib/hecks/hecks/adapters/journal_store/changes.rb +0 -26
  94. data/lib/hecks/hecks/adapters/journal_store/examination.rb +2 -23
  95. data/lib/hecks/hecks/adapters/journal_store/readings.rb +3 -11
  96. data/lib/hecks/hecks/adapters/journal_store.rb +0 -11
  97. data/lib/hecks/hecks/adapters/rehearsal/inquiry.rb +4 -11
  98. data/lib/hecks/hecks/adapters/rehearsal/memory_store.rb +0 -9
  99. data/lib/hecks/hecks/adapters/rehearsal/postgres_reading.rb +0 -4
  100. data/lib/hecks/hecks/codebase.behaviors +6 -0
  101. data/lib/hecks/hecks/codebase.bluebook +58 -37
  102. data/lib/hecks/hecks/composer.behaviors +68 -0
  103. data/lib/hecks/hecks/context_map.hecksagon +1 -1
  104. data/lib/hecks/hecks/custodian.behaviors +0 -6
  105. data/lib/hecks/hecks/custodian.bluebook +15 -92
  106. data/lib/hecks/hecks/hecks.bluebook +2 -2
  107. data/lib/hecks/hecks/hecks.hecksagon +2 -2
  108. data/lib/hecks/hecks/hecks.world +1 -1
  109. data/lib/hecks/hecks/rehearsal.bluebook +10 -16
  110. data/lib/hecks/hecks/tooling.bluebook +22 -22
  111. data/lib/hecks/kernel_capabilities/templates.rb +4 -4
  112. data/lib/hecks/kernel_capabilities.rb +1 -1
  113. data/lib/hecks/language/bluebook/aggregate.bluebook +1 -0
  114. data/lib/hecks/language/bluebook/command.bluebook +1 -0
  115. data/lib/hecks/language/bluebook/entity.bluebook +1 -0
  116. data/lib/hecks/language/bluebook/query.bluebook +1 -0
  117. data/lib/hecks/language/bluebook/shape.bluebook +8 -7
  118. data/lib/hecks/language/bluebook/vocabulary.bluebook +2 -3
  119. data/lib/hecks/language/hecksagon/port_operation.bluebook +1 -0
  120. data/lib/hecks/language/translation/translation_aggregate.bluebook +21 -24
  121. data/lib/hecks/ports/access_control.rb +2 -2
  122. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +3 -41
  123. data/lib/hecks/ports/persistence/plugins/era/lineage/coverage.rb +7 -7
  124. data/lib/hecks/ports/persistence/plugins/era/lineage/rewrite.rb +25 -2
  125. data/lib/hecks/ports/persistence/plugins/era/lineage/rules.rb +4 -4
  126. data/lib/hecks/ports/persistence/plugins/era/lineage.rb +17 -25
  127. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/base_sql.rb +0 -12
  128. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/domain_rename.rb +1 -1
  129. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +2 -22
  130. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +0 -1
  131. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +9 -3
  132. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +3 -29
  133. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/refusals.rb +2 -26
  134. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +6 -33
  135. data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +3 -3
  136. data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +2 -4
  137. data/lib/hecks/ports/persistence/plugins/era/translation/expression_sql.rb +52 -0
  138. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +23 -29
  139. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +1 -1
  140. data/lib/hecks/ports/persistence/plugins/era/translation.rb +0 -1
  141. data/lib/hecks/ports/persistence/plugins/era.rb +3 -6
  142. data/lib/hecks/ports.rb +0 -1
  143. data/lib/hecks/projection_files.rb +3 -1
  144. data/lib/hecks/projections/deploy/templates/lambda/nat_comment_oauth.tmpl +1 -1
  145. data/lib/hecks/projections/glossary/entries.rb +10 -4
  146. data/lib/hecks/projections/glossary/groups.rb +42 -0
  147. data/lib/hecks/projections/glossary/html/page.rb +7 -2
  148. data/lib/hecks/projections/glossary/html/parser.rb +1 -1
  149. data/lib/hecks/projections/glossary/html/sections.rb +31 -11
  150. data/lib/hecks/projections/glossary/html.rb +1 -2
  151. data/lib/hecks/projections/glossary/markdown.rb +31 -28
  152. data/lib/hecks/projections/glossary/mermaid.rb +3 -0
  153. data/lib/hecks/projections/glossary/page.css +143 -153
  154. data/lib/hecks/projections/glossary/page.js +63 -3
  155. data/lib/hecks/projections/glossary/sentences/actions.rb +88 -0
  156. data/lib/hecks/projections/glossary/sentences/paths.rb +77 -0
  157. data/lib/hecks/projections/glossary/sentences/queries.rb +90 -0
  158. data/lib/hecks/projections/glossary/sentences/value_objects.rb +32 -5
  159. data/lib/hecks/projections/glossary/sentences.rb +13 -3
  160. data/lib/hecks/projections/glossary/slugs.rb +4 -1
  161. data/lib/hecks/projections/glossary.rb +2 -1
  162. data/lib/hecks/projections/plain_english.rb +97 -0
  163. data/lib/hecks/projections/rust_vocabulary/arguments.rb +2 -2
  164. data/lib/hecks/projections/rust_vocabulary/enum_body.rb +20 -25
  165. data/lib/hecks/projections/rust_vocabulary/tests.rb +2 -2
  166. data/lib/hecks/projections/rust_vocabulary.rb +14 -6
  167. data/lib/hecks/projections/site/cms_editor/color.rb +0 -6
  168. data/lib/hecks/projections/statements/actions.rb +99 -0
  169. data/lib/hecks/projections/statements/relationships.rb +86 -0
  170. data/lib/hecks/projections/statements.rb +15 -24
  171. data/lib/hecks/projector/exporter/adapters.rb +112 -0
  172. data/lib/hecks/projector/exporter/translations.rb +18 -35
  173. data/lib/hecks/projector/exporter/worlds.rb +103 -0
  174. data/lib/hecks/projector/exporter.rb +5 -1
  175. data/lib/hecks/quality_control/adapters/agent.rb +6 -7
  176. data/lib/hecks/quality_control/adapters/agent_profile.rb +16 -114
  177. data/lib/hecks/quality_control/cli/qa_mine_combinations.rb +1 -1
  178. data/lib/hecks/quality_control/quality_control.bluebook +51 -51
  179. data/lib/hecks/runtime/loader/boot_steps.rb +0 -20
  180. data/lib/hecks/runtime/outbox.rb +2 -9
  181. data/lib/hecks/runtime/port_operation_interpreter.rb +1 -9
  182. data/lib/hecks/runtime/remote_dispatcher.rb +2 -2
  183. data/lib/hecks/runtime/value.rb +13 -0
  184. data/lib/hecks/rust_build/project_rust/target_ir.rb +23 -4
  185. data/lib/hecks/rust_build/wasm.rb +0 -12
  186. data/lib/hecks/rust_build/write_if_changed.rb +12 -12
  187. data/lib/hecks/rust_format.rb +77 -0
  188. data/lib/hecks/site/bluebook/site.bluebook +5 -5
  189. data/lib/hecks/sme/bluebook/sme.bluebook +12 -12
  190. data/lib/hecks/tickets/bluebook/tickets.bluebook +3 -3
  191. data/lib/hecks/tools/fuzz_sweep/findings.rb +3 -9
  192. data/lib/hecks/tools/fuzz_sweep.rb +1 -3
  193. data/lib/hecks/tools/translation_audit/verdicts.rb +3 -28
  194. data/lib/hecks/tools/translation_audit.rb +8 -10
  195. data/lib/hecks/tools/translation_scaffold/reporting.rb +1 -1
  196. data/lib/hecks/version.rb +1 -1
  197. data/lib/hecks/vocabulary.rb +2 -1
  198. data/lib/hecks.rb +3 -0
  199. data/prebuilt/{58208399bada10b0db99928c48e38789288fc58f7b71a72b21bfa386680e32ed.marshal → 02c09c73b272c1fb5a9ae6d87bb5e5e529208e00f6b4b597dc2c0fd70a9c0964.marshal} +0 -0
  200. data/prebuilt/{2b59737fbdbd5f44edda0fddce2611f45d76087b3a7c782d1f1a17ea58c77948.marshal → bb84a835cf6a15136bad5ca03aa5bf93a5b92f5f72444618d3ef2412b987fb32.marshal} +0 -0
  201. data/prebuilt/verdicts-f1f10da14c8e8f01b4c9b7e3e2d74be8cd2bf4676364ed17fa16975d2a076d75.json +1 -0
  202. data/rust/Cargo.toml +40 -0
  203. data/rust/build/Cargo.toml +36 -0
  204. data/rust/build/clippy.toml +4 -0
  205. data/rust/build/src/adapters_pass.rs +196 -0
  206. data/rust/build/src/binding_pass.rs +54 -13
  207. data/rust/build/src/build_artifact.rs +23 -5
  208. data/rust/build/src/cargo_sync.rs +69 -26
  209. data/rust/build/src/lineage_pass.rs +101 -87
  210. data/rust/build/src/main.rs +11 -2
  211. data/rust/build/src/pipeline.rs +80 -19
  212. data/rust/build/src/reserved_names.rs +6 -50
  213. data/rust/build/src/resolve.rs +82 -35
  214. data/rust/build/src/rustfmt.rs +100 -0
  215. data/rust/build/src/seams_pass.rs +85 -16
  216. data/rust/build/src/subprocess.rs +30 -6
  217. data/rust/build/src/tmp.rs +5 -2
  218. data/rust/build/src/translation_pass.rs +72 -22
  219. data/rust/build/src/world_pass.rs +109 -0
  220. data/rust/clippy.toml +4 -0
  221. data/rust/codegen/Cargo.toml +36 -0
  222. data/rust/codegen/clippy.toml +4 -0
  223. data/rust/codegen/src/asks.rs +40 -14
  224. data/rust/codegen/src/attr.rs +2 -2
  225. data/rust/codegen/src/bridging.rs +676 -117
  226. data/rust/codegen/src/commands.rs +979 -373
  227. data/rust/codegen/src/constraints.rs +88 -25
  228. data/rust/codegen/src/dependency_planning.rs +128 -34
  229. data/rust/codegen/src/domain_generator.rs +300 -170
  230. data/rust/codegen/src/exemplar.rs +87 -32
  231. data/rust/codegen/src/expr_emitter.rs +54 -6
  232. data/rust/codegen/src/fielded.rs +193 -41
  233. data/rust/codegen/src/hecks_naming.rs +124 -16
  234. data/rust/codegen/src/hecks_naming_tests.rs +81 -0
  235. data/rust/codegen/src/json.rs +80 -44
  236. data/rust/codegen/src/json_codec.rs +585 -149
  237. data/rust/codegen/src/literal.rs +104 -138
  238. data/rust/codegen/src/main.rs +145 -52
  239. data/rust/codegen/src/manifest.rs +76 -14
  240. data/rust/codegen/src/mutations.rs +1212 -239
  241. data/rust/codegen/src/naming.rs +111 -60
  242. data/rust/codegen/src/optional_pass.rs +90 -28
  243. data/rust/codegen/src/ports.rs +5 -4
  244. data/rust/codegen/src/prelude.rs +139 -49
  245. data/rust/codegen/src/queries.rs +601 -226
  246. data/rust/codegen/src/reactions.rs +268 -74
  247. data/rust/codegen/src/read_models.rs +606 -205
  248. data/rust/codegen/src/reference_specs.rs +16 -3
  249. data/rust/codegen/src/registry.rs +128 -79
  250. data/rust/codegen/src/reserved_names.rs +6 -50
  251. data/rust/codegen/src/shared.rs +71 -22
  252. data/rust/codegen/src/sidecars.rs +15 -5
  253. data/rust/codegen/src/skip_reason.rs +8 -2
  254. data/rust/codegen/src/types.rs +306 -108
  255. data/rust/host/Cargo.lock +1 -0
  256. data/rust/host/Cargo.toml +40 -4
  257. data/rust/host/HECKS_RELEASE +1 -1
  258. data/rust/host/clippy.toml +4 -0
  259. data/rust/host/src/api.rs +698 -218
  260. data/rust/host/src/auth.rs +491 -214
  261. data/rust/host/src/b64.rs +91 -0
  262. data/rust/host/src/bin/expr_harness.rs +6 -2
  263. data/rust/host/src/bin/lineage_harness.rs +47 -11
  264. data/rust/host/src/bin/mint_harness.rs +70 -37
  265. data/rust/host/src/bin/validate_harness.rs +16 -8
  266. data/rust/host/src/boot.rs +144 -68
  267. data/rust/host/src/boundary_fuzz/api.rs +130 -32
  268. data/rust/host/src/boundary_fuzz/auth.rs +108 -23
  269. data/rust/host/src/boundary_fuzz/expr_json.rs +85 -11
  270. data/rust/host/src/boundary_fuzz/ir.rs +164 -12
  271. data/rust/host/src/boundary_fuzz/server.rs +283 -36
  272. data/rust/host/src/boundary_fuzz/web.rs +56 -8
  273. data/rust/host/src/checkout.rs +78 -32
  274. data/rust/host/src/clock.rs +8 -0
  275. data/rust/host/src/commerce_ir.rs +333 -95
  276. data/rust/host/src/crypto.rs +33 -0
  277. data/rust/host/src/dispatch.rs +990 -331
  278. data/rust/host/src/expr_json.rs +1021 -273
  279. data/rust/host/src/extension.rs +24 -4
  280. data/rust/host/src/field_hints.rs +11 -7
  281. data/rust/host/src/fuzz_support.rs +85 -13
  282. data/rust/host/src/host.rs +100 -0
  283. data/rust/host/src/http.rs +22 -0
  284. data/rust/host/src/ir.rs +326 -16
  285. data/rust/host/src/journal.rs +277 -176
  286. data/rust/host/src/lambda_client.rs +219 -53
  287. data/rust/host/src/lib.rs +16 -4
  288. data/rust/host/src/log.rs +62 -11
  289. data/rust/host/src/mint.rs +1153 -326
  290. data/rust/host/src/needs.rs +185 -44
  291. data/rust/host/src/payments/keystore.rs +197 -45
  292. data/rust/host/src/payments/roles.rs +191 -0
  293. data/rust/host/src/payments/tests.rs +1445 -275
  294. data/rust/host/src/payments.rs +409 -121
  295. data/rust/host/src/platform_signin/attack_tests.rs +5 -5
  296. data/rust/host/src/platform_signin/config.rs +11 -11
  297. data/rust/host/src/platform_signin/cookie.rs +2 -2
  298. data/rust/host/src/platform_signin/extension.rs +2 -1
  299. data/rust/host/src/platform_signin/handler.rs +9 -8
  300. data/rust/host/src/platform_signin/jti.rs +4 -2
  301. data/rust/host/src/platform_signin/jwks.rs +2 -1
  302. data/rust/host/src/platform_signin/jws.rs +2 -37
  303. data/rust/host/src/platform_signin/known_answer_tests.rs +5 -1
  304. data/rust/host/src/platform_signin/mode_tests.rs +5 -3
  305. data/rust/host/src/platform_signin/pages.rs +20 -20
  306. data/rust/host/src/platform_signin/session.rs +8 -1
  307. data/rust/host/src/platform_signin/settings.rs +6 -6
  308. data/rust/host/src/platform_signin/strict_json.rs +12 -9
  309. data/rust/host/src/platform_signin/verify.rs +41 -41
  310. data/rust/host/src/platform_signin/wiring_support.rs +13 -18
  311. data/rust/host/src/presentation.rs +207 -63
  312. data/rust/host/src/presentation_write.rs +502 -187
  313. data/rust/host/src/query_step.rs +69 -18
  314. data/rust/host/src/rate_limit.rs +541 -142
  315. data/rust/host/src/reference_transform.rs +77 -25
  316. data/rust/host/src/reference_validate.rs +443 -104
  317. data/rust/host/src/resend.rs +190 -55
  318. data/rust/host/src/secrets.rs +116 -21
  319. data/rust/host/src/server.rs +483 -104
  320. data/rust/host/src/storage_shape.rs +88 -21
  321. data/rust/host/src/test_pg.rs +17 -7
  322. data/rust/host/src/ui_schema.rs +495 -207
  323. data/rust/host/src/wasm_runner.rs +21 -6
  324. data/rust/host/src/web/commerce.rs +101 -23
  325. data/rust/host/src/web/newsletter/cooldown.rs +10 -3
  326. data/rust/host/src/web/newsletter/template.rs +26 -7
  327. data/rust/host/src/web/newsletter/tests.rs +112 -23
  328. data/rust/host/src/web/newsletter.rs +209 -59
  329. data/rust/host/src/web/newsletter_send.rs +251 -79
  330. data/rust/host/src/web/registration_receipt/tests.rs +16 -4
  331. data/rust/host/src/web/registration_receipt.rs +100 -24
  332. data/rust/host/src/web/registrations.rs +1384 -332
  333. data/rust/host/src/web/resend_webhook.rs +138 -80
  334. data/rust/host/src/web.rs +2416 -508
  335. data/rust/lsp/Cargo.toml +36 -0
  336. data/rust/lsp/clippy.toml +4 -0
  337. data/rust/lsp/src/json.rs +29 -22
  338. data/rust/lsp/src/main.rs +81 -31
  339. data/rust/lsp/src/outline.rs +23 -7
  340. data/rust/lsp/src/rpc.rs +17 -4
  341. data/rust/parser/Cargo.toml +36 -0
  342. data/rust/parser/clippy.toml +4 -0
  343. data/rust/parser/src/build/closed_sets.rs +6 -1
  344. data/rust/parser/src/build/identity.rs +4 -3
  345. data/rust/parser/src/build/mod.rs +1 -0
  346. data/rust/parser/src/build/named_pattern.rs +26 -0
  347. data/rust/parser/src/build/naming.rs +2 -80
  348. data/rust/parser/src/build/pattern_subset.rs +6 -8
  349. data/rust/parser/src/build/query_derive.rs +3 -1
  350. data/rust/parser/src/build/query_inference.rs +14 -5
  351. data/rust/parser/src/build/read_model.rs +4 -1
  352. data/rust/parser/src/build/references.rs +4 -3
  353. data/rust/parser/src/canonical.rs +34 -15
  354. data/rust/parser/src/emit.rs +187 -105
  355. data/rust/parser/src/expr/ast_json.rs +134 -42
  356. data/rust/parser/src/expr/evaluator.rs +27 -9
  357. data/rust/parser/src/expr/mod.rs +54 -13
  358. data/rust/parser/src/expr/resolver.rs +299 -92
  359. data/rust/parser/src/ir.rs +35 -3
  360. data/rust/parser/src/keywords.rs +7168 -510
  361. data/rust/parser/src/lex.rs +11 -25
  362. data/rust/parser/src/lib.rs +1 -0
  363. data/rust/parser/src/main.rs +65 -6
  364. data/rust/parser/src/parse/adapter.rs +157 -0
  365. data/rust/parser/src/parse/aggregate.rs +19 -10
  366. data/rust/parser/src/parse/chapter.rs +16 -17
  367. data/rust/parser/src/parse/command.rs +35 -16
  368. data/rust/parser/src/parse/domain_port.rs +4 -7
  369. data/rust/parser/src/parse/entity.rs +21 -11
  370. data/rust/parser/src/parse/hecksagon.rs +10 -4
  371. data/rust/parser/src/parse/lifecycle.rs +9 -5
  372. data/rust/parser/src/parse/mod.rs +43 -91
  373. data/rust/parser/src/parse/needs.rs +21 -12
  374. data/rust/parser/src/parse/policy.rs +2 -2
  375. data/rust/parser/src/parse/process_manager.rs +9 -11
  376. data/rust/parser/src/parse/query.rs +8 -4
  377. data/rust/parser/src/parse/read_model.rs +57 -16
  378. data/rust/parser/src/parse/value_object.rs +7 -2
  379. data/rust/parser/src/parse/world.rs +322 -0
  380. data/rust/parser/src/ruby_value.rs +7 -6
  381. data/rust/src/exemplar/json.rs +4 -4
  382. data/rust/src/exemplar/mutations.rs +18 -0
  383. data/rust/src/exemplar/read_models.rs +1 -10
  384. data/rust/src/kernel/attribute_shapes/composite.rs +54 -14
  385. data/rust/src/kernel/attribute_shapes/list.rs +2 -2
  386. data/rust/src/kernel/attribute_shapes/mod.rs +8 -8
  387. data/rust/src/kernel/attribute_shapes/scalar.rs +2 -2
  388. data/rust/src/kernel/cli.rs +229 -112
  389. data/rust/src/kernel/dispatch.rs +323 -115
  390. data/rust/src/kernel/dispatch_guard_tests.rs +327 -65
  391. data/rust/src/kernel/expr.rs +203 -86
  392. data/rust/src/kernel/expression_operators/arithmetic.rs +138 -25
  393. data/rust/src/kernel/expression_operators/comparison.rs +87 -2
  394. data/rust/src/kernel/expression_operators/enumeration.rs +106 -22
  395. data/rust/src/kernel/expression_operators/logical.rs +9 -3
  396. data/rust/src/kernel/expression_operators/membership.rs +3 -1
  397. data/rust/src/kernel/expression_operators/mod.rs +34 -21
  398. data/rust/src/kernel/expression_operators/pattern_match.rs +46 -11
  399. data/rust/src/kernel/expression_operators/positional.rs +84 -30
  400. data/rust/src/kernel/expression_operators/presence.rs +52 -13
  401. data/rust/src/kernel/expression_operators/sign_test.rs +3 -1
  402. data/rust/src/kernel/expression_operators/sized.rs +24 -8
  403. data/rust/src/kernel/expression_operators/text.rs +120 -27
  404. data/rust/src/kernel/expression_operators/to_string.rs +10 -4
  405. data/rust/src/kernel/json.rs +230 -148
  406. data/rust/src/kernel/mod.rs +46 -33
  407. data/rust/src/kernel/named_query.rs +63 -15
  408. data/rust/src/kernel/needs.rs +112 -25
  409. data/rust/src/kernel/orchestrate.rs +980 -581
  410. data/rust/src/kernel/orchestrate_guard_tests.rs +538 -140
  411. data/rust/src/kernel/pattern.rs +107 -34
  412. data/rust/src/kernel/query_comparators.rs +118 -41
  413. data/rust/src/kernel/query_ordering.rs +13 -5
  414. data/rust/src/kernel/read_model.rs +479 -181
  415. data/rust/src/kernel/reference_lookup.rs +122 -26
  416. data/rust/src/kernel/repository.rs +293 -66
  417. data/rust/src/kernel/routing.rs +58 -42
  418. data/rust/src/kernel/ruby_float.rs +139 -0
  419. data/rust/src/kernel/vocab/aggregate_dispatch_order.rs +57 -57
  420. data/rust/src/kernel/vocab/entity_dispatch_order.rs +54 -54
  421. data/rust/src/kernel/vocab/field_hint.rs +19 -25
  422. data/rust/src/kernel/vocab/mod.rs +6 -6
  423. data/rust/src/kernel/vocab/query_comparator.rs +23 -24
  424. data/rust/src/kernel/vocab/refusal_template.rs +501 -297
  425. data/rust/src/lib.rs +50 -0
  426. data/rust/src/main.rs +4 -1
  427. data/rust/web/Cargo.toml +36 -0
  428. data/rust/web/clippy.toml +4 -0
  429. metadata +85 -15
  430. data/examples/pizzas/bluebook/hecksagon/mock_stripe_payment_adapter.rb +0 -36
  431. data/lib/hecks/adapters/driven/google_authentication.adapter +0 -3
  432. data/lib/hecks/adapters/driven/google_authentication.rb +0 -99
  433. data/lib/hecks/adapters/driven/mock_stripe_adapter.adapter +0 -3
  434. data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +0 -32
  435. data/lib/hecks/ports/authentication.port +0 -6
  436. data/lib/hecks/ports/authentication.rb +0 -67
  437. data/lib/hecks/ports/persistence/plugins/era/translation/approval_file.rb +0 -255
  438. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +0 -22
  439. data/prebuilt/verdicts-48318ca172edd21443b1ad02801c697fff100b746e828f09db987647641a5df2.json +0 -1
  440. data/rust/host/src/approval.rs +0 -652
data/rust/lsp/Cargo.toml CHANGED
@@ -14,3 +14,39 @@ path = "src/main.rs"
14
14
  # and src/json.rs vendors a minimal JSON pair as rust/build/src/json.rs does.
15
15
  # Revisit if it ever needs to serve concurrent requests.
16
16
  [dependencies]
17
+
18
+ # Clippy beyond its defaults: pedantic and nursery, plus the restriction lints that keep a panic
19
+ # out of library code. `hecks gate_run.gate stage=ci only=rust_clippy` makes each of these an error.
20
+ # The same table is in every crate's Cargo.toml; change them together.
21
+ [lints.clippy]
22
+ pedantic = { level = "warn", priority = -1 }
23
+ nursery = { level = "warn", priority = -1 }
24
+ unwrap_used = "warn"
25
+ expect_used = "warn"
26
+ panic = "warn"
27
+ dbg_macro = "warn"
28
+ todo = "warn"
29
+ unimplemented = "warn"
30
+ # Lints that ask for prose or an attribute on every item rather than for better code.
31
+ missing_errors_doc = "allow"
32
+ missing_panics_doc = "allow"
33
+ must_use_candidate = "allow"
34
+ return_self_not_must_use = "allow"
35
+ module_name_repetitions = "allow"
36
+ too_many_lines = "allow"
37
+ too_long_first_doc_paragraph = "allow"
38
+ doc_markdown = "allow"
39
+ # Numeric conversions here are deliberate: JSON numbers are f64 and ids are small.
40
+ cast_possible_truncation = "allow"
41
+ cast_possible_wrap = "allow"
42
+ cast_precision_loss = "allow"
43
+ cast_sign_loss = "allow"
44
+ # Naming heuristics that fire on ordinary short names.
45
+ similar_names = "allow"
46
+ many_single_char_names = "allow"
47
+ struct_field_names = "allow"
48
+ # Heuristics that cost more clarity than they buy here.
49
+ redundant_pub_crate = "allow"
50
+ future_not_send = "allow"
51
+ significant_drop_tightening = "allow"
52
+ match_same_arms = "allow"
@@ -0,0 +1,4 @@
1
+ # The restriction lints (unwrap, expect, panic) guard library code; a test panics to fail.
2
+ allow-unwrap-in-tests = true
3
+ allow-expect-in-tests = true
4
+ allow-panic-in-tests = true
data/rust/lsp/src/json.rs CHANGED
@@ -9,14 +9,17 @@ pub enum Json {
9
9
  Bool(bool),
10
10
  Number(i64),
11
11
  String(String),
12
- Array(Vec<Json>),
12
+ Array(Vec<Self>),
13
13
  /// Insertion-ordered pairs.
14
- Object(Vec<(String, Json)>),
14
+ Object(Vec<(String, Self)>),
15
15
  }
16
16
 
17
17
  impl Json {
18
- pub fn parse(text: &str) -> Result<Json, String> {
19
- let mut p = Parser { bytes: text.as_bytes(), pos: 0 };
18
+ pub fn parse(text: &str) -> Result<Self, String> {
19
+ let mut p = Parser {
20
+ bytes: text.as_bytes(),
21
+ pos: 0,
22
+ };
20
23
  p.skip_ws();
21
24
  let value = p.parse_value()?;
22
25
  p.skip_ws();
@@ -26,43 +29,43 @@ impl Json {
26
29
  Ok(value)
27
30
  }
28
31
 
29
- pub fn get(&self, key: &str) -> Option<&Json> {
32
+ pub fn get(&self, key: &str) -> Option<&Self> {
30
33
  match self {
31
- Json::Object(pairs) => pairs
34
+ Self::Object(pairs) => pairs
32
35
  .iter()
33
- .find(|(k, v)| k == key && !matches!(v, Json::Null))
36
+ .find(|(k, v)| k == key && !matches!(v, Self::Null))
34
37
  .map(|(_, v)| v),
35
38
  _ => None,
36
39
  }
37
40
  }
38
41
 
39
- pub fn as_str(&self) -> Option<&str> {
42
+ pub const fn as_str(&self) -> Option<&str> {
40
43
  match self {
41
- Json::String(s) => Some(s.as_str()),
44
+ Self::String(s) => Some(s.as_str()),
42
45
  _ => None,
43
46
  }
44
47
  }
45
48
 
46
- pub fn as_i64(&self) -> Option<i64> {
49
+ pub const fn as_i64(&self) -> Option<i64> {
47
50
  match self {
48
- Json::Number(n) => Some(*n),
51
+ Self::Number(n) => Some(*n),
49
52
  _ => None,
50
53
  }
51
54
  }
52
55
 
53
- pub fn as_array(&self) -> Option<&[Json]> {
56
+ pub const fn as_array(&self) -> Option<&[Self]> {
54
57
  match self {
55
- Json::Array(items) => Some(items.as_slice()),
58
+ Self::Array(items) => Some(items.as_slice()),
56
59
  _ => None,
57
60
  }
58
61
  }
59
62
 
60
- pub fn string(s: impl Into<String>) -> Json {
61
- Json::String(s.into())
63
+ pub fn string(s: impl Into<String>) -> Self {
64
+ Self::String(s.into())
62
65
  }
63
66
 
64
- pub fn object(pairs: Vec<(&str, Json)>) -> Json {
65
- Json::Object(pairs.into_iter().map(|(k, v)| (k.to_string(), v)).collect())
67
+ pub fn object(pairs: Vec<(&str, Self)>) -> Self {
68
+ Self::Object(pairs.into_iter().map(|(k, v)| (k.to_string(), v)).collect())
66
69
  }
67
70
  }
68
71
 
@@ -71,7 +74,7 @@ struct Parser<'a> {
71
74
  pos: usize,
72
75
  }
73
76
 
74
- impl<'a> Parser<'a> {
77
+ impl Parser<'_> {
75
78
  fn peek(&self) -> Option<u8> {
76
79
  self.bytes.get(self.pos).copied()
77
80
  }
@@ -261,7 +264,8 @@ impl<'a> Parser<'a> {
261
264
  }
262
265
  Some(_) => {
263
266
  let start = self.pos;
264
- let rest = std::str::from_utf8(&self.bytes[start..]).map_err(|e| e.to_string())?;
267
+ let rest =
268
+ std::str::from_utf8(&self.bytes[start..]).map_err(|e| e.to_string())?;
265
269
  let ch = rest.chars().next().ok_or("empty remainder")?;
266
270
  out.push(ch);
267
271
  self.pos += ch.len_utf8();
@@ -286,9 +290,9 @@ impl<'a> Parser<'a> {
286
290
  self.pos += 1;
287
291
  }
288
292
  }
289
- if matches!(self.peek(), Some(b'e') | Some(b'E')) {
293
+ if matches!(self.peek(), Some(b'e' | b'E')) {
290
294
  self.pos += 1;
291
- if matches!(self.peek(), Some(b'+') | Some(b'-')) {
295
+ if matches!(self.peek(), Some(b'+' | b'-')) {
292
296
  self.pos += 1;
293
297
  }
294
298
  while matches!(self.peek(), Some(c) if c.is_ascii_digit()) {
@@ -369,7 +373,10 @@ mod tests {
369
373
  fn round_trips_a_request() {
370
374
  let text = r#"{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}"#;
371
375
  let value = Json::parse(text).expect("parses");
372
- assert_eq!(value.get("method").and_then(Json::as_str), Some("initialize"));
376
+ assert_eq!(
377
+ value.get("method").and_then(Json::as_str),
378
+ Some("initialize")
379
+ );
373
380
  assert_eq!(value.get("id"), Some(&Json::Number(1)));
374
381
  }
375
382
 
data/rust/lsp/src/main.rs CHANGED
@@ -8,6 +8,7 @@ mod rpc;
8
8
 
9
9
  use json::Json;
10
10
  use std::collections::HashMap;
11
+ use std::fmt::Write as _;
11
12
  use std::io::{self, BufReader, Write};
12
13
  use std::path::{Path, PathBuf};
13
14
 
@@ -88,9 +89,10 @@ impl Server {
88
89
  "exit" => return false,
89
90
  "textDocument/didOpen" => {
90
91
  if let Some(doc) = message.get("params").and_then(|p| p.get("textDocument")) {
91
- if let (Some(uri), Some(text)) =
92
- (doc.get("uri").and_then(Json::as_str), doc.get("text").and_then(Json::as_str))
93
- {
92
+ if let (Some(uri), Some(text)) = (
93
+ doc.get("uri").and_then(Json::as_str),
94
+ doc.get("text").and_then(Json::as_str),
95
+ ) {
94
96
  self.documents.insert(uri.to_string(), text.to_string());
95
97
  self.check_document(uri, out);
96
98
  }
@@ -131,12 +133,15 @@ impl Server {
131
133
  .and_then(|p| p.get("textDocument"))
132
134
  .and_then(|t| t.get("uri"))
133
135
  .and_then(Json::as_str);
134
- let result = match uri.and_then(|u| self.documents.get(u)) {
135
- Some(text) => {
136
- Json::Array(outline::outline(text).iter().map(document_symbol_json).collect())
137
- }
138
- None => Json::Array(Vec::new()),
139
- };
136
+ let result = Json::Array(uri.and_then(|u| self.documents.get(u)).map_or_else(
137
+ Vec::new,
138
+ |text| {
139
+ outline::outline(text)
140
+ .iter()
141
+ .map(document_symbol_json)
142
+ .collect()
143
+ },
144
+ ));
140
145
  let _ = rpc::write_message(out, &rpc::response(id, result));
141
146
  }
142
147
  }
@@ -200,7 +205,11 @@ impl Server {
200
205
  let _ = std::fs::create_dir_all(parent);
201
206
  }
202
207
  if let Err(e) = std::fs::write(&temp_path, &text) {
203
- log(out, 1, &format!("hecks-lsp: could not stage {}: {e}", temp_path.display()));
208
+ log(
209
+ out,
210
+ 1,
211
+ &format!("hecks-lsp: could not stage {}: {e}", temp_path.display()),
212
+ );
204
213
  return;
205
214
  }
206
215
 
@@ -233,18 +242,23 @@ impl Server {
233
242
  let dir = path.parent()?;
234
243
  let mut siblings: Vec<PathBuf> = std::fs::read_dir(dir)
235
244
  .ok()?
236
- .filter_map(|e| e.ok())
245
+ .filter_map(std::result::Result::ok)
237
246
  .map(|e| e.path())
238
247
  .filter(|p| {
239
248
  *p != path
240
- && matches!(p.extension().and_then(|e| e.to_str()), Some("bluebook") | Some("hecksagon"))
249
+ && matches!(
250
+ p.extension().and_then(|e| e.to_str()),
251
+ Some("bluebook" | "hecksagon")
252
+ )
241
253
  })
242
254
  .collect();
243
255
  // Sorted so a name declared in several siblings resolves deterministically.
244
256
  siblings.sort();
245
257
 
246
258
  for sibling in siblings {
247
- let Ok(sibling_text) = std::fs::read_to_string(&sibling) else { continue };
259
+ let Ok(sibling_text) = std::fs::read_to_string(&sibling) else {
260
+ continue;
261
+ };
248
262
  let roots = outline::outline(&sibling_text);
249
263
  if let Some(symbol) = outline::find_by_name(&roots, &identifier) {
250
264
  return Some(location(&path_to_uri(&sibling), symbol.start_line));
@@ -280,10 +294,16 @@ fn identifier_at(line_text: &str, character: usize) -> Option<String> {
280
294
  /// A zero-width `Location` at the declaring line; the outline is line-based, so no column.
281
295
  fn location(uri: &str, line_1_indexed: usize) -> Json {
282
296
  let line0 = line_1_indexed.saturating_sub(1) as i64;
283
- let point = Json::object(vec![("line", Json::Number(line0)), ("character", Json::Number(0))]);
297
+ let point = Json::object(vec![
298
+ ("line", Json::Number(line0)),
299
+ ("character", Json::Number(0)),
300
+ ]);
284
301
  Json::object(vec![
285
302
  ("uri", Json::string(uri)),
286
- ("range", Json::object(vec![("start", point.clone()), ("end", point)])),
303
+ (
304
+ "range",
305
+ Json::object(vec![("start", point.clone()), ("end", point)]),
306
+ ),
287
307
  ])
288
308
  }
289
309
 
@@ -291,21 +311,38 @@ fn document_symbol_json(symbol: &outline::Symbol) -> Json {
291
311
  let start0 = symbol.start_line.saturating_sub(1) as i64;
292
312
  let end0 = symbol.end_line.max(symbol.start_line).saturating_sub(1) as i64;
293
313
  let range = Json::object(vec![
294
- ("start", Json::object(vec![("line", Json::Number(start0)), ("character", Json::Number(0))])),
295
- ("end", Json::object(vec![("line", Json::Number(end0)), ("character", Json::Number(0))])),
314
+ (
315
+ "start",
316
+ Json::object(vec![
317
+ ("line", Json::Number(start0)),
318
+ ("character", Json::Number(0)),
319
+ ]),
320
+ ),
321
+ (
322
+ "end",
323
+ Json::object(vec![
324
+ ("line", Json::Number(end0)),
325
+ ("character", Json::Number(0)),
326
+ ]),
327
+ ),
296
328
  ]);
297
329
  Json::object(vec![
298
330
  ("name", Json::string(symbol.name.clone())),
299
331
  ("kind", Json::Number(lsp_symbol_kind(symbol.kind))),
300
332
  ("range", range.clone()),
301
333
  ("selectionRange", range),
302
- ("children", Json::Array(symbol.children.iter().map(document_symbol_json).collect())),
334
+ (
335
+ "children",
336
+ Json::Array(symbol.children.iter().map(document_symbol_json).collect()),
337
+ ),
303
338
  ])
304
339
  }
305
340
 
306
341
  /// Maps a construct to an LSP `SymbolKind` number by how it reads in an outline.
307
- fn lsp_symbol_kind(kind: outline::Kind) -> i64 {
308
- use outline::Kind::*;
342
+ const fn lsp_symbol_kind(kind: outline::Kind) -> i64 {
343
+ use outline::Kind::{
344
+ Aggregate, Command, Entity, Policy, ProcessManager, Query, ReadModel, ValueObject,
345
+ };
309
346
  match kind {
310
347
  Aggregate => 5, // Class
311
348
  ProcessManager => 5, // Class
@@ -332,11 +369,17 @@ fn publish_diagnostics(out: &mut impl Write, uri: &str, diagnostics: Vec<Json>)
332
369
  ("uri", Json::string(uri)),
333
370
  ("diagnostics", Json::Array(diagnostics)),
334
371
  ]);
335
- let _ = rpc::write_message(out, &rpc::notification("textDocument/publishDiagnostics", params));
372
+ let _ = rpc::write_message(
373
+ out,
374
+ &rpc::notification("textDocument/publishDiagnostics", params),
375
+ );
336
376
  }
337
377
 
338
378
  fn log(out: &mut impl Write, severity: i64, message: &str) {
339
- let params = Json::object(vec![("type", Json::Number(severity)), ("message", Json::string(message))]);
379
+ let params = Json::object(vec![
380
+ ("type", Json::Number(severity)),
381
+ ("message", Json::string(message)),
382
+ ]);
340
383
  let _ = rpc::write_message(out, &rpc::notification("window/logMessage", params));
341
384
  }
342
385
 
@@ -347,13 +390,12 @@ fn lsp_diagnostic(diag: &diagnostics::FileDiagnostic, text: &str) -> Json {
347
390
  let line_len = text
348
391
  .lines()
349
392
  .nth(diag.line.saturating_sub(1))
350
- .map(|l| l.chars().count() as i64)
351
- .unwrap_or(0)
393
+ .map_or(0, |l| l.chars().count() as i64)
352
394
  .max(1);
353
395
 
354
396
  let mut message = diag.message.clone();
355
397
  if !diag.expected.is_empty() {
356
- message.push_str(&format!(" (expected one of: {})", diag.expected.join(", ")));
398
+ let _ = write!(message, " (expected one of: {})", diag.expected.join(", "));
357
399
  }
358
400
 
359
401
  Json::object(vec![
@@ -362,7 +404,10 @@ fn lsp_diagnostic(diag: &diagnostics::FileDiagnostic, text: &str) -> Json {
362
404
  Json::object(vec![
363
405
  (
364
406
  "start",
365
- Json::object(vec![("line", Json::Number(zero_based_line)), ("character", Json::Number(0))]),
407
+ Json::object(vec![
408
+ ("line", Json::Number(zero_based_line)),
409
+ ("character", Json::Number(0)),
410
+ ]),
366
411
  ),
367
412
  (
368
413
  "end",
@@ -374,7 +419,10 @@ fn lsp_diagnostic(diag: &diagnostics::FileDiagnostic, text: &str) -> Json {
374
419
  ]),
375
420
  ),
376
421
  // 1 = Error, 2 = Warning (LSP DiagnosticSeverity).
377
- ("severity", Json::Number(if diag.not_yet_implemented { 2 } else { 1 })),
422
+ (
423
+ "severity",
424
+ Json::Number(if diag.not_yet_implemented { 2 } else { 1 }),
425
+ ),
378
426
  ("source", Json::string("hecks-parse")),
379
427
  ("message", Json::string(message)),
380
428
  ])
@@ -386,14 +434,16 @@ fn lsp_diagnostic(diag: &diagnostics::FileDiagnostic, text: &str) -> Json {
386
434
  fn temp_path_for(uri: &str) -> PathBuf {
387
435
  let hash = fnv1a(uri.as_bytes());
388
436
  let basename = uri.rsplit('/').next().unwrap_or("buffer.bluebook");
389
- std::env::temp_dir().join("hecks-lsp").join(format!("{hash:016x}-{basename}"))
437
+ std::env::temp_dir()
438
+ .join("hecks-lsp")
439
+ .join(format!("{hash:016x}-{basename}"))
390
440
  }
391
441
 
392
442
  fn fnv1a(bytes: &[u8]) -> u64 {
393
- let mut hash: u64 = 0xcbf29ce484222325;
443
+ let mut hash: u64 = 0xcbf2_9ce4_8422_2325;
394
444
  for &b in bytes {
395
- hash ^= b as u64;
396
- hash = hash.wrapping_mul(0x100000001b3);
445
+ hash ^= u64::from(b);
446
+ hash = hash.wrapping_mul(0x0100_0000_01b3);
397
447
  }
398
448
  hash
399
449
  }
@@ -7,7 +7,7 @@ pub struct Symbol {
7
7
  pub kind: Kind,
8
8
  pub start_line: usize, // 1-indexed declaring line
9
9
  pub end_line: usize, // 1-indexed line of the closing `end`
10
- pub children: Vec<Symbol>,
10
+ pub children: Vec<Self>,
11
11
  }
12
12
 
13
13
  /// The construct keywords the outline recognizes.
@@ -35,7 +35,7 @@ const CONSTRUCTS: &[(&str, Kind)] = &[
35
35
  ];
36
36
 
37
37
  /// Whether a bare identifier can name this kind; only these are definition targets.
38
- pub fn is_reference_target(kind: Kind) -> bool {
38
+ pub const fn is_reference_target(kind: Kind) -> bool {
39
39
  matches!(kind, Kind::Aggregate | Kind::Entity | Kind::ValueObject)
40
40
  }
41
41
 
@@ -57,7 +57,13 @@ pub fn outline(text: &str) -> Vec<Symbol> {
57
57
  let trimmed = raw_line.trim();
58
58
 
59
59
  if let Some((name, kind)) = opens_construct(trimmed) {
60
- stack.push(Frame { name, kind, start_line: line_no, depth_at_push: depth, children: Vec::new() });
60
+ stack.push(Frame {
61
+ name,
62
+ kind,
63
+ start_line: line_no,
64
+ depth_at_push: depth,
65
+ children: Vec::new(),
66
+ });
61
67
  depth += 1;
62
68
  continue;
63
69
  }
@@ -69,8 +75,13 @@ pub fn outline(text: &str) -> Vec<Symbol> {
69
75
 
70
76
  if trimmed == "end" {
71
77
  depth = depth.saturating_sub(1);
72
- if matches!(stack.last(), Some(frame) if frame.depth_at_push == depth) {
73
- let frame = stack.pop().expect("just matched Some(frame) above");
78
+ if stack
79
+ .last()
80
+ .is_some_and(|frame| frame.depth_at_push == depth)
81
+ {
82
+ let Some(frame) = stack.pop() else {
83
+ continue;
84
+ };
74
85
  let symbol = Symbol {
75
86
  name: frame.name,
76
87
  kind: frame.kind,
@@ -91,10 +102,15 @@ pub fn outline(text: &str) -> Vec<Symbol> {
91
102
 
92
103
  fn opens_construct(trimmed: &str) -> Option<(String, Kind)> {
93
104
  for (keyword, kind) in CONSTRUCTS {
94
- let Some(after) = trimmed.strip_prefix(keyword).and_then(|r| r.strip_prefix(" \"")) else {
105
+ let Some(after) = trimmed
106
+ .strip_prefix(keyword)
107
+ .and_then(|r| r.strip_prefix(" \""))
108
+ else {
109
+ continue;
110
+ };
111
+ let Some(end_quote) = after.find('"') else {
95
112
  continue;
96
113
  };
97
- let Some(end_quote) = after.find('"') else { continue };
98
114
  if after[end_quote + 1..].trim() == "do" {
99
115
  return Some((after[..end_quote].to_string(), *kind));
100
116
  }
data/rust/lsp/src/rpc.rs CHANGED
@@ -19,13 +19,19 @@ pub fn read_message(stdin: &mut impl BufRead) -> io::Result<Option<Json>> {
19
19
  }
20
20
  if let Some(value) = line.strip_prefix("Content-Length:") {
21
21
  content_length = Some(value.trim().parse().map_err(|e| {
22
- io::Error::new(io::ErrorKind::InvalidData, format!("bad Content-Length: {e}"))
22
+ io::Error::new(
23
+ io::ErrorKind::InvalidData,
24
+ format!("bad Content-Length: {e}"),
25
+ )
23
26
  })?);
24
27
  }
25
28
  }
26
29
 
27
30
  let len = content_length.ok_or_else(|| {
28
- io::Error::new(io::ErrorKind::InvalidData, "message had no Content-Length header")
31
+ io::Error::new(
32
+ io::ErrorKind::InvalidData,
33
+ "message had no Content-Length header",
34
+ )
29
35
  })?;
30
36
  let mut buf = vec![0u8; len];
31
37
  stdin.read_exact(&mut buf)?;
@@ -44,7 +50,11 @@ pub fn write_message(stdout: &mut impl Write, value: &Json) -> io::Result<()> {
44
50
  }
45
51
 
46
52
  pub fn response(id: Json, result: Json) -> Json {
47
- Json::object(vec![("jsonrpc", Json::string("2.0")), ("id", id), ("result", result)])
53
+ Json::object(vec![
54
+ ("jsonrpc", Json::string("2.0")),
55
+ ("id", id),
56
+ ("result", result),
57
+ ])
48
58
  }
49
59
 
50
60
  pub fn notification(method: &str, params: Json) -> Json {
@@ -61,7 +71,10 @@ pub fn error_response(id: Json, code: i64, message: &str) -> Json {
61
71
  ("id", id),
62
72
  (
63
73
  "error",
64
- Json::object(vec![("code", Json::Number(code)), ("message", Json::string(message))]),
74
+ Json::object(vec![
75
+ ("code", Json::Number(code)),
76
+ ("message", Json::string(message)),
77
+ ]),
65
78
  ),
66
79
  ])
67
80
  }
@@ -19,3 +19,39 @@ path = "src/main.rs"
19
19
  # CI never attaches a debugger to dev binaries, so skip debuginfo to save build time.
20
20
  [profile.dev]
21
21
  debug = 0
22
+
23
+ # Clippy beyond its defaults: pedantic and nursery, plus the restriction lints that keep a panic
24
+ # out of library code. `hecks gate_run.gate stage=ci only=rust_clippy` makes each of these an error.
25
+ # The same table is in every crate's Cargo.toml; change them together.
26
+ [lints.clippy]
27
+ pedantic = { level = "warn", priority = -1 }
28
+ nursery = { level = "warn", priority = -1 }
29
+ unwrap_used = "warn"
30
+ expect_used = "warn"
31
+ panic = "warn"
32
+ dbg_macro = "warn"
33
+ todo = "warn"
34
+ unimplemented = "warn"
35
+ # Lints that ask for prose or an attribute on every item rather than for better code.
36
+ missing_errors_doc = "allow"
37
+ missing_panics_doc = "allow"
38
+ must_use_candidate = "allow"
39
+ return_self_not_must_use = "allow"
40
+ module_name_repetitions = "allow"
41
+ too_many_lines = "allow"
42
+ too_long_first_doc_paragraph = "allow"
43
+ doc_markdown = "allow"
44
+ # Numeric conversions here are deliberate: JSON numbers are f64 and ids are small.
45
+ cast_possible_truncation = "allow"
46
+ cast_possible_wrap = "allow"
47
+ cast_precision_loss = "allow"
48
+ cast_sign_loss = "allow"
49
+ # Naming heuristics that fire on ordinary short names.
50
+ similar_names = "allow"
51
+ many_single_char_names = "allow"
52
+ struct_field_names = "allow"
53
+ # Heuristics that cost more clarity than they buy here.
54
+ redundant_pub_crate = "allow"
55
+ future_not_send = "allow"
56
+ significant_drop_tightening = "allow"
57
+ match_same_arms = "allow"
@@ -0,0 +1,4 @@
1
+ # The restriction lints (unwrap, expect, panic) guard library code; a test panics to fail.
2
+ allow-unwrap-in-tests = true
3
+ allow-expect-in-tests = true
4
+ allow-panic-in-tests = true
@@ -21,7 +21,12 @@ pub fn synthesize(field_name: &str, values: &[String]) -> ir::ValueObject {
21
21
  closed_set: true,
22
22
  members: values
23
23
  .iter()
24
- .map(|value| vec![("value".to_string(), crate::ruby_value::Value::Str(value.clone()))])
24
+ .map(|value| {
25
+ vec![(
26
+ "value".to_string(),
27
+ crate::ruby_value::Value::Str(value.clone()),
28
+ )]
29
+ })
25
30
  .collect(),
26
31
  }
27
32
  }
@@ -70,9 +70,10 @@ pub fn resolve_identity_type(
70
70
  ));
71
71
  }
72
72
 
73
- let field = as_field
74
- .map(|s| s.to_string())
75
- .unwrap_or_else(|| crate::build::naming::snake(&target));
73
+ let field = as_field.map_or_else(
74
+ || crate::build::naming::snake(&target),
75
+ std::string::ToString::to_string,
76
+ );
76
77
  if attributes.iter().any(|attribute| attribute.name == field) {
77
78
  return Err(Diagnostic::new(
78
79
  file,
@@ -3,6 +3,7 @@
3
3
 
4
4
  pub mod closed_sets;
5
5
  pub mod identity;
6
+ pub mod named_pattern;
6
7
  pub mod naming;
7
8
  pub mod pattern_subset;
8
9
  pub mod query_derive;
@@ -0,0 +1,26 @@
1
+ //! The patterns a bluebook names instead of spelling: `matches: :snake_name` stands for exactly
2
+ //! its regex. Mirrors `Hecks::Bluebook::NamedPattern`; spec/named_pattern_spec.rb holds the two
3
+ //! tables to each other.
4
+
5
+ /// Name => the regex source it stands for.
6
+ const TABLE: &[(&str, &str)] = &[
7
+ ("present", r"[^ \t\n\r]"),
8
+ ("not_empty", r"[^\t\n\r]"),
9
+ ("no_whitespace", r"^[^ \t\n\r]+$"),
10
+ ("snake_name", r"^[a-z][a-z0-9_]*$"),
11
+ ("git_sha", r"^[0-9a-fA-F]{7,40}$"),
12
+ ("digits", r"^[0-9]+$"),
13
+ ];
14
+
15
+ /// The regex source `name` stands for, or `None` when the language gives no such name.
16
+ pub fn source(name: &str) -> Option<&'static str> {
17
+ TABLE
18
+ .iter()
19
+ .find(|(given, _)| *given == name)
20
+ .map(|(_, source)| *source)
21
+ }
22
+
23
+ /// Every name the language gives, in table order.
24
+ pub fn names() -> Vec<&'static str> {
25
+ TABLE.iter().map(|(name, _)| *name).collect()
26
+ }