herb 0.10.4 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (784) hide show
  1. checksums.yaml +4 -4
  2. data/Makefile +16 -6
  3. data/README.md +36 -119
  4. data/Rakefile +2 -11
  5. data/config/action_view_helpers/actioncable/action_cable_helper/action_cable_meta_tag.yml +12 -8
  6. data/config/action_view_helpers/actionpack/content_security_policy/content_security_policy?.yml +9 -6
  7. data/config/action_view_helpers/actionpack/content_security_policy/content_security_policy_nonce.yml +9 -6
  8. data/config/action_view_helpers/actionpack/polymorphic_routes/polymorphic_path.yml +20 -12
  9. data/config/action_view_helpers/actionpack/polymorphic_routes/polymorphic_url.yml +30 -18
  10. data/config/action_view_helpers/actionpack/request_forgery_protection/form_authenticity_token.yml +15 -9
  11. data/config/action_view_helpers/actionpack/request_forgery_protection/protect_against_forgery?.yml +9 -6
  12. data/config/action_view_helpers/actiontext/content_helper/render_action_text_content.yml +15 -9
  13. data/config/action_view_helpers/actiontext/content_helper/sanitize_action_text_content.yml +15 -9
  14. data/config/action_view_helpers/actiontext/tag_helper/rich_textarea_tag.yml +34 -22
  15. data/config/action_view_helpers/actionview/active_model_helper/error_message.yml +9 -6
  16. data/config/action_view_helpers/actionview/active_model_helper/error_wrapping.yml +9 -6
  17. data/config/action_view_helpers/actionview/active_model_helper/object.yml +9 -6
  18. data/config/action_view_helpers/actionview/asset_tag_helper/apply_stylesheet_media_default.yml +9 -6
  19. data/config/action_view_helpers/actionview/asset_tag_helper/audio_tag.yml +40 -27
  20. data/config/action_view_helpers/actionview/asset_tag_helper/auto_discovery_link_tag.yml +37 -23
  21. data/config/action_view_helpers/actionview/asset_tag_helper/auto_include_nonce.yml +9 -6
  22. data/config/action_view_helpers/actionview/asset_tag_helper/auto_include_nonce_for_scripts.yml +9 -6
  23. data/config/action_view_helpers/actionview/asset_tag_helper/auto_include_nonce_for_styles.yml +9 -6
  24. data/config/action_view_helpers/actionview/asset_tag_helper/favicon_link_tag.yml +32 -22
  25. data/config/action_view_helpers/actionview/asset_tag_helper/image_decoding.yml +9 -6
  26. data/config/action_view_helpers/actionview/asset_tag_helper/image_loading.yml +9 -6
  27. data/config/action_view_helpers/actionview/asset_tag_helper/image_tag.yml +67 -46
  28. data/config/action_view_helpers/actionview/asset_tag_helper/javascript_include_tag.yml +58 -39
  29. data/config/action_view_helpers/actionview/asset_tag_helper/picture_tag.yml +22 -14
  30. data/config/action_view_helpers/actionview/asset_tag_helper/preload_link_tag.yml +45 -30
  31. data/config/action_view_helpers/actionview/asset_tag_helper/preload_links_header.yml +9 -6
  32. data/config/action_view_helpers/actionview/asset_tag_helper/stylesheet_link_tag.yml +49 -30
  33. data/config/action_view_helpers/actionview/asset_tag_helper/video_tag.yml +53 -35
  34. data/config/action_view_helpers/actionview/asset_url_helper/asset_path.yml +16 -10
  35. data/config/action_view_helpers/actionview/asset_url_helper/asset_url.yml +16 -10
  36. data/config/action_view_helpers/actionview/asset_url_helper/audio_path.yml +16 -10
  37. data/config/action_view_helpers/actionview/asset_url_helper/audio_url.yml +16 -10
  38. data/config/action_view_helpers/actionview/asset_url_helper/compute_asset_extname.yml +9 -6
  39. data/config/action_view_helpers/actionview/asset_url_helper/compute_asset_host.yml +9 -6
  40. data/config/action_view_helpers/actionview/asset_url_helper/compute_asset_path.yml +9 -6
  41. data/config/action_view_helpers/actionview/asset_url_helper/font_path.yml +16 -10
  42. data/config/action_view_helpers/actionview/asset_url_helper/font_url.yml +16 -10
  43. data/config/action_view_helpers/actionview/asset_url_helper/image_path.yml +16 -10
  44. data/config/action_view_helpers/actionview/asset_url_helper/image_url.yml +16 -10
  45. data/config/action_view_helpers/actionview/asset_url_helper/javascript_path.yml +16 -10
  46. data/config/action_view_helpers/actionview/asset_url_helper/javascript_url.yml +16 -10
  47. data/config/action_view_helpers/actionview/asset_url_helper/public_compute_asset_path.yml +9 -6
  48. data/config/action_view_helpers/actionview/asset_url_helper/stylesheet_path.yml +16 -10
  49. data/config/action_view_helpers/actionview/asset_url_helper/stylesheet_url.yml +16 -10
  50. data/config/action_view_helpers/actionview/asset_url_helper/video_path.yml +16 -10
  51. data/config/action_view_helpers/actionview/asset_url_helper/video_url.yml +16 -10
  52. data/config/action_view_helpers/actionview/atom_feed_helper/atom_feed.yml +52 -27
  53. data/config/action_view_helpers/actionview/cache_helper/cache.yml +25 -15
  54. data/config/action_view_helpers/actionview/cache_helper/cache_fragment_name.yml +9 -6
  55. data/config/action_view_helpers/actionview/cache_helper/cache_if.yml +20 -12
  56. data/config/action_view_helpers/actionview/cache_helper/cache_unless.yml +20 -12
  57. data/config/action_view_helpers/actionview/cache_helper/caching_predicate.yml +9 -6
  58. data/config/action_view_helpers/actionview/cache_helper/digest_path_from_template.yml +9 -6
  59. data/config/action_view_helpers/actionview/cache_helper/fragment_for.yml +9 -6
  60. data/config/action_view_helpers/actionview/cache_helper/fragment_name_with_digest.yml +9 -6
  61. data/config/action_view_helpers/actionview/cache_helper/read_fragment_for.yml +9 -6
  62. data/config/action_view_helpers/actionview/cache_helper/uncacheable.yml +9 -6
  63. data/config/action_view_helpers/actionview/cache_helper/write_fragment_for.yml +9 -6
  64. data/config/action_view_helpers/actionview/capture_helper/capture.yml +9 -6
  65. data/config/action_view_helpers/actionview/capture_helper/content_for.yml +20 -12
  66. data/config/action_view_helpers/actionview/capture_helper/content_for_predicate.yml +15 -9
  67. data/config/action_view_helpers/actionview/capture_helper/provide.yml +15 -9
  68. data/config/action_view_helpers/actionview/capture_helper/with_output_buffer.yml +9 -6
  69. data/config/action_view_helpers/actionview/content_exfiltration_prevention_helper/prepend_content_exfiltration_prevention.yml +9 -6
  70. data/config/action_view_helpers/actionview/content_exfiltration_prevention_helper/prevent_content_exfiltration.yml +9 -6
  71. data/config/action_view_helpers/actionview/controller_helper/action_name.yml +9 -6
  72. data/config/action_view_helpers/actionview/controller_helper/assign_controller.yml +9 -6
  73. data/config/action_view_helpers/actionview/controller_helper/controller.yml +9 -6
  74. data/config/action_view_helpers/actionview/controller_helper/controller_name.yml +9 -6
  75. data/config/action_view_helpers/actionview/controller_helper/controller_path.yml +9 -6
  76. data/config/action_view_helpers/actionview/controller_helper/cookies.yml +9 -6
  77. data/config/action_view_helpers/actionview/controller_helper/flash.yml +9 -6
  78. data/config/action_view_helpers/actionview/controller_helper/headers.yml +9 -6
  79. data/config/action_view_helpers/actionview/controller_helper/logger.yml +9 -6
  80. data/config/action_view_helpers/actionview/controller_helper/params.yml +9 -6
  81. data/config/action_view_helpers/actionview/controller_helper/request.yml +9 -6
  82. data/config/action_view_helpers/actionview/controller_helper/request_forgery_protection_token.yml +9 -6
  83. data/config/action_view_helpers/actionview/controller_helper/response.yml +9 -6
  84. data/config/action_view_helpers/actionview/controller_helper/session.yml +9 -6
  85. data/config/action_view_helpers/actionview/csp_helper/csp_meta_tag.yml +18 -11
  86. data/config/action_view_helpers/actionview/csrf_helper/csrf_meta_tags.yml +16 -10
  87. data/config/action_view_helpers/actionview/date_helper/date_select.yml +85 -51
  88. data/config/action_view_helpers/actionview/date_helper/datetime_select.yml +65 -39
  89. data/config/action_view_helpers/actionview/date_helper/distance_of_time_in_words.yml +30 -18
  90. data/config/action_view_helpers/actionview/date_helper/relative_time_in_words.yml +35 -21
  91. data/config/action_view_helpers/actionview/date_helper/select_date.yml +50 -30
  92. data/config/action_view_helpers/actionview/date_helper/select_datetime.yml +65 -39
  93. data/config/action_view_helpers/actionview/date_helper/select_day.yml +40 -24
  94. data/config/action_view_helpers/actionview/date_helper/select_hour.yml +50 -30
  95. data/config/action_view_helpers/actionview/date_helper/select_minute.yml +40 -24
  96. data/config/action_view_helpers/actionview/date_helper/select_month.yml +60 -36
  97. data/config/action_view_helpers/actionview/date_helper/select_second.yml +35 -21
  98. data/config/action_view_helpers/actionview/date_helper/select_time.yml +55 -33
  99. data/config/action_view_helpers/actionview/date_helper/select_year.yml +45 -27
  100. data/config/action_view_helpers/actionview/date_helper/time_ago_in_words.yml +21 -13
  101. data/config/action_view_helpers/actionview/date_helper/time_select.yml +60 -36
  102. data/config/action_view_helpers/actionview/date_helper/time_tag.yml +32 -20
  103. data/config/action_view_helpers/actionview/debug_helper/debug.yml +15 -9
  104. data/config/action_view_helpers/actionview/form_builder/button.yml +60 -0
  105. data/config/action_view_helpers/actionview/form_builder/submit.yml +48 -0
  106. data/config/action_view_helpers/actionview/form_helper/apply_form_for_options.yml +9 -6
  107. data/config/action_view_helpers/actionview/form_helper/checkbox.yml +41 -25
  108. data/config/action_view_helpers/actionview/form_helper/color_field.yml +25 -15
  109. data/config/action_view_helpers/actionview/form_helper/date_field.yml +35 -21
  110. data/config/action_view_helpers/actionview/form_helper/datetime_field.yml +41 -25
  111. data/config/action_view_helpers/actionview/form_helper/email_field.yml +25 -15
  112. data/config/action_view_helpers/actionview/form_helper/emitted_hidden_id.yml +9 -6
  113. data/config/action_view_helpers/actionview/form_helper/fields.yml +37 -18
  114. data/config/action_view_helpers/actionview/form_helper/fields_for.yml +33 -15
  115. data/config/action_view_helpers/actionview/form_helper/file_field.yml +45 -27
  116. data/config/action_view_helpers/actionview/form_helper/form_for.yml +45 -24
  117. data/config/action_view_helpers/actionview/form_helper/form_with.yml +56 -30
  118. data/config/action_view_helpers/actionview/form_helper/form_with_generates_ids.yml +9 -6
  119. data/config/action_view_helpers/actionview/form_helper/form_with_generates_remote_forms.yml +9 -6
  120. data/config/action_view_helpers/actionview/form_helper/hidden_field.yml +25 -15
  121. data/config/action_view_helpers/actionview/form_helper/label.yml +52 -27
  122. data/config/action_view_helpers/actionview/form_helper/month_field.yml +25 -15
  123. data/config/action_view_helpers/actionview/form_helper/multipart.yml +9 -6
  124. data/config/action_view_helpers/actionview/form_helper/multiple_file_field_include_hidden.yml +9 -6
  125. data/config/action_view_helpers/actionview/form_helper/number_field.yml +45 -27
  126. data/config/action_view_helpers/actionview/form_helper/password_field.yml +25 -15
  127. data/config/action_view_helpers/actionview/form_helper/radio_button.yml +30 -18
  128. data/config/action_view_helpers/actionview/form_helper/range_field.yml +45 -27
  129. data/config/action_view_helpers/actionview/form_helper/search_field.yml +25 -15
  130. data/config/action_view_helpers/actionview/form_helper/telephone_field.yml +26 -16
  131. data/config/action_view_helpers/actionview/form_helper/text_field.yml +25 -15
  132. data/config/action_view_helpers/actionview/form_helper/textarea.yml +31 -19
  133. data/config/action_view_helpers/actionview/form_helper/time_field.yml +40 -24
  134. data/config/action_view_helpers/actionview/form_helper/url_field.yml +25 -15
  135. data/config/action_view_helpers/actionview/form_helper/week_field.yml +25 -15
  136. data/config/action_view_helpers/actionview/form_options_helper/collection_checkboxes.yml +58 -31
  137. data/config/action_view_helpers/actionview/form_options_helper/collection_radio_buttons.yml +57 -30
  138. data/config/action_view_helpers/actionview/form_options_helper/collection_select.yml +65 -39
  139. data/config/action_view_helpers/actionview/form_options_helper/grouped_collection_select.yml +65 -39
  140. data/config/action_view_helpers/actionview/form_options_helper/grouped_options_for_select.yml +35 -21
  141. data/config/action_view_helpers/actionview/form_options_helper/option_groups_from_collection_for_select.yml +40 -24
  142. data/config/action_view_helpers/actionview/form_options_helper/options_for_select.yml +20 -12
  143. data/config/action_view_helpers/actionview/form_options_helper/options_from_collection_for_select.yml +30 -18
  144. data/config/action_view_helpers/actionview/form_options_helper/select.yml +60 -36
  145. data/config/action_view_helpers/actionview/form_options_helper/time_zone_options_for_select.yml +25 -15
  146. data/config/action_view_helpers/actionview/form_options_helper/time_zone_select.yml +50 -30
  147. data/config/action_view_helpers/actionview/form_options_helper/weekday_options_for_select.yml +30 -18
  148. data/config/action_view_helpers/actionview/form_options_helper/weekday_select.yml +30 -18
  149. data/config/action_view_helpers/actionview/form_tag_helper/button_tag.yml +39 -21
  150. data/config/action_view_helpers/actionview/form_tag_helper/checkbox_tag.yml +33 -21
  151. data/config/action_view_helpers/actionview/form_tag_helper/color_field_tag.yml +26 -17
  152. data/config/action_view_helpers/actionview/form_tag_helper/date_field_tag.yml +27 -17
  153. data/config/action_view_helpers/actionview/form_tag_helper/datetime_field_tag.yml +28 -18
  154. data/config/action_view_helpers/actionview/form_tag_helper/default_enforce_utf8.yml +9 -6
  155. data/config/action_view_helpers/actionview/form_tag_helper/email_field_tag.yml +27 -17
  156. data/config/action_view_helpers/actionview/form_tag_helper/embed_authenticity_token_in_remote_forms.yml +9 -6
  157. data/config/action_view_helpers/actionview/form_tag_helper/field_id.yml +30 -18
  158. data/config/action_view_helpers/actionview/form_tag_helper/field_name.yml +30 -18
  159. data/config/action_view_helpers/actionview/form_tag_helper/field_set_tag.yml +23 -15
  160. data/config/action_view_helpers/actionview/form_tag_helper/file_field_tag.yml +35 -22
  161. data/config/action_view_helpers/actionview/form_tag_helper/form_tag.yml +38 -24
  162. data/config/action_view_helpers/actionview/form_tag_helper/hidden_field_tag.yml +27 -17
  163. data/config/action_view_helpers/actionview/form_tag_helper/image_submit_tag.yml +31 -21
  164. data/config/action_view_helpers/actionview/form_tag_helper/label_tag.yml +33 -17
  165. data/config/action_view_helpers/actionview/form_tag_helper/month_field_tag.yml +27 -17
  166. data/config/action_view_helpers/actionview/form_tag_helper/number_field_tag.yml +47 -29
  167. data/config/action_view_helpers/actionview/form_tag_helper/password_field_tag.yml +27 -17
  168. data/config/action_view_helpers/actionview/form_tag_helper/radio_button_tag.yml +32 -20
  169. data/config/action_view_helpers/actionview/form_tag_helper/range_field_tag.yml +47 -29
  170. data/config/action_view_helpers/actionview/form_tag_helper/search_field_tag.yml +27 -17
  171. data/config/action_view_helpers/actionview/form_tag_helper/select_tag.yml +47 -29
  172. data/config/action_view_helpers/actionview/form_tag_helper/submit_tag.yml +33 -21
  173. data/config/action_view_helpers/actionview/form_tag_helper/telephone_field_tag.yml +28 -18
  174. data/config/action_view_helpers/actionview/form_tag_helper/text_field_tag.yml +27 -17
  175. data/config/action_view_helpers/actionview/form_tag_helper/textarea_tag.yml +31 -20
  176. data/config/action_view_helpers/actionview/form_tag_helper/time_field_tag.yml +27 -17
  177. data/config/action_view_helpers/actionview/form_tag_helper/url_field_tag.yml +27 -17
  178. data/config/action_view_helpers/actionview/form_tag_helper/utf8_enforcer_tag.yml +9 -6
  179. data/config/action_view_helpers/actionview/form_tag_helper/week_field_tag.yml +28 -18
  180. data/config/action_view_helpers/actionview/javascript_helper/escape_javascript.yml +16 -10
  181. data/config/action_view_helpers/actionview/javascript_helper/javascript_cdata_section.yml +9 -6
  182. data/config/action_view_helpers/actionview/javascript_helper/javascript_tag.yml +41 -27
  183. data/config/action_view_helpers/actionview/number_helper/number_to_currency.yml +29 -18
  184. data/config/action_view_helpers/actionview/number_helper/number_to_human.yml +25 -15
  185. data/config/action_view_helpers/actionview/number_helper/number_to_human_size.yml +20 -12
  186. data/config/action_view_helpers/actionview/number_helper/number_to_percentage.yml +20 -12
  187. data/config/action_view_helpers/actionview/number_helper/number_to_phone.yml +33 -20
  188. data/config/action_view_helpers/actionview/number_helper/number_with_delimiter.yml +21 -13
  189. data/config/action_view_helpers/actionview/number_helper/number_with_precision.yml +25 -15
  190. data/config/action_view_helpers/actionview/output_safety_helper/raw.yml +15 -9
  191. data/config/action_view_helpers/actionview/output_safety_helper/safe_join.yml +20 -12
  192. data/config/action_view_helpers/actionview/output_safety_helper/to_sentence.yml +24 -15
  193. data/config/action_view_helpers/actionview/record_identifier/dom_class.yml +20 -12
  194. data/config/action_view_helpers/actionview/record_identifier/dom_id.yml +20 -12
  195. data/config/action_view_helpers/actionview/record_identifier/dom_target.yml +15 -9
  196. data/config/action_view_helpers/actionview/record_identifier/model_name_from_record_or_class.yml +9 -6
  197. data/config/action_view_helpers/actionview/rendering_helper/render.yml +108 -22
  198. data/config/action_view_helpers/actionview/sanitize_helper/sanitize.yml +25 -15
  199. data/config/action_view_helpers/actionview/sanitize_helper/sanitize_css.yml +15 -9
  200. data/config/action_view_helpers/actionview/sanitize_helper/sanitizer_vendor.yml +9 -6
  201. data/config/action_view_helpers/actionview/sanitize_helper/strip_links.yml +15 -9
  202. data/config/action_view_helpers/actionview/sanitize_helper/strip_tags.yml +15 -9
  203. data/config/action_view_helpers/actionview/tag_helper/cdata_section.yml +15 -9
  204. data/config/action_view_helpers/actionview/tag_helper/content_tag.yml +59 -38
  205. data/config/action_view_helpers/actionview/tag_helper/escape_once.yml +15 -9
  206. data/config/action_view_helpers/actionview/tag_helper/tag.yml +54 -31
  207. data/config/action_view_helpers/actionview/tag_helper/token_list.yml +16 -10
  208. data/config/action_view_helpers/actionview/text_helper/concat.yml +15 -9
  209. data/config/action_view_helpers/actionview/text_helper/current_cycle.yml +15 -9
  210. data/config/action_view_helpers/actionview/text_helper/cycle.yml +23 -14
  211. data/config/action_view_helpers/actionview/text_helper/excerpt.yml +33 -20
  212. data/config/action_view_helpers/actionview/text_helper/highlight.yml +37 -18
  213. data/config/action_view_helpers/actionview/text_helper/pluralize.yml +30 -18
  214. data/config/action_view_helpers/actionview/text_helper/reset_cycle.yml +15 -9
  215. data/config/action_view_helpers/actionview/text_helper/safe_concat.yml +9 -6
  216. data/config/action_view_helpers/actionview/text_helper/simple_format.yml +33 -20
  217. data/config/action_view_helpers/actionview/text_helper/truncate.yml +38 -23
  218. data/config/action_view_helpers/actionview/text_helper/word_wrap.yml +25 -15
  219. data/config/action_view_helpers/actionview/translation_helper/debug_missing_translation.yml +9 -6
  220. data/config/action_view_helpers/actionview/translation_helper/localize.yml +26 -16
  221. data/config/action_view_helpers/actionview/translation_helper/translate.yml +31 -19
  222. data/config/action_view_helpers/actionview/url_helper/button_to.yml +57 -33
  223. data/config/action_view_helpers/actionview/url_helper/button_to_generates_button_tag.yml +9 -6
  224. data/config/action_view_helpers/actionview/url_helper/current_page?.yml +25 -15
  225. data/config/action_view_helpers/actionview/url_helper/link_to.yml +76 -53
  226. data/config/action_view_helpers/actionview/url_helper/link_to_if.yml +54 -20
  227. data/config/action_view_helpers/actionview/url_helper/link_to_unless.yml +54 -20
  228. data/config/action_view_helpers/actionview/url_helper/link_to_unless_current.yml +49 -17
  229. data/config/action_view_helpers/actionview/url_helper/mail_to.yml +60 -34
  230. data/config/action_view_helpers/actionview/url_helper/phone_to.yml +40 -22
  231. data/config/action_view_helpers/actionview/url_helper/sms_to.yml +45 -25
  232. data/config/action_view_helpers/actionview/url_helper/url_for.yml +15 -9
  233. data/config/action_view_helpers/importmap-rails/importmap_tags_helper/javascript_import_module_tag.yml +32 -0
  234. data/config/action_view_helpers/importmap-rails/importmap_tags_helper/javascript_importmap_module_preload_tags.yml +39 -0
  235. data/config/action_view_helpers/importmap-rails/importmap_tags_helper/javascript_importmap_tags.yml +35 -0
  236. data/config/action_view_helpers/importmap-rails/importmap_tags_helper/javascript_inline_importmap_tag.yml +32 -0
  237. data/config/action_view_helpers/importmap-rails/importmap_tags_helper/javascript_module_preload_tag.yml +35 -0
  238. data/config/action_view_helpers/turbo-rails/drive_helper/turbo_exempts_page_from_cache.yml +9 -6
  239. data/config/action_view_helpers/turbo-rails/drive_helper/turbo_exempts_page_from_cache_tag.yml +12 -8
  240. data/config/action_view_helpers/turbo-rails/drive_helper/turbo_exempts_page_from_preview.yml +9 -6
  241. data/config/action_view_helpers/turbo-rails/drive_helper/turbo_exempts_page_from_preview_tag.yml +12 -8
  242. data/config/action_view_helpers/turbo-rails/drive_helper/turbo_page_requires_reload.yml +9 -6
  243. data/config/action_view_helpers/turbo-rails/drive_helper/turbo_page_requires_reload_tag.yml +12 -8
  244. data/config/action_view_helpers/turbo-rails/drive_helper/turbo_refresh_method_tag.yml +17 -11
  245. data/config/action_view_helpers/turbo-rails/drive_helper/turbo_refresh_scroll_tag.yml +17 -11
  246. data/config/action_view_helpers/turbo-rails/drive_helper/turbo_refreshes_with.yml +20 -12
  247. data/config/action_view_helpers/turbo-rails/frames_helper/turbo_frame_tag.yml +54 -33
  248. data/config/action_view_helpers/turbo-rails/includes_helper/turbo_include_tags.yml +9 -6
  249. data/config/action_view_helpers/turbo-rails/streams_action_helper/turbo_stream_action_tag.yml +32 -20
  250. data/config/action_view_helpers/turbo-rails/streams_action_helper/turbo_stream_refresh_tag.yml +18 -11
  251. data/config/action_view_helpers/turbo-rails/streams_helper/turbo_stream.yml +9 -6
  252. data/config/action_view_helpers/turbo-rails/streams_helper/turbo_stream_from.yml +28 -18
  253. data/config/html_elements.yml +597 -0
  254. data/config/options.yml +1 -0
  255. data/config/slots/components.yml +52 -0
  256. data/config/state/kind.yml +61 -0
  257. data/config/state/operators.yml +27 -0
  258. data/config/state/predicates.yml +39 -0
  259. data/config/state/transforms.yml +18 -0
  260. data/config/view_context_methods/actionview/base/annotate_rendered_view_with_filenames.yml +4 -4
  261. data/config/view_context_methods/actionview/base/assign.yml +4 -4
  262. data/config/view_context_methods/actionview/base/assigns.yml +4 -4
  263. data/config/view_context_methods/actionview/base/automatically_disable_submit_tag.yml +4 -4
  264. data/config/view_context_methods/actionview/base/compiled_method_container.yml +4 -4
  265. data/config/view_context_methods/actionview/base/config.yml +4 -4
  266. data/config/view_context_methods/actionview/base/default_form_builder.yml +4 -4
  267. data/config/view_context_methods/actionview/base/default_formats.yml +4 -4
  268. data/config/view_context_methods/actionview/base/field_error_proc.yml +4 -4
  269. data/config/view_context_methods/actionview/base/formats.yml +4 -4
  270. data/config/view_context_methods/actionview/base/in_rendering_context.yml +4 -4
  271. data/config/view_context_methods/actionview/base/locale.yml +4 -4
  272. data/config/view_context_methods/actionview/base/lookup_context.yml +4 -4
  273. data/config/view_context_methods/actionview/base/output_buffer.yml +4 -4
  274. data/config/view_context_methods/actionview/base/prefix_partial_path_with_controller_namespace.yml +4 -4
  275. data/config/view_context_methods/actionview/base/remove_hidden_field_autocomplete.yml +4 -4
  276. data/config/view_context_methods/actionview/base/streaming_completion_on_exception.yml +4 -4
  277. data/config/view_context_methods/actionview/base/view_flow.yml +4 -4
  278. data/config/view_context_methods/actionview/base/view_paths.yml +4 -4
  279. data/config/view_context_methods/actionview/base/view_renderer.yml +4 -4
  280. data/config/view_context_methods/actionview/template/local_assigns.yml +4 -4
  281. data/config/view_context_methods/activemodel/conversion/convert_to_model.yml +4 -4
  282. data/config/view_context_methods/activesupport/benchmarkable/benchmark.yml +4 -4
  283. data/config.yml +1240 -790
  284. data/exe/herb +2 -0
  285. data/ext/herb/error_helpers.c +355 -17
  286. data/ext/herb/error_helpers.h +1 -1
  287. data/ext/herb/extconf.rb +4 -2
  288. data/ext/herb/extension.c +137 -89
  289. data/ext/herb/extension_helpers.c +81 -42
  290. data/ext/herb/extension_helpers.h +4 -1
  291. data/ext/herb/nodes.c +826 -358
  292. data/ext/herb/nodes.h +3 -2
  293. data/ext/herb/parser_options_helpers.c +151 -0
  294. data/ext/herb/parser_options_helpers.h +14 -0
  295. data/herb.gemspec +2 -2
  296. data/lib/herb/action_view/helper_registry.rb +1358 -62
  297. data/lib/herb/analysis/partial_declaration.rb +140 -0
  298. data/lib/herb/analysis/partial_index.rb +189 -0
  299. data/lib/herb/analysis/partial_resolution.rb +161 -0
  300. data/lib/herb/analysis/partial_resolver.rb +144 -0
  301. data/lib/herb/analysis/project_index.rb +152 -0
  302. data/lib/herb/{action_view → analysis}/render_analyzer.rb +287 -77
  303. data/lib/herb/analysis/render_graph/ancestor_chain.rb +27 -0
  304. data/lib/herb/analysis/render_graph/builder.rb +376 -0
  305. data/lib/herb/analysis/render_graph/call_frame.rb +9 -0
  306. data/lib/herb/analysis/render_graph/call_site_location.rb +23 -0
  307. data/lib/herb/analysis/render_graph/inferred_signature.rb +21 -0
  308. data/lib/herb/analysis/render_graph/partial_call_site.rb +40 -0
  309. data/lib/herb/analysis/render_graph/partial_context.rb +46 -0
  310. data/lib/herb/analysis/render_graph/template_roots.rb +31 -0
  311. data/lib/herb/analysis/render_graph.rb +285 -0
  312. data/lib/herb/analysis/ruby_locals_index/local.rb +25 -0
  313. data/lib/herb/analysis/ruby_locals_index/named_reference.rb +22 -0
  314. data/lib/herb/analysis/ruby_locals_index/offset_table.rb +44 -0
  315. data/lib/herb/analysis/ruby_locals_index/reference_collector.rb +80 -0
  316. data/lib/herb/analysis/ruby_locals_index/state_locals.rb +49 -0
  317. data/lib/herb/analysis/ruby_locals_index.rb +165 -0
  318. data/lib/herb/analysis/ruby_reference.rb +67 -0
  319. data/lib/herb/analysis/template_dependencies/dependency_collector.rb +179 -0
  320. data/lib/herb/analysis/template_dependencies/node_dependency_collector.rb +309 -0
  321. data/lib/herb/analysis/template_dependencies.rb +562 -0
  322. data/lib/herb/ast/erb_render_node.rb +26 -94
  323. data/lib/herb/ast/helpers.rb +90 -10
  324. data/lib/herb/ast/herb_directive_node.rb +18 -0
  325. data/lib/herb/ast/node.rb +32 -2
  326. data/lib/herb/ast/nodes.rb +1342 -105
  327. data/lib/herb/backend.rb +73 -0
  328. data/lib/herb/bootstrap.rb +3 -7
  329. data/lib/herb/cli.rb +550 -32
  330. data/lib/herb/colors.rb +14 -0
  331. data/lib/herb/configuration.rb +71 -35
  332. data/lib/herb/defaults.yml +2 -1
  333. data/lib/herb/dev/assets.rb +57 -0
  334. data/lib/herb/dev/classifier.rb +84 -0
  335. data/lib/herb/dev/embedded.rb +27 -0
  336. data/lib/herb/dev/pipeline.rb +305 -0
  337. data/lib/herb/dev/protocol.rb +221 -0
  338. data/lib/herb/dev/runner.rb +175 -175
  339. data/lib/herb/dev/server.rb +89 -26
  340. data/lib/herb/dev/server_entry.rb +41 -6
  341. data/lib/herb/dev/watcher.rb +181 -0
  342. data/lib/herb/dev.rb +163 -0
  343. data/lib/herb/diagnostic/formatter.rb +88 -0
  344. data/lib/herb/diagnostic.rb +172 -0
  345. data/lib/herb/diff/operation.rb +36 -0
  346. data/lib/herb/diff/result.rb +62 -0
  347. data/lib/herb/diff.rb +10 -0
  348. data/lib/herb/engine/collector.rb +62 -0
  349. data/lib/herb/engine/compiler.rb +346 -108
  350. data/lib/herb/engine/component_tags/constant_resolver.rb +28 -0
  351. data/lib/herb/engine/component_tags/partial_resolver.rb +54 -0
  352. data/lib/herb/engine/component_tags/resolver.rb +32 -0
  353. data/lib/herb/engine/component_tags/visitor.rb +231 -0
  354. data/lib/herb/engine/css_inliner/inliner.rb +101 -0
  355. data/lib/herb/engine/css_inliner/visitor.rb +174 -0
  356. data/lib/herb/engine/errors.rb +122 -0
  357. data/lib/herb/engine/helpers.rb +82 -0
  358. data/lib/herb/engine/inline_render/inliner.rb +122 -0
  359. data/lib/herb/engine/inline_render/visitor.rb +267 -0
  360. data/lib/herb/engine/runtime/entry.rb +62 -0
  361. data/lib/herb/engine/runtime/error_page.rb +362 -0
  362. data/lib/herb/engine/runtime/html_safe_assertions.rb +217 -0
  363. data/lib/herb/engine/runtime/journal/summary.rb +227 -0
  364. data/lib/herb/engine/runtime/journal.rb +379 -0
  365. data/lib/herb/engine/runtime/middleware.rb +212 -0
  366. data/lib/herb/engine/runtime/observations.rb +73 -0
  367. data/lib/herb/engine/runtime/report.rb +204 -0
  368. data/lib/herb/engine/runtime/session.rb +437 -0
  369. data/lib/herb/engine/runtime.rb +21 -0
  370. data/lib/herb/engine/scoped_style/channel.rb +66 -0
  371. data/lib/herb/engine/scoped_style/collector.rb +74 -0
  372. data/lib/herb/engine/scoped_style/visitor.rb +533 -0
  373. data/lib/herb/engine/slots/annotation.rb +98 -0
  374. data/lib/herb/engine/slots/bindings.rb +61 -0
  375. data/lib/herb/engine/slots/callee.rb +118 -0
  376. data/lib/herb/engine/slots/component_definitions.rb +67 -0
  377. data/lib/herb/engine/slots/components/async.rb +24 -0
  378. data/lib/herb/engine/slots/components/base.rb +132 -0
  379. data/lib/herb/engine/slots/components/deferred.rb +81 -0
  380. data/lib/herb/engine/slots/components/fallback.rb +27 -0
  381. data/lib/herb/engine/slots/components/fragment.rb +99 -0
  382. data/lib/herb/engine/slots/components/lazy.rb +24 -0
  383. data/lib/herb/engine/slots/components.rb +52 -0
  384. data/lib/herb/engine/slots/dependencies/channel.rb +72 -0
  385. data/lib/herb/engine/slots/dependencies.rb +269 -0
  386. data/lib/herb/engine/slots/dynamics_compiler.rb +854 -0
  387. data/lib/herb/engine/slots/identifier.rb +35 -0
  388. data/lib/herb/engine/slots/manifest/channel.rb +74 -0
  389. data/lib/herb/engine/slots/manifest/collector.rb +75 -0
  390. data/lib/herb/engine/slots/markers.rb +128 -0
  391. data/lib/herb/engine/slots/render_bindings.rb +141 -0
  392. data/lib/herb/engine/slots/schema_compiler.rb +94 -0
  393. data/lib/herb/engine/slots/state_anchor.rb +94 -0
  394. data/lib/herb/engine/slots/state_compiler.rb +1326 -0
  395. data/lib/herb/engine/slots/state_directives.rb +854 -0
  396. data/lib/herb/engine/slots/state_kinds.rb +54 -0
  397. data/lib/herb/engine/slots/state_operators.rb +36 -0
  398. data/lib/herb/engine/slots/state_overrides.rb +79 -0
  399. data/lib/herb/engine/slots/state_predicates.rb +65 -0
  400. data/lib/herb/engine/slots/state_transforms.rb +42 -0
  401. data/lib/herb/engine/slots/statics.rb +185 -0
  402. data/lib/herb/engine/slots/subtree.rb +82 -0
  403. data/lib/herb/engine/slots/subtree_compiler.rb +255 -0
  404. data/lib/herb/engine/slots/types.rb +42 -0
  405. data/lib/herb/engine/slots/visitor.rb +2256 -0
  406. data/lib/herb/engine/validators/accessibility_validator.rb +3 -3
  407. data/lib/herb/engine/validators/base.rb +36 -0
  408. data/lib/herb/engine/validators/generator_template_validator.rb +39 -0
  409. data/lib/herb/engine/validators/nesting_validator.rb +3 -3
  410. data/lib/herb/engine/validators/render_validator.rb +13 -33
  411. data/lib/herb/engine/validators/security_validator.rb +3 -17
  412. data/lib/herb/engine/validators.rb +43 -0
  413. data/lib/herb/engine/visitors/auto_close_omitted_tags_visitor.rb +48 -0
  414. data/lib/herb/engine/visitors/content_for_visitor.rb +127 -0
  415. data/lib/herb/engine/{debug_visitor.rb → visitors/debug_visitor.rb} +121 -93
  416. data/lib/herb/engine/visitors/html_safe_assertions_visitor.rb +281 -0
  417. data/lib/herb/engine/visitors/instrumentation_visitor.rb +290 -0
  418. data/lib/herb/engine/visitors/optimize_visitor.rb +728 -0
  419. data/lib/herb/engine/visitors/remove_comments_visitor.rb +106 -0
  420. data/lib/herb/engine/visitors/source_attribution_visitor.rb +177 -0
  421. data/lib/herb/engine.rb +218 -257
  422. data/lib/herb/ensure_installed.rb +43 -0
  423. data/lib/herb/errors.rb +646 -157
  424. data/lib/herb/fingerprint.rb +82 -0
  425. data/lib/herb/html/elements.rb +18 -0
  426. data/lib/herb/html/util.rb +21 -2
  427. data/lib/herb/lex_result.rb +0 -10
  428. data/lib/herb/locate.rb +163 -0
  429. data/lib/herb/location.rb +20 -0
  430. data/lib/herb/parse_result.rb +17 -11
  431. data/lib/herb/parser_options.rb +65 -46
  432. data/lib/herb/position.rb +19 -0
  433. data/lib/herb/prism_inspect.rb +1 -4
  434. data/lib/herb/project.rb +28 -15
  435. data/lib/herb/range.rb +5 -0
  436. data/lib/herb/result.rb +2 -2
  437. data/lib/herb/ruby_program.rb +110 -0
  438. data/lib/herb/source_path.rb +232 -0
  439. data/lib/herb/token.rb +14 -3
  440. data/lib/herb/version.rb +1 -1
  441. data/lib/herb/visitor/context/origin.rb +52 -0
  442. data/lib/herb/visitor/context/replacements.rb +59 -0
  443. data/lib/herb/visitor/context.rb +169 -0
  444. data/lib/herb/visitor/context_aware.rb +45 -0
  445. data/lib/herb/visitor/diagnostics.rb +148 -0
  446. data/lib/herb/visitor/experimental.rb +33 -0
  447. data/lib/herb/visitor/parser_option_requirements.rb +151 -0
  448. data/lib/herb/visitor/stack.rb +192 -0
  449. data/lib/herb/visitor.rb +47 -1
  450. data/lib/herb/warnings.rb +25 -0
  451. data/lib/herb.rb +74 -63
  452. data/sig/herb/action_view/helper_registry.rbs +82 -10
  453. data/sig/herb/analysis/partial_declaration.rbs +80 -0
  454. data/sig/herb/analysis/partial_index.rbs +66 -0
  455. data/sig/herb/analysis/partial_resolution.rbs +57 -0
  456. data/sig/herb/analysis/partial_resolver.rbs +76 -0
  457. data/sig/herb/analysis/project_index.rbs +57 -0
  458. data/sig/herb/{action_view → analysis}/render_analyzer.rbs +25 -4
  459. data/sig/herb/analysis/render_graph/ancestor_chain.rbs +22 -0
  460. data/sig/herb/analysis/render_graph/builder.rbs +180 -0
  461. data/sig/herb/analysis/render_graph/call_frame.rbs +26 -0
  462. data/sig/herb/analysis/render_graph/call_site_location.rbs +28 -0
  463. data/sig/herb/analysis/render_graph/inferred_signature.rbs +27 -0
  464. data/sig/herb/analysis/render_graph/partial_call_site.rbs +36 -0
  465. data/sig/herb/analysis/render_graph/partial_context.rbs +31 -0
  466. data/sig/herb/analysis/render_graph/template_roots.rbs +32 -0
  467. data/sig/herb/analysis/render_graph.rbs +83 -0
  468. data/sig/herb/analysis/ruby_locals_index/local.rbs +21 -0
  469. data/sig/herb/analysis/ruby_locals_index/named_reference.rbs +20 -0
  470. data/sig/herb/analysis/ruby_locals_index/offset_table.rbs +26 -0
  471. data/sig/herb/analysis/ruby_locals_index/reference_collector.rbs +40 -0
  472. data/sig/herb/analysis/ruby_locals_index/state_locals.rbs +19 -0
  473. data/sig/herb/analysis/ruby_locals_index.rbs +62 -0
  474. data/sig/herb/analysis/ruby_reference.rbs +28 -0
  475. data/sig/herb/analysis/template_dependencies/dependency_collector.rbs +52 -0
  476. data/sig/herb/analysis/template_dependencies/node_dependency_collector.rbs +81 -0
  477. data/sig/herb/analysis/template_dependencies.rbs +125 -0
  478. data/sig/herb/ast/erb_render_node.rbs +10 -2
  479. data/sig/herb/ast/helpers.rbs +31 -1
  480. data/sig/herb/ast/herb_directive_node.rbs +13 -0
  481. data/sig/herb/ast/node.rbs +9 -0
  482. data/sig/herb/ast/nodes.rbs +662 -89
  483. data/sig/herb/backend.rbs +52 -0
  484. data/sig/herb/colors.rbs +3 -0
  485. data/sig/herb/configuration.rbs +27 -3
  486. data/sig/herb/dev/assets.rbs +27 -0
  487. data/sig/herb/dev/classifier.rbs +57 -0
  488. data/sig/herb/dev/embedded.rbs +21 -0
  489. data/sig/herb/dev/pipeline.rbs +118 -0
  490. data/sig/herb/dev/protocol.rbs +78 -0
  491. data/sig/herb/dev/runner.rbs +61 -23
  492. data/sig/herb/dev/server.rbs +49 -22
  493. data/sig/herb/dev/server_entry.rbs +46 -21
  494. data/sig/herb/dev/watcher.rbs +84 -0
  495. data/sig/herb/dev.rbs +58 -0
  496. data/sig/herb/diagnostic/formatter.rbs +28 -0
  497. data/sig/herb/diagnostic.rbs +88 -0
  498. data/sig/herb/diff/operation.rbs +36 -0
  499. data/sig/herb/diff/result.rbs +36 -0
  500. data/sig/herb/diff.rbs +6 -0
  501. data/sig/herb/engine/collector.rbs +48 -0
  502. data/sig/herb/engine/compiler.rbs +62 -23
  503. data/sig/herb/engine/component_tags/constant_resolver.rbs +19 -0
  504. data/sig/herb/engine/component_tags/partial_resolver.rbs +30 -0
  505. data/sig/herb/engine/component_tags/resolver.rbs +25 -0
  506. data/sig/herb/engine/component_tags/visitor.rbs +69 -0
  507. data/sig/herb/engine/css_inliner/inliner.rbs +65 -0
  508. data/sig/herb/engine/css_inliner/visitor.rbs +87 -0
  509. data/sig/herb/engine/errors.rbs +68 -0
  510. data/sig/herb/engine/helpers.rbs +28 -0
  511. data/sig/herb/engine/inline_render/inliner.rbs +39 -0
  512. data/sig/herb/engine/inline_render/visitor.rbs +104 -0
  513. data/sig/herb/engine/runtime/entry.rbs +43 -0
  514. data/sig/herb/engine/runtime/error_page.rbs +115 -0
  515. data/sig/herb/engine/runtime/html_safe_assertions.rbs +99 -0
  516. data/sig/herb/engine/runtime/journal/summary.rbs +172 -0
  517. data/sig/herb/engine/runtime/journal.rbs +126 -0
  518. data/sig/herb/engine/runtime/middleware.rbs +96 -0
  519. data/sig/herb/engine/runtime/observations.rbs +38 -0
  520. data/sig/herb/engine/runtime/report.rbs +97 -0
  521. data/sig/herb/engine/runtime/session.rbs +233 -0
  522. data/sig/herb/engine/runtime.rbs +14 -0
  523. data/sig/herb/engine/scoped_style/channel.rbs +45 -0
  524. data/sig/herb/engine/scoped_style/collector.rbs +45 -0
  525. data/sig/herb/engine/scoped_style/visitor.rbs +220 -0
  526. data/sig/herb/engine/slots/annotation.rbs +72 -0
  527. data/sig/herb/engine/slots/bindings.rbs +34 -0
  528. data/sig/herb/engine/slots/callee.rbs +62 -0
  529. data/sig/herb/engine/slots/component_definitions.rbs +19 -0
  530. data/sig/herb/engine/slots/components/async.rbs +20 -0
  531. data/sig/herb/engine/slots/components/base.rbs +60 -0
  532. data/sig/herb/engine/slots/components/deferred.rbs +29 -0
  533. data/sig/herb/engine/slots/components/fallback.rbs +21 -0
  534. data/sig/herb/engine/slots/components/fragment.rbs +34 -0
  535. data/sig/herb/engine/slots/components/lazy.rbs +20 -0
  536. data/sig/herb/engine/slots/components.rbs +30 -0
  537. data/sig/herb/engine/slots/dependencies/channel.rbs +51 -0
  538. data/sig/herb/engine/slots/dependencies.rbs +94 -0
  539. data/sig/herb/engine/slots/dynamics_compiler.rbs +349 -0
  540. data/sig/herb/engine/slots/identifier.rbs +19 -0
  541. data/sig/herb/engine/slots/manifest/channel.rbs +49 -0
  542. data/sig/herb/engine/slots/manifest/collector.rbs +45 -0
  543. data/sig/herb/engine/slots/markers.rbs +85 -0
  544. data/sig/herb/engine/slots/render_bindings.rbs +69 -0
  545. data/sig/herb/engine/slots/schema_compiler.rbs +62 -0
  546. data/sig/herb/engine/slots/state_anchor.rbs +41 -0
  547. data/sig/herb/engine/slots/state_compiler.rbs +258 -0
  548. data/sig/herb/engine/slots/state_directives.rbs +278 -0
  549. data/sig/herb/engine/slots/state_kinds.rbs +24 -0
  550. data/sig/herb/engine/slots/state_operators.rbs +19 -0
  551. data/sig/herb/engine/slots/state_overrides.rbs +33 -0
  552. data/sig/herb/engine/slots/state_predicates.rbs +16 -0
  553. data/sig/herb/engine/slots/state_transforms.rbs +15 -0
  554. data/sig/herb/engine/slots/statics.rbs +67 -0
  555. data/sig/herb/engine/slots/subtree.rbs +49 -0
  556. data/sig/herb/engine/slots/subtree_compiler.rbs +130 -0
  557. data/sig/herb/engine/slots/types.rbs +46 -0
  558. data/sig/herb/engine/slots/visitor.rbs +599 -0
  559. data/sig/herb/engine/validators/accessibility_validator.rbs +1 -1
  560. data/sig/herb/engine/validators/base.rbs +28 -0
  561. data/sig/herb/engine/validators/generator_template_validator.rbs +19 -0
  562. data/sig/herb/engine/validators/nesting_validator.rbs +1 -1
  563. data/sig/herb/engine/validators/render_validator.rbs +2 -6
  564. data/sig/herb/engine/validators/security_validator.rbs +1 -3
  565. data/sig/herb/engine/validators.rbs +21 -0
  566. data/sig/herb/engine/visitors/auto_close_omitted_tags_visitor.rbs +26 -0
  567. data/sig/herb/engine/visitors/content_for_visitor.rbs +52 -0
  568. data/sig/herb/engine/{debug_visitor.rbs → visitors/debug_visitor.rbs} +26 -15
  569. data/sig/herb/engine/visitors/html_safe_assertions_visitor.rbs +100 -0
  570. data/sig/herb/engine/visitors/instrumentation_visitor.rbs +111 -0
  571. data/sig/herb/engine/visitors/optimize_visitor.rbs +246 -0
  572. data/sig/herb/engine/visitors/remove_comments_visitor.rbs +66 -0
  573. data/sig/herb/engine/visitors/source_attribution_visitor.rbs +90 -0
  574. data/sig/herb/engine.rbs +47 -41
  575. data/sig/herb/ensure_installed.rbs +9 -0
  576. data/sig/herb/errors.rbs +293 -0
  577. data/sig/herb/fingerprint.rbs +37 -0
  578. data/sig/herb/html/elements.rbs +19 -0
  579. data/sig/herb/html/util.rbs +15 -1
  580. data/sig/herb/lex_result.rbs +0 -6
  581. data/sig/herb/locate.rbs +89 -0
  582. data/sig/herb/location.rbs +12 -0
  583. data/sig/herb/parse_result.rbs +10 -8
  584. data/sig/herb/parser_options.rbs +47 -21
  585. data/sig/herb/position.rbs +11 -0
  586. data/sig/herb/range.rbs +3 -0
  587. data/sig/herb/ruby_program.rbs +51 -0
  588. data/sig/herb/source_path.rbs +132 -0
  589. data/sig/herb/token.rbs +5 -2
  590. data/sig/herb/visitor/context/origin.rbs +51 -0
  591. data/sig/herb/visitor/context/replacements.rbs +39 -0
  592. data/sig/herb/visitor/context.rbs +83 -0
  593. data/sig/herb/visitor/context_aware.rbs +32 -0
  594. data/sig/herb/visitor/diagnostics.rbs +82 -0
  595. data/sig/herb/visitor/experimental.rbs +23 -0
  596. data/sig/herb/visitor/parser_option_requirements.rbs +76 -0
  597. data/sig/herb/visitor/stack.rbs +91 -0
  598. data/sig/herb/visitor.rbs +22 -0
  599. data/sig/herb/warnings.rbs +10 -0
  600. data/sig/herb.rbs +27 -10
  601. data/sig/serialized_ast_errors.rbs +58 -1
  602. data/sig/serialized_ast_nodes.rbs +58 -2
  603. data/src/analyze/action_view/attribute_extraction_helpers.c +73 -36
  604. data/src/analyze/action_view/generated_handlers.c +37 -1
  605. data/src/analyze/action_view/generated_handlers.h +2 -1
  606. data/src/analyze/action_view/helper_registry.c +1353 -58
  607. data/src/analyze/action_view/registry.c +10 -17
  608. data/src/analyze/action_view/stylesheet_link_tag.c +40 -0
  609. data/src/analyze/action_view/tag_helper_node_builders.c +57 -0
  610. data/src/analyze/action_view/tag_helpers.c +423 -93
  611. data/src/analyze/analyze.c +301 -64
  612. data/src/analyze/analyze_helpers.c +420 -23
  613. data/src/analyze/builders.c +79 -51
  614. data/src/analyze/conditional_elements.c +13 -8
  615. data/src/analyze/conditional_open_tags.c +11 -5
  616. data/src/analyze/control_type.c +16 -1
  617. data/src/analyze/herb_directives.c +701 -0
  618. data/src/analyze/invalid_structures.c +11 -7
  619. data/src/analyze/iteration_nodes.c +306 -0
  620. data/src/analyze/missing_end.c +116 -32
  621. data/src/analyze/parse_errors.c +8 -3
  622. data/src/analyze/postfix_conditionals.c +98 -63
  623. data/src/analyze/prism_annotate.c +13 -4
  624. data/src/analyze/render_nodes.c +345 -123
  625. data/src/analyze/strict_locals.c +30 -26
  626. data/src/analyze/ternary_conditionals.c +95 -70
  627. data/src/analyze/transform.c +43 -1
  628. data/src/ast/ast_node.c +3 -13
  629. data/src/ast/ast_nodes.c +911 -112
  630. data/src/ast/ast_pretty_print.c +161 -2
  631. data/src/diff/herb_diff.c +8 -0
  632. data/src/diff/herb_diff_attributes.c +1 -0
  633. data/src/diff/herb_diff_children.c +4 -3
  634. data/src/diff/herb_diff_helpers.c +7 -1
  635. data/src/diff/herb_diff_nodes.c +186 -71
  636. data/src/diff/herb_hash_tree.c +99 -1
  637. data/src/errors.c +1096 -128
  638. data/src/extract.c +30 -8
  639. data/src/herb.c +30 -11
  640. data/src/include/analyze/action_view/attribute_extraction_helpers.h +1 -1
  641. data/src/include/analyze/action_view/helper_registry.h +28 -4
  642. data/src/include/analyze/action_view/tag_helper_handler.h +1 -1
  643. data/src/include/analyze/action_view/tag_helper_node_builders.h +7 -0
  644. data/src/include/analyze/analyze.h +11 -0
  645. data/src/include/analyze/builders.h +16 -0
  646. data/src/include/analyze/helpers.h +23 -2
  647. data/src/include/analyze/herb_directive_kinds.h +41 -0
  648. data/src/include/analyze/herb_directives.h +14 -0
  649. data/src/include/analyze/iteration_nodes.h +11 -0
  650. data/src/include/analyze/prism_annotate.h +3 -3
  651. data/src/include/analyze/ternary_conditionals.h +2 -0
  652. data/src/include/ast/ast_node.h +1 -5
  653. data/src/include/ast/ast_nodes.h +76 -2
  654. data/src/include/ast/ast_pretty_print.h +1 -1
  655. data/src/include/diff/herb_diff.h +11 -0
  656. data/src/include/errors.h +156 -39
  657. data/src/include/extract.h +11 -0
  658. data/src/include/herb.h +6 -0
  659. data/src/include/lexer/erb_openers.h +29 -0
  660. data/src/include/lexer/lexer_peek_helpers.h +8 -1
  661. data/src/include/lexer/lexer_struct.h +4 -0
  662. data/src/include/lexer/token.h +3 -0
  663. data/src/include/lexer/token_struct.h +8 -6
  664. data/src/include/lib/hb_allocator.h +2 -1
  665. data/src/include/lib/hb_array.h +2 -0
  666. data/src/include/lib/hb_foreach.h +1 -1
  667. data/src/include/lib/hb_string.h +7 -0
  668. data/src/include/parser/dot_notation.h +1 -1
  669. data/src/include/parser/foreign_content_elements.h +32 -0
  670. data/src/include/parser/parser.h +16 -30
  671. data/src/include/parser/parser_helpers.h +13 -11
  672. data/src/include/parser/parser_options.h +41 -0
  673. data/src/include/prism/ruby_parser.h +6 -0
  674. data/src/include/util/html_elements.h +85 -0
  675. data/src/include/util/html_util.h +1 -0
  676. data/src/include/version.h +1 -1
  677. data/src/lexer/lexer_peek_helpers.c +15 -1
  678. data/src/lexer/token.c +83 -1
  679. data/src/lexer.c +196 -12
  680. data/src/lib/hb_allocator.c +2 -0
  681. data/src/lib/hb_array.c +26 -0
  682. data/src/lib/hb_string.c +26 -0
  683. data/src/main.c +1 -1
  684. data/src/parser/dot_notation.c +4 -3
  685. data/src/parser/match_tags.c +66 -1
  686. data/src/parser/parser_helpers.c +69 -37
  687. data/src/parser.c +606 -383
  688. data/src/parser_options_defaults.c +30 -0
  689. data/src/prism/prism_helpers.c +3 -0
  690. data/src/prism/ruby_parser.c +49 -0
  691. data/src/util/html_util.c +11 -58
  692. data/src/visitor.c +77 -1
  693. data/templates/ext/herb/error_helpers.c.erb +1 -1
  694. data/templates/ext/herb/nodes.c.erb +18 -13
  695. data/templates/ext/herb/nodes.h.erb +2 -1
  696. data/templates/ext/herb/parser_options_helpers.c.erb +69 -0
  697. data/templates/ext/herb/parser_options_helpers.h.erb +11 -0
  698. data/templates/java/nodes.c.erb +20 -16
  699. data/templates/java/nodes.h.erb +3 -2
  700. data/templates/java/org/herb/ParserOptions.java.erb +24 -0
  701. data/templates/java/org/herb/ast/HelperRegistry.java.erb +67 -31
  702. data/templates/java/org/herb/ast/HelperType.java.erb +29 -0
  703. data/templates/java/org/herb/ast/Nodes.java.erb +11 -7
  704. data/templates/java/parser_options_helpers.c.erb +45 -0
  705. data/templates/java/parser_options_helpers.h.erb +10 -0
  706. data/templates/javascript/packages/client/src/state-kinds.ts.erb +49 -0
  707. data/templates/javascript/packages/client/src/state-operators.ts.erb +15 -0
  708. data/templates/javascript/packages/client/src/state-predicates.ts.erb +27 -0
  709. data/templates/javascript/packages/client/src/state-transforms.ts.erb +19 -0
  710. data/templates/javascript/packages/core/src/action-view-helpers.ts.erb +47 -0
  711. data/templates/javascript/packages/core/src/built-in-components.ts.erb +67 -0
  712. data/templates/javascript/packages/core/src/errors.ts.erb +9 -3
  713. data/templates/javascript/packages/core/src/foreign-content-elements.ts.erb +18 -0
  714. data/templates/javascript/packages/core/src/html-constants.ts.erb +32 -0
  715. data/templates/javascript/packages/core/src/html-elements.ts.erb +41 -0
  716. data/templates/javascript/packages/core/src/node-type-guards.ts.erb +11 -7
  717. data/templates/javascript/packages/core/src/nodes.ts.erb +82 -19
  718. data/templates/javascript/packages/core/src/parser-options.ts.erb +41 -0
  719. data/templates/javascript/packages/core/src/visitor.ts.erb +1 -1
  720. data/templates/javascript/packages/node/extension/error_helpers.cpp.erb +3 -3
  721. data/templates/javascript/packages/node/extension/nodes.cpp.erb +17 -12
  722. data/templates/javascript/packages/node/extension/nodes.h.erb +3 -3
  723. data/templates/javascript/packages/node/extension/parser_options_helpers.cpp.erb +41 -0
  724. data/templates/javascript/packages/node/extension/parser_options_helpers.h.erb +12 -0
  725. data/templates/lib/herb/action_view/helper_registry.rb.erb +77 -3
  726. data/templates/lib/herb/ast/nodes.rb.erb +16 -6
  727. data/templates/lib/herb/engine/slots/component_definitions.rb.erb +38 -0
  728. data/templates/lib/herb/engine/slots/state_kinds.rb.erb +37 -0
  729. data/templates/lib/herb/engine/slots/state_operators.rb.erb +26 -0
  730. data/templates/lib/herb/engine/slots/state_predicates.rb.erb +39 -0
  731. data/templates/lib/herb/engine/slots/state_transforms.rb.erb +27 -0
  732. data/templates/lib/herb/errors.rb.erb +34 -6
  733. data/templates/lib/herb/html/elements.rb.erb +12 -0
  734. data/templates/lib/herb/parser_options.rb.erb +32 -0
  735. data/templates/lib/herb/visitor.rb.erb +7 -1
  736. data/templates/rust/herb-printer/src/printer_visitor.rs.erb +14 -0
  737. data/templates/rust/src/action_view_helpers.rs.erb +38 -0
  738. data/templates/rust/src/ast/nodes.rs.erb +24 -31
  739. data/templates/rust/src/errors.rs.erb +1 -1
  740. data/templates/rust/src/nodes.rs.erb +58 -26
  741. data/templates/rust/src/parser_options.rs.erb +16 -0
  742. data/templates/rust/src/prism/generated_deserialize.rs.erb +109 -0
  743. data/templates/rust/src/prism/generated_prettyprint.rs.erb +153 -0
  744. data/templates/rust/src/union_types.rs.erb +7 -1
  745. data/templates/rust/src/visitor.rs.erb +1 -1
  746. data/templates/src/analyze/action_view/helper_registry.c.erb +22 -0
  747. data/templates/src/analyze/missing_end.c.erb +13 -5
  748. data/templates/src/ast/ast_nodes.c.erb +41 -2
  749. data/templates/src/diff/herb_diff_nodes.c.erb +44 -8
  750. data/templates/src/errors.c.erb +8 -3
  751. data/templates/src/include/analyze/action_view/helper_registry.h.erb +19 -0
  752. data/templates/src/include/analyze/herb_directive_kinds.h.erb +25 -0
  753. data/templates/src/include/errors.h.erb +3 -1
  754. data/templates/src/include/parser/foreign_content_elements.h.erb +23 -0
  755. data/templates/src/include/parser/parser_options.h.erb +21 -0
  756. data/templates/src/include/util/html_elements.h.erb +28 -0
  757. data/templates/src/parser_options_defaults.c.erb +9 -0
  758. data/templates/template.rb +564 -9
  759. data/templates/wasm/error_helpers.cpp.erb +4 -4
  760. data/templates/wasm/nodes.cpp.erb +12 -12
  761. data/templates/wasm/nodes.h.erb +3 -3
  762. data/templates/wasm/parser_options_helpers.cpp.erb +25 -0
  763. data/templates/wasm/parser_options_helpers.h.erb +12 -0
  764. metadata +306 -27
  765. data/config/action_view_helpers/actionview/form_helper/button.yml +0 -38
  766. data/config/action_view_helpers/actionview/form_helper/submit.yml +0 -35
  767. data/lib/herb/ast.rb +0 -7
  768. data/lib/herb/diff_operation.rb +0 -34
  769. data/lib/herb/diff_result.rb +0 -59
  770. data/lib/herb/engine/error_formatter.rb +0 -432
  771. data/lib/herb/engine/parser_error_overlay.rb +0 -773
  772. data/lib/herb/engine/validation_error_overlay.rb +0 -182
  773. data/lib/herb/engine/validation_errors.rb +0 -65
  774. data/lib/herb/engine/validator.rb +0 -80
  775. data/sig/herb/ast.rbs +0 -6
  776. data/sig/herb/diff_operation.rbs +0 -34
  777. data/sig/herb/diff_result.rbs +0 -34
  778. data/sig/herb/engine/debug.rbs +0 -38
  779. data/sig/herb/engine/error_formatter.rbs +0 -47
  780. data/sig/herb/engine/parser_error_overlay.rbs +0 -41
  781. data/sig/herb/engine/validation_error_overlay.rbs +0 -35
  782. data/sig/herb/engine/validation_errors.rbs +0 -45
  783. data/sig/herb/engine/validator.rbs +0 -41
  784. data/sig/herb_c_extension.rbs +0 -10
