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
@@ -1,15 +1,14 @@
1
1
  # frozen_string_literal: false
2
2
 
3
+ require_relative "../html/util"
4
+
3
5
  module Herb
4
6
  class Engine
5
7
  class Compiler < ::Herb::Visitor
6
- EXPRESSION_TOKEN_TYPES = [:expr, :expr_escaped, :expr_block, :expr_block_escaped].freeze
7
-
8
- TRAILING_WHITESPACE = /[ \t]+\z/
9
- TRAILING_INDENTATION = /\n[ \t]+\z/
10
- TRAILING_INDENTATION_CAPTURE = /\n([ \t]+)\z/
11
- WHITESPACE_ONLY = /\A[ \t]+\z/
12
- WHITESPACE_ONLY_CAPTURE = /\A([ \t]+)\z/
8
+ PADDING_NEWLINES = Array.new(17) { |count| ("\n" * count).freeze }.freeze #: Array[String]
9
+ EXPRESSION_TOKEN_TYPES = [:expr, :expr_escaped, :expr_block, :expr_block_escaped].freeze #: Array[Symbol]
10
+ HORIZONTAL_SPACE = [" ", "\t"].freeze #: Array[String]
11
+ RAW_TEXT_ELEMENTS = ["script", "style"].freeze #: Array[String]
13
12
 
14
13
  attr_reader :tokens
15
14
 
@@ -17,20 +16,36 @@ module Herb
17
16
  super()
18
17
 
19
18
  @engine = engine
19
+ @source_lines = options[:source]&.lines
20
20
  @escape = options.fetch(:escape) { options.fetch(:escape_html, false) }
21
+ @trim = options[:trim] != false
22
+ @literal_prefix = options[:literal_prefix] || "<%"
23
+ @literal_postfix = options[:literal_postfix] || "%>"
21
24
  @tokens = [] #: Array[untyped]
25
+ @padding_before = nil #: Hash[Integer, Integer]?
22
26
  @element_stack = [] #: Array[String]
23
27
  @context_stack = [:html_content]
24
28
  @trim_next_whitespace = false
25
29
  @last_trim_consumed_newline = false
30
+ @pending_trim_newline_index = nil #: Integer?
31
+ @pending_trim_owns_next_whitespace = false
32
+ @pending_span_extra_index = nil #: Integer?
26
33
  @pending_leading_whitespace = nil
27
34
  @pending_leading_whitespace_insert_index = 0
28
35
  @current_element_source = nil
29
36
  end
30
37
 
31
- def generate_output
32
- optimized_tokens = optimize_tokens(@tokens)
38
+ def optimized_tokens
39
+ @optimized_tokens ||= optimize_tokens(@tokens)
40
+ end
41
+
42
+ def static_template_text
43
+ return unless optimized_tokens.all? { |token| token[0] == :text }
33
44
 
45
+ optimized_tokens.map { |token| token[1] }.join
46
+ end
47
+
48
+ def generate_output
34
49
  optimized_tokens.each do |type, value, context, escaped|
35
50
  case type
36
51
  when :text
@@ -49,26 +64,30 @@ module Herb
49
64
  @engine.send(:add_expression_block, indicator_for(type), value)
50
65
  when :expr_block_end
51
66
  @engine.send(:add_expression_block_end, value, escaped: escaped)
67
+ when :chain
68
+ @engine.send(:add_expression_result, value)
52
69
  end
53
70
  end
54
71
  end
55
72
 
56
73
  def visit_document_node(node)
57
74
  visit_all(node.children)
75
+
76
+ restore_pending_leading_whitespace! if @trim_next_whitespace
77
+
78
+ settle_pending_trim_newline!(false)
58
79
  end
59
80
 
60
81
  def visit_html_element_node(node)
61
- with_element_context(node) do
82
+ with_element_context(node) do |tag_name|
62
83
  visit(node.open_tag)
63
84
  visit_all(node.body)
