herb 0.10.1 → 0.11.1

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 +17 -7
  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 +1249 -786
  284. data/exe/herb +2 -0
  285. data/ext/herb/error_helpers.c +379 -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 -74
  289. data/ext/herb/extension_helpers.c +81 -35
  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 +3 -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 +1368 -105
  327. data/lib/herb/backend.rb +73 -0
  328. data/lib/herb/bootstrap.rb +8 -8
  329. data/lib/herb/cli.rb +555 -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 +180 -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 +387 -113
  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 +864 -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 +152 -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 +1325 -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 +2267 -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} +122 -94
  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 -259
  422. data/lib/herb/ensure_installed.rb +43 -0
  423. data/lib/herb/errors.rb +681 -153
  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 +69 -40
  432. data/lib/herb/position.rb +19 -0
  433. data/lib/herb/prism_inspect.rb +1 -4
  434. data/lib/herb/project.rb +39 -23
  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 +668 -89
  483. data/sig/herb/backend.rbs +52 -0
  484. data/sig/herb/bootstrap.rbs +2 -0
  485. data/sig/herb/colors.rbs +3 -0
  486. data/sig/herb/configuration.rbs +27 -3
  487. data/sig/herb/dev/assets.rbs +27 -0
  488. data/sig/herb/dev/classifier.rbs +57 -0
  489. data/sig/herb/dev/embedded.rbs +21 -0
  490. data/sig/herb/dev/pipeline.rbs +118 -0
  491. data/sig/herb/dev/protocol.rbs +78 -0
  492. data/sig/herb/dev/runner.rbs +64 -23
  493. data/sig/herb/dev/server.rbs +49 -22
  494. data/sig/herb/dev/server_entry.rbs +46 -21
  495. data/sig/herb/dev/watcher.rbs +84 -0
  496. data/sig/herb/dev.rbs +58 -0
  497. data/sig/herb/diagnostic/formatter.rbs +28 -0
  498. data/sig/herb/diagnostic.rbs +88 -0
  499. data/sig/herb/diff/operation.rbs +36 -0
  500. data/sig/herb/diff/result.rbs +36 -0
  501. data/sig/herb/diff.rbs +6 -0
  502. data/sig/herb/engine/collector.rbs +48 -0
  503. data/sig/herb/engine/compiler.rbs +74 -24
  504. data/sig/herb/engine/component_tags/constant_resolver.rbs +19 -0
  505. data/sig/herb/engine/component_tags/partial_resolver.rbs +30 -0
  506. data/sig/herb/engine/component_tags/resolver.rbs +25 -0
  507. data/sig/herb/engine/component_tags/visitor.rbs +69 -0
  508. data/sig/herb/engine/css_inliner/inliner.rbs +65 -0
  509. data/sig/herb/engine/css_inliner/visitor.rbs +87 -0
  510. data/sig/herb/engine/errors.rbs +68 -0
  511. data/sig/herb/engine/helpers.rbs +28 -0
  512. data/sig/herb/engine/inline_render/inliner.rbs +39 -0
  513. data/sig/herb/engine/inline_render/visitor.rbs +104 -0
  514. data/sig/herb/engine/runtime/entry.rbs +43 -0
  515. data/sig/herb/engine/runtime/error_page.rbs +115 -0
  516. data/sig/herb/engine/runtime/html_safe_assertions.rbs +99 -0
  517. data/sig/herb/engine/runtime/journal/summary.rbs +172 -0
  518. data/sig/herb/engine/runtime/journal.rbs +126 -0
  519. data/sig/herb/engine/runtime/middleware.rbs +96 -0
  520. data/sig/herb/engine/runtime/observations.rbs +38 -0
  521. data/sig/herb/engine/runtime/report.rbs +97 -0
  522. data/sig/herb/engine/runtime/session.rbs +233 -0
  523. data/sig/herb/engine/runtime.rbs +14 -0
  524. data/sig/herb/engine/scoped_style/channel.rbs +45 -0
  525. data/sig/herb/engine/scoped_style/collector.rbs +45 -0
  526. data/sig/herb/engine/scoped_style/visitor.rbs +220 -0
  527. data/sig/herb/engine/slots/annotation.rbs +72 -0
  528. data/sig/herb/engine/slots/bindings.rbs +34 -0
  529. data/sig/herb/engine/slots/callee.rbs +62 -0
  530. data/sig/herb/engine/slots/component_definitions.rbs +19 -0
  531. data/sig/herb/engine/slots/components/async.rbs +20 -0
  532. data/sig/herb/engine/slots/components/base.rbs +60 -0
  533. data/sig/herb/engine/slots/components/deferred.rbs +29 -0
  534. data/sig/herb/engine/slots/components/fallback.rbs +21 -0
  535. data/sig/herb/engine/slots/components/fragment.rbs +34 -0
  536. data/sig/herb/engine/slots/components/lazy.rbs +20 -0
  537. data/sig/herb/engine/slots/components.rbs +30 -0
  538. data/sig/herb/engine/slots/dependencies/channel.rbs +51 -0
  539. data/sig/herb/engine/slots/dependencies.rbs +94 -0
  540. data/sig/herb/engine/slots/dynamics_compiler.rbs +352 -0
  541. data/sig/herb/engine/slots/identifier.rbs +19 -0
  542. data/sig/herb/engine/slots/manifest/channel.rbs +49 -0
  543. data/sig/herb/engine/slots/manifest/collector.rbs +45 -0
  544. data/sig/herb/engine/slots/markers.rbs +99 -0
  545. data/sig/herb/engine/slots/render_bindings.rbs +69 -0
  546. data/sig/herb/engine/slots/schema_compiler.rbs +62 -0
  547. data/sig/herb/engine/slots/state_anchor.rbs +41 -0
  548. data/sig/herb/engine/slots/state_compiler.rbs +258 -0
  549. data/sig/herb/engine/slots/state_directives.rbs +278 -0
  550. data/sig/herb/engine/slots/state_kinds.rbs +24 -0
  551. data/sig/herb/engine/slots/state_operators.rbs +19 -0
  552. data/sig/herb/engine/slots/state_overrides.rbs +33 -0
  553. data/sig/herb/engine/slots/state_predicates.rbs +16 -0
  554. data/sig/herb/engine/slots/state_transforms.rbs +15 -0
  555. data/sig/herb/engine/slots/statics.rbs +67 -0
  556. data/sig/herb/engine/slots/subtree.rbs +49 -0
  557. data/sig/herb/engine/slots/subtree_compiler.rbs +130 -0
  558. data/sig/herb/engine/slots/types.rbs +46 -0
  559. data/sig/herb/engine/slots/visitor.rbs +603 -0
  560. data/sig/herb/engine/validators/accessibility_validator.rbs +1 -1
  561. data/sig/herb/engine/validators/base.rbs +28 -0
  562. data/sig/herb/engine/validators/generator_template_validator.rbs +19 -0
  563. data/sig/herb/engine/validators/nesting_validator.rbs +1 -1
  564. data/sig/herb/engine/validators/render_validator.rbs +2 -6
  565. data/sig/herb/engine/validators/security_validator.rbs +1 -3
  566. data/sig/herb/engine/validators.rbs +21 -0
  567. data/sig/herb/engine/visitors/auto_close_omitted_tags_visitor.rbs +26 -0
  568. data/sig/herb/engine/visitors/content_for_visitor.rbs +52 -0
  569. data/sig/herb/engine/{debug_visitor.rbs → visitors/debug_visitor.rbs} +26 -15
  570. data/sig/herb/engine/visitors/html_safe_assertions_visitor.rbs +100 -0
  571. data/sig/herb/engine/visitors/instrumentation_visitor.rbs +111 -0
  572. data/sig/herb/engine/visitors/optimize_visitor.rbs +246 -0
  573. data/sig/herb/engine/visitors/remove_comments_visitor.rbs +66 -0
  574. data/sig/herb/engine/visitors/source_attribution_visitor.rbs +90 -0
  575. data/sig/herb/engine.rbs +47 -41
  576. data/sig/herb/ensure_installed.rbs +9 -0
  577. data/sig/herb/errors.rbs +311 -0
  578. data/sig/herb/fingerprint.rbs +37 -0
  579. data/sig/herb/html/elements.rbs +19 -0
  580. data/sig/herb/html/util.rbs +15 -1
  581. data/sig/herb/lex_result.rbs +0 -6
  582. data/sig/herb/locate.rbs +89 -0
  583. data/sig/herb/location.rbs +12 -0
  584. data/sig/herb/parse_result.rbs +10 -8
  585. data/sig/herb/parser_options.rbs +53 -19
  586. data/sig/herb/position.rbs +11 -0
  587. data/sig/herb/range.rbs +3 -0
  588. data/sig/herb/ruby_program.rbs +51 -0
  589. data/sig/herb/source_path.rbs +132 -0
  590. data/sig/herb/token.rbs +5 -2
  591. data/sig/herb/visitor/context/origin.rbs +51 -0
  592. data/sig/herb/visitor/context/replacements.rbs +39 -0
  593. data/sig/herb/visitor/context.rbs +83 -0
  594. data/sig/herb/visitor/context_aware.rbs +32 -0
  595. data/sig/herb/visitor/diagnostics.rbs +82 -0
  596. data/sig/herb/visitor/experimental.rbs +23 -0
  597. data/sig/herb/visitor/parser_option_requirements.rbs +76 -0
  598. data/sig/herb/visitor/stack.rbs +91 -0
  599. data/sig/herb/visitor.rbs +22 -0
  600. data/sig/herb/warnings.rbs +10 -0
  601. data/sig/herb.rbs +27 -10
  602. data/sig/manifest.yaml +13 -0
  603. data/sig/serialized_ast_errors.rbs +62 -1
  604. data/sig/serialized_ast_nodes.rbs +59 -2
  605. data/src/analyze/action_view/attribute_extraction_helpers.c +73 -36
  606. data/src/analyze/action_view/generated_handlers.c +37 -1
  607. data/src/analyze/action_view/generated_handlers.h +2 -1
  608. data/src/analyze/action_view/helper_registry.c +1353 -58
  609. data/src/analyze/action_view/registry.c +10 -17
  610. data/src/analyze/action_view/stylesheet_link_tag.c +40 -0
  611. data/src/analyze/action_view/tag_helper_node_builders.c +63 -3
  612. data/src/analyze/action_view/tag_helpers.c +502 -111
  613. data/src/analyze/analyze.c +306 -89
  614. data/src/analyze/analyze_helpers.c +502 -237
  615. data/src/analyze/analyzed_ruby.c +2 -0
  616. data/src/analyze/builders.c +80 -51
  617. data/src/analyze/conditional_elements.c +13 -8
  618. data/src/analyze/conditional_open_tags.c +11 -5
  619. data/src/analyze/control_type.c +36 -13
  620. data/src/analyze/herb_directives.c +701 -0
  621. data/src/analyze/invalid_structures.c +11 -7
  622. data/src/analyze/iteration_nodes.c +306 -0
  623. data/src/analyze/missing_end.c +116 -32
  624. data/src/analyze/parse_errors.c +8 -3
  625. data/src/analyze/postfix_conditionals.c +98 -63
  626. data/src/analyze/prism_annotate.c +45 -13
  627. data/src/analyze/render_nodes.c +348 -123
  628. data/src/analyze/strict_locals.c +30 -26
  629. data/src/analyze/ternary_conditionals.c +95 -70
  630. data/src/analyze/transform.c +43 -1
  631. data/src/ast/ast_node.c +3 -13
  632. data/src/ast/ast_nodes.c +914 -113
  633. data/src/ast/ast_pretty_print.c +166 -3
  634. data/src/diff/herb_diff.c +8 -0
  635. data/src/diff/herb_diff_attributes.c +1 -0
  636. data/src/diff/herb_diff_children.c +4 -3
  637. data/src/diff/herb_diff_helpers.c +7 -1
  638. data/src/diff/herb_diff_nodes.c +186 -71
  639. data/src/diff/herb_hash_tree.c +99 -1
  640. data/src/errors.c +1124 -105
  641. data/src/extract.c +227 -144
  642. data/src/herb.c +43 -8
  643. data/src/include/analyze/action_view/attribute_extraction_helpers.h +1 -1
  644. data/src/include/analyze/action_view/helper_registry.h +28 -4
  645. data/src/include/analyze/action_view/tag_helper_handler.h +1 -1
  646. data/src/include/analyze/action_view/tag_helper_node_builders.h +7 -0
  647. data/src/include/analyze/analyze.h +11 -22
  648. data/src/include/analyze/analyzed_ruby.h +25 -0
  649. data/src/include/analyze/builders.h +16 -0
  650. data/src/include/analyze/helpers.h +25 -24
  651. data/src/include/analyze/herb_directive_kinds.h +41 -0
  652. data/src/include/analyze/herb_directives.h +14 -0
  653. data/src/include/analyze/iteration_nodes.h +11 -0
  654. data/src/include/analyze/prism_annotate.h +3 -3
  655. data/src/include/analyze/ternary_conditionals.h +2 -0
  656. data/src/include/ast/ast_node.h +1 -5
  657. data/src/include/ast/ast_nodes.h +78 -3
  658. data/src/include/ast/ast_pretty_print.h +1 -1
  659. data/src/include/diff/herb_diff.h +11 -0
  660. data/src/include/errors.h +163 -38
  661. data/src/include/extract.h +11 -0
  662. data/src/include/herb.h +6 -0
  663. data/src/include/lexer/erb_openers.h +29 -0
  664. data/src/include/lexer/lexer.h +1 -0
  665. data/src/include/lexer/lexer_peek_helpers.h +8 -1
  666. data/src/include/lexer/lexer_struct.h +4 -0
  667. data/src/include/lexer/token.h +5 -0
  668. data/src/include/lexer/token_struct.h +8 -6
  669. data/src/include/lib/hb_allocator.h +2 -1
  670. data/src/include/lib/hb_array.h +2 -0
  671. data/src/include/lib/hb_clock.h +15 -0
  672. data/src/include/lib/hb_foreach.h +1 -1
  673. data/src/include/lib/hb_string.h +7 -0
  674. data/src/include/parser/dot_notation.h +1 -1
  675. data/src/include/parser/foreign_content_elements.h +32 -0
  676. data/src/include/parser/parser.h +40 -26
  677. data/src/include/parser/parser_helpers.h +13 -11
  678. data/src/include/parser/parser_options.h +41 -0
  679. data/src/include/prism/herb_prism_node.h +6 -1
  680. data/src/include/prism/ruby_parser.h +6 -0
  681. data/src/include/util/html_elements.h +85 -0
  682. data/src/include/util/html_util.h +1 -0
  683. data/src/include/version.h +1 -1
  684. data/src/lexer/lexer_peek_helpers.c +15 -1
  685. data/src/lexer/token.c +89 -1
  686. data/src/lexer.c +228 -12
  687. data/src/lib/hb_allocator.c +2 -0
  688. data/src/lib/hb_array.c +26 -0
  689. data/src/lib/hb_string.c +26 -0
  690. data/src/main.c +1 -1
  691. data/src/parser/dot_notation.c +4 -3
  692. data/src/parser/match_tags.c +66 -1
  693. data/src/parser/parser_helpers.c +69 -37
  694. data/src/parser.c +658 -385
  695. data/src/parser_options_defaults.c +30 -0
  696. data/src/prism/prism_helpers.c +94 -0
  697. data/src/prism/ruby_parser.c +49 -0
  698. data/src/util/html_util.c +11 -58
  699. data/src/visitor.c +77 -1
  700. data/templates/ext/herb/error_helpers.c.erb +1 -1
  701. data/templates/ext/herb/nodes.c.erb +19 -14
  702. data/templates/ext/herb/nodes.h.erb +2 -1
  703. data/templates/ext/herb/parser_options_helpers.c.erb +69 -0
  704. data/templates/ext/herb/parser_options_helpers.h.erb +11 -0
  705. data/templates/java/nodes.c.erb +21 -17
  706. data/templates/java/nodes.h.erb +3 -2
  707. data/templates/java/org/herb/ParserOptions.java.erb +24 -0
  708. data/templates/java/org/herb/ast/HelperRegistry.java.erb +67 -31
  709. data/templates/java/org/herb/ast/HelperType.java.erb +29 -0
  710. data/templates/java/org/herb/ast/Nodes.java.erb +11 -7
  711. data/templates/java/parser_options_helpers.c.erb +45 -0
  712. data/templates/java/parser_options_helpers.h.erb +10 -0
  713. data/templates/javascript/packages/client/src/state-kinds.ts.erb +49 -0
  714. data/templates/javascript/packages/client/src/state-operators.ts.erb +15 -0
  715. data/templates/javascript/packages/client/src/state-predicates.ts.erb +27 -0
  716. data/templates/javascript/packages/client/src/state-transforms.ts.erb +19 -0
  717. data/templates/javascript/packages/core/src/action-view-helpers.ts.erb +47 -0
  718. data/templates/javascript/packages/core/src/built-in-components.ts.erb +67 -0
  719. data/templates/javascript/packages/core/src/errors.ts.erb +9 -3
  720. data/templates/javascript/packages/core/src/foreign-content-elements.ts.erb +18 -0
  721. data/templates/javascript/packages/core/src/html-constants.ts.erb +32 -0
  722. data/templates/javascript/packages/core/src/html-elements.ts.erb +41 -0
  723. data/templates/javascript/packages/core/src/node-type-guards.ts.erb +11 -7
  724. data/templates/javascript/packages/core/src/nodes.ts.erb +103 -20
  725. data/templates/javascript/packages/core/src/parser-options.ts.erb +41 -0
  726. data/templates/javascript/packages/core/src/visitor.ts.erb +1 -1
  727. data/templates/javascript/packages/node/extension/error_helpers.cpp.erb +3 -3
  728. data/templates/javascript/packages/node/extension/nodes.cpp.erb +18 -13
  729. data/templates/javascript/packages/node/extension/nodes.h.erb +3 -3
  730. data/templates/javascript/packages/node/extension/parser_options_helpers.cpp.erb +41 -0
  731. data/templates/javascript/packages/node/extension/parser_options_helpers.h.erb +12 -0
  732. data/templates/lib/herb/action_view/helper_registry.rb.erb +77 -3
  733. data/templates/lib/herb/ast/nodes.rb.erb +16 -6
  734. data/templates/lib/herb/engine/slots/component_definitions.rb.erb +38 -0
  735. data/templates/lib/herb/engine/slots/state_kinds.rb.erb +37 -0
  736. data/templates/lib/herb/engine/slots/state_operators.rb.erb +26 -0
  737. data/templates/lib/herb/engine/slots/state_predicates.rb.erb +39 -0
  738. data/templates/lib/herb/engine/slots/state_transforms.rb.erb +27 -0
  739. data/templates/lib/herb/errors.rb.erb +34 -6
  740. data/templates/lib/herb/html/elements.rb.erb +12 -0
  741. data/templates/lib/herb/parser_options.rb.erb +32 -0
  742. data/templates/lib/herb/visitor.rb.erb +7 -1
  743. data/templates/rust/herb-printer/src/printer_visitor.rs.erb +14 -0
  744. data/templates/rust/src/action_view_helpers.rs.erb +38 -0
  745. data/templates/rust/src/ast/nodes.rs.erb +21 -31
  746. data/templates/rust/src/errors.rs.erb +1 -1
  747. data/templates/rust/src/nodes.rs.erb +58 -26
  748. data/templates/rust/src/parser_options.rs.erb +16 -0
  749. data/templates/rust/src/prism/generated_deserialize.rs.erb +109 -0
  750. data/templates/rust/src/prism/generated_prettyprint.rs.erb +153 -0
  751. data/templates/rust/src/union_types.rs.erb +7 -1
  752. data/templates/rust/src/visitor.rs.erb +1 -1
  753. data/templates/src/analyze/action_view/helper_registry.c.erb +22 -0
  754. data/templates/src/analyze/missing_end.c.erb +13 -5
  755. data/templates/src/ast/ast_nodes.c.erb +41 -2
  756. data/templates/src/diff/herb_diff_nodes.c.erb +44 -8
  757. data/templates/src/errors.c.erb +8 -3
  758. data/templates/src/include/analyze/action_view/helper_registry.h.erb +19 -0
  759. data/templates/src/include/analyze/herb_directive_kinds.h.erb +25 -0
  760. data/templates/src/include/errors.h.erb +3 -1
  761. data/templates/src/include/parser/foreign_content_elements.h.erb +23 -0
  762. data/templates/src/include/parser/parser_options.h.erb +21 -0
  763. data/templates/src/include/util/html_elements.h.erb +28 -0
  764. data/templates/src/parser_options_defaults.c.erb +9 -0
  765. data/templates/template.rb +564 -9
  766. data/templates/wasm/error_helpers.cpp.erb +4 -4
  767. data/templates/wasm/nodes.cpp.erb +17 -27
  768. data/templates/wasm/nodes.h.erb +3 -3
  769. data/templates/wasm/parser_options_helpers.cpp.erb +25 -0
  770. data/templates/wasm/parser_options_helpers.h.erb +12 -0
  771. metadata +309 -30
  772. data/config/action_view_helpers/actionview/form_helper/button.yml +0 -38
  773. data/config/action_view_helpers/actionview/form_helper/submit.yml +0 -35
  774. data/lib/herb/ast.rb +0 -7
  775. data/lib/herb/diff_operation.rb +0 -34
  776. data/lib/herb/diff_result.rb +0 -59
  777. data/lib/herb/engine/error_formatter.rb +0 -432
  778. data/lib/herb/engine/parser_error_overlay.rb +0 -771
  779. data/lib/herb/engine/validation_error_overlay.rb +0 -182
  780. data/lib/herb/engine/validation_errors.rb +0 -65
  781. data/lib/herb/engine/validator.rb +0 -80
  782. data/sig/herb/ast.rbs +0 -6
  783. data/sig/herb/diff_operation.rbs +0 -34
  784. data/sig/herb/diff_result.rbs +0 -34
  785. data/sig/herb/engine/debug.rbs +0 -38
  786. data/sig/herb/engine/error_formatter.rbs +0 -47
  787. data/sig/herb/engine/parser_error_overlay.rbs +0 -41
  788. data/sig/herb/engine/validation_error_overlay.rbs +0 -35
  789. data/sig/herb/engine/validation_errors.rbs +0 -45
  790. data/sig/herb/engine/validator.rbs +0 -41
  791. data/sig/herb_c_extension.rbs +0 -10
  792. data/sig/vendor/did_you_mean.rbs +0 -6
  793. data/sig/vendor/parallel.rbs +0 -4
