herb 0.10.4-x86-linux-gnu → 0.11.1-x86-linux-gnu

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 (793) 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 +1243 -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 +859 -374
  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/3.2/herb.so +0 -0
  297. data/lib/herb/3.3/herb.so +0 -0
  298. data/lib/herb/3.4/herb.so +0 -0
  299. data/lib/herb/4.0/herb.so +0 -0
  300. data/lib/herb/action_view/helper_registry.rb +1358 -62
  301. data/lib/herb/analysis/partial_declaration.rb +140 -0
  302. data/lib/herb/analysis/partial_index.rb +189 -0
  303. data/lib/herb/analysis/partial_resolution.rb +161 -0
  304. data/lib/herb/analysis/partial_resolver.rb +144 -0
  305. data/lib/herb/analysis/project_index.rb +152 -0
  306. data/lib/herb/{action_view → analysis}/render_analyzer.rb +287 -77
  307. data/lib/herb/analysis/render_graph/ancestor_chain.rb +27 -0
  308. data/lib/herb/analysis/render_graph/builder.rb +376 -0
  309. data/lib/herb/analysis/render_graph/call_frame.rb +9 -0
  310. data/lib/herb/analysis/render_graph/call_site_location.rb +23 -0
  311. data/lib/herb/analysis/render_graph/inferred_signature.rb +21 -0
  312. data/lib/herb/analysis/render_graph/partial_call_site.rb +40 -0
  313. data/lib/herb/analysis/render_graph/partial_context.rb +46 -0
  314. data/lib/herb/analysis/render_graph/template_roots.rb +31 -0
  315. data/lib/herb/analysis/render_graph.rb +285 -0
  316. data/lib/herb/analysis/ruby_locals_index/local.rb +25 -0
  317. data/lib/herb/analysis/ruby_locals_index/named_reference.rb +22 -0
  318. data/lib/herb/analysis/ruby_locals_index/offset_table.rb +44 -0
  319. data/lib/herb/analysis/ruby_locals_index/reference_collector.rb +80 -0
  320. data/lib/herb/analysis/ruby_locals_index/state_locals.rb +49 -0
  321. data/lib/herb/analysis/ruby_locals_index.rb +165 -0
  322. data/lib/herb/analysis/ruby_reference.rb +67 -0
  323. data/lib/herb/analysis/template_dependencies/dependency_collector.rb +179 -0
  324. data/lib/herb/analysis/template_dependencies/node_dependency_collector.rb +309 -0
  325. data/lib/herb/analysis/template_dependencies.rb +562 -0
  326. data/lib/herb/ast/erb_render_node.rb +26 -94
  327. data/lib/herb/ast/helpers.rb +90 -10
  328. data/lib/herb/ast/herb_directive_node.rb +18 -0
  329. data/lib/herb/ast/node.rb +32 -2
  330. data/lib/herb/ast/nodes.rb +1368 -105
  331. data/lib/herb/backend.rb +73 -0
  332. data/lib/herb/bootstrap.rb +8 -8
  333. data/lib/herb/cli.rb +550 -32
  334. data/lib/herb/colors.rb +14 -0
  335. data/lib/herb/configuration.rb +71 -35
  336. data/lib/herb/defaults.yml +2 -1
  337. data/lib/herb/dev/assets.rb +57 -0
  338. data/lib/herb/dev/classifier.rb +84 -0
  339. data/lib/herb/dev/embedded.rb +27 -0
  340. data/lib/herb/dev/pipeline.rb +305 -0
  341. data/lib/herb/dev/protocol.rb +221 -0
  342. data/lib/herb/dev/runner.rb +180 -175
  343. data/lib/herb/dev/server.rb +89 -26
  344. data/lib/herb/dev/server_entry.rb +41 -6
  345. data/lib/herb/dev/watcher.rb +181 -0
  346. data/lib/herb/dev.rb +163 -0
  347. data/lib/herb/diagnostic/formatter.rb +88 -0
  348. data/lib/herb/diagnostic.rb +172 -0
  349. data/lib/herb/diff/operation.rb +36 -0
  350. data/lib/herb/diff/result.rb +62 -0
  351. data/lib/herb/diff.rb +10 -0
  352. data/lib/herb/engine/collector.rb +62 -0
  353. data/lib/herb/engine/compiler.rb +387 -113
  354. data/lib/herb/engine/component_tags/constant_resolver.rb +28 -0
  355. data/lib/herb/engine/component_tags/partial_resolver.rb +54 -0
  356. data/lib/herb/engine/component_tags/resolver.rb +32 -0
  357. data/lib/herb/engine/component_tags/visitor.rb +231 -0
  358. data/lib/herb/engine/css_inliner/inliner.rb +101 -0
  359. data/lib/herb/engine/css_inliner/visitor.rb +174 -0
  360. data/lib/herb/engine/errors.rb +122 -0
  361. data/lib/herb/engine/helpers.rb +82 -0
  362. data/lib/herb/engine/inline_render/inliner.rb +122 -0
  363. data/lib/herb/engine/inline_render/visitor.rb +267 -0
  364. data/lib/herb/engine/runtime/entry.rb +62 -0
  365. data/lib/herb/engine/runtime/error_page.rb +362 -0
  366. data/lib/herb/engine/runtime/html_safe_assertions.rb +217 -0
  367. data/lib/herb/engine/runtime/journal/summary.rb +227 -0
  368. data/lib/herb/engine/runtime/journal.rb +379 -0
  369. data/lib/herb/engine/runtime/middleware.rb +212 -0
  370. data/lib/herb/engine/runtime/observations.rb +73 -0
  371. data/lib/herb/engine/runtime/report.rb +204 -0
  372. data/lib/herb/engine/runtime/session.rb +437 -0
  373. data/lib/herb/engine/runtime.rb +21 -0
  374. data/lib/herb/engine/scoped_style/channel.rb +66 -0
  375. data/lib/herb/engine/scoped_style/collector.rb +74 -0
  376. data/lib/herb/engine/scoped_style/visitor.rb +533 -0
  377. data/lib/herb/engine/slots/annotation.rb +98 -0
  378. data/lib/herb/engine/slots/bindings.rb +61 -0
  379. data/lib/herb/engine/slots/callee.rb +118 -0
  380. data/lib/herb/engine/slots/component_definitions.rb +67 -0
  381. data/lib/herb/engine/slots/components/async.rb +24 -0
  382. data/lib/herb/engine/slots/components/base.rb +132 -0
  383. data/lib/herb/engine/slots/components/deferred.rb +81 -0
  384. data/lib/herb/engine/slots/components/fallback.rb +27 -0
  385. data/lib/herb/engine/slots/components/fragment.rb +99 -0
  386. data/lib/herb/engine/slots/components/lazy.rb +24 -0
  387. data/lib/herb/engine/slots/components.rb +52 -0
  388. data/lib/herb/engine/slots/dependencies/channel.rb +72 -0
  389. data/lib/herb/engine/slots/dependencies.rb +269 -0
  390. data/lib/herb/engine/slots/dynamics_compiler.rb +864 -0
  391. data/lib/herb/engine/slots/identifier.rb +35 -0
  392. data/lib/herb/engine/slots/manifest/channel.rb +74 -0
  393. data/lib/herb/engine/slots/manifest/collector.rb +75 -0
  394. data/lib/herb/engine/slots/markers.rb +152 -0
  395. data/lib/herb/engine/slots/render_bindings.rb +141 -0
  396. data/lib/herb/engine/slots/schema_compiler.rb +94 -0
  397. data/lib/herb/engine/slots/state_anchor.rb +94 -0
  398. data/lib/herb/engine/slots/state_compiler.rb +1325 -0
  399. data/lib/herb/engine/slots/state_directives.rb +854 -0
  400. data/lib/herb/engine/slots/state_kinds.rb +54 -0
  401. data/lib/herb/engine/slots/state_operators.rb +36 -0
  402. data/lib/herb/engine/slots/state_overrides.rb +79 -0
  403. data/lib/herb/engine/slots/state_predicates.rb +65 -0
  404. data/lib/herb/engine/slots/state_transforms.rb +42 -0
  405. data/lib/herb/engine/slots/statics.rb +185 -0
  406. data/lib/herb/engine/slots/subtree.rb +82 -0
  407. data/lib/herb/engine/slots/subtree_compiler.rb +255 -0
  408. data/lib/herb/engine/slots/types.rb +42 -0
  409. data/lib/herb/engine/slots/visitor.rb +2267 -0
  410. data/lib/herb/engine/validators/accessibility_validator.rb +3 -3
  411. data/lib/herb/engine/validators/base.rb +36 -0
  412. data/lib/herb/engine/validators/generator_template_validator.rb +39 -0
  413. data/lib/herb/engine/validators/nesting_validator.rb +3 -3
  414. data/lib/herb/engine/validators/render_validator.rb +13 -33
  415. data/lib/herb/engine/validators/security_validator.rb +3 -17
  416. data/lib/herb/engine/validators.rb +43 -0
  417. data/lib/herb/engine/visitors/auto_close_omitted_tags_visitor.rb +48 -0
  418. data/lib/herb/engine/visitors/content_for_visitor.rb +127 -0
  419. data/lib/herb/engine/{debug_visitor.rb → visitors/debug_visitor.rb} +121 -93
  420. data/lib/herb/engine/visitors/html_safe_assertions_visitor.rb +281 -0
  421. data/lib/herb/engine/visitors/instrumentation_visitor.rb +290 -0
  422. data/lib/herb/engine/visitors/optimize_visitor.rb +728 -0
  423. data/lib/herb/engine/visitors/remove_comments_visitor.rb +106 -0
  424. data/lib/herb/engine/visitors/source_attribution_visitor.rb +177 -0
  425. data/lib/herb/engine.rb +218 -259
  426. data/lib/herb/ensure_installed.rb +43 -0
  427. data/lib/herb/errors.rb +646 -157
  428. data/lib/herb/fingerprint.rb +82 -0
  429. data/lib/herb/html/elements.rb +18 -0
  430. data/lib/herb/html/util.rb +21 -2
  431. data/lib/herb/lex_result.rb +0 -10
  432. data/lib/herb/locate.rb +163 -0
  433. data/lib/herb/location.rb +20 -0
  434. data/lib/herb/parse_result.rb +17 -11
  435. data/lib/herb/parser_options.rb +65 -46
  436. data/lib/herb/position.rb +19 -0
  437. data/lib/herb/prism_inspect.rb +1 -4
  438. data/lib/herb/project.rb +28 -15
  439. data/lib/herb/range.rb +5 -0
  440. data/lib/herb/result.rb +2 -2
  441. data/lib/herb/ruby_program.rb +110 -0
  442. data/lib/herb/source_path.rb +232 -0
  443. data/lib/herb/token.rb +14 -3
  444. data/lib/herb/version.rb +1 -1
  445. data/lib/herb/visitor/context/origin.rb +52 -0
  446. data/lib/herb/visitor/context/replacements.rb +59 -0
  447. data/lib/herb/visitor/context.rb +169 -0
  448. data/lib/herb/visitor/context_aware.rb +45 -0
  449. data/lib/herb/visitor/diagnostics.rb +148 -0
  450. data/lib/herb/visitor/experimental.rb +33 -0
  451. data/lib/herb/visitor/parser_option_requirements.rb +151 -0
  452. data/lib/herb/visitor/stack.rb +192 -0
  453. data/lib/herb/visitor.rb +47 -1
  454. data/lib/herb/warnings.rb +25 -0
  455. data/lib/herb.rb +74 -63
  456. data/sig/herb/action_view/helper_registry.rbs +82 -10
  457. data/sig/herb/analysis/partial_declaration.rbs +80 -0
  458. data/sig/herb/analysis/partial_index.rbs +66 -0
  459. data/sig/herb/analysis/partial_resolution.rbs +57 -0
  460. data/sig/herb/analysis/partial_resolver.rbs +76 -0
  461. data/sig/herb/analysis/project_index.rbs +57 -0
  462. data/sig/herb/{action_view → analysis}/render_analyzer.rbs +25 -4
  463. data/sig/herb/analysis/render_graph/ancestor_chain.rbs +22 -0
  464. data/sig/herb/analysis/render_graph/builder.rbs +180 -0
  465. data/sig/herb/analysis/render_graph/call_frame.rbs +26 -0
  466. data/sig/herb/analysis/render_graph/call_site_location.rbs +28 -0
  467. data/sig/herb/analysis/render_graph/inferred_signature.rbs +27 -0
  468. data/sig/herb/analysis/render_graph/partial_call_site.rbs +36 -0
  469. data/sig/herb/analysis/render_graph/partial_context.rbs +31 -0
  470. data/sig/herb/analysis/render_graph/template_roots.rbs +32 -0
  471. data/sig/herb/analysis/render_graph.rbs +83 -0
  472. data/sig/herb/analysis/ruby_locals_index/local.rbs +21 -0
  473. data/sig/herb/analysis/ruby_locals_index/named_reference.rbs +20 -0
  474. data/sig/herb/analysis/ruby_locals_index/offset_table.rbs +26 -0
  475. data/sig/herb/analysis/ruby_locals_index/reference_collector.rbs +40 -0
  476. data/sig/herb/analysis/ruby_locals_index/state_locals.rbs +19 -0
  477. data/sig/herb/analysis/ruby_locals_index.rbs +62 -0
  478. data/sig/herb/analysis/ruby_reference.rbs +28 -0
  479. data/sig/herb/analysis/template_dependencies/dependency_collector.rbs +52 -0
  480. data/sig/herb/analysis/template_dependencies/node_dependency_collector.rbs +81 -0
  481. data/sig/herb/analysis/template_dependencies.rbs +125 -0
  482. data/sig/herb/ast/erb_render_node.rbs +10 -2
  483. data/sig/herb/ast/helpers.rbs +31 -1
  484. data/sig/herb/ast/herb_directive_node.rbs +13 -0
  485. data/sig/herb/ast/node.rbs +9 -0
  486. data/sig/herb/ast/nodes.rbs +668 -89
  487. data/sig/herb/backend.rbs +52 -0
  488. data/sig/herb/bootstrap.rbs +2 -0
  489. data/sig/herb/colors.rbs +3 -0
  490. data/sig/herb/configuration.rbs +27 -3
  491. data/sig/herb/dev/assets.rbs +27 -0
  492. data/sig/herb/dev/classifier.rbs +57 -0
  493. data/sig/herb/dev/embedded.rbs +21 -0
  494. data/sig/herb/dev/pipeline.rbs +118 -0
  495. data/sig/herb/dev/protocol.rbs +78 -0
  496. data/sig/herb/dev/runner.rbs +64 -23
  497. data/sig/herb/dev/server.rbs +49 -22
  498. data/sig/herb/dev/server_entry.rbs +46 -21
  499. data/sig/herb/dev/watcher.rbs +84 -0
  500. data/sig/herb/dev.rbs +58 -0
  501. data/sig/herb/diagnostic/formatter.rbs +28 -0
  502. data/sig/herb/diagnostic.rbs +88 -0
  503. data/sig/herb/diff/operation.rbs +36 -0
  504. data/sig/herb/diff/result.rbs +36 -0
  505. data/sig/herb/diff.rbs +6 -0
  506. data/sig/herb/engine/collector.rbs +48 -0
  507. data/sig/herb/engine/compiler.rbs +74 -24
  508. data/sig/herb/engine/component_tags/constant_resolver.rbs +19 -0
  509. data/sig/herb/engine/component_tags/partial_resolver.rbs +30 -0
  510. data/sig/herb/engine/component_tags/resolver.rbs +25 -0
  511. data/sig/herb/engine/component_tags/visitor.rbs +69 -0
  512. data/sig/herb/engine/css_inliner/inliner.rbs +65 -0
  513. data/sig/herb/engine/css_inliner/visitor.rbs +87 -0
  514. data/sig/herb/engine/errors.rbs +68 -0
  515. data/sig/herb/engine/helpers.rbs +28 -0
  516. data/sig/herb/engine/inline_render/inliner.rbs +39 -0
  517. data/sig/herb/engine/inline_render/visitor.rbs +104 -0
  518. data/sig/herb/engine/runtime/entry.rbs +43 -0
  519. data/sig/herb/engine/runtime/error_page.rbs +115 -0
  520. data/sig/herb/engine/runtime/html_safe_assertions.rbs +99 -0
  521. data/sig/herb/engine/runtime/journal/summary.rbs +172 -0
  522. data/sig/herb/engine/runtime/journal.rbs +126 -0
  523. data/sig/herb/engine/runtime/middleware.rbs +96 -0
  524. data/sig/herb/engine/runtime/observations.rbs +38 -0
  525. data/sig/herb/engine/runtime/report.rbs +97 -0
  526. data/sig/herb/engine/runtime/session.rbs +233 -0
  527. data/sig/herb/engine/runtime.rbs +14 -0
  528. data/sig/herb/engine/scoped_style/channel.rbs +45 -0
  529. data/sig/herb/engine/scoped_style/collector.rbs +45 -0
  530. data/sig/herb/engine/scoped_style/visitor.rbs +220 -0
  531. data/sig/herb/engine/slots/annotation.rbs +72 -0
  532. data/sig/herb/engine/slots/bindings.rbs +34 -0
  533. data/sig/herb/engine/slots/callee.rbs +62 -0
  534. data/sig/herb/engine/slots/component_definitions.rbs +19 -0
  535. data/sig/herb/engine/slots/components/async.rbs +20 -0
  536. data/sig/herb/engine/slots/components/base.rbs +60 -0
  537. data/sig/herb/engine/slots/components/deferred.rbs +29 -0
  538. data/sig/herb/engine/slots/components/fallback.rbs +21 -0
  539. data/sig/herb/engine/slots/components/fragment.rbs +34 -0
  540. data/sig/herb/engine/slots/components/lazy.rbs +20 -0
  541. data/sig/herb/engine/slots/components.rbs +30 -0
  542. data/sig/herb/engine/slots/dependencies/channel.rbs +51 -0
  543. data/sig/herb/engine/slots/dependencies.rbs +94 -0
  544. data/sig/herb/engine/slots/dynamics_compiler.rbs +352 -0
  545. data/sig/herb/engine/slots/identifier.rbs +19 -0
  546. data/sig/herb/engine/slots/manifest/channel.rbs +49 -0
  547. data/sig/herb/engine/slots/manifest/collector.rbs +45 -0
  548. data/sig/herb/engine/slots/markers.rbs +99 -0
  549. data/sig/herb/engine/slots/render_bindings.rbs +69 -0
  550. data/sig/herb/engine/slots/schema_compiler.rbs +62 -0
  551. data/sig/herb/engine/slots/state_anchor.rbs +41 -0
  552. data/sig/herb/engine/slots/state_compiler.rbs +258 -0
  553. data/sig/herb/engine/slots/state_directives.rbs +278 -0
  554. data/sig/herb/engine/slots/state_kinds.rbs +24 -0
  555. data/sig/herb/engine/slots/state_operators.rbs +19 -0
  556. data/sig/herb/engine/slots/state_overrides.rbs +33 -0
  557. data/sig/herb/engine/slots/state_predicates.rbs +16 -0
  558. data/sig/herb/engine/slots/state_transforms.rbs +15 -0
  559. data/sig/herb/engine/slots/statics.rbs +67 -0
  560. data/sig/herb/engine/slots/subtree.rbs +49 -0
  561. data/sig/herb/engine/slots/subtree_compiler.rbs +130 -0
  562. data/sig/herb/engine/slots/types.rbs +46 -0
  563. data/sig/herb/engine/slots/visitor.rbs +603 -0
  564. data/sig/herb/engine/validators/accessibility_validator.rbs +1 -1
  565. data/sig/herb/engine/validators/base.rbs +28 -0
  566. data/sig/herb/engine/validators/generator_template_validator.rbs +19 -0
  567. data/sig/herb/engine/validators/nesting_validator.rbs +1 -1
  568. data/sig/herb/engine/validators/render_validator.rbs +2 -6
  569. data/sig/herb/engine/validators/security_validator.rbs +1 -3
  570. data/sig/herb/engine/validators.rbs +21 -0
  571. data/sig/herb/engine/visitors/auto_close_omitted_tags_visitor.rbs +26 -0
  572. data/sig/herb/engine/visitors/content_for_visitor.rbs +52 -0
  573. data/sig/herb/engine/{debug_visitor.rbs → visitors/debug_visitor.rbs} +26 -15
  574. data/sig/herb/engine/visitors/html_safe_assertions_visitor.rbs +100 -0
  575. data/sig/herb/engine/visitors/instrumentation_visitor.rbs +111 -0
  576. data/sig/herb/engine/visitors/optimize_visitor.rbs +246 -0
  577. data/sig/herb/engine/visitors/remove_comments_visitor.rbs +66 -0
  578. data/sig/herb/engine/visitors/source_attribution_visitor.rbs +90 -0
  579. data/sig/herb/engine.rbs +47 -41
  580. data/sig/herb/ensure_installed.rbs +9 -0
  581. data/sig/herb/errors.rbs +293 -0
  582. data/sig/herb/fingerprint.rbs +37 -0
  583. data/sig/herb/html/elements.rbs +19 -0
  584. data/sig/herb/html/util.rbs +15 -1
  585. data/sig/herb/lex_result.rbs +0 -6
  586. data/sig/herb/locate.rbs +89 -0
  587. data/sig/herb/location.rbs +12 -0
  588. data/sig/herb/parse_result.rbs +10 -8
  589. data/sig/herb/parser_options.rbs +47 -21
  590. data/sig/herb/position.rbs +11 -0
  591. data/sig/herb/range.rbs +3 -0
  592. data/sig/herb/ruby_program.rbs +51 -0
  593. data/sig/herb/source_path.rbs +132 -0
  594. data/sig/herb/token.rbs +5 -2
  595. data/sig/herb/visitor/context/origin.rbs +51 -0
  596. data/sig/herb/visitor/context/replacements.rbs +39 -0
  597. data/sig/herb/visitor/context.rbs +83 -0
  598. data/sig/herb/visitor/context_aware.rbs +32 -0
  599. data/sig/herb/visitor/diagnostics.rbs +82 -0
  600. data/sig/herb/visitor/experimental.rbs +23 -0
  601. data/sig/herb/visitor/parser_option_requirements.rbs +76 -0
  602. data/sig/herb/visitor/stack.rbs +91 -0
  603. data/sig/herb/visitor.rbs +22 -0
  604. data/sig/herb/warnings.rbs +10 -0
  605. data/sig/herb.rbs +27 -10
  606. data/sig/serialized_ast_errors.rbs +58 -1
  607. data/sig/serialized_ast_nodes.rbs +59 -2
  608. data/src/analyze/action_view/attribute_extraction_helpers.c +73 -36
  609. data/src/analyze/action_view/generated_handlers.c +37 -1
  610. data/src/analyze/action_view/generated_handlers.h +2 -1
  611. data/src/analyze/action_view/helper_registry.c +1353 -58
  612. data/src/analyze/action_view/registry.c +10 -17
  613. data/src/analyze/action_view/stylesheet_link_tag.c +40 -0
  614. data/src/analyze/action_view/tag_helper_node_builders.c +63 -3
  615. data/src/analyze/action_view/tag_helpers.c +497 -111
  616. data/src/analyze/analyze.c +306 -89
  617. data/src/analyze/analyze_helpers.c +502 -243
  618. data/src/analyze/analyzed_ruby.c +2 -0
  619. data/src/analyze/builders.c +80 -51
  620. data/src/analyze/conditional_elements.c +13 -8
  621. data/src/analyze/conditional_open_tags.c +11 -5
  622. data/src/analyze/control_type.c +30 -5
  623. data/src/analyze/herb_directives.c +701 -0
  624. data/src/analyze/invalid_structures.c +11 -7
  625. data/src/analyze/iteration_nodes.c +306 -0
  626. data/src/analyze/missing_end.c +116 -32
  627. data/src/analyze/parse_errors.c +8 -3
  628. data/src/analyze/postfix_conditionals.c +98 -63
  629. data/src/analyze/prism_annotate.c +45 -13
  630. data/src/analyze/render_nodes.c +345 -123
  631. data/src/analyze/strict_locals.c +30 -26
  632. data/src/analyze/ternary_conditionals.c +95 -70
  633. data/src/analyze/transform.c +43 -1
  634. data/src/ast/ast_node.c +3 -13
  635. data/src/ast/ast_nodes.c +914 -113
  636. data/src/ast/ast_pretty_print.c +166 -3
  637. data/src/diff/herb_diff.c +8 -0
  638. data/src/diff/herb_diff_attributes.c +1 -0
  639. data/src/diff/herb_diff_children.c +4 -3
  640. data/src/diff/herb_diff_helpers.c +7 -1
  641. data/src/diff/herb_diff_nodes.c +186 -71
  642. data/src/diff/herb_hash_tree.c +99 -1
  643. data/src/errors.c +1096 -128
  644. data/src/extract.c +227 -144
  645. data/src/herb.c +30 -11
  646. data/src/include/analyze/action_view/attribute_extraction_helpers.h +1 -1
  647. data/src/include/analyze/action_view/helper_registry.h +28 -4
  648. data/src/include/analyze/action_view/tag_helper_handler.h +1 -1
  649. data/src/include/analyze/action_view/tag_helper_node_builders.h +7 -0
  650. data/src/include/analyze/analyze.h +11 -22
  651. data/src/include/analyze/analyzed_ruby.h +25 -0
  652. data/src/include/analyze/builders.h +16 -0
  653. data/src/include/analyze/helpers.h +25 -24
  654. data/src/include/analyze/herb_directive_kinds.h +41 -0
  655. data/src/include/analyze/herb_directives.h +14 -0
  656. data/src/include/analyze/iteration_nodes.h +11 -0
  657. data/src/include/analyze/prism_annotate.h +3 -3
  658. data/src/include/analyze/ternary_conditionals.h +2 -0
  659. data/src/include/ast/ast_node.h +1 -5
  660. data/src/include/ast/ast_nodes.h +78 -3
  661. data/src/include/ast/ast_pretty_print.h +1 -1
  662. data/src/include/diff/herb_diff.h +11 -0
  663. data/src/include/errors.h +156 -39
  664. data/src/include/extract.h +11 -0
  665. data/src/include/herb.h +6 -0
  666. data/src/include/lexer/erb_openers.h +29 -0
  667. data/src/include/lexer/lexer.h +1 -0
  668. data/src/include/lexer/lexer_peek_helpers.h +8 -1
  669. data/src/include/lexer/lexer_struct.h +4 -0
  670. data/src/include/lexer/token.h +3 -0
  671. data/src/include/lexer/token_struct.h +8 -6
  672. data/src/include/lib/hb_allocator.h +2 -1
  673. data/src/include/lib/hb_array.h +2 -0
  674. data/src/include/lib/hb_foreach.h +1 -1
  675. data/src/include/lib/hb_string.h +7 -0
  676. data/src/include/parser/dot_notation.h +1 -1
  677. data/src/include/parser/foreign_content_elements.h +32 -0
  678. data/src/include/parser/parser.h +16 -30
  679. data/src/include/parser/parser_helpers.h +13 -11
  680. data/src/include/parser/parser_options.h +41 -0
  681. data/src/include/prism/herb_prism_node.h +6 -1
  682. data/src/include/prism/ruby_parser.h +6 -0
  683. data/src/include/util/html_elements.h +85 -0
  684. data/src/include/util/html_util.h +1 -0
  685. data/src/include/version.h +1 -1
  686. data/src/lexer/lexer_peek_helpers.c +15 -1
  687. data/src/lexer/token.c +83 -1
  688. data/src/lexer.c +228 -12
  689. data/src/lib/hb_allocator.c +2 -0
  690. data/src/lib/hb_array.c +26 -0
  691. data/src/lib/hb_string.c +26 -0
  692. data/src/main.c +1 -1
  693. data/src/parser/dot_notation.c +4 -3
  694. data/src/parser/match_tags.c +66 -1
  695. data/src/parser/parser_helpers.c +69 -37
  696. data/src/parser.c +606 -383
  697. data/src/parser_options_defaults.c +30 -0
  698. data/src/prism/prism_helpers.c +94 -0
  699. data/src/prism/ruby_parser.c +49 -0
  700. data/src/util/html_util.c +11 -58
  701. data/src/visitor.c +77 -1
  702. data/templates/ext/herb/error_helpers.c.erb +1 -1
  703. data/templates/ext/herb/nodes.c.erb +19 -14
  704. data/templates/ext/herb/nodes.h.erb +2 -1
  705. data/templates/ext/herb/parser_options_helpers.c.erb +69 -0
  706. data/templates/ext/herb/parser_options_helpers.h.erb +11 -0
  707. data/templates/java/nodes.c.erb +21 -17
  708. data/templates/java/nodes.h.erb +3 -2
  709. data/templates/java/org/herb/ParserOptions.java.erb +24 -0
  710. data/templates/java/org/herb/ast/HelperRegistry.java.erb +67 -31
  711. data/templates/java/org/herb/ast/HelperType.java.erb +29 -0
  712. data/templates/java/org/herb/ast/Nodes.java.erb +11 -7
  713. data/templates/java/parser_options_helpers.c.erb +45 -0
  714. data/templates/java/parser_options_helpers.h.erb +10 -0
  715. data/templates/javascript/packages/client/src/state-kinds.ts.erb +49 -0
  716. data/templates/javascript/packages/client/src/state-operators.ts.erb +15 -0
  717. data/templates/javascript/packages/client/src/state-predicates.ts.erb +27 -0
  718. data/templates/javascript/packages/client/src/state-transforms.ts.erb +19 -0
  719. data/templates/javascript/packages/core/src/action-view-helpers.ts.erb +47 -0
  720. data/templates/javascript/packages/core/src/built-in-components.ts.erb +67 -0
  721. data/templates/javascript/packages/core/src/errors.ts.erb +9 -3
  722. data/templates/javascript/packages/core/src/foreign-content-elements.ts.erb +18 -0
  723. data/templates/javascript/packages/core/src/html-constants.ts.erb +32 -0
  724. data/templates/javascript/packages/core/src/html-elements.ts.erb +41 -0
  725. data/templates/javascript/packages/core/src/node-type-guards.ts.erb +11 -7
  726. data/templates/javascript/packages/core/src/nodes.ts.erb +103 -20
  727. data/templates/javascript/packages/core/src/parser-options.ts.erb +41 -0
  728. data/templates/javascript/packages/core/src/visitor.ts.erb +1 -1
  729. data/templates/javascript/packages/node/extension/error_helpers.cpp.erb +3 -3
  730. data/templates/javascript/packages/node/extension/nodes.cpp.erb +18 -13
  731. data/templates/javascript/packages/node/extension/nodes.h.erb +3 -3
  732. data/templates/javascript/packages/node/extension/parser_options_helpers.cpp.erb +41 -0
  733. data/templates/javascript/packages/node/extension/parser_options_helpers.h.erb +12 -0
  734. data/templates/lib/herb/action_view/helper_registry.rb.erb +77 -3
  735. data/templates/lib/herb/ast/nodes.rb.erb +16 -6
  736. data/templates/lib/herb/engine/slots/component_definitions.rb.erb +38 -0
  737. data/templates/lib/herb/engine/slots/state_kinds.rb.erb +37 -0
  738. data/templates/lib/herb/engine/slots/state_operators.rb.erb +26 -0
  739. data/templates/lib/herb/engine/slots/state_predicates.rb.erb +39 -0
  740. data/templates/lib/herb/engine/slots/state_transforms.rb.erb +27 -0
  741. data/templates/lib/herb/errors.rb.erb +34 -6
  742. data/templates/lib/herb/html/elements.rb.erb +12 -0
  743. data/templates/lib/herb/parser_options.rb.erb +32 -0
  744. data/templates/lib/herb/visitor.rb.erb +7 -1
  745. data/templates/rust/herb-printer/src/printer_visitor.rs.erb +14 -0
  746. data/templates/rust/src/action_view_helpers.rs.erb +38 -0
  747. data/templates/rust/src/ast/nodes.rs.erb +21 -31
  748. data/templates/rust/src/errors.rs.erb +1 -1
  749. data/templates/rust/src/nodes.rs.erb +58 -26
  750. data/templates/rust/src/parser_options.rs.erb +16 -0
  751. data/templates/rust/src/prism/generated_deserialize.rs.erb +109 -0
  752. data/templates/rust/src/prism/generated_prettyprint.rs.erb +153 -0
  753. data/templates/rust/src/union_types.rs.erb +7 -1
  754. data/templates/rust/src/visitor.rs.erb +1 -1
  755. data/templates/src/analyze/action_view/helper_registry.c.erb +22 -0
  756. data/templates/src/analyze/missing_end.c.erb +13 -5
  757. data/templates/src/ast/ast_nodes.c.erb +41 -2
  758. data/templates/src/diff/herb_diff_nodes.c.erb +44 -8
  759. data/templates/src/errors.c.erb +8 -3
  760. data/templates/src/include/analyze/action_view/helper_registry.h.erb +19 -0
  761. data/templates/src/include/analyze/herb_directive_kinds.h.erb +25 -0
  762. data/templates/src/include/errors.h.erb +3 -1
  763. data/templates/src/include/parser/foreign_content_elements.h.erb +23 -0
  764. data/templates/src/include/parser/parser_options.h.erb +21 -0
  765. data/templates/src/include/util/html_elements.h.erb +28 -0
  766. data/templates/src/parser_options_defaults.c.erb +9 -0
  767. data/templates/template.rb +564 -9
  768. data/templates/wasm/error_helpers.cpp.erb +4 -4
  769. data/templates/wasm/nodes.cpp.erb +17 -27
  770. data/templates/wasm/nodes.h.erb +3 -3
  771. data/templates/wasm/parser_options_helpers.cpp.erb +25 -0
  772. data/templates/wasm/parser_options_helpers.h.erb +12 -0
  773. metadata +306 -27
  774. data/config/action_view_helpers/actionview/form_helper/button.yml +0 -38
  775. data/config/action_view_helpers/actionview/form_helper/submit.yml +0 -35
  776. data/lib/herb/ast.rb +0 -7
  777. data/lib/herb/diff_operation.rb +0 -34
  778. data/lib/herb/diff_result.rb +0 -59
  779. data/lib/herb/engine/error_formatter.rb +0 -432
  780. data/lib/herb/engine/parser_error_overlay.rb +0 -773
  781. data/lib/herb/engine/validation_error_overlay.rb +0 -182
  782. data/lib/herb/engine/validation_errors.rb +0 -65
  783. data/lib/herb/engine/validator.rb +0 -80
  784. data/sig/herb/ast.rbs +0 -6
  785. data/sig/herb/diff_operation.rbs +0 -34
  786. data/sig/herb/diff_result.rbs +0 -34
  787. data/sig/herb/engine/debug.rbs +0 -38
  788. data/sig/herb/engine/error_formatter.rbs +0 -47
  789. data/sig/herb/engine/parser_error_overlay.rbs +0 -41
  790. data/sig/herb/engine/validation_error_overlay.rbs +0 -35
  791. data/sig/herb/engine/validation_errors.rbs +0 -45
  792. data/sig/herb/engine/validator.rbs +0 -41
  793. 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,30 @@ 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
