herb 0.10.4-x86_64-linux-gnu → 0.11.1-x86_64-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
@@ -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,327 +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;
165
-
166
- if (node->type == PM_BLOCK_NODE) {
167
- pm_block_node_t* block_node = (pm_block_node_t*) node;
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", "}");
168
127
 
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;
251
-
252
- if (node->type == PM_UNLESS_NODE) {
253
- const pm_unless_node_t* unless_node = (const pm_unless_node_t*) node;
254
-
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;
202
+ bool inline_condition_keyword_offset(const analyzed_ruby_T* analyzed, uint32_t* offset) {
203
+ if (!analyzed || !analyzed->root || !offset) { return false; }
257
204
 
258
- if (has_if_keyword && has_end_keyword) { analyzed->unless_node_count++; }
259
- }
205
+ inline_condition_offset_T context = {
206
+ .source_start = analyzed->parser.start,
207
+ .offset = UINT32_MAX,
208
+ .found = false,
209
+ };
260
210
 
261
- pm_visit_child_nodes(node, search_unless_nodes, analyzed);
262
-
263
- return false;
264
- }
265
-
266
- bool search_when_nodes(const pm_node_t* node, void* data) {
267
- analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
211
+ pm_visit_node(analyzed->root, search_inline_condition_offset, &context);
268
212
 
269
- if (node->type == PM_WHEN_NODE) { analyzed->when_node_count++; }
213
+ if (!context.found) { return false; }
270
214
 
271
- pm_visit_child_nodes(node, search_when_nodes, analyzed);
215
+ *offset = context.offset;
272
216
 
273
- return false;
217
+ return true;
274
218
  }
275
219
 
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_CASE_MATCH_NODE) {
281
- const pm_case_match_node_t* case_match_node = (const pm_case_match_node_t*) node;
282
-
283
- if (case_match_node->predicate != NULL && case_match_node->predicate->type == PM_MATCH_PREDICATE_NODE) {
284
- analyzed->in_node_count++;
285
- }
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; }
286
224
  }
287
225
 
288
- pm_visit_child_nodes(node, search_in_nodes, analyzed);
289
-
290
226
  return false;
291
227
  }
292
228
 