@@ -0,0 +1,854 @@
1
+ # frozen_string_literal: true
2
+ # typed: false
3
+
4
+ require_relative "../../../herb"
5
+ require_relative "../../engine"
6
+ require_relative "visitor"
7
+ require_relative "state_overrides"
8
+
9
+ module Herb
10
+ class Engine
11
+ module Slots
12
+ # Compiles a template into Ruby that returns its dynamic values rather than its HTML.
13
+ #
14
+ # `Herb::Engine` answers "what does this template render". This answers "what did the template
15
+ # evaluate to render it", which is the half that changes when state changes:
16
+ #
17
+ # require "herb/engine/slots/dynamics_compiler"
18
+ #
19
+ # source = Herb::Engine::Slots::DynamicsCompiler.new(%(<h1><%= @title %></h1>)).src
20
+ # view.instance_eval(source)
21
+ # #=> { template: "app/views/posts/index.html.erb", version: "fd3dfd36", slots: { 0 => "Hello" } }
22
+ #
23
+ # The names follow Phoenix LiveView, which splits a rendered template into its `static` strings
24
+ # and its `dynamic` values for the same reason. A template's statics never change between
25
+ # renders, so anything re-rendering on a state change only has to send the dynamics.
26
+ #
27
+ # This is a separate compiler rather than an option on `Herb::Engine` because that class is a
28
+ # drop-in for `Erubi::Engine` and has to keep answering the way Erubi does.
29
+ #
30
+ # ## Values name the template they came from
31
+ #
32
+ # An index means nothing on its own, because it is a position in one template's numbering, and
33
+ # it means something else in the next template. So the values arrive wrapped in the identifier
34
+ # and version `Visitor` gave the markers, which is the same pair the page carries in
35
+ # `<!--herb-region:ID:VERSION-->`. A client holding both can tell that they were compiled
36
+ # together, and a version that no longer matches says the indices cannot be trusted.
37
+ #
38
+ # ## The shape follows the template, not the render
39
+ #
40
+ # Every insertion point owns an index, decided while compiling and the same on every render.
41
+ # Control flow owns one too, because what it decided is itself a value that changes:
42
+ #
43
+ # <% if admin? %><%= secret %><% else %><%= public %><% end %>
44
+ # #=> { 0 => { branch: 0, slots: { 1 => "s" } } } when admin?
45
+ # #=> { 0 => { branch: 1, slots: { 2 => "p" } } } otherwise
46
+ #
47
+ # Both branches keep their own indices, so a condition flipping changes which indices are
48
+ # present and never what an index means.
49
+ #
50
+ # ## Absent means it did not run
51
+ #
52
+ # A key is missing when the code that would have filled it never ran, which is the same thing
53
+ # the rendered markup says by not being there. Nothing has to be sent about a branch that was
54
+ # not taken, and nothing can be learned about one either.
55
+ #
56
+ # A conditional and a collection are always present, because both are evaluated on every render
57
+ # even when they produce nothing. A conditional that matched no branch is `{ branch: nil }` and
58
+ # an empty collection is `{ items: {} }`, both of which the client has to be told.
59
+ #
60
+ # ## Collections group by item
61
+ #
62
+ # A collection holds its items in render order, each item carrying the slots inside it:
63
+ #
64
+ # <% users.each do |user| %><%= user.first %> <%= user.last %><% end %>
65
+ # #=> { 0 => { items: { 1 => { 1 => "Marco", 2 => "Roth" },
66
+ # 2 => { 1 => "Joe", 2 => "Doe" } } } }
67
+ #
68
+ # Grouping the other way would give one list per slot and leave the client to zip them back
69
+ # together, which it cannot do once an item is inserted rather than appended.
70
+ #
71
+ # An item is keyed by the key its template declares, through `herb-key` or `id` or a
72
+ # `<%# herb:key %>` directive, which is what makes it survive being reordered. `Visitor`
73
+ # decides what that key is and this evaluates it, so an item arrives under the same key the
74
+ # marker around it carries. A collection that declares none falls back to position.
75
+ #
76
+ # ## A partial keeps its own values
77
+ #
78
+ # `<%= render "posts/card" %>` evaluates to that partial's own values, so the slot holding it
79
+ # holds a whole payload rather than a string:
80
+ #
81
+ # { template: "index.html.erb", version: "a1b2c3d4",
82
+ # slots: { 0 => { template: "_card.html.erb", version: "e5f6a7b8", slots: { 0 => "Marco" } } } }
83
+ #
84
+ # Nothing else would work, because the partial numbers its slots in its own template and the
85
+ # page marks them out as their own region. Coercing it to a string would flatten a partial's
86
+ # values into the markup they were meant to replace, and a partial rendering a partial is
87
+ # ordinary, so this nests as deeply as the template does.
88
+ #
89
+ # ## Escaping
90
+ #
91
+ # A value carries the escaping of the place it was written, because that is where it is going
92
+ # back to. The same expression is escaped differently in an attribute, in a `<script>`, and in
93
+ # text, so the tree is left intact and the compiler decides as it normally would.
94
+ #
95
+ # ## Blocks
96
+ #
97
+ # A tag that takes a block, such as `<%= form_with do |f| %>`, owns an entry holding everything
98
+ # the block rendered, because the helper wraps that output in markup of its own that only the
99
+ # helper can produce. What the template wrote inside the block keeps its own indices alongside:
100
+ #
101
+ # <%= form_with(model: @user) do |f| %><%= f.label %><% end %>
102
+ # #=> { 0 => "<form>Name</form>", 1 => "Name" }
103
+ #
104
+ # So a caller that can address slot 1 sends a value, and one that cannot falls back to slot 0
105
+ # and the whole block. Slot 1 is inside slot 0, which the client already has to reason about
106
+ # for conditionals and collections.
107
+ #
108
+ # A block yielding more than once is the exception, since one index cannot stand for the several
109
+ # values its interior took. `each` and the other iterations are compiled as collections for that
110
+ # reason, and a helper that yields repeatedly reports the last value its interior took.
111
+ #
112
+ class DynamicsCompiler < Herb::Engine
113
+ BUFFER = "__herb_dynamics" #: String
114
+ BLOCK_BUFFER = "__herb_block" #: String
115
+ SLOT_BUFFER = "__herb_slot" #: String
116
+ SCOPE_BUFFER = "__herb_scope" #: String
117
+ ITEMS_BUFFER = "__herb_items" #: String
118
+ KEY_BUFFER = "__herb_key" #: String
119
+ OCCURRENCE_BUFFER = "__herb_occurrence" #: String
120
+
121
+ BRANCHING_NODES = [
122
+ "AST_ERB_IF_NODE",
123
+ "AST_ERB_UNLESS_NODE",
124
+ "AST_ERB_ELSE_NODE",
125
+ "AST_ERB_WHEN_NODE",
126
+ "AST_ERB_IN_NODE"
127
+ ].freeze #: Array[String]
128
+
129
+ class Compiler < Herb::Engine::Compiler
130
+ #: (untyped, ?Hash[Symbol, untyped]) -> void
131
+ def initialize(engine, options = {})
132
+ super
133
+
134
+ @slot_visitor = engine.slot_visitor
135
+ @current_node = nil
136
+ @current_attribute = nil
137
+ @current_rcdata = nil
138
+ @rendering = false
139
+ @capturing_part = false
140
+ @block_depth = 0
141
+
142
+ branch_counts = {} #: Hash[Integer, Integer]
143
+ branch_owner = {} #: Hash[untyped, Integer]
144
+
145
+ @branch_counts = branch_counts
146
+ @branch_owner = branch_owner.compare_by_identity
147
+ end
148
+
149
+ #: (untyped) -> void
150
+ def visit_html_attribute_node(node)
151
+ previous = @current_attribute
152
+ @current_attribute = node
153
+
154
+ super
155
+ ensure
156
+ @current_attribute = previous
157
+ end
158
+
159
+ #: (untyped) -> void
160
+ def visit_html_element_node(node)
161
+ index = @slot_visitor.index_for(node)
162
+ previous = @current_rcdata
163
+ slot = index ? @slot_visitor.slots[index] : nil #: untyped
164
+
165
+ @current_rcdata = node if slot&.type == :raw_text_interpolation
166
+
167
+ if slot&.type == :keyed
168
+ @tokens << [:scope, "", nil, [:open_keyed, index, slot.key_expression]]
169
+
170
+ begin
171
+ super
172
+ ensure
173
+ @tokens << [:scope, "", nil, [:close_keyed, index]]
174
+ end
175
+ else
176
+ super
177
+ end
178
+ ensure
179
+ @current_rcdata = previous
180
+ end
181
+
182
+ #: (untyped) -> void
183
+ def visit_erb_content_node(node)
184
+ previous = @current_node
185
+ @current_node = node
186
+
187
+ super
188
+ ensure
189
+ @current_node = previous
190
+ end
191
+
192
+ #: (untyped) -> void
193
+ def visit_erb_yield_node(node)
194
+ previous = @current_node
195
+ @current_node = node
196
+
197
+ super
198
+ ensure
199
+ @current_node = previous
200
+ end
201
+
202
+ #: (untyped) -> void
203
+ def visit_erb_render_node(node)
204
+ previous = @current_node
205
+ @current_node = node
206
+ @rendering = node.end_node.nil?
207
+
208
+ super
209
+ ensure
210
+ @current_node = previous
211
+ @rendering = false
212
+ end
213
+
214
+ #: (untyped) { () -> void } -> void
215
+ def visit_erb_control_node(node, &block)
216
+ return super unless block
217
+ return super unless branch?(node)
218
+
219
+ index = @branch_owner[node]
220
+
221
+ branched = lambda do
222
+ @tokens << [:scope, "", nil, [:branch, index, next_branch(index)]]
223
+
224
+ yield
225
+ end
226
+
227
+ super(node, &branched)
228
+ end
229
+
230
+ #: (untyped) -> void
231
+ def visit_erb_if_node(node)
232
+ conditional(node) { super }
233
+ end
234
+
235
+ #: (untyped) -> void
236
+ def visit_erb_unless_node(node)
237
+ conditional(node) { super }
238
+ end
239
+
240
+ #: (untyped) -> void
241
+ def visit_erb_case_node(node)
242
+ conditional(node) { super }
243
+ end
244
+
245
+ #: (untyped) -> void
246
+ def visit_erb_case_match_node(node)
247
+ conditional(node) { super }
248
+ end
249
+
250
+ #: (untyped) -> void
251
+ def visit_erb_iteration_block_node(node)
252
+ collection(node) do |index|
253
+ visit_erb_control_node(node) do
254
+ item(index) do
255
+ visit_all(node.body)
256
+
257
+ visit(node.rescue_clause)
258
+ visit(node.else_clause)
259
+ visit(node.ensure_clause)
260
+ end
261
+
262
+ visit(node.end_node)
263
+ end
264
+ end
265
+ end
266
+
267
+ #: (untyped) -> void
268
+ def visit_erb_for_node(node)
269
+ iteration(node, :statements)
270
+ end
271
+
272
+ #: (untyped) -> void
273
+ def visit_erb_while_node(node)
274
+ iteration(node, :statements)
275
+ end
276
+
277
+ #: (untyped) -> void
278
+ def visit_erb_until_node(node)
279
+ iteration(node, :statements)
280
+ end
281
+
282
+ #: (untyped) -> void
283
+ def visit_erb_block_node(node)
284
+ return super unless output_block?(node)
285
+
286
+ opening = node.tag_opening.value
287
+
288
+ return super if erb_escaped?(opening)
289
+
290
+ should_escape = should_escape_output?(opening)
291
+ index = claim(node)
292
+
293
+ @tokens << [
294
+ should_escape ? :expr_block_escaped : :expr_block,
295
+ node.content.value.strip,
296
+ current_context,
297
+ index
298
+ ]
299
+
300
+ @last_trim_consumed_newline = false
301
+ @trim_next_whitespace = true if right_trim?(node)
302
+
303
+ @block_depth += 1
304
+
305
+ begin
306
+ visit_all(node.body)
307
+ ensure
308
+ @block_depth -= 1
309
+ end
310
+
311
+ visit_erb_block_end_node(node.end_node, escaped: should_escape)
312
+ end
313
+
314
+ #: () -> void
315
+ def generate_output
316
+ @engine.send(:capture_occurrence)
317
+
318
+ optimize_tokens(@tokens).each do |type, value, context, extra|
319
+ case type
320
+ when :text then @engine.send(:add_text, value)
321
+ when :code then @engine.send(:add_code, value)
322
+ when :scope then @engine.send(:add_scope, *extra)
323
+ when :dynamic
324
+ index, escaped, nested = extra
325
+
326
+ @engine.send(:add_dynamic, value, context, index, escaped, nested: nested)
327
+ when :expr_block, :expr_block_escaped
328
+ @engine.send(:add_dynamic_block, value, extra, type == :expr_block_escaped)
329
+ when :expr_block_end
330
+ @engine.send(:add_expression_block_end, value, escaped: extra)
331
+ end
332
+ end
333
+ end
334
+
335
+ private
336
+
337
+ #: (untyped) -> Integer?
338
+ def claim(node)
339
+ return nil if @capturing_part
340
+
341
+ @slot_visitor.index_for(@current_attribute || @current_rcdata || node)
342
+ end
343
+
344
+ #: (String) -> void
345
+ def add_expression(code)
346
+ @tokens << [:dynamic, code, current_context, [claim(@current_node), false, @rendering]]
347
+ @last_trim_consumed_newline = false
348
+ end
349
+
350
+ #: (String) -> void
351
+ def add_expression_escaped(code)
352
+ @tokens << [:dynamic, code, current_context, [claim(@current_node), true, @rendering]]
353
+ @last_trim_consumed_newline = false
354
+ end
355
+
356
+ #: (untyped) -> bool
357
+ def output_block?(node)
358
+ node.tag_opening.value.include?("=")
359
+ end
360
+
361
+ #: (untyped) -> bool
362
+ def branch?(node)
363
+ @branch_owner.key?(node)
364
+ end
365
+
366
+ #: (Integer) -> Integer
367
+ def next_branch(index)
368
+ count = @branch_counts[index] || 0
369
+ @branch_counts[index] = count + 1
370
+
371
+ count
372
+ end
373
+
374
+ #: (untyped) { () -> void } -> void
375
+ def conditional(node)
376
+ return yield if branch?(node)
377
+
378
+ if @current_attribute || @current_rcdata
379
+ return yield if @capturing_part
380
+
381
+ index = claim(node)
382
+
383
+ return yield unless index
384
+
385
+ @capturing_part = true
386
+ @tokens << [:scope, "", nil, [:part_open]]
387
+
388
+ yield
389
+
390
+ @tokens << [:scope, "", nil, [:part_close, index]]
391
+ @capturing_part = false
392
+
393
+ return
394
+ end
395
+
396
+ index = claim(node)
397
+
398
+ return yield unless index
399
+
400
+ own_branches(node, index)
401
+
402
+ @tokens << [:scope, "", nil, [:open_conditional, index]]
403
+
404
+ yield
405
+
406
+ @tokens << [:scope, "", nil, [:close_conditional, index]]
407
+ end
408
+
409
+ #: (untyped, Integer) -> void
410
+ def own_branches(node, index)
411
+ return unless node
412
+
413
+ @branch_owner[node] = index if BRANCHING_NODES.include?(node.type.to_s)
414
+
415
+ [:subsequent, :else_clause, :conditions].each do |property|
416
+ next unless node.respond_to?(property)
417
+
418
+ value = node.send(property)
419
+
420
+ case value
421
+ when Array then value.each { |child| own_branches(child, index) }
422
+ when nil then next
423
+ else own_branches(value, index)
424
+ end
425
+ end
426
+ end
427
+
428
+ #: (untyped) { (Integer?) -> void } -> void
429
+ def collection(node)
430
+ index = claim(node)
431
+
432
+ return yield(nil) unless index
433
+
434
+ @tokens << [:scope, "", nil, [:open_collection, index]]
435
+
436
+ yield(index)
437
+
438
+ @tokens << [:scope, "", nil, [:close_collection, index]]
439
+ end
440
+
441
+ #: (Integer?) { () -> void } -> void
442
+ def item(index)
443
+ return yield unless index
444
+
445
+ @tokens << [:scope, "", nil, [:item_begin, index, item_key(index)]]
446
+
447
+ yield
448
+
449
+ @tokens << [:scope, "", nil, [:item_end, index]]
450
+ end
451
+
452
+ #: (Integer) -> String?
453
+ def item_key(index)
454
+ @slot_visitor.slots[index]&.key_expression
455
+ end
456
+
457
+ #: (untyped, Symbol) -> void
458
+ def iteration(node, part)
459
+ collection(node) do |index|
460
+ visit_erb_control_node(node) do
461
+ item(index) do
462
+ visit_all(node.send(part) || [])
463
+ end
464
+
465
+ visit(node.end_node)
466
+ end
467
+ end
468
+ end
469
+ end
470
+
471
+ class Prune < Herb::Visitor
472
+ #: (Visitor, Integer) -> void
473
+ def initialize(slot_visitor, index)
474
+ super()
475
+
476
+ @slot_visitor = slot_visitor
477
+ @index = index
478
+ end
479
+
480
+ #: (untyped) -> void
481
+ def visit_document_node(node)
482
+ target = @slot_visitor.slot_nodes[@index]
483
+
484
+ return unless target
485
+
486
+ keep(node, target)
487
+ end
488
+
489
+ private
490
+
491
+ #: (untyped, untyped) -> void
492
+ def keep(node, target)
493
+ Visitor::BRANCH_BODY_PROPERTIES.each do |property|
494
+ next unless node.respond_to?(property)
495
+
496
+ value = node.send(property)
497
+
498
+ case value
499
+ when Array
500
+ if property == :conditions
501
+ value.each { |arm| keep(arm, target) if contains?(arm, target) }
502
+ else
503
+ value.replace(value.select { |child| child.equal?(target) || contains?(child, target) || @slot_visitor.assignment_node?(child) })
504
+ value.each { |child| keep(child, target) if !child.equal?(target) && contains?(child, target) }
505
+ end
506
+ when Herb::AST::Node
507
+ keep(value, target) if contains?(value, target)
508
+ end
509
+ end
510
+
511
+ Visitor::BRANCH_CONTINUATION_PROPERTIES.each do |property|
512
+ next unless node.respond_to?(property)
513
+
514
+ continuation = node.send(property)
515
+
516
+ keep(continuation, target) if continuation && contains?(continuation, target)
517
+ end
518
+ end
519
+
520
+ #: (untyped, untyped) -> bool
521
+ def contains?(node, target)
522
+ return true if node.equal?(target)
523
+ return false unless node.is_a?(Herb::AST::Node)
524
+
525
+ node.compact_child_nodes.any? { |child| contains?(child, target) }
526
+ end
527
+ end
528
+
529
+ attr_reader :slot_visitor #: Visitor
530
+
531
+ #: (String, ?Hash[Symbol, untyped]) -> void
532
+ def initialize(input, properties = {})
533
+ @block_depth = 0
534
+ @scopes = [] #: Array[Integer]
535
+ @withheld = {} #: Hash[Integer, bool]
536
+ @input = input
537
+ @filename = properties[:filename]
538
+ @slot_visitor = properties[:slot_visitor] || Visitor.new(mode: :server, mark: false)
539
+ @slot_visitor.state_overrides!
540
+ visitors = [*properties[:visitors], @slot_visitor]
541
+ visitors << Prune.new(@slot_visitor, properties[:block]) if properties[:block]
542
+
543
+ super(
544
+ input,
545
+ properties.merge(
546
+ bufvar: BUFFER,
547
+ bufval: "::Hash.new",
548
+ postamble: "#{BUFFER}\n",
549
+ visitors: visitors
550
+ )
551
+ )
552
+ end
553
+
554
+ #: () -> untyped
555
+ def compiler_class
556
+ Compiler
557
+ end
558
+
559
+ #: (String) -> void
560
+ def add_text(text)
561
+ return if @block_depth.zero?
562
+
563
+ super
564
+ end
565
+
566
+ #: (Symbol, *untyped) -> void
567
+ def add_scope(kind, *)
568
+ send(:"scope_#{kind}", *)
569
+ end
570
+
571
+ #: (String, Symbol?, Integer?, bool, ?nested: bool) -> void
572
+ def add_dynamic(code, context, index, escaped, nested: false)
573
+ value = if index && boolean_presence?(index)
574
+ "!!(#{code})"
575
+ elsif nested
576
+ "(#{code})"
577
+ else
578
+ dynamic_value(code, context, escaped)
579
+ end
580
+
581
+ unless @block_depth.zero?
582
+ if index && boolean_presence?(index)
583
+ attribute = @slot_visitor.slots[index].attribute.to_s.inspect
584
+
585
+ return add_block_dynamic("(#{assignment(index, value)}) ? #{attribute} : \"\"")
586
+ end
587
+
588
+ if index && interpolated?(index)
589
+ return add_block_dynamic("(#{assignment(index, value)}).fetch(-1)")
590
+ end
591
+
592
+ return add_block_dynamic(index ? assignment(index, value) : value)
593
+ end
594
+ return if index.nil?
595
+
596
+ @src << "; " << assignment(index, value) << ";"
597
+ end
598
+
599
+ #: (Integer) -> bool
600
+ def boolean_presence?(index)
601
+ @slot_visitor.slots[index]&.type == :boolean_attribute
602
+ end
603
+
604
+ #: (String, Integer?, bool) -> void
605
+ def add_dynamic_block(code, index, escaped)
606
+ @_in_expression_block = true
607
+ @_expression_block_open_paren = true
608
+
609
+ opening = escaped ? "#{@escapefunc}((" : "("
610
+
611
+ @src << if @block_depth.zero?
612
+ "; #{current_scope}[#{index}] = #{opening}#{code}"
613
+ else
614
+ "; #{@bufvar} << #{opening}#{code}"
615
+ end
616
+
617
+ open_block
618
+ end
619
+
620
+ #: (String, ?escaped: bool) -> void
621
+ def add_expression_block_end(code, escaped: false)
622
+ @src << "; ::Herb::Engine.raw(" << @bufvar << ")"
623
+
624
+ close_block
625
+
626
+ super
627
+ end
628
+
629
+ #: () -> String
630
+ def inspect
631
+ "#<#{self.class.name}>"
632
+ end
633
+
634
+ private
635
+
636
+ #: (String) -> void
637
+ def add_postamble(_postamble)
638
+ super("{ template: #{@slot_visitor.identifier.inspect}, " \
639
+ "version: #{@slot_visitor.version.inspect}, " \
640
+ "occurrence: #{OCCURRENCE_BUFFER}#{region_seeds}, " \
641
+ "slots: #{BUFFER} }\n")
642
+ end
643
+
644
+ #: () -> String
645
+ def region_seeds
646
+ names = @slot_visitor.seeded_region_states
647
+
648
+ return "" if names.nil? || names.empty?
649
+
650
+ pairs = names.map { |name| "#{name.inspect} => #{name}" }.join(", ")
651
+
652
+ ", seeds: #{Markers.seeds_expression(pairs)}"
653
+ end
654
+
655
+ #: () -> void
656
+ def capture_occurrence
657
+ @src << "; #{OCCURRENCE_BUFFER} = #{@slot_visitor.occurrence_expression};"
658
+ end
659
+
660
+ #: () -> String
661
+ def current_scope
662
+ @scopes.empty? ? BUFFER : "#{SCOPE_BUFFER}#{@scopes.last}"
663
+ end
664
+
665
+ #: (Integer) -> void
666
+ def scope_open_conditional(index)
667
+ @src << "; #{SLOT_BUFFER}#{index} = nil;"
668
+ end
669
+
670
+ #: (Integer, Integer) -> void
671
+ def scope_branch(index, branch)
672
+ leave_scope(index)
673
+
674
+ @withheld[index] = withheld?(index, branch)
675
+
676
+ statics = payload_statics(index, branch)
677
+ parked = statics ? " statics: #{statics.inspect}," : ""
678
+
679
+ @src << "; #{SLOT_BUFFER}#{index} = { branch: #{branch},#{parked} slots: (#{SCOPE_BUFFER}#{index} = ::Hash.new) };"
680
+
681
+ @scopes.push(index)
682
+ end
683
+
684
+ #: (Integer, Integer) -> String?
685
+ def payload_statics(index, branch)
686
+ return nil unless server_mode? || withheld?(index, branch)
687
+
688
+ branch_statics["#{index}:#{branch}"]
689
+ end
690
+
691
+ #: () -> bool
692
+ def server_mode?
693
+ @input.is_a?(String) && Visitor.directive_mode(@input) == :server
694
+ end
695
+
696
+ #: (Integer, Integer) -> bool
697
+ def withheld?(index, branch)
698
+ branch.zero? && @slot_visitor.deferred_entries.key?(index)
699
+ end
700
+
701
+ #: (Integer) -> String?
702
+ def item_statics(index)
703
+ return nil unless server_mode? || @scopes.any? { |scope| @withheld[scope] }
704
+
705
+ branch_statics["#{index}:#{Markers::ITEM_STATICS}"]
706
+ end
707
+
708
+ #: () -> Hash[String, String]
709
+ def branch_statics
710
+ @branch_statics ||= begin
711
+ visitor = Visitor.new(fatal: false)
712
+
713
+ Herb::Engine.new(@input, visitors: [visitor], filename: @filename)
714
+
715
+ visitor.statics || {}
716
+ end
717
+ end
718
+
719
+ #: (Integer) -> void
720
+ def scope_close_conditional(index)
721
+ leave_scope(index)
722
+
723
+ @withheld.delete(index)
724
+
725
+ @src << "; #{current_scope}[#{index}] = (#{SLOT_BUFFER}#{index} || { branch: nil });"
726
+ end
727
+
728
+ #: (Integer) -> void
729
+ def scope_open_collection(index)
730
+ @src << "; #{ITEMS_BUFFER}#{index} = ::Hash.new;"
731
+ end
732
+
733
+ #: (Integer, ?String?) -> void
734
+ def scope_item_begin(index, key = nil)
735
+ @src << "; #{KEY_BUFFER}#{index} = (#{key}).to_s" if key
736
+ @src << "; #{SCOPE_BUFFER}#{index} = ::Hash.new;"
737
+
738
+ @scopes.push(index)
739
+ end
740
+
741
+ #: (Integer) -> void
742
+ def scope_item_end(index)
743
+ leave_scope(index)
744
+
745
+ return unless keyed?(index)
746
+
747
+ @src << item_seeds(index)
748
+ @src << "; #{ITEMS_BUFFER}#{index}[#{KEY_BUFFER}#{index}.to_s] = #{SCOPE_BUFFER}#{index};"
749
+ end
750
+
751
+ #: (Integer) -> bool
752
+ def keyed?(index)
753
+ !@slot_visitor.slots[index]&.key_expression.nil?
754
+ end
755
+
756
+ #: (Integer) -> String
757
+ def item_seeds(index)
758
+ names = @slot_visitor.seeded_item_states[index]
759
+
760
+ return "" if names.nil? || names.empty?
761
+
762
+ pairs = names.map { |name| "#{name.inspect} => #{name}" }.join(", ")
763
+
764
+ "; #{SCOPE_BUFFER}#{index}[:seeds] = #{Markers.seeds_expression(pairs)};"
765
+ end
766
+
767
+ #: (Integer) -> void
768
+ def scope_close_collection(index)
769
+ statics = item_statics(index)
770
+ parked = statics ? ", statics: #{statics.inspect}" : ""
771
+
772
+ @src << "; #{current_scope}[#{index}] = { items: #{ITEMS_BUFFER}#{index}, order: #{ITEMS_BUFFER}#{index}.keys#{parked} };"
773
+ end
774
+
775
+ #: (Integer, String) -> void
776
+ def scope_open_keyed(index, key)
777
+ @src << "; #{KEY_BUFFER}#{index} = (#{key}).to_s"
778
+ @src << "; #{SCOPE_BUFFER}#{index} = ::Hash.new;"
779
+
780
+ @scopes.push(index)
781
+ end
782
+
783
+ #: (Integer) -> void
784
+ def scope_close_keyed(index)
785
+ leave_scope(index)
786
+
787
+ @src << "; #{current_scope}[#{index}] = { key: #{KEY_BUFFER}#{index}, slots: #{SCOPE_BUFFER}#{index} };"
788
+ end
789
+
790
+ #: (Integer) -> void
791
+ def leave_scope(index)
792
+ @scopes.pop if @scopes.last == index
793
+ end
794
+
795
+ #: (String, Symbol?, bool) -> String
796
+ def dynamic_value(code, context, escaped)
797
+ escapefunc = context_escape_function(context)
798
+
799
+ return "#{escapefunc}((#{code}))" if escapefunc
800
+ return "#{@escapefunc}((#{code}))" if escaped
801
+
802
+ "(#{code}).to_s"
803
+ end
804
+
805
+ #: (Integer, String) -> String
806
+ def assignment(index, value)
807
+ if interpolated?(index)
808
+ "(#{current_scope}[#{index}] ||= []) << #{value}"
809
+ else
810
+ "#{current_scope}[#{index}] = #{value}"
811
+ end
812
+ end
813
+
814
+ #: (Integer) -> bool
815
+ def interpolated?(index)
816
+ @slot_visitor.slots[index]&.interpolated? || false
817
+ end
818
+
819
+ #: (String) -> void
820
+ def add_block_dynamic(value)
821
+ @src << "; " << @bufvar << " << (" << value << ");"
822
+ end
823
+
824
+ #: () -> void
825
+ def scope_part_open
826
+ open_block
827
+ end
828
+
829
+ #: (Integer) -> void
830
+ def scope_part_close(index)
831
+ buffer = @bufvar
832
+
833
+ close_block
834
+
835
+ @src << "; " << assignment(index, buffer) << ";"
836
+ end
837
+
838
+ #: () -> void
839
+ def open_block
840
+ @block_depth += 1
841
+ @bufvar = "#{BLOCK_BUFFER}#{@block_depth}"
842
+
843
+ @src << "; " << @bufvar << " = ::String.new;"
844
+ end
845
+
846
+ #: () -> void
847
+ def close_block
848
+ @block_depth -= 1
849
+ @bufvar = @block_depth.zero? ? BUFFER : "#{BLOCK_BUFFER}#{@block_depth}"
850
+ end
851
+ end
852
+ end
853
+ end
854
+ end