64
85
 
65
- tag_name = node.tag_name&.value&.downcase
66
-
67
86
  if node.open_tag.is_a?(Herb::AST::ERBOpenTagNode) && tag_name && node.close_tag
68
87
  if node.close_tag.is_a?(Herb::AST::ERBEndNode)
69
- remove_trailing_whitespace_from_last_token! if left_trim?(node.close_tag)
88
+ remove_trailing_whitespace_from_last_token! if @trim && left_trim?(node.close_tag)
70
89
  add_text("</#{tag_name}>")
71
- @trim_next_whitespace = true
90
+ @trim_next_whitespace = true if @trim
72
91
  else
73
92
  add_text("</#{tag_name}>")
74
93
  end
@@ -96,7 +115,7 @@ module Herb
96
115
  end
97
116
 
98
117
  def visit_html_attribute_node(node)
99
- add_whitespace(" ")
118
+ add_text(" ") unless preceded_by_whitespace?
100
119
 
101
120
  visit(node.name)
102
121
 
@@ -157,13 +176,6 @@ module Herb
157
176
  end
158
177
 
159
178
  def visit_html_close_tag_node(node)
160
- tag_name = node.tag_name&.value&.downcase
161
-
162
- if @engine.content_for_head && tag_name == "head"
163
- escaped_html = @engine.content_for_head.gsub("'", "\\\\'")
164
- @tokens << [:expr, "'#{escaped_html}'.html_safe", current_context]
165
- end
166
-
167
179
  add_text(node.tag_opening&.value)
168
180
  add_text(node.tag_name&.value)
169
181
  add_text(node.tag_closing&.value)
@@ -182,7 +194,7 @@ module Herb
182
194
  end
183
195
 
184
196
  def visit_whitespace_node(node)
185
- add_whitespace(node.value.value)
197
+ add_text(node.value.value)
186
198
  end
187
199
 
188
200
  def visit_html_comment_node(node)
@@ -203,6 +215,13 @@ module Herb
203
215
  add_text(node.tag_closing.value)
204
216
  end
205
217
 
218
+ def visit_xml_processing_instruction_node(node)
219
+ add_text(node.tag_opening.value)
220
+ add_text(node.target.value)
221
+ visit_all(node.children)
222
+ add_text(node.tag_closing.value)
223
+ end
224
+
206
225
  def visit_cdata_node(node)
207
226
  add_text(node.tag_opening.value)
208
227
  visit_all(node.children)
@@ -215,9 +234,26 @@ module Herb
215
234
  process_erb_tag(node)
216
235
  end
217
236
 
237
+ def visit_erb_comment_node(node)
238
+ process_erb_tag(node)
239
+ end
240
+
218
241
  def visit_erb_control_node(node, &)
219
242
  if node.content
220
- apply_trim(node, node.content.value.strip)
243
+ if node.tag_opening && erb_escaped?(node.tag_opening.value)
244
+ add_escaped_erb_tag(node)
245
+ elsif continues_into_next_node?(node)
246
+ @continued_head = node
247
+ else
248
+ head = @continued_head
249
+ @continued_head = nil
250
+
251
+ code_index = @tokens.length
252
+ raw = head ? head.content.value + node.content.value : node.content.value
253
+
254
+ apply_trim(head || node, raw.strip)
255
+ keep_line_count(node, at: code_index, raw: raw)
256
+ end
221
257
  end
222
258
 
223
259
  yield if block_given?
@@ -246,7 +282,7 @@ module Herb
246
282
  end
247
283
 
248
284
  def visit_erb_case_node(node)
249
- visit_erb_control_with_parts(node, :conditions, :else_clause, :end_node)
285
+ visit_erb_control_with_parts(node, *case_parts(node))
250
286
  end
251
287
 
252
288
  def visit_erb_when_node(node)
@@ -282,7 +318,7 @@ module Herb
282
318
  end