+
241
+ def visit_erb_strict_locals_node(node)
242
+ process_erb_tag(node)
243
+ end
244
+
218
245
  def visit_erb_control_node(node, &)
219
246
  if node.content
220
- apply_trim(node, node.content.value.strip)
247
+ if node.tag_opening && erb_escaped?(node.tag_opening.value)
248
+ add_escaped_erb_tag(node)
249
+ elsif continues_into_next_node?(node)
250
+ @continued_head = node
251
+ else
252
+ head = @continued_head
253
+ @continued_head = nil
254
+
255
+ code_index = @tokens.length
256
+ raw = head ? head.content.value + node.content.value : node.content.value
257
+
258
+ apply_trim(head || node, raw.strip)
259
+ keep_line_count(node, at: code_index, raw: raw)
260
+ end
221
261
  end
222
262
 
223
263
  yield if block_given?
@@ -246,7 +286,7 @@ module Herb
246
286
  end
247
287
 
248
288
  def visit_erb_case_node(node)
249
- visit_erb_control_with_parts(node, :conditions, :else_clause, :end_node)
289
+ visit_erb_case_parts(node)
250
290
  end
251
291
 
252
292
  def visit_erb_when_node(node)
@@ -282,7 +322,7 @@ module Herb
282
322
  end
283
323
 