@@ -7,6 +7,7 @@
7
7
  #include "../include/analyze/analyzed_ruby.h"
8
8
  #include "../include/analyze/helpers.h"
9
9
  #include "../include/ast/ast_nodes.h"
10
+ #include "../include/lexer/token.h"
10
11
  #include "../include/lib/hb_array.h"
11
12
  #include "../include/lib/string.h"
12
13
  #include "../include/prism/prism_helpers.h"
@@ -92,321 +93,313 @@ bool has_inline_case_condition(analyzed_ruby_T* analyzed) {
92
93
  || (has_case_match_node(analyzed) && has_in_node(analyzed));
93
94
  }
94
95
 
95
- bool has_error_message(analyzed_ruby_T* analyzed, const char* message) {
96
- for (const pm_diagnostic_t* error = (const pm_diagnostic_t*) analyzed->parser.error_list.head; error != NULL;
97
- error = (const pm_diagnostic_t*) error->node.next) {
98
- if (string_equals(error->message, message)) { return true; }
99
- }
96
+ typedef struct {
97
+ const uint8_t* source_start;
98
+ uint32_t offset;
99
+ bool found;
100
+ } inline_condition_offset_T;
100
101
 
101
- return false;
102
- }
103
-
104
- bool search_if_nodes(const pm_node_t* node, void* data) {
105
- analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
102
+ static bool search_inline_condition_offset(const pm_node_t* node, void* data) {
103
+ inline_condition_offset_T* context = (inline_condition_offset_T*) data;
106
104
 
107
- if (node->type == PM_IF_NODE) {
108
- const pm_if_node_t* if_node = (const pm_if_node_t*) node;
105
+ uint32_t keyword_offset = UINT32_MAX;
109
106
 
110
- bool has_if_keyword = if_node->if_keyword_loc.start != NULL && if_node->if_keyword_loc.end != NULL;
111
- bool has_end_keyword = if_node->end_keyword_loc.start != NULL && if_node->end_keyword_loc.end != NULL;
112
-
113
- if (has_if_keyword && has_end_keyword) { analyzed->if_node_count++; }
107
+ if (node->type == PM_WHEN_NODE) {
108
+ keyword_offset = (uint32_t) (((const pm_when_node_t*) node)->keyword_loc.start - context->source_start);
109
+ } else if (node->type == PM_IN_NODE) {
110
+ keyword_offset = (uint32_t) (((const pm_in_node_t*) node)->in_loc.start - context->source_start);
111
+ } else if (node->type == PM_MATCH_PREDICATE_NODE) {
112
+ keyword_offset = (uint32_t) (((const pm_match_predicate_node_t*) node)->operator_loc.start - context->source_start);
114
113
  }
115
114
 
116
- pm_visit_child_nodes(node, search_if_nodes, analyzed);
117
-
118
- return false;
119
- }
120
-
121
- bool is_do_block(pm_location_t opening_location) {
122
- size_t length = opening_location.end - opening_location.start;
123
-
124
- return length == 2 && opening_location.start[0] == 'd' && opening_location.start[1] == 'o';
125
- }
126
-
127
- bool is_brace_block(pm_location_t opening_location) {
128
- size_t length = opening_location.end - opening_location.start;
129
-
130
- return length == 1 && opening_location.start[0] == '{';
131
- }
132
-
133
- static bool has_location(pm_location_t location) {
134
- return location.start != NULL && location.end != NULL && (location.end - location.start) > 0;
135
- }
136
-
137
- static bool is_end_keyword(pm_location_t location) {
138
- if (location.start == NULL || location.end == NULL) { return false; }
139
-
140
- size_t length = location.end - location.start;
141
-
142
- return length == 3 && location.start[0] == 'e' && location.start[1] == 'n' && location.start[2] == 'd';
143
- }
144
-
145
- bool is_closing_brace(pm_location_t location) {
146
- if (location.start == NULL || location.end == NULL) { return false; }
147
-
148
- size_t length = location.end - location.start;
149
-
150
- return length == 1 && location.start[0] == '}';
151
- }
152
-
153
- bool has_valid_block_closing(pm_location_t opening_loc, pm_location_t closing_loc) {
154
- if (is_do_block(opening_loc)) {
155
- return is_end_keyword(closing_loc);
156
- } else if (is_brace_block(opening_loc)) {
157
- return is_closing_brace(closing_loc);
115
+ if (keyword_offset != UINT32_MAX && (!context->found || keyword_offset < context->offset)) {
116
+ context->offset = keyword_offset;
117
+ context->found = true;
158
118
  }
159
119
 
120
+ pm_visit_child_nodes(node, search_inline_condition_offset, context);
121
+
160
122
  return false;
161
123
  }
162
124
 
163
- bool search_block_nodes(const pm_node_t* node, void* data) {
164
- analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
125
+ static hb_string_T control_continuation_keywords[] = HB_STRING_LIST("else", "elsif", "when", "in", "rescue", "ensure");
126
+ static hb_string_T control_terminator_keywords[] = HB_STRING_LIST("end", "}");
165
127
 
166
- if (node->type == PM_BLOCK_NODE) {
167
- pm_block_node_t* block_node = (pm_block_node_t*) node;
168
-
169
- bool has_opening = is_do_block(block_node->opening_loc) || is_brace_block(block_node->opening_loc);
170
- bool is_unclosed = !has_valid_block_closing(block_node->opening_loc, block_node->closing_loc);
171
-
172
- if (has_opening && is_unclosed) { analyzed->block_node_count++; }
173
- }
174
-
175
- if (node->type == PM_LAMBDA_NODE) {
176
- pm_lambda_node_t* lambda_node = (pm_lambda_node_t*) node;
177
-
178
- bool has_opening = is_do_block(lambda_node->opening_loc) || is_brace_block(lambda_node->opening_loc);
179
- bool is_unclosed = !has_valid_block_closing(lambda_node->opening_loc, lambda_node->closing_loc);
180
-
181
- if (has_opening && is_unclosed) { analyzed->block_node_count++; }
128
+ static bool matches_keyword(hb_string_T keyword, const hb_string_T* keywords, size_t count) {
129
+ for (size_t index = 0; index < count; index++) {
130
+ if (hb_string_equals(keyword, keywords[index])) { return true; }
182
131
  }
183
132
 
184
- pm_visit_child_nodes(node, search_block_nodes, analyzed);
185
-
186
133
  return false;
187
134
  }
188
135
 
189
- bool search_case_nodes(const pm_node_t* node, void* data) {
190
- analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
191
-
192
- if (node->type == PM_CASE_NODE) { analyzed->case_node_count++; }
193
-
194
- pm_visit_child_nodes(node, search_case_nodes, analyzed);
195
-
196
- return false;
136
+ static bool is_control_continuation_keyword(hb_string_T keyword) {
137
+ return matches_keyword(
138
+ keyword,
139
+ control_continuation_keywords,
140
+ sizeof(control_continuation_keywords) / sizeof(control_continuation_keywords[0])
141
+ );
197
142
  }
198
143
 
199
- bool search_case_match_nodes(const pm_node_t* node, void* data) {
200
- analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
201
-
202
- if (node->type == PM_CASE_MATCH_NODE) { analyzed->case_match_node_count++; }
203
-
204
- pm_visit_child_nodes(node, search_case_match_nodes, analyzed);
205
-
206
- return false;
144
+ static bool is_control_role_keyword(hb_string_T keyword) {
145
+ return is_control_continuation_keyword(keyword)
146
+ || matches_keyword(
147
+ keyword,
148
+ control_terminator_keywords,
149
+ sizeof(control_terminator_keywords) / sizeof(control_terminator_keywords[0])
150
+ );
207
151
  }
208
152
 
209
- bool search_while_nodes(const pm_node_t* node, void* data) {
210
- analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
153
+ bool control_role_split_offset(const analyzed_ruby_T* analyzed, uint32_t* offset) {
154
+ if (!analyzed || !offset) { return false; }
211
155
 
212
- if (node->type == PM_WHILE_NODE) { analyzed->while_node_count++; }
156
+ uint32_t first = UINT32_MAX;
157
+ uint32_t second = UINT32_MAX;
158
+ bool first_continues = false;
213
159
 
214
- pm_visit_child_nodes(node, search_while_nodes, analyzed);
160
+ for (const pm_diagnostic_t* diagnostic = (const pm_diagnostic_t*) analyzed->parser.error_list.head;
161
+ diagnostic != NULL;
162
+ diagnostic = (const pm_diagnostic_t*) diagnostic->node.next) {
163
+ if (diagnostic->diag_id != PM_ERR_UNEXPECTED_TOKEN_IGNORE) { continue; }
215
164
 
216
- return false;
217
- }
218
-
219
- bool search_for_nodes(const pm_node_t* node, void* data) {
220
- analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
221
-
222
- if (node->type == PM_FOR_NODE) { analyzed->for_node_count++; }
165
+ hb_string_T keyword = hb_string_from_data(
166
+ (const char*) diagnostic->location.start,
167
+ (size_t) (diagnostic->location.end - diagnostic->location.start)
168
+ );
223
169
 
224
- pm_visit_child_nodes(node, search_for_nodes, analyzed);
170
+ if (!is_control_role_keyword(keyword)) { continue; }
225
171
 
226
- return false;
227
- }
172
+ uint32_t start = (uint32_t) (diagnostic->location.start - analyzed->parser.start);
228
173
 
229
- bool search_until_nodes(const pm_node_t* node, void* data) {
230
- analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
174
+ if (start < first) {
175
+ second = first;
176
+ first = start;
177
+ first_continues = is_control_continuation_keyword(keyword);
178
+ } else if (start < second) {
179
+ second = start;
180
+ }
181
+ }
231
182
 
232
- if (node->type == PM_UNTIL_NODE) { analyzed->until_node_count++; }
183
+ if (second == UINT32_MAX) { return false; }
184
+ if (!first_continues) { return false; }
233
185
 
234
- pm_visit_child_nodes(node, search_until_nodes, analyzed);
186
+ *offset = second;
235
187
 
236
- return false;
188
+ return true;
237
189
  }
238
190
 
239
- bool search_begin_nodes(const pm_node_t* node, void* data) {
240
- analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
191
+ bool has_inline_pattern_match(analyzed_ruby_T* analyzed, hb_string_T content) {
192
+ if (!has_case_match_node(analyzed) || !has_in_node(analyzed)) { return false; }
241
193
 
242
- if (node->type == PM_BEGIN_NODE) { analyzed->begin_node_count++; }
194
+ uint32_t offset = 0;
243
195
 
244
- pm_visit_child_nodes(node, search_begin_nodes, analyzed);
196
+ if (!inline_condition_keyword_offset(analyzed, &offset)) { return false; }
197
+ if (offset > content.length) { return false; }
245
198
 
246
- return false;
199
+ return memchr(content.data, '\n', offset) == NULL;
247
200
  }
248
201
 
249
- bool search_unless_nodes(const pm_node_t* node, void* data) {
250
- analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
202
+ bool inline_condition_keyword_offset(const analyzed_ruby_T* analyzed, uint32_t* offset) {
203
+ if (!analyzed || !analyzed->root || !offset) { return false; }
251
204
 
252
- if (node->type == PM_UNLESS_NODE) {
253
- const pm_unless_node_t* unless_node = (const pm_unless_node_t*) node;
205
+ inline_condition_offset_T context = {
206
+ .source_start = analyzed->parser.start,
207
+ .offset = UINT32_MAX,
208
+ .found = false,
209
+ };
254
210
 
255
- bool has_if_keyword = unless_node->keyword_loc.start != NULL && unless_node->keyword_loc.end != NULL;
256
- bool has_end_keyword = unless_node->end_keyword_loc.start != NULL && unless_node->end_keyword_loc.end != NULL;
211
+ pm_visit_node(analyzed->root, search_inline_condition_offset, &context);
257
212
 
258
- if (has_if_keyword && has_end_keyword) { analyzed->unless_node_count++; }
259
- }
213
+ if (!context.found) { return false; }
260
214
 
261
- pm_visit_child_nodes(node, search_unless_nodes, analyzed);
215
+ *offset = context.offset;
262
216
 
263
- return false;
217
+ return true;
264
218
  }
265
219
 
266
- bool search_when_nodes(const pm_node_t* node, void* data) {
267
- analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
268
-
269
- if (node->type == PM_WHEN_NODE) { analyzed->when_node_count++; }
270
-
271
- pm_visit_child_nodes(node, search_when_nodes, analyzed);
220
+ bool has_error_message(analyzed_ruby_T* analyzed, const char* message) {
221
+ for (const pm_diagnostic_t* error = (const pm_diagnostic_t*) analyzed->parser.error_list.head; error != NULL;
222
+ error = (const pm_diagnostic_t*) error->node.next) {
223
+ if (string_equals(error->message, message)) { return true; }
224
+ }
272
225
 
273
226
  return false;
274
227
  }
275
228
 
276
- bool search_in_nodes(const pm_node_t* node, void* data) {
277
- analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
278
-
279
- if (node->type == PM_IN_NODE) { analyzed->in_node_count++; }
280
- if (node->type == PM_MATCH_PREDICATE_NODE) { analyzed->in_node_count++; }
281
-
282
- pm_visit_child_nodes(node, search_in_nodes, analyzed);
229
+ bool is_do_block(pm_location_t opening_location) {
230
+ size_t length = opening_location.end - opening_location.start;
283
231
 
284
- return false;
232
+ return length == 2 && opening_location.start[0] == 'd' && opening_location.start[1] == 'o';
285
233
  }
286
234
 
287
- bool search_unexpected_elsif_nodes(analyzed_ruby_T* analyzed) {
288
- if (has_error_message(analyzed, "unexpected 'elsif', ignoring it")) {
289
- analyzed->elsif_node_count++;
290
- return true;
291
- }
235
+ bool is_brace_block(pm_location_t opening_location) {
236
+ size_t length = opening_location.end - opening_location.start;
292
237
 
293
- return false;
238
+ return length == 1 && opening_location.start[0] == '{';
294
239
  }
295
240
 
296
- bool search_unexpected_else_nodes(analyzed_ruby_T* analyzed) {
297
- if (has_error_message(analyzed, "unexpected 'else', ignoring it")) {
298
- analyzed->else_node_count++;
299
- return true;
300
- }
301
-
302
- return false;
241
+ static bool has_location(pm_location_t location) {
242
+ return location.start != NULL && location.end != NULL && (location.end - location.start) > 0;
303
243
  }
304
244
 
305
- bool search_unexpected_end_nodes(analyzed_ruby_T* analyzed) {
306
- if (has_error_message(analyzed, "unexpected 'end', ignoring it")) {
307
- if (has_error_message(analyzed, "unexpected '=', ignoring it")) {
308
- // `=end`
309
- return false;
310
- }
311
-
312
- analyzed->end_count++;
313
- return true;
314
- }
315
-
316
- return false;
317
- }
245
+ static bool is_end_keyword(pm_location_t location) {
246
+ if (location.start == NULL || location.end == NULL) { return false; }
318
247
 
319
- bool search_unexpected_block_closing_nodes(analyzed_ruby_T* analyzed) {
320
- if (has_error_message(analyzed, "unexpected '}', ignoring it")) {
321
- analyzed->block_closing_count++;
322
- return true;
323
- }
248
+ size_t length = location.end - location.start;
324
249
 
325
- return false;
250
+ return length == 3 && location.start[0] == 'e' && location.start[1] == 'n' && location.start[2] == 'd';
326
251
  }
327
252
 
328
- bool search_unexpected_when_nodes(analyzed_ruby_T* analyzed) {
329
- if (has_error_message(analyzed, "unexpected 'when', ignoring it")) {
330
- analyzed->when_node_count++;
331
- return true;
332
- }
333
-
334
- return false;
335
- }
253
+ bool is_closing_brace(pm_location_t location) {
254
+ if (location.start == NULL || location.end == NULL) { return false; }
336
255
 
337
- bool search_unexpected_in_nodes(analyzed_ruby_T* analyzed) {
338
- if (has_error_message(analyzed, "unexpected 'in', ignoring it")) {
339
- analyzed->in_node_count++;
340
- return true;
341
- }
256
+ size_t length = location.end - location.start;
342
257
 
343
- return false;
258
+ return length == 1 && location.start[0] == '}';
344
259
  }
345
260
 
346
- bool search_unexpected_rescue_nodes(analyzed_ruby_T* analyzed) {
347
- if (has_error_message(analyzed, "unexpected 'rescue', ignoring it")) {
348
- analyzed->rescue_node_count++;
349
- return true;
261
+ bool has_valid_block_closing(pm_location_t opening_loc, pm_location_t closing_loc) {
262
+ if (is_do_block(opening_loc)) {
263
+ return is_end_keyword(closing_loc);
264
+ } else if (is_brace_block(opening_loc)) {
265
+ return is_closing_brace(closing_loc);
350
266
  }
351
267
 
352
268
  return false;
353
269
  }
354
270
 
355
- bool search_unexpected_ensure_nodes(analyzed_ruby_T* analyzed) {
356
- if (has_error_message(analyzed, "unexpected 'ensure', ignoring it")) {
357
- analyzed->ensure_node_count++;
358
- return true;
359
- }
360
-
361
- return false;
271
+ static bool has_keyword_location(pm_location_t location) {
272
+ return location.start != NULL && location.end != NULL;
362
273
  }
363
274
 
364
- bool search_yield_nodes(const pm_node_t* node, void* data) {
365
- analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
366
-
367
- if (node->type == PM_YIELD_NODE) { analyzed->yield_node_count++; }
275
+ static bool is_unclosed_block(pm_location_t opening_loc, pm_location_t closing_loc) {
276
+ bool has_opening = is_do_block(opening_loc) || is_brace_block(opening_loc);
368
277
 
369
- pm_visit_child_nodes(node, search_yield_nodes, analyzed);
370
-
371
- return false;
278
+ return has_opening && !has_valid_block_closing(opening_loc, closing_loc);
372
279
  }
373
280
 
374
- bool search_then_keywords(const pm_node_t* node, void* data) {
281
+ bool search_control_flow_nodes(const pm_node_t* node, void* data) {
375
282
  analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
376
283
 
377
284
  switch (node->type) {
378
285
  case PM_IF_NODE: {
379
286
  const pm_if_node_t* if_node = (const pm_if_node_t*) node;
380
- if (if_node->then_keyword_loc.start != NULL && if_node->then_keyword_loc.end != NULL) {
381
- analyzed->then_keyword_count++;
287
+
288
+ if (has_keyword_location(if_node->if_keyword_loc) && has_keyword_location(if_node->end_keyword_loc)) {
289
+ analyzed->if_node_count++;
382
290
  }
291
+
292
+ if (has_keyword_location(if_node->then_keyword_loc)) { analyzed->then_keyword_count++; }
383
293
  break;
384
294
  }
385
295
 
386
296
  case PM_UNLESS_NODE: {
387
297
  const pm_unless_node_t* unless_node = (const pm_unless_node_t*) node;
388
- if (unless_node->then_keyword_loc.start != NULL && unless_node->then_keyword_loc.end != NULL) {
389
- analyzed->then_keyword_count++;
298
+
299
+ if (has_keyword_location(unless_node->keyword_loc) && has_keyword_location(unless_node->end_keyword_loc)) {
300
+ analyzed->unless_node_count++;
390
301
  }
302
+
303
+ if (has_keyword_location(unless_node->then_keyword_loc)) { analyzed->then_keyword_count++; }
391
304
  break;
392
305
  }
393
306
 
394
307
  case PM_WHEN_NODE: {
395
308
  const pm_when_node_t* when_node = (const pm_when_node_t*) node;
396
- if (when_node->then_keyword_loc.start != NULL && when_node->then_keyword_loc.end != NULL) {
397
- analyzed->then_keyword_count++;
309
+
310
+ analyzed->when_node_count++;
311
+
312
+ if (has_keyword_location(when_node->then_keyword_loc)) { analyzed->then_keyword_count++; }
313
+ break;
314
+ }
315
+
316
+ case PM_BLOCK_NODE: {
317
+ const pm_block_node_t* block_node = (const pm_block_node_t*) node;
318
+
319
+ if (is_unclosed_block(block_node->opening_loc, block_node->closing_loc)) { analyzed->block_node_count++; }
320
+ break;
321
+ }
322
+
323
+ case PM_LAMBDA_NODE: {
324
+ const pm_lambda_node_t* lambda_node = (const pm_lambda_node_t*) node;
325
+
326
+ if (is_unclosed_block(lambda_node->opening_loc, lambda_node->closing_loc)) { analyzed->block_node_count++; }
327
+ break;
328
+ }
329
+
330
+ case PM_CASE_MATCH_NODE: {
331
+ const pm_case_match_node_t* case_match_node = (const pm_case_match_node_t*) node;
332
+
333
+ analyzed->case_match_node_count++;
334
+
335
+ if (case_match_node->predicate != NULL && case_match_node->predicate->type == PM_MATCH_PREDICATE_NODE) {
336
+ analyzed->in_node_count++;
398
337
  }
399
338
  break;
400
339
  }
401
340
 
341
+ case PM_CASE_NODE: analyzed->case_node_count++; break;
342
+ case PM_IN_NODE: analyzed->in_node_count++; break;
343
+ case PM_WHILE_NODE: analyzed->while_node_count++; break;
344
+ case PM_FOR_NODE: analyzed->for_node_count++; break;
345
+ case PM_UNTIL_NODE: analyzed->until_node_count++; break;
346
+ case PM_BEGIN_NODE: analyzed->begin_node_count++; break;
347
+ case PM_YIELD_NODE: analyzed->yield_node_count++; break;
348
+
402
349
  default: break;
403
350
  }
404
351
 
405
- pm_visit_child_nodes(node, search_then_keywords, analyzed);
352
+ pm_visit_child_nodes(node, search_control_flow_nodes, analyzed);
406
353
 
407
354
  return false;
408
355
  }
409
356
 
357
+ void search_unexpected_keyword_errors(analyzed_ruby_T* analyzed) {
358
+ bool unexpected_elsif = false;
359
+ bool unexpected_else = false;
360
+ bool unexpected_end = false;
361
+ bool unexpected_equals = false;
362
+ bool unexpected_closing_brace = false;
363
+ bool unexpected_when = false;
364
+ bool unexpected_in = false;
365
+ bool unexpected_rescue = false;
366
+ bool unexpected_ensure = false;
367
+
368
+ for (const pm_diagnostic_t* error = (const pm_diagnostic_t*) analyzed->parser.error_list.head; error != NULL;
369
+ error = (const pm_diagnostic_t*) error->node.next) {
370
+ const char* message = error->message;
371
+
372
+ if (string_equals(message, "unexpected 'elsif', ignoring it")) {
373
+ unexpected_elsif = true;
374
+ } else if (string_equals(message, "unexpected 'else', ignoring it")) {
375
+ unexpected_else = true;
376
+ } else if (string_equals(message, "unexpected 'end', ignoring it")) {
377
+ unexpected_end = true;
378
+ } else if (string_equals(message, "unexpected '=', ignoring it")) {
379
+ unexpected_equals = true;
380
+ } else if (string_equals(message, "unexpected '}', ignoring it")) {
381
+ unexpected_closing_brace = true;
382
+ } else if (string_equals(message, "unexpected 'when', ignoring it")) {
383
+ unexpected_when = true;
384
+ } else if (string_equals(message, "unexpected 'in', ignoring it")) {
385
+ unexpected_in = true;
386
+ } else if (string_equals(message, "unexpected 'rescue', ignoring it")) {
387
+ unexpected_rescue = true;
388
+ } else if (string_equals(message, "unexpected 'ensure', ignoring it")) {
389
+ unexpected_ensure = true;
390
+ }
391
+ }
392
+
393
+ if (unexpected_elsif) { analyzed->elsif_node_count++; }
394
+ if (unexpected_else) { analyzed->else_node_count++; }
395
+ if (unexpected_end && !unexpected_equals) { analyzed->end_count++; }
396
+ if (unexpected_when) { analyzed->when_node_count++; }
397
+ if (unexpected_in) { analyzed->in_node_count++; }
398
+ if (unexpected_rescue) { analyzed->rescue_node_count++; }
399
+ if (unexpected_ensure) { analyzed->ensure_node_count++; }
400
+ if (unexpected_closing_brace) { analyzed->block_closing_count++; }
401
+ }
402
+
410
403
  static bool is_postfix_conditional(const pm_statements_node_t* statements, pm_location_t keyword_location) {
411
404
  if (statements == NULL) { return false; }
412
405
 
@@ -610,6 +603,122 @@ static void append_parameter(
610
603
  );
611
604
  }
612
605
 
606
+ static void append_required_positional(
607
+ hb_array_T* result,
608
+ pm_node_t* node,
609
+ pm_parser_t* parser,
610
+ const char* source,
611
+ size_t source_base_offset,
612
+ const uint8_t* prism_source_start,
613
+ hb_allocator_T* allocator
614
+ );
615
+
616
+ static void append_multi_target_parameters(
617
+ hb_array_T* result,
618
+ pm_multi_target_node_t* multi_target,
619
+ pm_parser_t* parser,
620
+ const char* source,
621
+ size_t source_base_offset,
622
+ const uint8_t* prism_source_start,
623
+ hb_allocator_T* allocator
624
+ ) {
625
+ for (size_t index = 0; index < multi_target->lefts.size; index++) {
626
+ append_required_positional(
627
+ result,
628
+ multi_target->lefts.nodes[index],
629
+ parser,
630
+ source,
631
+ source_base_offset,
632
+ prism_source_start,
633
+ allocator
634
+ );
635
+ }
636
+
637
+ if (multi_target->rest && multi_target->rest->type == PM_SPLAT_NODE) {
638
+ pm_splat_node_t* splat = (pm_splat_node_t*) multi_target->rest;
639
+
640
+ if (splat->expression && splat->expression->type == PM_REQUIRED_PARAMETER_NODE) {
641
+ pm_required_parameter_node_t* required = (pm_required_parameter_node_t*) splat->expression;
642
+ pm_constant_t* constant = pm_constant_pool_id_to_constant(&parser->constant_pool, required->name);
643
+
644
+ if (constant) {
645
+ char* name = hb_allocator_strndup(allocator, (const char*) constant->start, constant->length);
646
+ pm_node_t* node = splat->expression;
647
+
648
+ append_parameter(
649
+ result,
650
+ create_parameter_name_token(node->location, name, prism_source_start, source_base_offset, source, allocator),
651
+ NULL,
652
+ "rest",
653
+ false,
654
+ prism_to_source_position(node->location.start, prism_source_start, source_base_offset, source),
655
+ prism_to_source_position(node->location.end, prism_source_start, source_base_offset, source),
656
+ allocator
657
+ );
658
+
659
+ hb_allocator_dealloc(allocator, name);
660
+ }
661
+ }
662
+ }
663
+
664
+ for (size_t index = 0; index < multi_target->rights.size; index++) {
665
+ append_required_positional(
666
+ result,
667
+ multi_target->rights.nodes[index],
668
+ parser,
669
+ source,
670
+ source_base_offset,
671
+ prism_source_start,
672
+ allocator
673
+ );
674
+ }
675
+ }
676
+
677
+ static void append_required_positional(
678
+ hb_array_T* result,
679
+ pm_node_t* node,
680
+ pm_parser_t* parser,
681
+ const char* source,
682
+ size_t source_base_offset,
683
+ const uint8_t* prism_source_start,
684
+ hb_allocator_T* allocator
685
+ ) {
686
+ if (node->type == PM_MULTI_TARGET_NODE) {
687
+ append_multi_target_parameters(
688
+ result,
689
+ (pm_multi_target_node_t*) node,
690
+ parser,
691
+ source,
692
+ source_base_offset,
693
+ prism_source_start,
694
+ allocator
695
+ );
696
+
697
+ return;
698
+ }
699
+
700
+ if (node->type != PM_REQUIRED_PARAMETER_NODE) { return; }
701
+
702
+ pm_required_parameter_node_t* required = (pm_required_parameter_node_t*) node;
703
+ pm_constant_t* constant = pm_constant_pool_id_to_constant(&parser->constant_pool, required->name);
704
+ if (!constant) { return; }
705
+
706
+ char* name = hb_allocator_strndup(allocator, (const char*) constant->start, constant->length);
707
+
708
+ append_parameter(
709
+ result,
710
+ create_parameter_name_token(node->location, name, prism_source_start, source_base_offset, source, allocator),
711
+ NULL,
712
+ "positional",
713
+ true,
714
+ prism_to_source_position(node->location.start, prism_source_start, source_base_offset, source),
715
+ prism_to_source_position(node->location.end, prism_source_start, source_base_offset, source),
716
+ allocator
717
+ );
718
+
719
+ hb_allocator_dealloc(allocator, name);
720
+ }
721
+
613
722
  hb_array_T* extract_parameters_from_prism(
614
723
  pm_parameters_node_t* parameters,
615
724
  pm_parser_t* parser,
@@ -627,31 +736,17 @@ hb_array_T* extract_parameters_from_prism(
627
736
 
628
737
  hb_array_T* result = hb_array_init(count, allocator);
629
738
 
630
- // Required positional: |item|
739
+ // Required positional: |item|, including destructured |(key, value)|
631
740
  for (size_t index = 0; index < parameters->requireds.size; index++) {
632
- pm_node_t* node = parameters->requireds.nodes[index];
633
- if (node->type != PM_REQUIRED_PARAMETER_NODE) { continue; }
634
-
635
- pm_required_parameter_node_t* required = (pm_required_parameter_node_t*) node;
636
- pm_constant_t* constant = pm_constant_pool_id_to_constant(&parser->constant_pool, required->name);
637
- if (!constant) { continue; }
638
-
639
- char* name = hb_allocator_strndup(allocator, (const char*) constant->start, constant->length);
640
- position_T start = prism_to_source_position(node->location.start, prism_source_start, source_base_offset, source);
641
- position_T end = prism_to_source_position(node->location.end, prism_source_start, source_base_offset, source);
642
-
643
- append_parameter(
741
+ append_required_positional(
644
742
  result,
645
- create_parameter_name_token(node->location, name, prism_source_start, source_base_offset, source, allocator),
646
- NULL,
647
- "positional",
648
- true,
649
- start,
650
- end,
743
+ parameters->requireds.nodes[index],
744
+ parser,
745
+ source,
746
+ source_base_offset,
747
+ prism_source_start,
651
748
  allocator
652
749
  );
653
-
654
- hb_allocator_dealloc(allocator, name);
655
750
  }
656
751
 
657
752
  // Optional positional: |item = nil|
@@ -725,9 +820,33 @@ hb_array_T* extract_parameters_from_prism(
725
820
  );
726
821
 
727
822
  hb_allocator_dealloc(allocator, name);
823
+ } else {
824
+ append_parameter(
825
+ result,
826
+ NULL,
827
+ NULL,
828
+ "rest",
829
+ false,
830
+ prism_to_source_position(parameters->rest->location.start, prism_source_start, source_base_offset, source),
831
+ prism_to_source_position(parameters->rest->location.end, prism_source_start, source_base_offset, source),
832
+ allocator
833
+ );
728
834
  }
729
835
  }
730
836
 
837
+ // Post-rest positional: the |last| in |item, *rest, last|
838
+ for (size_t index = 0; index < parameters->posts.size; index++) {
839
+ append_required_positional(
840
+ result,
841
+ parameters->posts.nodes[index],
842
+ parser,
843
+ source,
844
+ source_base_offset,
845
+ prism_source_start,
846
+ allocator
847
+ );
848
+ }
849
+
731
850
  // Keywords: |name:| or |title: "default"|
732
851
  for (size_t index = 0; index < parameters->keywords.size; index++) {
733
852
  pm_node_t* keyword = parameters->keywords.nodes[index];
@@ -874,6 +993,17 @@ hb_array_T* extract_parameters_from_prism(
874
993
  );
875
994
 
876
995
  hb_allocator_dealloc(allocator, name);
996
+ } else {
997
+ append_parameter(
998
+ result,
999
+ NULL,
1000
+ NULL,
1001
+ "block",
1002
+ false,
1003
+ prism_to_source_position(block_param->base.location.start, prism_source_start, source_base_offset, source),
1004
+ prism_to_source_position(block_param->base.location.end, prism_source_start, source_base_offset, source),
1005
+ allocator
1006
+ );
877
1007
  }
878
1008
  }
879
1009
 
@@ -883,7 +1013,7 @@ hb_array_T* extract_parameters_from_prism(
883
1013
  hb_array_T* extract_block_arguments_from_erb_node(
884
1014
  const AST_ERB_CONTENT_NODE_T* erb_node,
885
1015
  const char* source,
886
- hb_array_T* errors,
1016
+ hb_array_T** errors,
887
1017
  hb_allocator_T* allocator
888
1018
  ) {
889
1019
  if (!erb_node || !erb_node->analyzed_ruby || !erb_node->analyzed_ruby->parsed) { return hb_array_init(0, allocator); }
@@ -919,7 +1049,7 @@ hb_array_T* extract_block_arguments_from_erb_node(
919
1049
  RUBY_PARSE_ERROR_T* parse_error =
920
1050
  ruby_parse_error_from_prism_error_with_positions(error, error_start, error_end, allocator);
921
1051
 
922
- hb_array_append(errors, parse_error);
1052
+ hb_array_append_lazy(errors, parse_error, allocator);
923
1053
  }
924
1054
  }
925
1055
 
@@ -932,3 +1062,138 @@ hb_array_T* extract_block_arguments_from_erb_node(
932
1062
  allocator
933
1063
  );
934
1064
  }
1065
+
1066
+ bool is_erb_output_tag(const AST_ERB_CONTENT_NODE_T* erb_node) {
1067
+ if (!erb_node || !erb_node->tag_opening) { return false; }
1068
+
1069
+ hb_string_T opening = erb_node->tag_opening->value;
1070
+
1071
+ return opening.length >= 3 && opening.data[0] == '<' && opening.data[1] == '%' && opening.data[2] == '=';
1072
+ }
1073
+
1074
+ static bool is_escape_neutral(hb_string_T content) {
1075
+ for (uint32_t index = 0; index < content.length; index++) {
1076
+ switch (content.data[index]) {
1077
+ case '&':
1078
+ case '<':
1079
+ case '>':
1080
+ case '"':
1081
+ case '\'': return false;
1082
+
1083
+ default: break;
1084
+ }
1085
+ }
1086
+
1087
+ return true;
1088
+ }
1089
+
1090
+ static bool is_plain_decimal_integer(hb_string_T source) {
1091
+ uint32_t index = (source.length > 0 && source.data[0] == '-') ? 1 : 0;
1092
+
1093
+ if (index >= source.length) { return false; }
1094
+ if (source.data[index] == '0' && (source.length - index) > 1) { return false; }
1095
+
1096
+ for (uint32_t position = index; position < source.length; position++) {
1097
+ if (source.data[position] < '0' || source.data[position] > '9') { return false; }
1098
+ }
1099
+
1100
+ return true;
1101
+ }
1102
+
1103
+ static bool prism_node_static_output(const pm_node_t* node, hb_string_T* output) {
1104
+ if (!node || !output) { return false; }
1105
+
1106
+ switch (node->type) {
1107
+ case PM_STRING_NODE: {
1108
+ const pm_string_t* unescaped = &((const pm_string_node_t*) node)->unescaped;
1109
+
1110
+ *output = hb_string_from_data((const char*) pm_string_source(unescaped), pm_string_length(unescaped));
1111
+ break;
1112
+ }
1113
+
1114
+ case PM_SYMBOL_NODE: {
1115
+ const pm_string_t* unescaped = &((const pm_symbol_node_t*) node)->unescaped;
1116
+
1117
+ *output = hb_string_from_data((const char*) pm_string_source(unescaped), pm_string_length(unescaped));
1118
+ break;
1119
+ }
1120
+
1121
+ case PM_INTEGER_NODE: {
1122
+ hb_string_T source =
1123
+ hb_string_from_data((const char*) node->location.start, (size_t) (node->location.end - node->location.start));
1124
+
1125
+ if (!is_plain_decimal_integer(source)) { return false; }
1126
+
1127
+ *output = source;
1128
+ break;
1129
+ }
1130
+
1131
+ case PM_TRUE_NODE: *output = hb_string("true"); break;
1132
+ case PM_FALSE_NODE: *output = hb_string("false"); break;
1133
+ case PM_NIL_NODE: *output = HB_STRING_EMPTY; break;
1134
+
1135
+ default: return false;
1136
+ }
1137
+
1138
+ return is_escape_neutral(*output);
1139
+ }
1140
+
1141
+ static AST_NODE_T* create_static_output_node(
1142
+ hb_string_T content,
1143
+ static_output_node_type_T node_type,
1144
+ position_T start_position,
1145
+ position_T end_position,
1146
+ hb_allocator_T* allocator
1147
+ ) {
1148
+ switch (node_type) {
1149
+ case STATIC_OUTPUT_NODE_HTML_TEXT:
1150
+ return (
1151
+ AST_NODE_T*
1152
+ ) ast_html_text_node_init(content, start_position, end_position, hb_array_init(0, allocator), allocator);
1153
+
1154
+ case STATIC_OUTPUT_NODE_LITERAL:
1155
+ return (
1156
+ AST_NODE_T*
1157
+ ) ast_literal_node_init(content, start_position, end_position, hb_array_init(0, allocator), allocator);
1158
+
1159
+ default: return NULL;
1160
+ }
1161
+ }
1162
+
1163
+ bool append_static_output_node(
1164
+ hb_array_T* statements,
1165
+ const pm_statements_node_t* body,
1166
+ const analyzed_ruby_T* analyzed,
1167
+ position_T content_start,
1168
+ static_output_node_type_T node_type,
1169
+ hb_allocator_T* allocator
1170
+ ) {
1171
+ if (!statements || !body || !analyzed) { return false; }
1172
+ if (node_type == STATIC_OUTPUT_NODE_NONE) { return false; }
1173
+ if (body->body.size != 1) { return false; }
1174
+
1175
+ const pm_node_t* literal = body->body.nodes[0];
1176
+ const uint8_t* parser_start = analyzed->parser.start;
1177
+
1178
+ if (literal->location.start < parser_start || literal->location.end > analyzed->parser.end) { return false; }
1179
+
1180
+ hb_string_T content;
1181
+
1182
+ if (!prism_node_static_output(literal, &content)) { return false; }
1183
+ if (content.length == 0) { return true; }
1184
+
1185
+ size_t offset = (size_t) (literal->location.start - parser_start);
1186
+ size_t length = (size_t) (literal->location.end - literal->location.start);
1187
+
1188
+ position_T start_position = { .line = content_start.line, .column = content_start.column + (uint32_t) offset };
1189
+ position_T end_position = { .line = content_start.line,
1190
+ .column = content_start.column + (uint32_t) (offset + length) };
1191
+
1192
+ AST_NODE_T* node = create_static_output_node(content, node_type, start_position, end_position, allocator);
1193
+
1194
+ if (!node) { return false; }
1195
+
1196
+ hb_array_append(statements, node);
1197
+
1198
+ return true;
1199
+ }