283
319
 
284
320
  def visit_erb_case_match_node(node)
285
- visit_erb_control_with_parts(node, :conditions, :else_clause, :end_node)
321
+ visit_erb_control_with_parts(node, *case_parts(node))
286
322
  end
287
323
 
288
324
  def visit_erb_in_node(node)
@@ -296,11 +332,12 @@ module Herb
296
332
  def visit_erb_block_node(node)
297
333
  opening = node.tag_opening.value
298
334
 
299
- check_for_escaped_erb_tag!(opening)
335
+ return add_escaped_erb_block(node) if erb_escaped?(opening)
300
336
 
301
337
  if opening.include?("=")
302
338
  should_escape = should_escape_output?(opening)
303
- code = node.content.value.strip
339
+ code = ::Herb::Engine::Helpers.strip_trailing_comment(node.content.value.strip)
340
+ code_index = @tokens.length
304
341
 
305
342
  @tokens << if should_escape
306
343
  [:expr_block_escaped, code, current_context]
@@ -308,6 +345,8 @@ module Herb
308
345
  [:expr_block, code, current_context]
309
346
  end
310
347
 
348
+ keep_line_count(node, at: code_index)
349
+
311
350
  @last_trim_consumed_newline = false
312
351
  @trim_next_whitespace = true if right_trim?(node)
313
352
 
@@ -324,12 +363,22 @@ module Herb
324
363
  end
325
364
  end
326
365
 
366
+ def visit_erb_iteration_block_node(node)
367
+ visit_erb_block_node(node)
368
+ end
369
+
370
+ def visit_erb_render_node(node)
371
+ return process_erb_tag(node) unless node.end_node
372
+
373
+ visit_erb_block_node(node)
374
+ end
375
+
327
376
  def visit_erb_block_end_node(node, escaped: false)
328
- remove_trailing_whitespace_from_last_token! if left_trim?(node)
377
+ remove_trailing_whitespace_from_last_token! if @trim && left_trim?(node)
329
378
 
330
- code = node.content.value.strip
379
+ code = ::Herb::Engine::Helpers.strip_trailing_comment(node.content.value.strip)
331
380
 
332
- if at_line_start?
381
+ if @trim && at_line_start?
333
382
  leading_space = extract_and_remove_leading_space!
334
383
  right_space = " \n"
335
384
 
@@ -340,6 +389,12 @@ module Herb
340
389
  end
341
390
  end
342
391
 
392
+ def case_parts(node)
393
+ parts = [:conditions, :else_clause, :end_node]
394
+
395
+ erb_escaped?(node.tag_opening.value) ? [:children, *parts] : parts
396
+ end
397
+
343
398
  def visit_erb_control_with_parts(node, *parts)
344
399
  visit_erb_control_node(node) do
345
400
  parts.each do |part|
@@ -358,13 +413,25 @@ module Herb
358
413
 
359
414
  private
360
415
 
361
- def check_for_escaped_erb_tag!(opening)
362
- return unless opening.start_with?("<%%")
416
+ def add_escaped_erb_tag(node)
417
+ opening = node.tag_opening.value.sub("<%%") { @literal_prefix }
418
+ closing = (node.tag_closing&.value || "").sub(/%>\z/) { @literal_postfix }
419
+
420
+ add_text("#{opening}#{node.content.value}#{closing}")
421
+ end
363
422
 
364
- raise Herb::Engine::GeneratorTemplateError,
365
- "This file appears to be a generator template (a template used to generate ERB files) " \
366
- "rather than a standard ERB template. It contains escaped ERB tags like <%%= %> which " \
367
- "produce literal ERB output in the generated file."
423
+ def add_escaped_erb_block(node)
424
+ add_escaped_erb_tag(node)
425
+ visit_all(node.body)
426
+
427
+ end_node = node.end_node
428
+ return unless end_node
429
+
430
+ if erb_escaped?(end_node.tag_opening.value)
431
+ add_escaped_erb_tag(end_node)
432
+ else
433
+ visit(end_node)
434
+ end
368
435
  end