284
324
  def visit_erb_case_match_node(node)
285
- visit_erb_control_with_parts(node, :conditions, :else_clause, :end_node)
325
+ visit_erb_case_parts(node)
286
326
  end
287
327
 
288
328
  def visit_erb_in_node(node)
@@ -296,11 +336,12 @@ module Herb
296
336
  def visit_erb_block_node(node)
297
337
  opening = node.tag_opening.value
298
338
 
299
- check_for_escaped_erb_tag!(opening)
339
+ return add_escaped_erb_block(node) if erb_escaped?(opening)
300
340
 
301
341
  if opening.include?("=")
302
342
  should_escape = should_escape_output?(opening)
303
- code = node.content.value.strip
343
+ code = ::Herb::Engine::Helpers.strip_trailing_comment(node.content.value.strip)
344
+ code_index = @tokens.length
304
345
 
305
346
  @tokens << if should_escape
306
347
  [:expr_block_escaped, code, current_context]
@@ -308,6 +349,8 @@ module Herb
308
349
  [:expr_block, code, current_context]
309
350
  end
310
351
 
352
+ keep_line_count(node, at: code_index)
353
+
311
354
  @last_trim_consumed_newline = false
312
355
  @trim_next_whitespace = true if right_trim?(node)
313
356
 
@@ -324,12 +367,22 @@ module Herb
324
367
  end