293
- bool search_unexpected_elsif_nodes(analyzed_ruby_T* analyzed) {
294
- if (has_error_message(analyzed, "unexpected 'elsif', ignoring it")) {
295
- analyzed->elsif_node_count++;
296
- return true;
297
- }
229
+ bool is_do_block(pm_location_t opening_location) {
230
+ size_t length = opening_location.end - opening_location.start;
298
231
 
299
- return false;
232
+ return length == 2 && opening_location.start[0] == 'd' && opening_location.start[1] == 'o';
300
233
  }
301
234
 
302
- bool search_unexpected_else_nodes(analyzed_ruby_T* analyzed) {
303
- if (has_error_message(analyzed, "unexpected 'else', ignoring it")) {
304
- analyzed->else_node_count++;
305
- return true;
306
- }
235
+ bool is_brace_block(pm_location_t opening_location) {
236
+ size_t length = opening_location.end - opening_location.start;
307
237
 
308
- return false;
238
+ return length == 1 && opening_location.start[0] == '{';
309
239
  }
310
240
 
311
- bool search_unexpected_end_nodes(analyzed_ruby_T* analyzed) {
312
- if (has_error_message(analyzed, "unexpected 'end', ignoring it")) {
313
- if (has_error_message(analyzed, "unexpected '=', ignoring it")) {
314
- // `=end`
315
- return false;
316
- }
317
-
318
- analyzed->end_count++;
319
- return true;
320
- }
321
-
322
- return false;
241
+ static bool has_location(pm_location_t location) {
242
+ return location.start != NULL && location.end != NULL && (location.end - location.start) > 0;
323
243
  }
324
244
 
325
- bool search_unexpected_block_closing_nodes(analyzed_ruby_T* analyzed) {
326
- if (has_error_message(analyzed, "unexpected '}', ignoring it")) {
327
- analyzed->block_closing_count++;
328
- return true;
329
- }
330
-
331
- return false;
332
- }
245
+ static bool is_end_keyword(pm_location_t location) {
246
+ if (location.start == NULL || location.end == NULL) { return false; }
333
247
 
334
- bool search_unexpected_when_nodes(analyzed_ruby_T* analyzed) {
335
- if (has_error_message(analyzed, "unexpected 'when', ignoring it")) {
336
- analyzed->when_node_count++;
337
- return true;
338
- }
248
+ size_t length = location.end - location.start;
339
249
 
340
- return false;
250
+ return length == 3 && location.start[0] == 'e' && location.start[1] == 'n' && location.start[2] == 'd';
341
251
  }
342
252
 
343
- bool search_unexpected_in_nodes(analyzed_ruby_T* analyzed) {
344
- if (has_error_message(analyzed, "unexpected 'in', ignoring it")) {
345
- analyzed->in_node_count++;
346
- return true;
347
- }
348
-
349
- return false;
350
- }
253
+ bool is_closing_brace(pm_location_t location) {
254
+ if (location.start == NULL || location.end == NULL) { return false; }
351
255
 
352
- bool search_unexpected_rescue_nodes(analyzed_ruby_T* analyzed) {
353
- if (has_error_message(analyzed, "unexpected 'rescue', ignoring it")) {
354
- analyzed->rescue_node_count++;
355
- return true;
356
- }
256
+ size_t length = location.end - location.start;
357
257
 
358
- return false;
258
+ return length == 1 && location.start[0] == '}';
359
259
  }
360
260
 
361
- bool search_unexpected_ensure_nodes(analyzed_ruby_T* analyzed) {
362
- if (has_error_message(analyzed, "unexpected 'ensure', ignoring it")) {
363
- analyzed->ensure_node_count++;
364
- 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);
365
266
  }
366
267
 
367
268
  return false;
368
269
  }
369
270
 
370
- bool search_yield_nodes(const pm_node_t* node, void* data) {
371
- analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
372
-
373
- if (node->type == PM_YIELD_NODE) { analyzed->yield_node_count++; }
271
+ static bool has_keyword_location(pm_location_t location) {
272
+ return location.start != NULL && location.end != NULL;
273
+ }
374
274
 
375
- pm_visit_child_nodes(node, search_yield_nodes, analyzed);
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);
376
277
 
377
- return false;
278
+ return has_opening && !has_valid_block_closing(opening_loc, closing_loc);
378
279
  }
379
280
 
380
- bool search_then_keywords(const pm_node_t* node, void* data) {
281
+ bool search_control_flow_nodes(const pm_node_t* node, void* data) {
381
282
  analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
382
283
 
383
284
  switch (node->type) {
384
285
  case PM_IF_NODE: {
385
286
  const pm_if_node_t* if_node = (const pm_if_node_t*) node;
386
- if (if_node->then_keyword_loc.start != NULL && if_node->then_keyword_loc.end != NULL) {
387
- 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++;
388
290
  }
291
+
292
+ if (has_keyword_location(if_node->then_keyword_loc)) { analyzed->then_keyword_count++; }
389
293
  break;
390
294
  }
391
295
 
392
296
  case PM_UNLESS_NODE: {
393
297
  const pm_unless_node_t* unless_node = (const pm_unless_node_t*) node;
394
- if (unless_node->then_keyword_loc.start != NULL && unless_node->then_keyword_loc.end != NULL) {
395
- 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++;
396
301
  }
302
+
303
+ if (has_keyword_location(unless_node->then_keyword_loc)) { analyzed->then_keyword_count++; }
397
304
  break;
398
305
  }
399
306
 
400
307
  case PM_WHEN_NODE: {
401
308
  const pm_when_node_t* when_node = (const pm_when_node_t*) node;
402
- if (when_node->then_keyword_loc.start != NULL && when_node->then_keyword_loc.end != NULL) {
403
- 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++;
404
337
  }
405
338
  break;
406
339
  }
407
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
+
408
349
  default: break;
409
350
  }
410
351
 
411
- pm_visit_child_nodes(node, search_then_keywords, analyzed);
352
+ pm_visit_child_nodes(node, search_control_flow_nodes, analyzed);
412
353
 
413
354
  return false;
414
355
  }
415
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
+
416
403
  static bool is_postfix_conditional(const pm_statements_node_t* statements, pm_location_t keyword_location) {
417
404
  if (statements == NULL) { return false; }
418
405
 
@@ -616,6 +603,122 @@ static void append_parameter(
616
603
  );
617
604
  }
618
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
+
619
722
  hb_array_T* extract_parameters_from_prism(
620
723
  pm_parameters_node_t* parameters,
621
724
  pm_parser_t* parser,
@@ -633,31 +736,17 @@ hb_array_T* extract_parameters_from_prism(
633
736
 
634
737
  hb_array_T* result = hb_array_init(count, allocator);
635
738
 
636
- // Required positional: |item|
739
+ // Required positional: |item|, including destructured |(key, value)|
637
740
  for (size_t index = 0; index < parameters->requireds.size; index++) {
638
- pm_node_t* node = parameters->requireds.nodes[index];
639
- if (node->type != PM_REQUIRED_PARAMETER_NODE) { continue; }
640
-
641
- pm_required_parameter_node_t* required = (pm_required_parameter_node_t*) node;
642
- pm_constant_t* constant = pm_constant_pool_id_to_constant(&parser->constant_pool, required->name);
643
- if (!constant) { continue; }
644
-
645
- char* name = hb_allocator_strndup(allocator, (const char*) constant->start, constant->length);
646
- position_T start = prism_to_source_position(node->location.start, prism_source_start, source_base_offset, source);
647
- position_T end = prism_to_source_position(node->location.end, prism_source_start, source_base_offset, source);
648
-
649
- append_parameter(
741
+ append_required_positional(
650
742
  result,
651
- create_parameter_name_token(node->location, name, prism_source_start, source_base_offset, source, allocator),
652
- NULL,
653
- "positional",
654
- true,
655
- start,
656
- end,
743
+ parameters->requireds.nodes[index],
744
+ parser,
745
+ source,
746
+ source_base_offset,
747
+ prism_source_start,
657
748
  allocator
658
749
  );
659
-
660
- hb_allocator_dealloc(allocator, name);
661
750
  }
662
751
 
663
752
  // Optional positional: |item = nil|
@@ -731,9 +820,33 @@ hb_array_T* extract_parameters_from_prism(
731
820
  );
732
821
 
733
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
+ );
734
834
  }
735
835
  }
736
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
+
737
850
  // Keywords: |name:| or |title: "default"|
738
851
  for (size_t index = 0; index < parameters->keywords.size; index++) {
739
852
  pm_node_t* keyword = parameters->keywords.nodes[index];
@@ -880,6 +993,17 @@ hb_array_T* extract_parameters_from_prism(
880
993
  );
881
994
 
882
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
+ );
883
1007
  }
884
1008
  }
885
1009
 
@@ -889,7 +1013,7 @@ hb_array_T* extract_parameters_from_prism(
889
1013
  hb_array_T* extract_block_arguments_from_erb_node(
890
1014
  const AST_ERB_CONTENT_NODE_T* erb_node,
891
1015
  const char* source,
892
- hb_array_T* errors,
1016
+ hb_array_T** errors,
893
1017
  hb_allocator_T* allocator
894
1018
  ) {
895
1019
  if (!erb_node || !erb_node->analyzed_ruby || !erb_node->analyzed_ruby->parsed) { return hb_array_init(0, allocator); }
@@ -925,7 +1049,7 @@ hb_array_T* extract_block_arguments_from_erb_node(
925
1049
  RUBY_PARSE_ERROR_T* parse_error =
926
1050
  ruby_parse_error_from_prism_error_with_positions(error, error_start, error_end, allocator);
927
1051
 
928
- hb_array_append(errors, parse_error);
1052
+ hb_array_append_lazy(errors, parse_error, allocator);
929
1053
  }
930
1054
  }
931
1055
 
@@ -938,3 +1062,138 @@ hb_array_T* extract_block_arguments_from_erb_node(
938
1062
  allocator
939
1063
  );
940
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
+ }