369
436
 
370
437
  def current_context
@@ -379,7 +446,7 @@ module Herb
379
446
  @context_stack.pop
380
447
  end
381
448
 
382
- #: (untyped node) { () -> untyped } -> untyped
449
+ #: (untyped node) { (String?) -> untyped } -> untyped
383
450
  def with_element_context(node)
384
451
  tag_name = node.tag_name&.value&.downcase
385
452
  previous_element_source = @current_element_source
@@ -393,9 +460,9 @@ module Herb
393
460
  push_context(:style_content)
394
461
  end
395
462
 
396
- yield
463
+ yield(tag_name)
397
464
 
398
- pop_context if ["script", "style"].include?(tag_name)
465
+ pop_context if RAW_TEXT_ELEMENTS.include?(tag_name)
399
466
 
400
467
  @element_stack.pop if tag_name
401
468
  @current_element_source = previous_element_source
@@ -404,28 +471,67 @@ module Herb
404
471
  def process_erb_tag(node, skip_comment_check: false)
405
472
  opening = node.tag_opening.value
406
473
 
407
- check_for_escaped_erb_tag!(opening)
474
+ return add_escaped_erb_tag(node) if erb_escaped?(opening)
475
+
476
+ if !skip_comment_check && erb_omitted?(opening)
477
+ unless @trim
478
+ keep_span_line_count(node)
479
+
480
+ return
481
+ end
408
482
 
409
- if !skip_comment_check && erb_comment?(opening)
410
483
  follows_newline = leading_space_follows_newline?
411
484
  remove_trailing_whitespace_from_last_token! if left_trim?(node)
485
+ swallows_newline = at_line_start?
412
486
 
413
- if at_line_start?
487
+ if swallows_newline
414
488
  leading_space = extract_and_remove_leading_space!
415
489
  @trim_next_whitespace = true
416
490
  save_pending_leading_whitespace!(leading_space) if !leading_space.empty? && follows_newline
417
491
  end
492
+
493
+ keep_span_line_count(node, extra: swallows_newline ? 1 : 0)
494
+ @pending_span_extra_index = @tokens.length if swallows_newline
495
+
418
496
  return
419
497
  end
420
- return if erb_graphql?(opening)
421
498
 
422
- code = node.content.value.strip
499
+ code = ::Herb::Engine::Helpers.strip_trailing_comment(node.content.value.strip)
500
+
501
+ code_index = @tokens.length
423
502
 
424
503
  if erb_output?(opening)
425
504
  process_erb_output(node, opening, code)
426
505
  else
427
506
  apply_trim(node, code)
428
507
  end
508
+
509
+ absorbed = erb_output?(opening) && ::Herb::Engine::Helpers.ends_on_heredoc_terminator?(code) ? 1 : 0
510
+
511
+ keep_line_count(node, at: code_index, absorbed: absorbed)
512
+ end
513
+
514
+ #: (untyped, ?extra: Integer) -> void
515
+ def keep_span_line_count(node, extra: 0)
516
+ lines = node.content.value.count("\n") + extra
517
+
518
+ return unless lines.positive?
519
+
520
+ @padding_before ||= Hash.new(0)
521
+ @padding_before[@tokens.length] += lines
522
+ end
523
+
524
+ def keep_line_count(node, extra: 0, at: nil, absorbed: 0, raw: nil)
525
+ raw ||= node.content.value
526
+
527
+ leading = raw[0, raw.length - raw.lstrip.length].to_s.count("\n")
528
+ trailing = raw.count("\n") - raw.strip.count("\n") - leading + extra - absorbed
529
+
530
+ block_comment = raw.include?("=begin") || raw.include?("=end")
531
+
532
+ @padding_before ||= Hash.new(0)
533
+ @padding_before[at] += leading if at && leading.positive? && !block_comment
534
+ @padding_before[@tokens.length] += trailing if trailing.positive?
429
535
  end