325
368
  end
326
369
 
370
+ def visit_erb_iteration_block_node(node)
371
+ visit_erb_block_node(node)
372
+ end
373
+
374
+ def visit_erb_render_node(node)
375
+ return process_erb_tag(node) unless node.end_node
376
+
377
+ visit_erb_block_node(node)
378
+ end
379
+
327
380
  def visit_erb_block_end_node(node, escaped: false)
328
- remove_trailing_whitespace_from_last_token! if left_trim?(node)
381
+ remove_trailing_whitespace_from_last_token! if @trim && left_trim?(node)
329
382
 
330
- code = node.content.value.strip
383
+ code = ::Herb::Engine::Helpers.strip_trailing_comment(node.content.value.strip)
331
384
 
332
- if at_line_start?
385
+ if @trim && at_line_start?
333
386
  leading_space = extract_and_remove_leading_space!
334
387
  right_space = " \n"
335
388
 
@@ -340,8 +393,18 @@ module Herb
340
393
  end
341
394
  end
342
395
 
343
- def visit_erb_control_with_parts(node, *parts)
396
+ def visit_erb_case_parts(node)
397
+ parts = [:conditions, :else_clause, :end_node]
398
+
399
+ return visit_erb_control_with_parts(node, :children, *parts) if erb_escaped?(node.tag_opening.value)
400
+
401
+ visit_erb_control_with_parts(node, *parts) { skip_case_children(node.children) }
402
+ end
403
+
404
+ def visit_erb_control_with_parts(node, *parts, &)
344
405
  visit_erb_control_node(node) do