430
536
 
431
537
  def add_text(text)
@@ -436,9 +542,14 @@ module Herb
436
542
  text = text.sub(/\A[ \t]*\r?\n/, "")
437
543
  @trim_next_whitespace = false
438
544
 
545
+ settle_pending_trim_newline!(@last_trim_consumed_newline)
546
+ settle_pending_span_extra!(@last_trim_consumed_newline)
439
547
  restore_pending_leading_whitespace! unless @last_trim_consumed_newline
440
548
  else
441
549
  @last_trim_consumed_newline = false
550
+
551
+ settle_pending_trim_newline!(false)
552
+ settle_pending_span_extra!(false)
442
553
  end
443
554
 
444
555
  @pending_leading_whitespace = nil
@@ -448,10 +559,6 @@ module Herb
448
559
  @tokens << [:text, text, current_context]
449
560
  end
450
561
 
451
- def add_whitespace(whitespace)
452
- @tokens << [:whitespace, whitespace, current_context]
453
- end
454
-
455
562
  def add_code(code)
456
563
  @tokens << [:code, code, current_context]
457
564
  end
@@ -468,82 +575,98 @@ module Herb
468
575
 
469
576
  def optimize_tokens(tokens)
470
577
  return tokens if tokens.empty?
471
-
472
- compacted = compact_whitespace_tokens(tokens)
578
+ return optimize_tokens_with_padding(tokens) if @padding_before
473
579
 
474
580
  optimized = [] #: Array[untyped]
475
- current_text = ""
581
+ current_text = nil #: String?
476
582
  current_context = nil
477
583
 
478
- compacted.each do |type, value, context, escaped|
584
+ tokens.each do |token|
585
+ type = token[0]
586
+
479
587
  if type == :text
480
- current_text += value
481
- current_context ||= context
588
+ value = token[1]
589
+
590
+ if current_text
591
+ current_text << value
592
+ current_context ||= token[2]
593
+ else
594
+ current_text = value.dup
595
+ current_context = token[2]
596
+ end
482
597
  else
483
- unless current_text.empty?
598
+ if current_text
484
599
  optimized << [:text, current_text, current_context]
485
600
 
486
- current_text = ""
601
+ current_text = nil
487
602
  current_context = nil
488
603
  end
489
604
 
490
- optimized << [type, value, context, escaped]
605
+ optimized << [type, token[1], token[2], token[3]]
491
606
  end
492
607
  end
493
608
 
494
- optimized << [:text, current_text, current_context] unless current_text.empty?
609
+ optimized << [:text, current_text, current_context] if current_text
495
610
 
496
611
  optimized
497
612
  end
498
613
 
499
- def compact_whitespace_tokens(tokens)
500
- return tokens if tokens.empty?
501
-
502
- tokens.map.with_index { |token, index|
503
- next token unless token[0] == :whitespace
504
-
505
- next nil if adjacent_whitespace?(tokens, index)
506
- next nil if whitespace_before_code_sequence?(tokens, index)
507
-
508
- [:text, token[1], token[2]]
509
- }.compact
614
+ def padding_newlines(count)
615
+ PADDING_NEWLINES[count] || ("\n" * count)
510
616
  end
511
617
 
512
- def adjacent_whitespace?(tokens, index)
513
- prev_token = index.positive? ? tokens[index - 1] : nil
514
- next_token = index < tokens.length - 1 ? tokens[index + 1] : nil
515
-
516
- trailing_whitespace?(prev_token) || leading_whitespace?(next_token)
517
- end
618
+ def optimize_tokens_with_padding(tokens)
619
+ optimized = [] #: Array[untyped]
620
+ current_text = nil #: String?
621
+ current_context = nil
622
+ pending_padding = 0
518
623
 
519
- def trailing_whitespace?(token)
520
- return false unless token
624
+ tokens.each_with_index do |token, index|
625
+ pending_padding += @padding_before[index]
521
626
 
522
- token[0] == :whitespace || (token[0] == :text && token[1] =~ /\s\z/)
523
- end
627
+ if token[0] == :text
628
+ if pending_padding.positive?
629
+ if current_text
630
+ optimized << [:text, current_text, current_context]
631
+ current_text = nil
632
+ current_context = nil
633
+ end
524
634
 
525
- def leading_whitespace?(token)
526
- token && token[0] == :text && token[1] =~ /\A\s/
527
- end
635
+ optimized << [:code, padding_newlines(pending_padding), nil]
636
+ pending_padding = 0
637
+ end
528
638
 
529
- def whitespace_before_code_sequence?(tokens, current_index)
530
- previous_token = tokens[current_index - 1] if current_index.positive?
639
+ if current_text
640
+ current_text << token[1]
641
+ current_context ||= token[2]
642
+ else
643
+ current_text = token[1].dup
644
+ current_context = token[2]
645
+ end
531
646
 
532
- return false unless previous_token && previous_token[0] == :code
647
+ next
648
+ end
533
649
 
534
- token_before_code = find_token_before_code_sequence(tokens, current_index)
650
+ if current_text
651
+ optimized << [:text, current_text, current_context]
652
+ current_text = nil
653
+ current_context = nil
654
+ end
535
655
 
536
- return false unless token_before_code
656
+ if pending_padding.positive?
657
+ optimized << [:code, padding_newlines(pending_padding), nil]
658
+ pending_padding = 0
659
+ end
537
660
 
538
- trailing_whitespace?(token_before_code)
539
- end
661
+ optimized << [token[0], token[1], token[2], token[3]]
662
+ end
540
663
 
541
- def find_token_before_code_sequence(tokens, whitespace_index)
542
- search_index = whitespace_index - 1
664
+ optimized << [:text, current_text, current_context] if current_text
543
665
 
544
- search_index -= 1 while search_index >= 0 && tokens[search_index][0] == :code
666
+ pending_padding += @padding_before[tokens.length]
667
+ optimized << [:code, padding_newlines(pending_padding), nil] if pending_padding.positive?
545
668
 
546
- search_index >= 0 ? tokens[search_index] : nil
669
+ optimized
547
670
  end
548
671
 
549
672
  def process_erb_output(node, opening, code)
@@ -554,6 +677,8 @@ module Herb
554
677
  @last_trim_consumed_newline = false
555
678
  end
556
679
 
680
+ settle_pending_trim_newline!(false)
681
+
557
682
  should_escape = should_escape_output?(opening)
558
683
  add_expression_with_escaping(code, should_escape)
559
684
  @trim_next_whitespace = true if right_trim?(node)
@@ -582,6 +707,36 @@ module Herb
582
707
  end
583
708
  end
584
709
 
710
+ #: (String) -> Integer
711
+ def trailing_space_length(text)
712
+ count = 0
713
+ count += 1 while count < text.length && HORIZONTAL_SPACE.include?(text[text.length - 1 - count])
714
+
715
+ count
716
+ end
717
+
718
+ #: (String) -> String
719
+ def trailing_spaces(text)
720
+ text[text.length - trailing_space_length(text), text.length].to_s
721
+ end
722
+
723
+ #: (String) -> void
724
+ def remove_trailing_spaces!(text)
725
+ text.replace(text[0, text.length - trailing_space_length(text)].to_s)
726
+ end
727
+
728
+ #: (String) -> bool
729
+ def whitespace_only?(text)
730
+ !text.empty? && trailing_space_length(text) == text.length
731
+ end
732
+
733
+ #: (String) -> bool
734
+ def trailing_indentation?(text)
735
+ spaces = trailing_space_length(text)
736
+
737
+ spaces.positive? && text[text.length - spaces - 1] == "\n"
738
+ end
739
+
585
740
  def at_line_start?