406
+ yield if block_given?
407
+
345
408
  parts.each do |part|
346
409
  value = node.send(part)
347
410
  case value
@@ -358,13 +421,25 @@ module Herb
358
421
 
359
422
  private
360
423
 
361
- def check_for_escaped_erb_tag!(opening)
362
- return unless opening.start_with?("<%%")
424
+ def add_escaped_erb_tag(node)
425
+ opening = node.tag_opening.value.sub("<%%") { @literal_prefix }
426
+ closing = (node.tag_closing&.value || "").sub(/%>\z/) { @literal_postfix }
427
+
428
+ add_text("#{opening}#{node.content.value}#{closing}")
429
+ end
430
+
431
+ def add_escaped_erb_block(node)
432
+ add_escaped_erb_tag(node)
433
+ visit_all(node.body)
363
434
 
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."
435
+ end_node = node.end_node
436
+ return unless end_node
437
+
438
+ if erb_escaped?(end_node.tag_opening.value)
439
+ add_escaped_erb_tag(end_node)
440
+ else
441
+ visit(end_node)
442
+ end
368
443
  end
369
444
 
370
445
  def current_context
@@ -379,7 +454,7 @@ module Herb
379
454
  @context_stack.pop
380
455
  end
381
456
 
382
- #: (untyped node) { () -> untyped } -> untyped
457
+ #: (untyped node) { (String?) -> untyped } -> untyped
383
458
  def with_element_context(node)