586
741
  return true if @tokens.empty?
587
742
 
@@ -589,7 +744,7 @@ module Herb
589
744
  last_value = @tokens.last[1]
590
745
 
591
746
  if last_type == :text
592
- last_value.empty? || last_value.end_with?("\n") || (last_value =~ WHITESPACE_ONLY && preceding_token_ends_with_newline?) || last_value =~ TRAILING_INDENTATION
747
+ last_value.empty? || last_value.end_with?("\n") || (whitespace_only?(last_value) && preceding_token_ends_with_newline?) || trailing_indentation?(last_value)
593
748
  elsif EXPRESSION_TOKEN_TYPES.include?(last_type)
594
749
  @last_trim_consumed_newline
595
750
  else
@@ -609,13 +764,30 @@ module Herb
609
764
  end
610
765
 
611
766
  def left_trim?(node)
612
- node.tag_opening.value == "<%-"
767
+ node.tag_opening&.value == "<%-"
613
768
  end
614
769
 
615
770
  def right_trim?(node)
616
771
  node.tag_closing&.value == "-%>"
617
772
  end
618
773
 
774
+ def preceded_by_whitespace?
775
+ index = @tokens.length - 1
776
+ index -= 1 while index >= 0 && emits_nothing?(@tokens[index])
777
+
778
+ return false if index.negative?
779
+
780
+ token = @tokens[index]
781
+
782
+ return false unless token[0] == :text
783
+
784
+ token[1].match?(/\s\z/)
785
+ end
786
+
787
+ def emits_nothing?(token)
788
+ token[0] == :code || (token[0] == :text && token[1].empty?)
789
+ end
790
+
619
791
  def last_text_token
620
792
  return unless @tokens.last && @tokens.last[0] == :text
621
793
 
@@ -628,7 +800,7 @@ module Herb
628
800
 
629
801
  text = token[1]
630
802
 
631
- return Regexp.last_match(1) if text =~ TRAILING_INDENTATION_CAPTURE || text =~ WHITESPACE_ONLY_CAPTURE
803
+ return trailing_spaces(text) if trailing_indentation?(text) || whitespace_only?(text)
632
804
 
633
805
  ""
634
806
  end
@@ -639,10 +811,17 @@ module Herb
639
811
 
640
812
  text = token[1]
641
813
 
642
- return true if text.match?(TRAILING_INDENTATION)
643
- return true if @last_trim_consumed_newline && text.match?(WHITESPACE_ONLY)
814
+ return true if trailing_indentation?(text)
644
815
 
645
- false
816
+ whitespace_only?(text) && (preceding_text_ends_with_newline? || @last_trim_consumed_newline)
817
+ end
818
+
819
+ def preceding_text_ends_with_newline?
820
+ return true unless @tokens.length >= 2
821
+
822
+ preceding = @tokens[-2]
823
+
824
+ preceding[0] == :text && preceding[1].end_with?("\n")
646
825
  end
647
826
 
648
827
  def extract_and_remove_leading_space!
@@ -651,9 +830,9 @@ module Herb
651
830
 
652
831
  text = @tokens.last[1]
653
832
 
654
- if text =~ TRAILING_INDENTATION
655
- text.sub!(TRAILING_WHITESPACE, "")
656
- elsif text =~ WHITESPACE_ONLY
833
+ if trailing_indentation?(text)
834
+ remove_trailing_spaces!(text)
835
+ elsif whitespace_only?(text)
657
836
  text.replace("")
658
837
  end
659
838
 
@@ -663,23 +842,77 @@ module Herb
663
842
  end
664
843
 
665
844
  def apply_trim(node, code)
845
+ return add_code(code) unless @trim
846
+
666
847
  follows_newline = leading_space_follows_newline?
667
848
  removed_whitespace = left_trim?(node) ? remove_trailing_whitespace_from_last_token! : ""