384
459
  tag_name = node.tag_name&.value&.downcase
385
460
  previous_element_source = @current_element_source
@@ -393,9 +468,9 @@ module Herb
393
468
  push_context(:style_content)
394
469
  end
395
470
 
396
- yield
471
+ yield(tag_name)
397
472
 
398
- pop_context if ["script", "style"].include?(tag_name)
473
+ pop_context if RAW_TEXT_ELEMENTS.include?(tag_name)
399
474
 
400
475
  @element_stack.pop if tag_name
401
476
  @current_element_source = previous_element_source
@@ -404,28 +479,67 @@ module Herb
404
479
  def process_erb_tag(node, skip_comment_check: false)
405
480
  opening = node.tag_opening.value
406
481
 
407
- check_for_escaped_erb_tag!(opening)
482
+ return add_escaped_erb_tag(node) if erb_escaped?(opening)
483
+
484
+ if !skip_comment_check && erb_omitted?(opening)
485
+ unless @trim
486
+ keep_span_line_count(node)
487
+
488
+ return
489
+ end
408
490
 
409
- if !skip_comment_check && erb_comment?(opening)
410
491
  follows_newline = leading_space_follows_newline?
411
492
  remove_trailing_whitespace_from_last_token! if left_trim?(node)
493
+ swallows_newline = at_line_start?
412
494
 
413
- if at_line_start?
495
+ if swallows_newline
414
496
  leading_space = extract_and_remove_leading_space!
415
497
  @trim_next_whitespace = true
416
498
  save_pending_leading_whitespace!(leading_space) if !leading_space.empty? && follows_newline
417
499
  end
500
+
501
+ keep_span_line_count(node, extra: swallows_newline ? 1 : 0)
502
+ @pending_span_extra_index = @tokens.length if swallows_newline
503
+
418
504
  return
419
505
  end
420
- return if erb_graphql?(opening)
421
506
 
422
- code = node.content.value.strip
507
+ code = ::Herb::Engine::Helpers.strip_trailing_comment(node.content.value.strip)
508
+
509
+ code_index = @tokens.length
423
510
 
424
511
  if erb_output?(opening)
425
512
  process_erb_output(node, opening, code)
426
513
  else
427
514
  apply_trim(node, code)
428
515
  end
516
+
517
+ absorbed = erb_output?(opening) && ::Herb::Engine::Helpers.ends_on_heredoc_terminator?(code) ? 1 : 0
518
+
519
+ keep_line_count(node, at: code_index, absorbed: absorbed)
520
+ end
521
+
522
+ #: (untyped, ?extra: Integer) -> void
523
+ def keep_span_line_count(node, extra: 0)
524
+ lines = node.content.value.count("\n") + extra
525
+
526
+ return unless lines.positive?
527
+
528
+ @padding_before ||= Hash.new(0)
529
+ @padding_before[@tokens.length] += lines
530
+ end
531
+
532
+ def keep_line_count(node, extra: 0, at: nil, absorbed: 0, raw: nil)
533
+ raw ||= node.content.value
534
+
535
+ leading = raw[0, raw.length - raw.lstrip.length].to_s.count("\n")
536
+ trailing = raw.count("\n") - raw.strip.count("\n") - leading + extra - absorbed
537
+
538
+ block_comment = raw.include?("=begin") || raw.include?("=end")
539
+
540
+ @padding_before ||= Hash.new(0)
541
+ @padding_before[at] += leading if at && leading.positive? && !block_comment
542
+ @padding_before[@tokens.length] += trailing if trailing.positive?
429
543
  end
430
544
 
431
545
  def add_text(text)
@@ -436,9 +550,14 @@ module Herb
436
550
  text = text.sub(/\A[ \t]*\r?\n/, "")
437
551
  @trim_next_whitespace = false
438
552
 
553
+ settle_pending_trim_newline!(@last_trim_consumed_newline)
554
+ settle_pending_span_extra!(@last_trim_consumed_newline)
439
555
  restore_pending_leading_whitespace! unless @last_trim_consumed_newline
440
556
  else
441
557
  @last_trim_consumed_newline = false
558
+
559
+ settle_pending_trim_newline!(false)
560
+ settle_pending_span_extra!(false)
442
561
  end
443
562
 
444
563
  @pending_leading_whitespace = nil
@@ -448,10 +567,6 @@ module Herb
448
567
  @tokens << [:text, text, current_context]
449
568
  end
450
569
 
451
- def add_whitespace(whitespace)
452
- @tokens << [:whitespace, whitespace, current_context]
453
- end
454
-
455
570
  def add_code(code)
456
571
  @tokens << [:code, code, current_context]
457
572
  end
@@ -468,82 +583,98 @@ module Herb
468
583
 
469
584
  def optimize_tokens(tokens)
470
585
  return tokens if tokens.empty?
471
-
472
- compacted = compact_whitespace_tokens(tokens)
586
+ return optimize_tokens_with_padding(tokens) if @padding_before
473
587
 
474
588
  optimized = [] #: Array[untyped]
475
- current_text = ""
589
+ current_text = nil #: String?
476
590
  current_context = nil
477
591
 
478
- compacted.each do |type, value, context, escaped|
592
+ tokens.each do |token|
593
+ type = token[0]
594
+
479
595
  if type == :text
480
- current_text += value
481
- current_context ||= context
596
+ value = token[1]
597
+
598
+ if current_text
599
+ current_text << value
600
+ current_context ||= token[2]
601
+ else
602
+ current_text = value.dup
603
+ current_context = token[2]
604
+ end
482
605
  else
483
- unless current_text.empty?
606
+ if current_text
484
607
  optimized << [:text, current_text, current_context]
485
608
 
486
- current_text = ""
609
+ current_text = nil
487
610
  current_context = nil
488
611
  end
489
612
 
490
- optimized << [type, value, context, escaped]
613
+ optimized << [type, token[1], token[2], token[3]]
491
614
  end
492
615
  end
493
616
 
494
- optimized << [:text, current_text, current_context] unless current_text.empty?
617
+ optimized << [:text, current_text, current_context] if current_text
495
618
 
496
619
  optimized
497
620
  end
498
621
 
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
622
+ def padding_newlines(count)
623
+ PADDING_NEWLINES[count] || ("\n" * count)
510
624
  end
511
625
 
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
626
+ def optimize_tokens_with_padding(tokens)
627
+ optimized = [] #: Array[untyped]
628
+ current_text = nil #: String?
629
+ current_context = nil
630
+ pending_padding = 0
518
631
 
519
- def trailing_whitespace?(token)
520
- return false unless token
632
+ tokens.each_with_index do |token, index|
633
+ pending_padding += @padding_before[index]
521
634
 
522
- token[0] == :whitespace || (token[0] == :text && token[1] =~ /\s\z/)
523
- end
635
+ if token[0] == :text
636
+ if pending_padding.positive?
637
+ if current_text
638
+ optimized << [:text, current_text, current_context]
639
+ current_text = nil
640
+ current_context = nil
641
+ end
524
642
 
525
- def leading_whitespace?(token)
526
- token && token[0] == :text && token[1] =~ /\A\s/
527
- end
643
+ optimized << [:code, padding_newlines(pending_padding), nil]
644
+ pending_padding = 0
645
+ end
528
646
 
529
- def whitespace_before_code_sequence?(tokens, current_index)
530
- previous_token = tokens[current_index - 1] if current_index.positive?
647
+ if current_text
648
+ current_text << token[1]
649
+ current_context ||= token[2]
650
+ else
651
+ current_text = token[1].dup
652
+ current_context = token[2]
653
+ end
531
654
 
532
- return false unless previous_token && previous_token[0] == :code
655
+ next
656
+ end
533
657
 
534
- token_before_code = find_token_before_code_sequence(tokens, current_index)
658
+ if current_text
659
+ optimized << [:text, current_text, current_context]
660
+ current_text = nil
661
+ current_context = nil
662
+ end
535
663
 
536
- return false unless token_before_code
664
+ if pending_padding.positive?
665
+ optimized << [:code, padding_newlines(pending_padding), nil]
666
+ pending_padding = 0
667
+ end
537
668
 
538
- trailing_whitespace?(token_before_code)
539
- end
669
+ optimized << [token[0], token[1], token[2], token[3]]
670
+ end
540
671
 
541
- def find_token_before_code_sequence(tokens, whitespace_index)
542
- search_index = whitespace_index - 1
672
+ optimized << [:text, current_text, current_context] if current_text
543
673
 
544
- search_index -= 1 while search_index >= 0 && tokens[search_index][0] == :code
674
+ pending_padding += @padding_before[tokens.length]
675
+ optimized << [:code, padding_newlines(pending_padding), nil] if pending_padding.positive?
545
676
 
546
- search_index >= 0 ? tokens[search_index] : nil
677
+ optimized
547
678
  end
548
679
 
549
680
  def process_erb_output(node, opening, code)
@@ -554,6 +685,8 @@ module Herb
554
685
  @last_trim_consumed_newline = false
555
686
  end
556
687
 
688
+ settle_pending_trim_newline!(false)
689
+
557
690
  should_escape = should_escape_output?(opening)
558
691
  add_expression_with_escaping(code, should_escape)
559
692
  @trim_next_whitespace = true if right_trim?(node)
@@ -582,6 +715,36 @@ module Herb
582
715
  end
583
716
  end
584
717
 
718
+ #: (String) -> Integer
719
+ def trailing_space_length(text)
720
+ count = 0
721
+ count += 1 while count < text.length && HORIZONTAL_SPACE.include?(text[text.length - 1 - count])
722
+
723
+ count
724
+ end
725
+
726
+ #: (String) -> String
727
+ def trailing_spaces(text)
728
+ text[text.length - trailing_space_length(text), text.length].to_s
729
+ end
730
+
731
+ #: (String) -> void
732
+ def remove_trailing_spaces!(text)
733
+ text.replace(text[0, text.length - trailing_space_length(text)].to_s)
734
+ end
735
+
736
+ #: (String) -> bool
737
+ def whitespace_only?(text)
738
+ !text.empty? && trailing_space_length(text) == text.length
739
+ end
740
+
741
+ #: (String) -> bool
742
+ def trailing_indentation?(text)
743
+ spaces = trailing_space_length(text)
744
+
745
+ spaces.positive? && text[text.length - spaces - 1] == "\n"
746
+ end
747
+
585
748
  def at_line_start?
586
749
  return true if @tokens.empty?
587
750
 
@@ -589,7 +752,7 @@ module Herb
589
752
  last_value = @tokens.last[1]
590
753
 
591
754
  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
755
+ last_value.empty? || last_value.end_with?("\n") || (whitespace_only?(last_value) && preceding_token_ends_with_newline?) || trailing_indentation?(last_value)
593
756
  elsif EXPRESSION_TOKEN_TYPES.include?(last_type)
594
757
  @last_trim_consumed_newline
595
758
  else
@@ -609,13 +772,30 @@ module Herb
609
772
  end
610
773
 
611
774
  def left_trim?(node)
612
- node.tag_opening.value == "<%-"
775
+ node.tag_opening&.value == "<%-"
613
776
  end
614
777
 
615
778
  def right_trim?(node)
616
779
  node.tag_closing&.value == "-%>"
617
780
  end
618
781
 