668
849
 
669
850
  if at_line_start?
670
851
  leading_space = extract_and_remove_leading_space!
671
852
  effective_leading_space = leading_space.empty? ? removed_whitespace : leading_space
672
- right_space = Herb::Engine.heredoc?(code) ? "\n" : " \n"
853
+ right_space = if Herb::Engine::Helpers.heredoc?(code)
854
+ "\n"
855
+ elsif without_source?(node)
856
+ " "
857
+ else
858
+ " \n"
859
+ end
673
860
 
674
861
  @pending_leading_whitespace_insert_index = @tokens.length
675
862
  @pending_leading_whitespace = effective_leading_space if !effective_leading_space.empty? && follows_newline
676
863
  @tokens << [:code, "#{effective_leading_space}#{code}#{right_space}", current_context]
677
864
  @trim_next_whitespace = true
865
+
866
+ if right_space.end_with?(" \n")
867
+ @pending_trim_newline_index = @tokens.length - 1
868
+ @pending_trim_owns_next_whitespace = true
869
+ end
678
870
  else
679
871
  @tokens << [:code, code, current_context]
680
872
  end
681
873
  end
682
874
 
875
+ def continues_into_next_node?(node)
876
+ node.tag_closing.nil? && !node.content.nil?
877
+ end
878
+
879
+ #: (untyped) -> bool
880
+ def without_source?(node)
881
+ position = node.tag_closing&.location&.end || node.location&.end
882
+
883
+ !position.nil? && !position.line.positive?
884
+ end
885
+
886
+ #: (bool) -> void
887
+ def settle_pending_span_extra!(keep)
888
+ index = @pending_span_extra_index
889
+
890
+ return unless index
891
+
892
+ @pending_span_extra_index = nil
893
+
894
+ return if keep
895
+
896
+ @padding_before[index] -= 1 if @padding_before&.key?(index)
897
+ end
898
+
899
+ #: (bool) -> void
900
+ def settle_pending_trim_newline!(keep)
901
+ index = @pending_trim_newline_index
902
+
903
+ return unless index
904
+
905
+ owned = @pending_trim_owns_next_whitespace
906
+
907
+ @pending_trim_newline_index = nil
908
+ @pending_trim_owns_next_whitespace = false
909
+
910
+ return if keep
911
+
912
+ @tokens[index][1] = @tokens[index][1].chomp
913
+ @trim_next_whitespace = false if owned
914
+ end
915
+
683
916
  def save_pending_leading_whitespace!(whitespace)
684
917
  @pending_leading_whitespace = whitespace
685
918
  @pending_leading_whitespace_insert_index = @tokens.length
@@ -689,6 +922,11 @@ module Herb
689
922
  return unless @pending_leading_whitespace
690
923
 
691
924
  @tokens.insert(@pending_leading_whitespace_insert_index, [:text, @pending_leading_whitespace, current_context])
925
+
926
+ return unless @pending_trim_newline_index
927
+ return if @pending_trim_newline_index < @pending_leading_whitespace_insert_index
928
+
929
+ @pending_trim_newline_index += 1
692
930
  end
693
931
 
694
932
  def remove_trailing_whitespace_from_last_token!
@@ -696,12 +934,12 @@ module Herb
696
934
  return "" unless token
697
935
 
698
936
  text = token[1]
699
- removed = text[TRAILING_WHITESPACE] || ""
937
+ removed = trailing_spaces(text)
700
938
 
701
- if text =~ TRAILING_INDENTATION
702
- text.sub!(TRAILING_WHITESPACE, "")
939
+ if trailing_indentation?(text)
940
+ remove_trailing_spaces!(text)
703
941
  token[1] = text
704
- elsif text =~ WHITESPACE_ONLY
942
+ elsif whitespace_only?(text)
705
943
  text.replace("")
706
944
  token[1] = text
707
945
  end