782
+ def preceded_by_whitespace?
783
+ index = @tokens.length - 1
784
+ index -= 1 while index >= 0 && emits_nothing?(@tokens[index])
785
+
786
+ return false if index.negative?
787
+
788
+ token = @tokens[index]
789
+
790
+ return false unless token[0] == :text
791
+
792
+ token[1].match?(/\s\z/)
793
+ end
794
+
795
+ def emits_nothing?(token)
796
+ token[0] == :code || (token[0] == :text && token[1].empty?)
797
+ end
798
+
619
799
  def last_text_token
620
800
  return unless @tokens.last && @tokens.last[0] == :text
621
801
 
@@ -628,7 +808,7 @@ module Herb
628
808
 
629
809
  text = token[1]
630
810
 
631
- return Regexp.last_match(1) if text =~ TRAILING_INDENTATION_CAPTURE || text =~ WHITESPACE_ONLY_CAPTURE
811
+ return trailing_spaces(text) if trailing_indentation?(text) || whitespace_only?(text)
632
812
 
633
813
  ""
634
814
  end
@@ -639,10 +819,19 @@ module Herb
639
819
 
640
820
  text = token[1]
641
821
 
642
- return true if text.match?(TRAILING_INDENTATION)
643
- return true if @last_trim_consumed_newline && text.match?(WHITESPACE_ONLY)
822
+ return true if trailing_indentation?(text)
823
+
824
+ whitespace_only?(text) && (preceding_token_value_ends_with_newline? || @last_trim_consumed_newline)
825
+ end
826
+
827
+ def preceding_token_value_ends_with_newline?
828
+ return true unless @tokens.length >= 2
829
+
830
+ preceding = @tokens[-2]
644
831
 
645
- false
832
+ return @last_trim_consumed_newline if EXPRESSION_TOKEN_TYPES.include?(preceding[0])
833
+
834
+ preceding[1].end_with?("\n")
646
835
  end
647
836
 
648
837
  def extract_and_remove_leading_space!
@@ -651,9 +840,9 @@ module Herb
651
840
 
652
841
  text = @tokens.last[1]
653
842
 
654
- if text =~ TRAILING_INDENTATION
655
- text.sub!(TRAILING_WHITESPACE, "")
656
- elsif text =~ WHITESPACE_ONLY
843
+ if trailing_indentation?(text)
844
+ remove_trailing_spaces!(text)
845
+ elsif whitespace_only?(text)
657
846
  text.replace("")
658
847
  end
659
848
 
@@ -663,23 +852,103 @@ module Herb
663
852
  end
664
853
 
665
854
  def apply_trim(node, code)
855
+ return add_code(code) unless @trim
856
+
666
857
  follows_newline = leading_space_follows_newline?
667
858
  removed_whitespace = left_trim?(node) ? remove_trailing_whitespace_from_last_token! : ""
859
+ line_start = at_line_start?
860
+
861
+ drop_pending_trim_newline! if follows_trimmed_statement_tag?(node)
668
862
 
669
- if at_line_start?
863
+ if line_start
670
864
  leading_space = extract_and_remove_leading_space!
671
865
  effective_leading_space = leading_space.empty? ? removed_whitespace : leading_space
672
- right_space = Herb::Engine.heredoc?(code) ? "\n" : " \n"
673
-
674
- @pending_leading_whitespace_insert_index = @tokens.length
675
- @pending_leading_whitespace = effective_leading_space if !effective_leading_space.empty? && follows_newline
866
+ right_space = if Herb::Engine::Helpers.heredoc?(code)
867
+ "\n"
868
+ elsif without_source?(node)
869
+ " "
870
+ else
871
+ " \n"
872
+ end
873
+
874
+ save_pending_leading_whitespace!(effective_leading_space) if !effective_leading_space.empty? && follows_newline
676
875
  @tokens << [:code, "#{effective_leading_space}#{code}#{right_space}", current_context]
677
876
  @trim_next_whitespace = true
877
+
878
+ if right_space.end_with?(" \n")
879
+ @pending_trim_newline_index = @tokens.length - 1
880
+ @pending_trim_owns_next_whitespace = true
881
+ end
678
882
  else
679
883
  @tokens << [:code, code, current_context]
680
884
  end
681
885
  end
682
886
 
887
+ def continues_into_next_node?(node)
888
+ node.tag_closing.nil? && !node.content.nil?
889
+ end
890
+
891
+ #: (untyped) -> bool
892
+ def without_source?(node)
893
+ position = node.tag_closing&.location&.end || node.location&.end
894
+
895
+ !position.nil? && !position.line.positive?
896
+ end
897
+
898
+ #: (bool) -> void
899
+ def settle_pending_span_extra!(keep)
900
+ index = @pending_span_extra_index
901
+
902
+ return unless index
903
+
904
+ @pending_span_extra_index = nil
905
+
906
+ return if keep
907
+
908
+ @padding_before[index] -= 1 if @padding_before&.key?(index)
909
+ end
910
+
911
+ #: (bool) -> void
912
+ def settle_pending_trim_newline!(keep)
913
+ index = @pending_trim_newline_index
914
+
915
+ return unless index
916
+
917
+ owned = @pending_trim_owns_next_whitespace
918
+
919
+ @pending_trim_newline_index = nil
920
+ @pending_trim_owns_next_whitespace = false
921
+
922
+ return if keep
923
+
924
+ @tokens[index][1] = @tokens[index][1].chomp
925
+ @trim_next_whitespace = false if owned
926
+ end
927
+
928
+ #: (Array[untyped]) -> void
929
+ def skip_case_children(children)
930
+ text = children.grep(Herb::AST::HTMLTextNode).map(&:content).join
931
+
932
+ settle_pending_trim_newline!(true) if text.match?(/\A[ \t]*\r?\n/)
933
+ end
934
+
935
+ #: (untyped) -> bool
936
+ def follows_trimmed_statement_tag?(node)
937
+ return false if without_source?(node)
938
+
939
+ !@pending_trim_newline_index.nil? && @pending_trim_newline_index == @tokens.length - 1
940
+ end
941
+
942
+ #: () -> void
943
+ def drop_pending_trim_newline!
944
+ index = @pending_trim_newline_index
945
+ return unless index
946
+
947
+ @tokens[index][1] = @tokens[index][1].chomp
948
+ @pending_trim_newline_index = nil
949
+ @pending_trim_owns_next_whitespace = false
950
+ end
951
+
683
952
  def save_pending_leading_whitespace!(whitespace)
684
953
  @pending_leading_whitespace = whitespace
685
954
  @pending_leading_whitespace_insert_index = @tokens.length
@@ -689,6 +958,11 @@ module Herb
689
958
  return unless @pending_leading_whitespace
690
959
 
691
960
  @tokens.insert(@pending_leading_whitespace_insert_index, [:text, @pending_leading_whitespace, current_context])
961
+
962
+ return unless @pending_trim_newline_index
963
+ return if @pending_trim_newline_index < @pending_leading_whitespace_insert_index
964
+
965
+ @pending_trim_newline_index += 1
692
966
  end
693
967
 
694
968
  def remove_trailing_whitespace_from_last_token!
@@ -696,12 +970,12 @@ module Herb
696
970
  return "" unless token
697
971
 
698
972
  text = token[1]
699
- removed = text[TRAILING_WHITESPACE] || ""
973
+ removed = trailing_spaces(text)
700
974
 
701
- if text =~ TRAILING_INDENTATION
702
- text.sub!(TRAILING_WHITESPACE, "")
975
+ if trailing_indentation?(text)
976
+ remove_trailing_spaces!(text)
703
977
  token[1] = text
704
- elsif text =~ WHITESPACE_ONLY
978
+ elsif whitespace_only?(text)
705
979
  text.replace("")
706
980
  token[1] = text
707
981
  end