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.
- checksums.yaml +4 -4
- data/Makefile +17 -7
- data/README.md +36 -119
- data/Rakefile +2 -11
- data/config/action_view_helpers/actioncable/action_cable_helper/action_cable_meta_tag.yml +12 -8
- data/config/action_view_helpers/actionpack/content_security_policy/content_security_policy?.yml +9 -6
- data/config/action_view_helpers/actionpack/content_security_policy/content_security_policy_nonce.yml +9 -6
- data/config/action_view_helpers/actionpack/polymorphic_routes/polymorphic_path.yml +20 -12
- data/config/action_view_helpers/actionpack/polymorphic_routes/polymorphic_url.yml +30 -18
- data/config/action_view_helpers/actionpack/request_forgery_protection/form_authenticity_token.yml +15 -9
- data/config/action_view_helpers/actionpack/request_forgery_protection/protect_against_forgery?.yml +9 -6
- data/config/action_view_helpers/actiontext/content_helper/render_action_text_content.yml +15 -9
- data/config/action_view_helpers/actiontext/content_helper/sanitize_action_text_content.yml +15 -9
- data/config/action_view_helpers/actiontext/tag_helper/rich_textarea_tag.yml +34 -22
- data/config/action_view_helpers/actionview/active_model_helper/error_message.yml +9 -6
- data/config/action_view_helpers/actionview/active_model_helper/error_wrapping.yml +9 -6
- data/config/action_view_helpers/actionview/active_model_helper/object.yml +9 -6
- data/config/action_view_helpers/actionview/asset_tag_helper/apply_stylesheet_media_default.yml +9 -6
- data/config/action_view_helpers/actionview/asset_tag_helper/audio_tag.yml +40 -27
- data/config/action_view_helpers/actionview/asset_tag_helper/auto_discovery_link_tag.yml +37 -23
- data/config/action_view_helpers/actionview/asset_tag_helper/auto_include_nonce.yml +9 -6
- data/config/action_view_helpers/actionview/asset_tag_helper/auto_include_nonce_for_scripts.yml +9 -6
- data/config/action_view_helpers/actionview/asset_tag_helper/auto_include_nonce_for_styles.yml +9 -6
- data/config/action_view_helpers/actionview/asset_tag_helper/favicon_link_tag.yml +32 -22
- data/config/action_view_helpers/actionview/asset_tag_helper/image_decoding.yml +9 -6
- data/config/action_view_helpers/actionview/asset_tag_helper/image_loading.yml +9 -6
- data/config/action_view_helpers/actionview/asset_tag_helper/image_tag.yml +67 -46
- data/config/action_view_helpers/actionview/asset_tag_helper/javascript_include_tag.yml +58 -39
- data/config/action_view_helpers/actionview/asset_tag_helper/picture_tag.yml +22 -14
- data/config/action_view_helpers/actionview/asset_tag_helper/preload_link_tag.yml +45 -30
- data/config/action_view_helpers/actionview/asset_tag_helper/preload_links_header.yml +9 -6
- data/config/action_view_helpers/actionview/asset_tag_helper/stylesheet_link_tag.yml +49 -30
- data/config/action_view_helpers/actionview/asset_tag_helper/video_tag.yml +53 -35
- data/config/action_view_helpers/actionview/asset_url_helper/asset_path.yml +16 -10
- data/config/action_view_helpers/actionview/asset_url_helper/asset_url.yml +16 -10
- data/config/action_view_helpers/actionview/asset_url_helper/audio_path.yml +16 -10
- data/config/action_view_helpers/actionview/asset_url_helper/audio_url.yml +16 -10
- data/config/action_view_helpers/actionview/asset_url_helper/compute_asset_extname.yml +9 -6
- data/config/action_view_helpers/actionview/asset_url_helper/compute_asset_host.yml +9 -6
- data/config/action_view_helpers/actionview/asset_url_helper/compute_asset_path.yml +9 -6
- data/config/action_view_helpers/actionview/asset_url_helper/font_path.yml +16 -10
- data/config/action_view_helpers/actionview/asset_url_helper/font_url.yml +16 -10
- data/config/action_view_helpers/actionview/asset_url_helper/image_path.yml +16 -10
- data/config/action_view_helpers/actionview/asset_url_helper/image_url.yml +16 -10
- data/config/action_view_helpers/actionview/asset_url_helper/javascript_path.yml +16 -10
- data/config/action_view_helpers/actionview/asset_url_helper/javascript_url.yml +16 -10
- data/config/action_view_helpers/actionview/asset_url_helper/public_compute_asset_path.yml +9 -6
- data/config/action_view_helpers/actionview/asset_url_helper/stylesheet_path.yml +16 -10
- data/config/action_view_helpers/actionview/asset_url_helper/stylesheet_url.yml +16 -10
- data/config/action_view_helpers/actionview/asset_url_helper/video_path.yml +16 -10
- data/config/action_view_helpers/actionview/asset_url_helper/video_url.yml +16 -10
- data/config/action_view_helpers/actionview/atom_feed_helper/atom_feed.yml +52 -27
- data/config/action_view_helpers/actionview/cache_helper/cache.yml +25 -15
- data/config/action_view_helpers/actionview/cache_helper/cache_fragment_name.yml +9 -6
- data/config/action_view_helpers/actionview/cache_helper/cache_if.yml +20 -12
- data/config/action_view_helpers/actionview/cache_helper/cache_unless.yml +20 -12
- data/config/action_view_helpers/actionview/cache_helper/caching_predicate.yml +9 -6
- data/config/action_view_helpers/actionview/cache_helper/digest_path_from_template.yml +9 -6
- data/config/action_view_helpers/actionview/cache_helper/fragment_for.yml +9 -6
- data/config/action_view_helpers/actionview/cache_helper/fragment_name_with_digest.yml +9 -6
- data/config/action_view_helpers/actionview/cache_helper/read_fragment_for.yml +9 -6
- data/config/action_view_helpers/actionview/cache_helper/uncacheable.yml +9 -6
- data/config/action_view_helpers/actionview/cache_helper/write_fragment_for.yml +9 -6
- data/config/action_view_helpers/actionview/capture_helper/capture.yml +9 -6
- data/config/action_view_helpers/actionview/capture_helper/content_for.yml +20 -12
- data/config/action_view_helpers/actionview/capture_helper/content_for_predicate.yml +15 -9
- data/config/action_view_helpers/actionview/capture_helper/provide.yml +15 -9
- data/config/action_view_helpers/actionview/capture_helper/with_output_buffer.yml +9 -6
- data/config/action_view_helpers/actionview/content_exfiltration_prevention_helper/prepend_content_exfiltration_prevention.yml +9 -6
- data/config/action_view_helpers/actionview/content_exfiltration_prevention_helper/prevent_content_exfiltration.yml +9 -6
- data/config/action_view_helpers/actionview/controller_helper/action_name.yml +9 -6
- data/config/action_view_helpers/actionview/controller_helper/assign_controller.yml +9 -6
- data/config/action_view_helpers/actionview/controller_helper/controller.yml +9 -6
- data/config/action_view_helpers/actionview/controller_helper/controller_name.yml +9 -6
- data/config/action_view_helpers/actionview/controller_helper/controller_path.yml +9 -6
- data/config/action_view_helpers/actionview/controller_helper/cookies.yml +9 -6
- data/config/action_view_helpers/actionview/controller_helper/flash.yml +9 -6
- data/config/action_view_helpers/actionview/controller_helper/headers.yml +9 -6
- data/config/action_view_helpers/actionview/controller_helper/logger.yml +9 -6
- data/config/action_view_helpers/actionview/controller_helper/params.yml +9 -6
- data/config/action_view_helpers/actionview/controller_helper/request.yml +9 -6
- data/config/action_view_helpers/actionview/controller_helper/request_forgery_protection_token.yml +9 -6
- data/config/action_view_helpers/actionview/controller_helper/response.yml +9 -6
- data/config/action_view_helpers/actionview/controller_helper/session.yml +9 -6
- data/config/action_view_helpers/actionview/csp_helper/csp_meta_tag.yml +18 -11
- data/config/action_view_helpers/actionview/csrf_helper/csrf_meta_tags.yml +16 -10
- data/config/action_view_helpers/actionview/date_helper/date_select.yml +85 -51
- data/config/action_view_helpers/actionview/date_helper/datetime_select.yml +65 -39
- data/config/action_view_helpers/actionview/date_helper/distance_of_time_in_words.yml +30 -18
- data/config/action_view_helpers/actionview/date_helper/relative_time_in_words.yml +35 -21
- data/config/action_view_helpers/actionview/date_helper/select_date.yml +50 -30
- data/config/action_view_helpers/actionview/date_helper/select_datetime.yml +65 -39
- data/config/action_view_helpers/actionview/date_helper/select_day.yml +40 -24
- data/config/action_view_helpers/actionview/date_helper/select_hour.yml +50 -30
- data/config/action_view_helpers/actionview/date_helper/select_minute.yml +40 -24
- data/config/action_view_helpers/actionview/date_helper/select_month.yml +60 -36
- data/config/action_view_helpers/actionview/date_helper/select_second.yml +35 -21
- data/config/action_view_helpers/actionview/date_helper/select_time.yml +55 -33
- data/config/action_view_helpers/actionview/date_helper/select_year.yml +45 -27
- data/config/action_view_helpers/actionview/date_helper/time_ago_in_words.yml +21 -13
- data/config/action_view_helpers/actionview/date_helper/time_select.yml +60 -36
- data/config/action_view_helpers/actionview/date_helper/time_tag.yml +32 -20
- data/config/action_view_helpers/actionview/debug_helper/debug.yml +15 -9
- data/config/action_view_helpers/actionview/form_builder/button.yml +60 -0
- data/config/action_view_helpers/actionview/form_builder/submit.yml +48 -0
- data/config/action_view_helpers/actionview/form_helper/apply_form_for_options.yml +9 -6
- data/config/action_view_helpers/actionview/form_helper/checkbox.yml +41 -25
- data/config/action_view_helpers/actionview/form_helper/color_field.yml +25 -15
- data/config/action_view_helpers/actionview/form_helper/date_field.yml +35 -21
- data/config/action_view_helpers/actionview/form_helper/datetime_field.yml +41 -25
- data/config/action_view_helpers/actionview/form_helper/email_field.yml +25 -15
- data/config/action_view_helpers/actionview/form_helper/emitted_hidden_id.yml +9 -6
- data/config/action_view_helpers/actionview/form_helper/fields.yml +37 -18
- data/config/action_view_helpers/actionview/form_helper/fields_for.yml +33 -15
- data/config/action_view_helpers/actionview/form_helper/file_field.yml +45 -27
- data/config/action_view_helpers/actionview/form_helper/form_for.yml +45 -24
- data/config/action_view_helpers/actionview/form_helper/form_with.yml +56 -30
- data/config/action_view_helpers/actionview/form_helper/form_with_generates_ids.yml +9 -6
- data/config/action_view_helpers/actionview/form_helper/form_with_generates_remote_forms.yml +9 -6
- data/config/action_view_helpers/actionview/form_helper/hidden_field.yml +25 -15
- data/config/action_view_helpers/actionview/form_helper/label.yml +52 -27
- data/config/action_view_helpers/actionview/form_helper/month_field.yml +25 -15
- data/config/action_view_helpers/actionview/form_helper/multipart.yml +9 -6
- data/config/action_view_helpers/actionview/form_helper/multiple_file_field_include_hidden.yml +9 -6
- data/config/action_view_helpers/actionview/form_helper/number_field.yml +45 -27
- data/config/action_view_helpers/actionview/form_helper/password_field.yml +25 -15
- data/config/action_view_helpers/actionview/form_helper/radio_button.yml +30 -18
- data/config/action_view_helpers/actionview/form_helper/range_field.yml +45 -27
- data/config/action_view_helpers/actionview/form_helper/search_field.yml +25 -15
- data/config/action_view_helpers/actionview/form_helper/telephone_field.yml +26 -16
- data/config/action_view_helpers/actionview/form_helper/text_field.yml +25 -15
- data/config/action_view_helpers/actionview/form_helper/textarea.yml +31 -19
- data/config/action_view_helpers/actionview/form_helper/time_field.yml +40 -24
- data/config/action_view_helpers/actionview/form_helper/url_field.yml +25 -15
- data/config/action_view_helpers/actionview/form_helper/week_field.yml +25 -15
- data/config/action_view_helpers/actionview/form_options_helper/collection_checkboxes.yml +58 -31
- data/config/action_view_helpers/actionview/form_options_helper/collection_radio_buttons.yml +57 -30
- data/config/action_view_helpers/actionview/form_options_helper/collection_select.yml +65 -39
- data/config/action_view_helpers/actionview/form_options_helper/grouped_collection_select.yml +65 -39
- data/config/action_view_helpers/actionview/form_options_helper/grouped_options_for_select.yml +35 -21
- data/config/action_view_helpers/actionview/form_options_helper/option_groups_from_collection_for_select.yml +40 -24
- data/config/action_view_helpers/actionview/form_options_helper/options_for_select.yml +20 -12
- data/config/action_view_helpers/actionview/form_options_helper/options_from_collection_for_select.yml +30 -18
- data/config/action_view_helpers/actionview/form_options_helper/select.yml +60 -36
- data/config/action_view_helpers/actionview/form_options_helper/time_zone_options_for_select.yml +25 -15
- data/config/action_view_helpers/actionview/form_options_helper/time_zone_select.yml +50 -30
- data/config/action_view_helpers/actionview/form_options_helper/weekday_options_for_select.yml +30 -18
- data/config/action_view_helpers/actionview/form_options_helper/weekday_select.yml +30 -18
- data/config/action_view_helpers/actionview/form_tag_helper/button_tag.yml +39 -21
- data/config/action_view_helpers/actionview/form_tag_helper/checkbox_tag.yml +33 -21
- data/config/action_view_helpers/actionview/form_tag_helper/color_field_tag.yml +26 -17
- data/config/action_view_helpers/actionview/form_tag_helper/date_field_tag.yml +27 -17
- data/config/action_view_helpers/actionview/form_tag_helper/datetime_field_tag.yml +28 -18
- data/config/action_view_helpers/actionview/form_tag_helper/default_enforce_utf8.yml +9 -6
- data/config/action_view_helpers/actionview/form_tag_helper/email_field_tag.yml +27 -17
- data/config/action_view_helpers/actionview/form_tag_helper/embed_authenticity_token_in_remote_forms.yml +9 -6
- data/config/action_view_helpers/actionview/form_tag_helper/field_id.yml +30 -18
- data/config/action_view_helpers/actionview/form_tag_helper/field_name.yml +30 -18
- data/config/action_view_helpers/actionview/form_tag_helper/field_set_tag.yml +23 -15
- data/config/action_view_helpers/actionview/form_tag_helper/file_field_tag.yml +35 -22
- data/config/action_view_helpers/actionview/form_tag_helper/form_tag.yml +38 -24
- data/config/action_view_helpers/actionview/form_tag_helper/hidden_field_tag.yml +27 -17
- data/config/action_view_helpers/actionview/form_tag_helper/image_submit_tag.yml +31 -21
- data/config/action_view_helpers/actionview/form_tag_helper/label_tag.yml +33 -17
- data/config/action_view_helpers/actionview/form_tag_helper/month_field_tag.yml +27 -17
- data/config/action_view_helpers/actionview/form_tag_helper/number_field_tag.yml +47 -29
- data/config/action_view_helpers/actionview/form_tag_helper/password_field_tag.yml +27 -17
- data/config/action_view_helpers/actionview/form_tag_helper/radio_button_tag.yml +32 -20
- data/config/action_view_helpers/actionview/form_tag_helper/range_field_tag.yml +47 -29
- data/config/action_view_helpers/actionview/form_tag_helper/search_field_tag.yml +27 -17
- data/config/action_view_helpers/actionview/form_tag_helper/select_tag.yml +47 -29
- data/config/action_view_helpers/actionview/form_tag_helper/submit_tag.yml +33 -21
- data/config/action_view_helpers/actionview/form_tag_helper/telephone_field_tag.yml +28 -18
- data/config/action_view_helpers/actionview/form_tag_helper/text_field_tag.yml +27 -17
- data/config/action_view_helpers/actionview/form_tag_helper/textarea_tag.yml +31 -20
- data/config/action_view_helpers/actionview/form_tag_helper/time_field_tag.yml +27 -17
- data/config/action_view_helpers/actionview/form_tag_helper/url_field_tag.yml +27 -17
- data/config/action_view_helpers/actionview/form_tag_helper/utf8_enforcer_tag.yml +9 -6
- data/config/action_view_helpers/actionview/form_tag_helper/week_field_tag.yml +28 -18
- data/config/action_view_helpers/actionview/javascript_helper/escape_javascript.yml +16 -10
- data/config/action_view_helpers/actionview/javascript_helper/javascript_cdata_section.yml +9 -6
- data/config/action_view_helpers/actionview/javascript_helper/javascript_tag.yml +41 -27
- data/config/action_view_helpers/actionview/number_helper/number_to_currency.yml +29 -18
- data/config/action_view_helpers/actionview/number_helper/number_to_human.yml +25 -15
- data/config/action_view_helpers/actionview/number_helper/number_to_human_size.yml +20 -12
- data/config/action_view_helpers/actionview/number_helper/number_to_percentage.yml +20 -12
- data/config/action_view_helpers/actionview/number_helper/number_to_phone.yml +33 -20
- data/config/action_view_helpers/actionview/number_helper/number_with_delimiter.yml +21 -13
- data/config/action_view_helpers/actionview/number_helper/number_with_precision.yml +25 -15
- data/config/action_view_helpers/actionview/output_safety_helper/raw.yml +15 -9
- data/config/action_view_helpers/actionview/output_safety_helper/safe_join.yml +20 -12
- data/config/action_view_helpers/actionview/output_safety_helper/to_sentence.yml +24 -15
- data/config/action_view_helpers/actionview/record_identifier/dom_class.yml +20 -12
- data/config/action_view_helpers/actionview/record_identifier/dom_id.yml +20 -12
- data/config/action_view_helpers/actionview/record_identifier/dom_target.yml +15 -9
- data/config/action_view_helpers/actionview/record_identifier/model_name_from_record_or_class.yml +9 -6
- data/config/action_view_helpers/actionview/rendering_helper/render.yml +108 -22
- data/config/action_view_helpers/actionview/sanitize_helper/sanitize.yml +25 -15
- data/config/action_view_helpers/actionview/sanitize_helper/sanitize_css.yml +15 -9
- data/config/action_view_helpers/actionview/sanitize_helper/sanitizer_vendor.yml +9 -6
- data/config/action_view_helpers/actionview/sanitize_helper/strip_links.yml +15 -9
- data/config/action_view_helpers/actionview/sanitize_helper/strip_tags.yml +15 -9
- data/config/action_view_helpers/actionview/tag_helper/cdata_section.yml +15 -9
- data/config/action_view_helpers/actionview/tag_helper/content_tag.yml +59 -38
- data/config/action_view_helpers/actionview/tag_helper/escape_once.yml +15 -9
- data/config/action_view_helpers/actionview/tag_helper/tag.yml +54 -31
- data/config/action_view_helpers/actionview/tag_helper/token_list.yml +16 -10
- data/config/action_view_helpers/actionview/text_helper/concat.yml +15 -9
- data/config/action_view_helpers/actionview/text_helper/current_cycle.yml +15 -9
- data/config/action_view_helpers/actionview/text_helper/cycle.yml +23 -14
- data/config/action_view_helpers/actionview/text_helper/excerpt.yml +33 -20
- data/config/action_view_helpers/actionview/text_helper/highlight.yml +37 -18
- data/config/action_view_helpers/actionview/text_helper/pluralize.yml +30 -18
- data/config/action_view_helpers/actionview/text_helper/reset_cycle.yml +15 -9
- data/config/action_view_helpers/actionview/text_helper/safe_concat.yml +9 -6
- data/config/action_view_helpers/actionview/text_helper/simple_format.yml +33 -20
- data/config/action_view_helpers/actionview/text_helper/truncate.yml +38 -23
- data/config/action_view_helpers/actionview/text_helper/word_wrap.yml +25 -15
- data/config/action_view_helpers/actionview/translation_helper/debug_missing_translation.yml +9 -6
- data/config/action_view_helpers/actionview/translation_helper/localize.yml +26 -16
- data/config/action_view_helpers/actionview/translation_helper/translate.yml +31 -19
- data/config/action_view_helpers/actionview/url_helper/button_to.yml +57 -33
- data/config/action_view_helpers/actionview/url_helper/button_to_generates_button_tag.yml +9 -6
- data/config/action_view_helpers/actionview/url_helper/current_page?.yml +25 -15
- data/config/action_view_helpers/actionview/url_helper/link_to.yml +76 -53
- data/config/action_view_helpers/actionview/url_helper/link_to_if.yml +54 -20
- data/config/action_view_helpers/actionview/url_helper/link_to_unless.yml +54 -20
- data/config/action_view_helpers/actionview/url_helper/link_to_unless_current.yml +49 -17
- data/config/action_view_helpers/actionview/url_helper/mail_to.yml +60 -34
- data/config/action_view_helpers/actionview/url_helper/phone_to.yml +40 -22
- data/config/action_view_helpers/actionview/url_helper/sms_to.yml +45 -25
- data/config/action_view_helpers/actionview/url_helper/url_for.yml +15 -9
- data/config/action_view_helpers/importmap-rails/importmap_tags_helper/javascript_import_module_tag.yml +32 -0
- data/config/action_view_helpers/importmap-rails/importmap_tags_helper/javascript_importmap_module_preload_tags.yml +39 -0
- data/config/action_view_helpers/importmap-rails/importmap_tags_helper/javascript_importmap_tags.yml +35 -0
- data/config/action_view_helpers/importmap-rails/importmap_tags_helper/javascript_inline_importmap_tag.yml +32 -0
- data/config/action_view_helpers/importmap-rails/importmap_tags_helper/javascript_module_preload_tag.yml +35 -0
- data/config/action_view_helpers/turbo-rails/drive_helper/turbo_exempts_page_from_cache.yml +9 -6
- data/config/action_view_helpers/turbo-rails/drive_helper/turbo_exempts_page_from_cache_tag.yml +12 -8
- data/config/action_view_helpers/turbo-rails/drive_helper/turbo_exempts_page_from_preview.yml +9 -6
- data/config/action_view_helpers/turbo-rails/drive_helper/turbo_exempts_page_from_preview_tag.yml +12 -8
- data/config/action_view_helpers/turbo-rails/drive_helper/turbo_page_requires_reload.yml +9 -6
- data/config/action_view_helpers/turbo-rails/drive_helper/turbo_page_requires_reload_tag.yml +12 -8
- data/config/action_view_helpers/turbo-rails/drive_helper/turbo_refresh_method_tag.yml +17 -11
- data/config/action_view_helpers/turbo-rails/drive_helper/turbo_refresh_scroll_tag.yml +17 -11
- data/config/action_view_helpers/turbo-rails/drive_helper/turbo_refreshes_with.yml +20 -12
- data/config/action_view_helpers/turbo-rails/frames_helper/turbo_frame_tag.yml +54 -33
- data/config/action_view_helpers/turbo-rails/includes_helper/turbo_include_tags.yml +9 -6
- data/config/action_view_helpers/turbo-rails/streams_action_helper/turbo_stream_action_tag.yml +32 -20
- data/config/action_view_helpers/turbo-rails/streams_action_helper/turbo_stream_refresh_tag.yml +18 -11
- data/config/action_view_helpers/turbo-rails/streams_helper/turbo_stream.yml +9 -6
- data/config/action_view_helpers/turbo-rails/streams_helper/turbo_stream_from.yml +28 -18
- data/config/html_elements.yml +597 -0
- data/config/options.yml +1 -0
- data/config/slots/components.yml +52 -0
- data/config/state/kind.yml +61 -0
- data/config/state/operators.yml +27 -0
- data/config/state/predicates.yml +39 -0
- data/config/state/transforms.yml +18 -0
- data/config/view_context_methods/actionview/base/annotate_rendered_view_with_filenames.yml +4 -4
- data/config/view_context_methods/actionview/base/assign.yml +4 -4
- data/config/view_context_methods/actionview/base/assigns.yml +4 -4
- data/config/view_context_methods/actionview/base/automatically_disable_submit_tag.yml +4 -4
- data/config/view_context_methods/actionview/base/compiled_method_container.yml +4 -4
- data/config/view_context_methods/actionview/base/config.yml +4 -4
- data/config/view_context_methods/actionview/base/default_form_builder.yml +4 -4
- data/config/view_context_methods/actionview/base/default_formats.yml +4 -4
- data/config/view_context_methods/actionview/base/field_error_proc.yml +4 -4
- data/config/view_context_methods/actionview/base/formats.yml +4 -4
- data/config/view_context_methods/actionview/base/in_rendering_context.yml +4 -4
- data/config/view_context_methods/actionview/base/locale.yml +4 -4
- data/config/view_context_methods/actionview/base/lookup_context.yml +4 -4
- data/config/view_context_methods/actionview/base/output_buffer.yml +4 -4
- data/config/view_context_methods/actionview/base/prefix_partial_path_with_controller_namespace.yml +4 -4
- data/config/view_context_methods/actionview/base/remove_hidden_field_autocomplete.yml +4 -4
- data/config/view_context_methods/actionview/base/streaming_completion_on_exception.yml +4 -4
- data/config/view_context_methods/actionview/base/view_flow.yml +4 -4
- data/config/view_context_methods/actionview/base/view_paths.yml +4 -4
- data/config/view_context_methods/actionview/base/view_renderer.yml +4 -4
- data/config/view_context_methods/actionview/template/local_assigns.yml +4 -4
- data/config/view_context_methods/activemodel/conversion/convert_to_model.yml +4 -4
- data/config/view_context_methods/activesupport/benchmarkable/benchmark.yml +4 -4
- data/config.yml +1249 -786
- data/exe/herb +2 -0
- data/ext/herb/error_helpers.c +379 -17
- data/ext/herb/error_helpers.h +1 -1
- data/ext/herb/extconf.rb +4 -2
- data/ext/herb/extension.c +137 -74
- data/ext/herb/extension_helpers.c +81 -35
- data/ext/herb/extension_helpers.h +4 -1
- data/ext/herb/nodes.c +859 -374
- data/ext/herb/nodes.h +3 -2
- data/ext/herb/parser_options_helpers.c +151 -0
- data/ext/herb/parser_options_helpers.h +14 -0
- data/herb.gemspec +3 -2
- data/lib/herb/action_view/helper_registry.rb +1358 -62
- data/lib/herb/analysis/partial_declaration.rb +140 -0
- data/lib/herb/analysis/partial_index.rb +189 -0
- data/lib/herb/analysis/partial_resolution.rb +161 -0
- data/lib/herb/analysis/partial_resolver.rb +144 -0
- data/lib/herb/analysis/project_index.rb +152 -0
- data/lib/herb/{action_view → analysis}/render_analyzer.rb +287 -77
- data/lib/herb/analysis/render_graph/ancestor_chain.rb +27 -0
- data/lib/herb/analysis/render_graph/builder.rb +376 -0
- data/lib/herb/analysis/render_graph/call_frame.rb +9 -0
- data/lib/herb/analysis/render_graph/call_site_location.rb +23 -0
- data/lib/herb/analysis/render_graph/inferred_signature.rb +21 -0
- data/lib/herb/analysis/render_graph/partial_call_site.rb +40 -0
- data/lib/herb/analysis/render_graph/partial_context.rb +46 -0
- data/lib/herb/analysis/render_graph/template_roots.rb +31 -0
- data/lib/herb/analysis/render_graph.rb +285 -0
- data/lib/herb/analysis/ruby_locals_index/local.rb +25 -0
- data/lib/herb/analysis/ruby_locals_index/named_reference.rb +22 -0
- data/lib/herb/analysis/ruby_locals_index/offset_table.rb +44 -0
- data/lib/herb/analysis/ruby_locals_index/reference_collector.rb +80 -0
- data/lib/herb/analysis/ruby_locals_index/state_locals.rb +49 -0
- data/lib/herb/analysis/ruby_locals_index.rb +165 -0
- data/lib/herb/analysis/ruby_reference.rb +67 -0
- data/lib/herb/analysis/template_dependencies/dependency_collector.rb +179 -0
- data/lib/herb/analysis/template_dependencies/node_dependency_collector.rb +309 -0
- data/lib/herb/analysis/template_dependencies.rb +562 -0
- data/lib/herb/ast/erb_render_node.rb +26 -94
- data/lib/herb/ast/helpers.rb +90 -10
- data/lib/herb/ast/herb_directive_node.rb +18 -0
- data/lib/herb/ast/node.rb +32 -2
- data/lib/herb/ast/nodes.rb +1368 -105
- data/lib/herb/backend.rb +73 -0
- data/lib/herb/bootstrap.rb +8 -8
- data/lib/herb/cli.rb +555 -32
- data/lib/herb/colors.rb +14 -0
- data/lib/herb/configuration.rb +71 -35
- data/lib/herb/defaults.yml +2 -1
- data/lib/herb/dev/assets.rb +57 -0
- data/lib/herb/dev/classifier.rb +84 -0
- data/lib/herb/dev/embedded.rb +27 -0
- data/lib/herb/dev/pipeline.rb +305 -0
- data/lib/herb/dev/protocol.rb +221 -0
- data/lib/herb/dev/runner.rb +180 -175
- data/lib/herb/dev/server.rb +89 -26
- data/lib/herb/dev/server_entry.rb +41 -6
- data/lib/herb/dev/watcher.rb +181 -0
- data/lib/herb/dev.rb +163 -0
- data/lib/herb/diagnostic/formatter.rb +88 -0
- data/lib/herb/diagnostic.rb +172 -0
- data/lib/herb/diff/operation.rb +36 -0
- data/lib/herb/diff/result.rb +62 -0
- data/lib/herb/diff.rb +10 -0
- data/lib/herb/engine/collector.rb +62 -0
- data/lib/herb/engine/compiler.rb +387 -113
- data/lib/herb/engine/component_tags/constant_resolver.rb +28 -0
- data/lib/herb/engine/component_tags/partial_resolver.rb +54 -0
- data/lib/herb/engine/component_tags/resolver.rb +32 -0
- data/lib/herb/engine/component_tags/visitor.rb +231 -0
- data/lib/herb/engine/css_inliner/inliner.rb +101 -0
- data/lib/herb/engine/css_inliner/visitor.rb +174 -0
- data/lib/herb/engine/errors.rb +122 -0
- data/lib/herb/engine/helpers.rb +82 -0
- data/lib/herb/engine/inline_render/inliner.rb +122 -0
- data/lib/herb/engine/inline_render/visitor.rb +267 -0
- data/lib/herb/engine/runtime/entry.rb +62 -0
- data/lib/herb/engine/runtime/error_page.rb +362 -0
- data/lib/herb/engine/runtime/html_safe_assertions.rb +217 -0
- data/lib/herb/engine/runtime/journal/summary.rb +227 -0
- data/lib/herb/engine/runtime/journal.rb +379 -0
- data/lib/herb/engine/runtime/middleware.rb +212 -0
- data/lib/herb/engine/runtime/observations.rb +73 -0
- data/lib/herb/engine/runtime/report.rb +204 -0
- data/lib/herb/engine/runtime/session.rb +437 -0
- data/lib/herb/engine/runtime.rb +21 -0
- data/lib/herb/engine/scoped_style/channel.rb +66 -0
- data/lib/herb/engine/scoped_style/collector.rb +74 -0
- data/lib/herb/engine/scoped_style/visitor.rb +533 -0
- data/lib/herb/engine/slots/annotation.rb +98 -0
- data/lib/herb/engine/slots/bindings.rb +61 -0
- data/lib/herb/engine/slots/callee.rb +118 -0
- data/lib/herb/engine/slots/component_definitions.rb +67 -0
- data/lib/herb/engine/slots/components/async.rb +24 -0
- data/lib/herb/engine/slots/components/base.rb +132 -0
- data/lib/herb/engine/slots/components/deferred.rb +81 -0
- data/lib/herb/engine/slots/components/fallback.rb +27 -0
- data/lib/herb/engine/slots/components/fragment.rb +99 -0
- data/lib/herb/engine/slots/components/lazy.rb +24 -0
- data/lib/herb/engine/slots/components.rb +52 -0
- data/lib/herb/engine/slots/dependencies/channel.rb +72 -0
- data/lib/herb/engine/slots/dependencies.rb +269 -0
- data/lib/herb/engine/slots/dynamics_compiler.rb +864 -0
- data/lib/herb/engine/slots/identifier.rb +35 -0
- data/lib/herb/engine/slots/manifest/channel.rb +74 -0
- data/lib/herb/engine/slots/manifest/collector.rb +75 -0
- data/lib/herb/engine/slots/markers.rb +152 -0
- data/lib/herb/engine/slots/render_bindings.rb +141 -0
- data/lib/herb/engine/slots/schema_compiler.rb +94 -0
- data/lib/herb/engine/slots/state_anchor.rb +94 -0
- data/lib/herb/engine/slots/state_compiler.rb +1325 -0
- data/lib/herb/engine/slots/state_directives.rb +854 -0
- data/lib/herb/engine/slots/state_kinds.rb +54 -0
- data/lib/herb/engine/slots/state_operators.rb +36 -0
- data/lib/herb/engine/slots/state_overrides.rb +79 -0
- data/lib/herb/engine/slots/state_predicates.rb +65 -0
- data/lib/herb/engine/slots/state_transforms.rb +42 -0
- data/lib/herb/engine/slots/statics.rb +185 -0
- data/lib/herb/engine/slots/subtree.rb +82 -0
- data/lib/herb/engine/slots/subtree_compiler.rb +255 -0
- data/lib/herb/engine/slots/types.rb +42 -0
- data/lib/herb/engine/slots/visitor.rb +2267 -0
- data/lib/herb/engine/validators/accessibility_validator.rb +3 -3
- data/lib/herb/engine/validators/base.rb +36 -0
- data/lib/herb/engine/validators/generator_template_validator.rb +39 -0
- data/lib/herb/engine/validators/nesting_validator.rb +3 -3
- data/lib/herb/engine/validators/render_validator.rb +13 -33
- data/lib/herb/engine/validators/security_validator.rb +3 -17
- data/lib/herb/engine/validators.rb +43 -0
- data/lib/herb/engine/visitors/auto_close_omitted_tags_visitor.rb +48 -0
- data/lib/herb/engine/visitors/content_for_visitor.rb +127 -0
- data/lib/herb/engine/{debug_visitor.rb → visitors/debug_visitor.rb} +122 -94
- data/lib/herb/engine/visitors/html_safe_assertions_visitor.rb +281 -0
- data/lib/herb/engine/visitors/instrumentation_visitor.rb +290 -0
- data/lib/herb/engine/visitors/optimize_visitor.rb +728 -0
- data/lib/herb/engine/visitors/remove_comments_visitor.rb +106 -0
- data/lib/herb/engine/visitors/source_attribution_visitor.rb +177 -0
- data/lib/herb/engine.rb +218 -259
- data/lib/herb/ensure_installed.rb +43 -0
- data/lib/herb/errors.rb +681 -153
- data/lib/herb/fingerprint.rb +82 -0
- data/lib/herb/html/elements.rb +18 -0
- data/lib/herb/html/util.rb +21 -2
- data/lib/herb/lex_result.rb +0 -10
- data/lib/herb/locate.rb +163 -0
- data/lib/herb/location.rb +20 -0
- data/lib/herb/parse_result.rb +17 -11
- data/lib/herb/parser_options.rb +69 -40
- data/lib/herb/position.rb +19 -0
- data/lib/herb/prism_inspect.rb +1 -4
- data/lib/herb/project.rb +39 -23
- data/lib/herb/range.rb +5 -0
- data/lib/herb/result.rb +2 -2
- data/lib/herb/ruby_program.rb +110 -0
- data/lib/herb/source_path.rb +232 -0
- data/lib/herb/token.rb +14 -3
- data/lib/herb/version.rb +1 -1
- data/lib/herb/visitor/context/origin.rb +52 -0
- data/lib/herb/visitor/context/replacements.rb +59 -0
- data/lib/herb/visitor/context.rb +169 -0
- data/lib/herb/visitor/context_aware.rb +45 -0
- data/lib/herb/visitor/diagnostics.rb +148 -0
- data/lib/herb/visitor/experimental.rb +33 -0
- data/lib/herb/visitor/parser_option_requirements.rb +151 -0
- data/lib/herb/visitor/stack.rb +192 -0
- data/lib/herb/visitor.rb +47 -1
- data/lib/herb/warnings.rb +25 -0
- data/lib/herb.rb +74 -63
- data/sig/herb/action_view/helper_registry.rbs +82 -10
- data/sig/herb/analysis/partial_declaration.rbs +80 -0
- data/sig/herb/analysis/partial_index.rbs +66 -0
- data/sig/herb/analysis/partial_resolution.rbs +57 -0
- data/sig/herb/analysis/partial_resolver.rbs +76 -0
- data/sig/herb/analysis/project_index.rbs +57 -0
- data/sig/herb/{action_view → analysis}/render_analyzer.rbs +25 -4
- data/sig/herb/analysis/render_graph/ancestor_chain.rbs +22 -0
- data/sig/herb/analysis/render_graph/builder.rbs +180 -0
- data/sig/herb/analysis/render_graph/call_frame.rbs +26 -0
- data/sig/herb/analysis/render_graph/call_site_location.rbs +28 -0
- data/sig/herb/analysis/render_graph/inferred_signature.rbs +27 -0
- data/sig/herb/analysis/render_graph/partial_call_site.rbs +36 -0
- data/sig/herb/analysis/render_graph/partial_context.rbs +31 -0
- data/sig/herb/analysis/render_graph/template_roots.rbs +32 -0
- data/sig/herb/analysis/render_graph.rbs +83 -0
- data/sig/herb/analysis/ruby_locals_index/local.rbs +21 -0
- data/sig/herb/analysis/ruby_locals_index/named_reference.rbs +20 -0
- data/sig/herb/analysis/ruby_locals_index/offset_table.rbs +26 -0
- data/sig/herb/analysis/ruby_locals_index/reference_collector.rbs +40 -0
- data/sig/herb/analysis/ruby_locals_index/state_locals.rbs +19 -0
- data/sig/herb/analysis/ruby_locals_index.rbs +62 -0
- data/sig/herb/analysis/ruby_reference.rbs +28 -0
- data/sig/herb/analysis/template_dependencies/dependency_collector.rbs +52 -0
- data/sig/herb/analysis/template_dependencies/node_dependency_collector.rbs +81 -0
- data/sig/herb/analysis/template_dependencies.rbs +125 -0
- data/sig/herb/ast/erb_render_node.rbs +10 -2
- data/sig/herb/ast/helpers.rbs +31 -1
- data/sig/herb/ast/herb_directive_node.rbs +13 -0
- data/sig/herb/ast/node.rbs +9 -0
- data/sig/herb/ast/nodes.rbs +668 -89
- data/sig/herb/backend.rbs +52 -0
- data/sig/herb/bootstrap.rbs +2 -0
- data/sig/herb/colors.rbs +3 -0
- data/sig/herb/configuration.rbs +27 -3
- data/sig/herb/dev/assets.rbs +27 -0
- data/sig/herb/dev/classifier.rbs +57 -0
- data/sig/herb/dev/embedded.rbs +21 -0
- data/sig/herb/dev/pipeline.rbs +118 -0
- data/sig/herb/dev/protocol.rbs +78 -0
- data/sig/herb/dev/runner.rbs +64 -23
- data/sig/herb/dev/server.rbs +49 -22
- data/sig/herb/dev/server_entry.rbs +46 -21
- data/sig/herb/dev/watcher.rbs +84 -0
- data/sig/herb/dev.rbs +58 -0
- data/sig/herb/diagnostic/formatter.rbs +28 -0
- data/sig/herb/diagnostic.rbs +88 -0
- data/sig/herb/diff/operation.rbs +36 -0
- data/sig/herb/diff/result.rbs +36 -0
- data/sig/herb/diff.rbs +6 -0
- data/sig/herb/engine/collector.rbs +48 -0
- data/sig/herb/engine/compiler.rbs +74 -24
- data/sig/herb/engine/component_tags/constant_resolver.rbs +19 -0
- data/sig/herb/engine/component_tags/partial_resolver.rbs +30 -0
- data/sig/herb/engine/component_tags/resolver.rbs +25 -0
- data/sig/herb/engine/component_tags/visitor.rbs +69 -0
- data/sig/herb/engine/css_inliner/inliner.rbs +65 -0
- data/sig/herb/engine/css_inliner/visitor.rbs +87 -0
- data/sig/herb/engine/errors.rbs +68 -0
- data/sig/herb/engine/helpers.rbs +28 -0
- data/sig/herb/engine/inline_render/inliner.rbs +39 -0
- data/sig/herb/engine/inline_render/visitor.rbs +104 -0
- data/sig/herb/engine/runtime/entry.rbs +43 -0
- data/sig/herb/engine/runtime/error_page.rbs +115 -0
- data/sig/herb/engine/runtime/html_safe_assertions.rbs +99 -0
- data/sig/herb/engine/runtime/journal/summary.rbs +172 -0
- data/sig/herb/engine/runtime/journal.rbs +126 -0
- data/sig/herb/engine/runtime/middleware.rbs +96 -0
- data/sig/herb/engine/runtime/observations.rbs +38 -0
- data/sig/herb/engine/runtime/report.rbs +97 -0
- data/sig/herb/engine/runtime/session.rbs +233 -0
- data/sig/herb/engine/runtime.rbs +14 -0
- data/sig/herb/engine/scoped_style/channel.rbs +45 -0
- data/sig/herb/engine/scoped_style/collector.rbs +45 -0
- data/sig/herb/engine/scoped_style/visitor.rbs +220 -0
- data/sig/herb/engine/slots/annotation.rbs +72 -0
- data/sig/herb/engine/slots/bindings.rbs +34 -0
- data/sig/herb/engine/slots/callee.rbs +62 -0
- data/sig/herb/engine/slots/component_definitions.rbs +19 -0
- data/sig/herb/engine/slots/components/async.rbs +20 -0
- data/sig/herb/engine/slots/components/base.rbs +60 -0
- data/sig/herb/engine/slots/components/deferred.rbs +29 -0
- data/sig/herb/engine/slots/components/fallback.rbs +21 -0
- data/sig/herb/engine/slots/components/fragment.rbs +34 -0
- data/sig/herb/engine/slots/components/lazy.rbs +20 -0
- data/sig/herb/engine/slots/components.rbs +30 -0
- data/sig/herb/engine/slots/dependencies/channel.rbs +51 -0
- data/sig/herb/engine/slots/dependencies.rbs +94 -0
- data/sig/herb/engine/slots/dynamics_compiler.rbs +352 -0
- data/sig/herb/engine/slots/identifier.rbs +19 -0
- data/sig/herb/engine/slots/manifest/channel.rbs +49 -0
- data/sig/herb/engine/slots/manifest/collector.rbs +45 -0
- data/sig/herb/engine/slots/markers.rbs +99 -0
- data/sig/herb/engine/slots/render_bindings.rbs +69 -0
- data/sig/herb/engine/slots/schema_compiler.rbs +62 -0
- data/sig/herb/engine/slots/state_anchor.rbs +41 -0
- data/sig/herb/engine/slots/state_compiler.rbs +258 -0
- data/sig/herb/engine/slots/state_directives.rbs +278 -0
- data/sig/herb/engine/slots/state_kinds.rbs +24 -0
- data/sig/herb/engine/slots/state_operators.rbs +19 -0
- data/sig/herb/engine/slots/state_overrides.rbs +33 -0
- data/sig/herb/engine/slots/state_predicates.rbs +16 -0
- data/sig/herb/engine/slots/state_transforms.rbs +15 -0
- data/sig/herb/engine/slots/statics.rbs +67 -0
- data/sig/herb/engine/slots/subtree.rbs +49 -0
- data/sig/herb/engine/slots/subtree_compiler.rbs +130 -0
- data/sig/herb/engine/slots/types.rbs +46 -0
- data/sig/herb/engine/slots/visitor.rbs +603 -0
- data/sig/herb/engine/validators/accessibility_validator.rbs +1 -1
- data/sig/herb/engine/validators/base.rbs +28 -0
- data/sig/herb/engine/validators/generator_template_validator.rbs +19 -0
- data/sig/herb/engine/validators/nesting_validator.rbs +1 -1
- data/sig/herb/engine/validators/render_validator.rbs +2 -6
- data/sig/herb/engine/validators/security_validator.rbs +1 -3
- data/sig/herb/engine/validators.rbs +21 -0
- data/sig/herb/engine/visitors/auto_close_omitted_tags_visitor.rbs +26 -0
- data/sig/herb/engine/visitors/content_for_visitor.rbs +52 -0
- data/sig/herb/engine/{debug_visitor.rbs → visitors/debug_visitor.rbs} +26 -15
- data/sig/herb/engine/visitors/html_safe_assertions_visitor.rbs +100 -0
- data/sig/herb/engine/visitors/instrumentation_visitor.rbs +111 -0
- data/sig/herb/engine/visitors/optimize_visitor.rbs +246 -0
- data/sig/herb/engine/visitors/remove_comments_visitor.rbs +66 -0
- data/sig/herb/engine/visitors/source_attribution_visitor.rbs +90 -0
- data/sig/herb/engine.rbs +47 -41
- data/sig/herb/ensure_installed.rbs +9 -0
- data/sig/herb/errors.rbs +311 -0
- data/sig/herb/fingerprint.rbs +37 -0
- data/sig/herb/html/elements.rbs +19 -0
- data/sig/herb/html/util.rbs +15 -1
- data/sig/herb/lex_result.rbs +0 -6
- data/sig/herb/locate.rbs +89 -0
- data/sig/herb/location.rbs +12 -0
- data/sig/herb/parse_result.rbs +10 -8
- data/sig/herb/parser_options.rbs +53 -19
- data/sig/herb/position.rbs +11 -0
- data/sig/herb/range.rbs +3 -0
- data/sig/herb/ruby_program.rbs +51 -0
- data/sig/herb/source_path.rbs +132 -0
- data/sig/herb/token.rbs +5 -2
- data/sig/herb/visitor/context/origin.rbs +51 -0
- data/sig/herb/visitor/context/replacements.rbs +39 -0
- data/sig/herb/visitor/context.rbs +83 -0
- data/sig/herb/visitor/context_aware.rbs +32 -0
- data/sig/herb/visitor/diagnostics.rbs +82 -0
- data/sig/herb/visitor/experimental.rbs +23 -0
- data/sig/herb/visitor/parser_option_requirements.rbs +76 -0
- data/sig/herb/visitor/stack.rbs +91 -0
- data/sig/herb/visitor.rbs +22 -0
- data/sig/herb/warnings.rbs +10 -0
- data/sig/herb.rbs +27 -10
- data/sig/manifest.yaml +13 -0
- data/sig/serialized_ast_errors.rbs +62 -1
- data/sig/serialized_ast_nodes.rbs +59 -2
- data/src/analyze/action_view/attribute_extraction_helpers.c +73 -36
- data/src/analyze/action_view/generated_handlers.c +37 -1
- data/src/analyze/action_view/generated_handlers.h +2 -1
- data/src/analyze/action_view/helper_registry.c +1353 -58
- data/src/analyze/action_view/registry.c +10 -17
- data/src/analyze/action_view/stylesheet_link_tag.c +40 -0
- data/src/analyze/action_view/tag_helper_node_builders.c +63 -3
- data/src/analyze/action_view/tag_helpers.c +502 -111
- data/src/analyze/analyze.c +306 -89
- data/src/analyze/analyze_helpers.c +502 -237
- data/src/analyze/analyzed_ruby.c +2 -0
- data/src/analyze/builders.c +80 -51
- data/src/analyze/conditional_elements.c +13 -8
- data/src/analyze/conditional_open_tags.c +11 -5
- data/src/analyze/control_type.c +36 -13
- data/src/analyze/herb_directives.c +701 -0
- data/src/analyze/invalid_structures.c +11 -7
- data/src/analyze/iteration_nodes.c +306 -0
- data/src/analyze/missing_end.c +116 -32
- data/src/analyze/parse_errors.c +8 -3
- data/src/analyze/postfix_conditionals.c +98 -63
- data/src/analyze/prism_annotate.c +45 -13
- data/src/analyze/render_nodes.c +348 -123
- data/src/analyze/strict_locals.c +30 -26
- data/src/analyze/ternary_conditionals.c +95 -70
- data/src/analyze/transform.c +43 -1
- data/src/ast/ast_node.c +3 -13
- data/src/ast/ast_nodes.c +914 -113
- data/src/ast/ast_pretty_print.c +166 -3
- data/src/diff/herb_diff.c +8 -0
- data/src/diff/herb_diff_attributes.c +1 -0
- data/src/diff/herb_diff_children.c +4 -3
- data/src/diff/herb_diff_helpers.c +7 -1
- data/src/diff/herb_diff_nodes.c +186 -71
- data/src/diff/herb_hash_tree.c +99 -1
- data/src/errors.c +1124 -105
- data/src/extract.c +227 -144
- data/src/herb.c +43 -8
- data/src/include/analyze/action_view/attribute_extraction_helpers.h +1 -1
- data/src/include/analyze/action_view/helper_registry.h +28 -4
- data/src/include/analyze/action_view/tag_helper_handler.h +1 -1
- data/src/include/analyze/action_view/tag_helper_node_builders.h +7 -0
- data/src/include/analyze/analyze.h +11 -22
- data/src/include/analyze/analyzed_ruby.h +25 -0
- data/src/include/analyze/builders.h +16 -0
- data/src/include/analyze/helpers.h +25 -24
- data/src/include/analyze/herb_directive_kinds.h +41 -0
- data/src/include/analyze/herb_directives.h +14 -0
- data/src/include/analyze/iteration_nodes.h +11 -0
- data/src/include/analyze/prism_annotate.h +3 -3
- data/src/include/analyze/ternary_conditionals.h +2 -0
- data/src/include/ast/ast_node.h +1 -5
- data/src/include/ast/ast_nodes.h +78 -3
- data/src/include/ast/ast_pretty_print.h +1 -1
- data/src/include/diff/herb_diff.h +11 -0
- data/src/include/errors.h +163 -38
- data/src/include/extract.h +11 -0
- data/src/include/herb.h +6 -0
- data/src/include/lexer/erb_openers.h +29 -0
- data/src/include/lexer/lexer.h +1 -0
- data/src/include/lexer/lexer_peek_helpers.h +8 -1
- data/src/include/lexer/lexer_struct.h +4 -0
- data/src/include/lexer/token.h +5 -0
- data/src/include/lexer/token_struct.h +8 -6
- data/src/include/lib/hb_allocator.h +2 -1
- data/src/include/lib/hb_array.h +2 -0
- data/src/include/lib/hb_clock.h +15 -0
- data/src/include/lib/hb_foreach.h +1 -1
- data/src/include/lib/hb_string.h +7 -0
- data/src/include/parser/dot_notation.h +1 -1
- data/src/include/parser/foreign_content_elements.h +32 -0
- data/src/include/parser/parser.h +40 -26
- data/src/include/parser/parser_helpers.h +13 -11
- data/src/include/parser/parser_options.h +41 -0
- data/src/include/prism/herb_prism_node.h +6 -1
- data/src/include/prism/ruby_parser.h +6 -0
- data/src/include/util/html_elements.h +85 -0
- data/src/include/util/html_util.h +1 -0
- data/src/include/version.h +1 -1
- data/src/lexer/lexer_peek_helpers.c +15 -1
- data/src/lexer/token.c +89 -1
- data/src/lexer.c +228 -12
- data/src/lib/hb_allocator.c +2 -0
- data/src/lib/hb_array.c +26 -0
- data/src/lib/hb_string.c +26 -0
- data/src/main.c +1 -1
- data/src/parser/dot_notation.c +4 -3
- data/src/parser/match_tags.c +66 -1
- data/src/parser/parser_helpers.c +69 -37
- data/src/parser.c +658 -385
- data/src/parser_options_defaults.c +30 -0
- data/src/prism/prism_helpers.c +94 -0
- data/src/prism/ruby_parser.c +49 -0
- data/src/util/html_util.c +11 -58
- data/src/visitor.c +77 -1
- data/templates/ext/herb/error_helpers.c.erb +1 -1
- data/templates/ext/herb/nodes.c.erb +19 -14
- data/templates/ext/herb/nodes.h.erb +2 -1
- data/templates/ext/herb/parser_options_helpers.c.erb +69 -0
- data/templates/ext/herb/parser_options_helpers.h.erb +11 -0
- data/templates/java/nodes.c.erb +21 -17
- data/templates/java/nodes.h.erb +3 -2
- data/templates/java/org/herb/ParserOptions.java.erb +24 -0
- data/templates/java/org/herb/ast/HelperRegistry.java.erb +67 -31
- data/templates/java/org/herb/ast/HelperType.java.erb +29 -0
- data/templates/java/org/herb/ast/Nodes.java.erb +11 -7
- data/templates/java/parser_options_helpers.c.erb +45 -0
- data/templates/java/parser_options_helpers.h.erb +10 -0
- data/templates/javascript/packages/client/src/state-kinds.ts.erb +49 -0
- data/templates/javascript/packages/client/src/state-operators.ts.erb +15 -0
- data/templates/javascript/packages/client/src/state-predicates.ts.erb +27 -0
- data/templates/javascript/packages/client/src/state-transforms.ts.erb +19 -0
- data/templates/javascript/packages/core/src/action-view-helpers.ts.erb +47 -0
- data/templates/javascript/packages/core/src/built-in-components.ts.erb +67 -0
- data/templates/javascript/packages/core/src/errors.ts.erb +9 -3
- data/templates/javascript/packages/core/src/foreign-content-elements.ts.erb +18 -0
- data/templates/javascript/packages/core/src/html-constants.ts.erb +32 -0
- data/templates/javascript/packages/core/src/html-elements.ts.erb +41 -0
- data/templates/javascript/packages/core/src/node-type-guards.ts.erb +11 -7
- data/templates/javascript/packages/core/src/nodes.ts.erb +103 -20
- data/templates/javascript/packages/core/src/parser-options.ts.erb +41 -0
- data/templates/javascript/packages/core/src/visitor.ts.erb +1 -1
- data/templates/javascript/packages/node/extension/error_helpers.cpp.erb +3 -3
- data/templates/javascript/packages/node/extension/nodes.cpp.erb +18 -13
- data/templates/javascript/packages/node/extension/nodes.h.erb +3 -3
- data/templates/javascript/packages/node/extension/parser_options_helpers.cpp.erb +41 -0
- data/templates/javascript/packages/node/extension/parser_options_helpers.h.erb +12 -0
- data/templates/lib/herb/action_view/helper_registry.rb.erb +77 -3
- data/templates/lib/herb/ast/nodes.rb.erb +16 -6
- data/templates/lib/herb/engine/slots/component_definitions.rb.erb +38 -0
- data/templates/lib/herb/engine/slots/state_kinds.rb.erb +37 -0
- data/templates/lib/herb/engine/slots/state_operators.rb.erb +26 -0
- data/templates/lib/herb/engine/slots/state_predicates.rb.erb +39 -0
- data/templates/lib/herb/engine/slots/state_transforms.rb.erb +27 -0
- data/templates/lib/herb/errors.rb.erb +34 -6
- data/templates/lib/herb/html/elements.rb.erb +12 -0
- data/templates/lib/herb/parser_options.rb.erb +32 -0
- data/templates/lib/herb/visitor.rb.erb +7 -1
- data/templates/rust/herb-printer/src/printer_visitor.rs.erb +14 -0
- data/templates/rust/src/action_view_helpers.rs.erb +38 -0
- data/templates/rust/src/ast/nodes.rs.erb +21 -31
- data/templates/rust/src/errors.rs.erb +1 -1
- data/templates/rust/src/nodes.rs.erb +58 -26
- data/templates/rust/src/parser_options.rs.erb +16 -0
- data/templates/rust/src/prism/generated_deserialize.rs.erb +109 -0
- data/templates/rust/src/prism/generated_prettyprint.rs.erb +153 -0
- data/templates/rust/src/union_types.rs.erb +7 -1
- data/templates/rust/src/visitor.rs.erb +1 -1
- data/templates/src/analyze/action_view/helper_registry.c.erb +22 -0
- data/templates/src/analyze/missing_end.c.erb +13 -5
- data/templates/src/ast/ast_nodes.c.erb +41 -2
- data/templates/src/diff/herb_diff_nodes.c.erb +44 -8
- data/templates/src/errors.c.erb +8 -3
- data/templates/src/include/analyze/action_view/helper_registry.h.erb +19 -0
- data/templates/src/include/analyze/herb_directive_kinds.h.erb +25 -0
- data/templates/src/include/errors.h.erb +3 -1
- data/templates/src/include/parser/foreign_content_elements.h.erb +23 -0
- data/templates/src/include/parser/parser_options.h.erb +21 -0
- data/templates/src/include/util/html_elements.h.erb +28 -0
- data/templates/src/parser_options_defaults.c.erb +9 -0
- data/templates/template.rb +564 -9
- data/templates/wasm/error_helpers.cpp.erb +4 -4
- data/templates/wasm/nodes.cpp.erb +17 -27
- data/templates/wasm/nodes.h.erb +3 -3
- data/templates/wasm/parser_options_helpers.cpp.erb +25 -0
- data/templates/wasm/parser_options_helpers.h.erb +12 -0
- metadata +309 -30
- data/config/action_view_helpers/actionview/form_helper/button.yml +0 -38
- data/config/action_view_helpers/actionview/form_helper/submit.yml +0 -35
- data/lib/herb/ast.rb +0 -7
- data/lib/herb/diff_operation.rb +0 -34
- data/lib/herb/diff_result.rb +0 -59
- data/lib/herb/engine/error_formatter.rb +0 -432
- data/lib/herb/engine/parser_error_overlay.rb +0 -771
- data/lib/herb/engine/validation_error_overlay.rb +0 -182
- data/lib/herb/engine/validation_errors.rb +0 -65
- data/lib/herb/engine/validator.rb +0 -80
- data/sig/herb/ast.rbs +0 -6
- data/sig/herb/diff_operation.rbs +0 -34
- data/sig/herb/diff_result.rbs +0 -34
- data/sig/herb/engine/debug.rbs +0 -38
- data/sig/herb/engine/error_formatter.rbs +0 -47
- data/sig/herb/engine/parser_error_overlay.rbs +0 -41
- data/sig/herb/engine/validation_error_overlay.rbs +0 -35
- data/sig/herb/engine/validation_errors.rbs +0 -45
- data/sig/herb/engine/validator.rbs +0 -41
- data/sig/herb_c_extension.rbs +0 -10
- data/sig/vendor/did_you_mean.rbs +0 -6
- data/sig/vendor/parallel.rbs +0 -4
data/src/parser.c
CHANGED
|
@@ -23,10 +23,10 @@
|
|
|
23
23
|
#include <strings.h>
|
|
24
24
|
|
|
25
25
|
#define MAX_CONSECUTIVE_ERRORS 10
|
|
26
|
-
|
|
27
|
-
static void
|
|
28
|
-
static
|
|
29
|
-
static
|
|
26
|
+
static void parser_parse_in_data_state(parser_T* parser, hb_array_T* children, hb_array_T** errors);
|
|
27
|
+
static void parser_parse_foreign_content(parser_T* parser, hb_array_T* children, hb_array_T** errors);
|
|
28
|
+
static bool parser_element_has_foreign_content(parser_T* parser, hb_string_T tag_name);
|
|
29
|
+
static AST_NODE_T* parser_parse_erb_tag(parser_T* parser);
|
|
30
30
|
static void parser_handle_whitespace(parser_T* parser, token_T* whitespace_token, hb_array_T* children);
|
|
31
31
|
static void parser_consume_whitespace(parser_T* parser, hb_array_T* children);
|
|
32
32
|
static void parser_skip_erb_content(lexer_T* lexer);
|
|
@@ -35,21 +35,6 @@ static bool parser_lookahead_erb_is_control_flow(parser_T* parser);
|
|
|
35
35
|
static void parser_handle_erb_in_open_tag(parser_T* parser, hb_array_T* children);
|
|
36
36
|
static void parser_handle_whitespace_in_open_tag(parser_T* parser, hb_array_T* children);
|
|
37
37
|
|
|
38
|
-
const parser_options_T HERB_DEFAULT_PARSER_OPTIONS = { .track_whitespace = false,
|
|
39
|
-
.analyze = true,
|
|
40
|
-
.strict = true,
|
|
41
|
-
.action_view_helpers = false,
|
|
42
|
-
.transform_conditionals = false,
|
|
43
|
-
.render_nodes = false,
|
|
44
|
-
.strict_locals = false,
|
|
45
|
-
.prism_nodes_deep = false,
|
|
46
|
-
.prism_nodes = false,
|
|
47
|
-
.prism_program = false,
|
|
48
|
-
.dot_notation_tags = false,
|
|
49
|
-
.html = true,
|
|
50
|
-
.start_line = 0,
|
|
51
|
-
.start_column = 0 };
|
|
52
|
-
|
|
53
38
|
size_t parser_sizeof(void) {
|
|
54
39
|
return sizeof(struct PARSER_STRUCT);
|
|
55
40
|
}
|
|
@@ -60,25 +45,32 @@ void herb_parser_init(parser_T* parser, lexer_T* lexer, parser_options_T options
|
|
|
60
45
|
parser->current_token = lexer_next_token(lexer);
|
|
61
46
|
parser->open_tags_stack = hb_array_init(16, parser->allocator);
|
|
62
47
|
parser->state = PARSER_STATE_DATA;
|
|
63
|
-
parser->
|
|
48
|
+
parser->foreign_content_kind = FOREIGN_CONTENT_NONE;
|
|
49
|
+
parser->foreign_content_tag_name = HB_STRING_NULL;
|
|
50
|
+
parser->svg_depth = 0;
|
|
51
|
+
parser->xml_document = false;
|
|
64
52
|
parser->options = options;
|
|
65
53
|
parser->consecutive_error_count = 0;
|
|
66
54
|
parser->in_recovery_mode = false;
|
|
55
|
+
|
|
56
|
+
for (size_t index = 0; index < HERB_MAX_FOREIGN_CONTENT_ELEMENTS; index++) {
|
|
57
|
+
parser->foreign_content_absent_from[index] = UINT32_MAX;
|
|
58
|
+
}
|
|
67
59
|
}
|
|
68
60
|
|
|
69
61
|
static AST_CDATA_NODE_T* parser_parse_cdata(parser_T* parser) {
|
|
70
|
-
hb_array_T* errors =
|
|
62
|
+
hb_array_T* errors = NULL;
|
|
71
63
|
hb_array_T* children = hb_array_init(8, parser->allocator);
|
|
72
64
|
hb_buffer_T content;
|
|
73
65
|
hb_buffer_init(&content, 128, parser->allocator);
|
|
74
66
|
|
|
75
|
-
token_T* tag_opening = parser_consume_expected(parser, TOKEN_CDATA_START, errors);
|
|
67
|
+
token_T* tag_opening = parser_consume_expected(parser, TOKEN_CDATA_START, &errors);
|
|
76
68
|
position_T start = parser->current_token->location.start;
|
|
77
69
|
|
|
78
70
|
while (token_is_none_of(parser, TOKEN_CDATA_END, TOKEN_EOF)) {
|
|
79
71
|
if (token_is(parser, TOKEN_ERB_START)) {
|
|
80
72
|
parser_append_literal_node_from_buffer(parser, &content, children, start);
|
|
81
|
-
|
|
73
|
+
AST_NODE_T* erb_node = parser_parse_erb_tag(parser);
|
|
82
74
|
hb_array_append(children, erb_node);
|
|
83
75
|
start = parser->current_token->location.start;
|
|
84
76
|
continue;
|
|
@@ -90,7 +82,7 @@ static AST_CDATA_NODE_T* parser_parse_cdata(parser_T* parser) {
|
|
|
90
82
|
}
|
|
91
83
|
|
|
92
84
|
parser_append_literal_node_from_buffer(parser, &content, children, start);
|
|
93
|
-
token_T* tag_closing = parser_consume_expected(parser, TOKEN_CDATA_END, errors);
|
|
85
|
+
token_T* tag_closing = parser_consume_expected(parser, TOKEN_CDATA_END, &errors);
|
|
94
86
|
|
|
95
87
|
AST_CDATA_NODE_T* cdata = ast_cdata_node_init(
|
|
96
88
|
tag_opening,
|
|
@@ -103,26 +95,59 @@ static AST_CDATA_NODE_T* parser_parse_cdata(parser_T* parser) {
|
|
|
103
95
|
);
|
|
104
96
|
|
|
105
97
|
hb_buffer_free(&content);
|
|
106
|
-
token_free(tag_opening, parser->allocator);
|
|
107
|
-
token_free(tag_closing, parser->allocator);
|
|
108
98
|
|
|
109
99
|
return cdata;
|
|
110
100
|
}
|
|
111
101
|
|
|
102
|
+
// <!-- a <!-->
|
|
103
|
+
static token_T* parser_parse_html_comment_abrupt_end(
|
|
104
|
+
parser_T* parser,
|
|
105
|
+
hb_buffer_T* comment,
|
|
106
|
+
hb_array_T* children,
|
|
107
|
+
position_T start
|
|
108
|
+
) {
|
|
109
|
+
token_T* nested_start = parser_advance(parser);
|
|
110
|
+
token_T* tag_end = parser_advance(parser);
|
|
111
|
+
|
|
112
|
+
position_T dashes_start = nested_start->location.start;
|
|
113
|
+
dashes_start.column += 2;
|
|
114
|
+
|
|
115
|
+
hb_buffer_append_string(comment, hb_string("<!"));
|
|
116
|
+
|
|
117
|
+
hb_string_T content = { .data = comment->value, .length = (uint32_t) comment->length };
|
|
118
|
+
hb_array_append(children, ast_literal_node_init(content, start, dashes_start, NULL, parser->allocator));
|
|
119
|
+
hb_buffer_clear(comment);
|
|
120
|
+
|
|
121
|
+
token_T* comment_end = hb_allocator_alloc(parser->allocator, sizeof(token_T));
|
|
122
|
+
|
|
123
|
+
comment_end->type = TOKEN_HTML_COMMENT_END;
|
|
124
|
+
comment_end->value = hb_string_from_data(hb_allocator_strndup(parser->allocator, "-->", 3), 3);
|
|
125
|
+
comment_end->owns_value = true;
|
|
126
|
+
comment_end->location = (location_T) { .start = dashes_start, .end = tag_end->location.end };
|
|
127
|
+
comment_end->range = (range_T) { .from = nested_start->range.from + 2, .to = tag_end->range.to };
|
|
128
|
+
|
|
129
|
+
token_free(nested_start, parser->allocator);
|
|
130
|
+
token_free(tag_end, parser->allocator);
|
|
131
|
+
|
|
132
|
+
return comment_end;
|
|
133
|
+
}
|
|
134
|
+
|
|
112
135
|
static AST_HTML_COMMENT_NODE_T* parser_parse_html_comment(parser_T* parser) {
|
|
113
|
-
hb_array_T* errors =
|
|
136
|
+
hb_array_T* errors = NULL;
|
|
114
137
|
hb_array_T* children = hb_array_init(8, parser->allocator);
|
|
115
|
-
token_T* comment_start = parser_consume_expected(parser, TOKEN_HTML_COMMENT_START, errors);
|
|
138
|
+
token_T* comment_start = parser_consume_expected(parser, TOKEN_HTML_COMMENT_START, &errors);
|
|
116
139
|
position_T start = parser->current_token->location.start;
|
|
117
140
|
|
|
118
141
|
hb_buffer_T comment;
|
|
119
142
|
hb_buffer_init(&comment, 512, parser->allocator);
|
|
120
143
|
|
|
144
|
+
token_T* comment_end = NULL;
|
|
145
|
+
|
|
121
146
|
while (token_is_none_of(parser, TOKEN_HTML_COMMENT_END, TOKEN_HTML_COMMENT_INVALID_END, TOKEN_EOF)) {
|
|
122
147
|
if (token_is(parser, TOKEN_ERB_START)) {
|
|
123
148
|
parser_append_literal_node_from_buffer(parser, &comment, children, start);
|
|
124
149
|
|
|
125
|
-
|
|
150
|
+
AST_NODE_T* erb_node = parser_parse_erb_tag(parser);
|
|
126
151
|
hb_array_append(children, erb_node);
|
|
127
152
|
|
|
128
153
|
start = parser->current_token->location.start;
|
|
@@ -130,6 +155,33 @@ static AST_HTML_COMMENT_NODE_T* parser_parse_html_comment(parser_T* parser) {
|
|
|
130
155
|
continue;
|
|
131
156
|
}
|
|
132
157
|
|
|
158
|
+
if (token_is(parser, TOKEN_HTML_COMMENT_START)) {
|
|
159
|
+
lexer_T lexer_copy = *parser->lexer;
|
|
160
|
+
token_T* next_token = lexer_next_token(&lexer_copy);
|
|
161
|
+
token_type_T next_type = next_token ? next_token->type : TOKEN_EOF;
|
|
162
|
+
|
|
163
|
+
if (next_token) { token_free(next_token, parser->allocator); }
|
|
164
|
+
|
|
165
|
+
// <!--[if !mso]><!--><meta><!--<![endif]-->
|
|
166
|
+
if (next_type == TOKEN_HTML_TAG_END) {
|
|
167
|
+
comment_end = parser_parse_html_comment_abrupt_end(parser, &comment, children, start);
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// <!-- outer <!-- inner -->
|
|
172
|
+
if (next_type != TOKEN_EOF && parser->options.strict) {
|
|
173
|
+
append_nested_comment_error(
|
|
174
|
+
comment_start,
|
|
175
|
+
parser->current_token,
|
|
176
|
+
parser->current_token->location.start,
|
|
177
|
+
parser->current_token->location.end,
|
|
178
|
+
parser->allocator,
|
|
179
|
+
&errors,
|
|
180
|
+
&parser->options
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
133
185
|
token_T* token = parser_advance(parser);
|
|
134
186
|
hb_buffer_append_string(&comment, token->value);
|
|
135
187
|
token_free(token, parser->allocator);
|
|
@@ -137,19 +189,31 @@ static AST_HTML_COMMENT_NODE_T* parser_parse_html_comment(parser_T* parser) {
|
|
|
137
189
|
|
|
138
190
|
parser_append_literal_node_from_buffer(parser, &comment, children, start);
|
|
139
191
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
if (token_is(parser, TOKEN_HTML_COMMENT_INVALID_END)) {
|
|
192
|
+
if (comment_end != NULL) {
|
|
193
|
+
// closed by <!-->
|
|
194
|
+
} else if (token_is(parser, TOKEN_HTML_COMMENT_INVALID_END)) {
|
|
143
195
|
comment_end = parser_advance(parser);
|
|
144
196
|
append_invalid_comment_closing_tag_error(
|
|
145
197
|
comment_end,
|
|
146
198
|
comment_end->location.start,
|
|
147
199
|
comment_end->location.end,
|
|
148
200
|
parser->allocator,
|
|
149
|
-
errors
|
|
201
|
+
&errors,
|
|
202
|
+
&parser->options
|
|
203
|
+
);
|
|
204
|
+
} else if (token_is(parser, TOKEN_EOF)) {
|
|
205
|
+
append_unclosed_comment_error(
|
|
206
|
+
comment_start,
|
|
207
|
+
comment_start->location.start,
|
|
208
|
+
parser->current_token->location.start,
|
|
209
|
+
parser->allocator,
|
|
210
|
+
&errors,
|
|
211
|
+
&parser->options
|
|
150
212
|
);
|
|
213
|
+
|
|
214
|
+
comment_end = parser_advance(parser);
|
|
151
215
|
} else {
|
|
152
|
-
comment_end = parser_consume_expected(parser, TOKEN_HTML_COMMENT_END, errors);
|
|
216
|
+
comment_end = parser_consume_expected(parser, TOKEN_HTML_COMMENT_END, &errors);
|
|
153
217
|
}
|
|
154
218
|
|
|
155
219
|
AST_HTML_COMMENT_NODE_T* comment_node = ast_html_comment_node_init(
|
|
@@ -163,19 +227,17 @@ static AST_HTML_COMMENT_NODE_T* parser_parse_html_comment(parser_T* parser) {
|
|
|
163
227
|
);
|
|
164
228
|
|
|
165
229
|
hb_buffer_free(&comment);
|
|
166
|
-
token_free(comment_start, parser->allocator);
|
|
167
|
-
token_free(comment_end, parser->allocator);
|
|
168
230
|
|
|
169
231
|
return comment_node;
|
|
170
232
|
}
|
|
171
233
|
|
|
172
234
|
static AST_HTML_DOCTYPE_NODE_T* parser_parse_html_doctype(parser_T* parser) {
|
|
173
|
-
hb_array_T* errors =
|
|
235
|
+
hb_array_T* errors = NULL;
|
|
174
236
|
hb_array_T* children = hb_array_init(8, parser->allocator);
|
|
175
237
|
hb_buffer_T content;
|
|
176
238
|
hb_buffer_init(&content, 64, parser->allocator);
|
|
177
239
|
|
|
178
|
-
token_T* tag_opening = parser_consume_expected(parser, TOKEN_HTML_DOCTYPE, errors);
|
|
240
|
+
token_T* tag_opening = parser_consume_expected(parser, TOKEN_HTML_DOCTYPE, &errors);
|
|
179
241
|
|
|
180
242
|
position_T start = parser->current_token->location.start;
|
|
181
243
|
|
|
@@ -183,20 +245,20 @@ static AST_HTML_DOCTYPE_NODE_T* parser_parse_html_doctype(parser_T* parser) {
|
|
|
183
245
|
if (token_is(parser, TOKEN_ERB_START)) {
|
|
184
246
|
parser_append_literal_node_from_buffer(parser, &content, children, start);
|
|
185
247
|
|
|
186
|
-
|
|
248
|
+
AST_NODE_T* erb_node = parser_parse_erb_tag(parser);
|
|
187
249
|
hb_array_append(children, erb_node);
|
|
188
250
|
|
|
189
251
|
continue;
|
|
190
252
|
}
|
|
191
253
|
|
|
192
|
-
token_T* token = parser_consume_expected(parser, parser->current_token->type, errors);
|
|
254
|
+
token_T* token = parser_consume_expected(parser, parser->current_token->type, &errors);
|
|
193
255
|
hb_buffer_append_string(&content, token->value);
|
|
194
256
|
token_free(token, parser->allocator);
|
|
195
257
|
}
|
|
196
258
|
|
|
197
259
|
parser_append_literal_node_from_buffer(parser, &content, children, start);
|
|
198
260
|
|
|
199
|
-
token_T* tag_closing = parser_consume_expected(parser, TOKEN_HTML_TAG_END, errors);
|
|
261
|
+
token_T* tag_closing = parser_consume_expected(parser, TOKEN_HTML_TAG_END, &errors);
|
|
200
262
|
|
|
201
263
|
AST_HTML_DOCTYPE_NODE_T* doctype = ast_html_doctype_node_init(
|
|
202
264
|
tag_opening,
|
|
@@ -208,20 +270,20 @@ static AST_HTML_DOCTYPE_NODE_T* parser_parse_html_doctype(parser_T* parser) {
|
|
|
208
270
|
parser->allocator
|
|
209
271
|
);
|
|
210
272
|
|
|
211
|
-
token_free(tag_opening, parser->allocator);
|
|
212
|
-
token_free(tag_closing, parser->allocator);
|
|
213
273
|
hb_buffer_free(&content);
|
|
214
274
|
|
|
215
275
|
return doctype;
|
|
216
276
|
}
|
|
217
277
|
|
|
218
278
|
static AST_XML_DECLARATION_NODE_T* parser_parse_xml_declaration(parser_T* parser) {
|
|
219
|
-
hb_array_T* errors =
|
|
279
|
+
hb_array_T* errors = NULL;
|
|
220
280
|
hb_array_T* children = hb_array_init(8, parser->allocator);
|
|
221
281
|
hb_buffer_T content;
|
|
222
282
|
hb_buffer_init(&content, 64, parser->allocator);
|
|
223
283
|
|
|
224
|
-
token_T* tag_opening = parser_consume_expected(parser, TOKEN_XML_DECLARATION, errors);
|
|
284
|
+
token_T* tag_opening = parser_consume_expected(parser, TOKEN_XML_DECLARATION, &errors);
|
|
285
|
+
|
|
286
|
+
parser->xml_document = true;
|
|
225
287
|
|
|
226
288
|
position_T start = parser->current_token->location.start;
|
|
227
289
|
|
|
@@ -229,7 +291,7 @@ static AST_XML_DECLARATION_NODE_T* parser_parse_xml_declaration(parser_T* parser
|
|
|
229
291
|
if (token_is(parser, TOKEN_ERB_START)) {
|
|
230
292
|
parser_append_literal_node_from_buffer(parser, &content, children, start);
|
|
231
293
|
|
|
232
|
-
|
|
294
|
+
AST_NODE_T* erb_node = parser_parse_erb_tag(parser);
|
|
233
295
|
hb_array_append(children, erb_node);
|
|
234
296
|
|
|
235
297
|
start = parser->current_token->location.start;
|
|
@@ -244,7 +306,7 @@ static AST_XML_DECLARATION_NODE_T* parser_parse_xml_declaration(parser_T* parser
|
|
|
244
306
|
|
|
245
307
|
parser_append_literal_node_from_buffer(parser, &content, children, start);
|
|
246
308
|
|
|
247
|
-
token_T* tag_closing = parser_consume_expected(parser, TOKEN_XML_DECLARATION_END, errors);
|
|
309
|
+
token_T* tag_closing = parser_consume_expected(parser, TOKEN_XML_DECLARATION_END, &errors);
|
|
248
310
|
|
|
249
311
|
AST_XML_DECLARATION_NODE_T* xml_declaration = ast_xml_declaration_node_init(
|
|
250
312
|
tag_opening,
|
|
@@ -256,14 +318,61 @@ static AST_XML_DECLARATION_NODE_T* parser_parse_xml_declaration(parser_T* parser
|
|
|
256
318
|
parser->allocator
|
|
257
319
|
);
|
|
258
320
|
|
|
259
|
-
token_free(tag_opening, parser->allocator);
|
|
260
|
-
token_free(tag_closing, parser->allocator);
|
|
261
321
|
hb_buffer_free(&content);
|
|
262
322
|
|
|
263
323
|
return xml_declaration;
|
|
264
324
|
}
|
|
265
325
|
|
|
266
|
-
static
|
|
326
|
+
static AST_XML_PROCESSING_INSTRUCTION_NODE_T* parser_parse_xml_processing_instruction(parser_T* parser) {
|
|
327
|
+
hb_array_T* errors = NULL;
|
|
328
|
+
hb_array_T* children = hb_array_init(8, parser->allocator);
|
|
329
|
+
hb_buffer_T content;
|
|
330
|
+
hb_buffer_init(&content, 64, parser->allocator);
|
|
331
|
+
|
|
332
|
+
token_T* tag_opening = parser_consume_expected(parser, TOKEN_XML_PROCESSING_INSTRUCTION_START, &errors);
|
|
333
|
+
token_T* target = parser_consume_expected(parser, TOKEN_IDENTIFIER, &errors);
|
|
334
|
+
|
|
335
|
+
position_T start = parser->current_token->location.start;
|
|
336
|
+
|
|
337
|
+
while (token_is_none_of(parser, TOKEN_XML_DECLARATION_END, TOKEN_HTML_TAG_END, TOKEN_EOF)) {
|
|
338
|
+
if (token_is(parser, TOKEN_ERB_START)) {
|
|
339
|
+
parser_append_literal_node_from_buffer(parser, &content, children, start);
|
|
340
|
+
|
|
341
|
+
AST_NODE_T* erb_node = parser_parse_erb_tag(parser);
|
|
342
|
+
hb_array_append(children, erb_node);
|
|
343
|
+
|
|
344
|
+
start = parser->current_token->location.start;
|
|
345
|
+
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
token_T* token = parser_advance(parser);
|
|
350
|
+
hb_buffer_append_string(&content, token->value);
|
|
351
|
+
token_free(token, parser->allocator);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
parser_append_literal_node_from_buffer(parser, &content, children, start);
|
|
355
|
+
|
|
356
|
+
token_type_T closing_type = token_is(parser, TOKEN_HTML_TAG_END) ? TOKEN_HTML_TAG_END : TOKEN_XML_DECLARATION_END;
|
|
357
|
+
token_T* tag_closing = parser_consume_expected(parser, closing_type, &errors);
|
|
358
|
+
|
|
359
|
+
AST_XML_PROCESSING_INSTRUCTION_NODE_T* processing_instruction = ast_xml_processing_instruction_node_init(
|
|
360
|
+
tag_opening,
|
|
361
|
+
target,
|
|
362
|
+
children,
|
|
363
|
+
tag_closing,
|
|
364
|
+
tag_opening->location.start,
|
|
365
|
+
tag_closing->location.end,
|
|
366
|
+
errors,
|
|
367
|
+
parser->allocator
|
|
368
|
+
);
|
|
369
|
+
|
|
370
|
+
hb_buffer_free(&content);
|
|
371
|
+
|
|
372
|
+
return processing_instruction;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
static AST_HTML_TEXT_NODE_T* parser_parse_text_content(parser_T* parser, hb_array_T** document_errors) {
|
|
267
376
|
position_T start = parser->current_token->location.start;
|
|
268
377
|
|
|
269
378
|
hb_buffer_T content;
|
|
@@ -275,6 +384,8 @@ static AST_HTML_TEXT_NODE_T* parser_parse_text_content(parser_T* parser, hb_arra
|
|
|
275
384
|
TOKEN_HTML_TAG_START_CLOSE,
|
|
276
385
|
TOKEN_HTML_DOCTYPE,
|
|
277
386
|
TOKEN_HTML_COMMENT_START,
|
|
387
|
+
TOKEN_XML_DECLARATION,
|
|
388
|
+
TOKEN_XML_PROCESSING_INSTRUCTION_START,
|
|
278
389
|
TOKEN_ERB_START,
|
|
279
390
|
TOKEN_EOF
|
|
280
391
|
)) {
|
|
@@ -295,7 +406,13 @@ static AST_HTML_TEXT_NODE_T* parser_parse_text_content(parser_T* parser, hb_arra
|
|
|
295
406
|
position_T stray_end = peek_token->location.end;
|
|
296
407
|
token_free(peek_token, parser->allocator);
|
|
297
408
|
|
|
298
|
-
append_stray_erb_closing_tag_error(
|
|
409
|
+
append_stray_erb_closing_tag_error(
|
|
410
|
+
stray_start,
|
|
411
|
+
stray_end,
|
|
412
|
+
parser->allocator,
|
|
413
|
+
document_errors,
|
|
414
|
+
&parser->options
|
|
415
|
+
);
|
|
299
416
|
|
|
300
417
|
token_T* percent = parser_advance(parser);
|
|
301
418
|
hb_buffer_append_string(&content, percent->value);
|
|
@@ -316,7 +433,7 @@ static AST_HTML_TEXT_NODE_T* parser_parse_text_content(parser_T* parser, hb_arra
|
|
|
316
433
|
token_free(token, parser->allocator);
|
|
317
434
|
}
|
|
318
435
|
|
|
319
|
-
hb_array_T* errors =
|
|
436
|
+
hb_array_T* errors = NULL;
|
|
320
437
|
|
|
321
438
|
AST_HTML_TEXT_NODE_T* text_node = NULL;
|
|
322
439
|
|
|
@@ -334,22 +451,42 @@ static AST_HTML_TEXT_NODE_T* parser_parse_text_content(parser_T* parser, hb_arra
|
|
|
334
451
|
return text_node;
|
|
335
452
|
}
|
|
336
453
|
|
|
454
|
+
static bool parser_token_starts_tag(const parser_T* parser) {
|
|
455
|
+
return token_is_any_of(
|
|
456
|
+
parser,
|
|
457
|
+
TOKEN_HTML_TAG_START,
|
|
458
|
+
TOKEN_HTML_TAG_START_CLOSE,
|
|
459
|
+
TOKEN_HTML_COMMENT_START,
|
|
460
|
+
TOKEN_HTML_DOCTYPE,
|
|
461
|
+
TOKEN_XML_PROCESSING_INSTRUCTION_START
|
|
462
|
+
);
|
|
463
|
+
}
|
|
464
|
+
|
|
337
465
|
static AST_HTML_ATTRIBUTE_NAME_NODE_T* parser_parse_html_attribute_name(parser_T* parser) {
|
|
338
|
-
hb_array_T* errors =
|
|
466
|
+
hb_array_T* errors = NULL;
|
|
339
467
|
hb_array_T* children = hb_array_init(8, parser->allocator);
|
|
340
468
|
hb_buffer_T buffer;
|
|
341
469
|
hb_buffer_init(&buffer, 128, parser->allocator);
|
|
342
470
|
position_T start = parser->current_token->location.start;
|
|
343
471
|
|
|
472
|
+
// <div =foo>
|
|
473
|
+
if (token_is(parser, TOKEN_EQUALS)) {
|
|
474
|
+
token_T* equals = parser_advance(parser);
|
|
475
|
+
hb_buffer_append_string(&buffer, equals->value);
|
|
476
|
+
token_free(equals, parser->allocator);
|
|
477
|
+
}
|
|
478
|
+
|
|
344
479
|
while (token_is_none_of(
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
480
|
+
parser,
|
|
481
|
+
TOKEN_EQUALS,
|
|
482
|
+
TOKEN_WHITESPACE,
|
|
483
|
+
TOKEN_NEWLINE,
|
|
484
|
+
TOKEN_SLASH,
|
|
485
|
+
TOKEN_HTML_TAG_END,
|
|
486
|
+
TOKEN_HTML_TAG_SELF_CLOSE,
|
|
487
|
+
TOKEN_EOF
|
|
488
|
+
)
|
|
489
|
+
&& !parser_token_starts_tag(parser)) {
|
|
353
490
|
if (token_is(parser, TOKEN_ERB_START)) {
|
|
354
491
|
hb_string_T tag = parser->current_token->value;
|
|
355
492
|
bool is_output_tag = (tag.length >= 3 && tag.data[2] == '=');
|
|
@@ -363,13 +500,24 @@ static AST_HTML_ATTRIBUTE_NAME_NODE_T* parser_parse_html_attribute_name(parser_T
|
|
|
363
500
|
|
|
364
501
|
parser_append_literal_node_from_buffer(parser, &buffer, children, start);
|
|
365
502
|
|
|
366
|
-
|
|
503
|
+
AST_NODE_T* erb_node = parser_parse_erb_tag(parser);
|
|
367
504
|
hb_array_append(children, erb_node);
|
|
368
505
|
|
|
369
506
|
start = parser->current_token->location.start;
|
|
370
507
|
continue;
|
|
371
508
|
}
|
|
372
509
|
|
|
510
|
+
if (token_is(parser, TOKEN_QUOTE)) {
|
|
511
|
+
append_unexpected_character_in_attribute_name_error(
|
|
512
|
+
parser->current_token,
|
|
513
|
+
parser->current_token->location.start,
|
|
514
|
+
parser->current_token->location.end,
|
|
515
|
+
parser->allocator,
|
|
516
|
+
&errors,
|
|
517
|
+
&parser->options
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
|
|
373
521
|
token_T* token = parser_advance(parser);
|
|
374
522
|
hb_buffer_append_string(&buffer, token->value);
|
|
375
523
|
token_free(token, parser->allocator);
|
|
@@ -402,7 +550,7 @@ static AST_HTML_ATTRIBUTE_NAME_NODE_T* parser_parse_html_attribute_name(parser_T
|
|
|
402
550
|
static AST_HTML_ATTRIBUTE_VALUE_NODE_T* parser_parse_quoted_html_attribute_value(
|
|
403
551
|
parser_T* parser,
|
|
404
552
|
hb_array_T* children,
|
|
405
|
-
hb_array_T
|
|
553
|
+
hb_array_T** errors
|
|
406
554
|
) {
|
|
407
555
|
hb_buffer_T buffer;
|
|
408
556
|
hb_buffer_init(&buffer, 512, parser->allocator);
|
|
@@ -450,26 +598,23 @@ static AST_HTML_ATTRIBUTE_VALUE_NODE_T* parser_parse_quoted_html_attribute_value
|
|
|
450
598
|
opening_quote->location.start,
|
|
451
599
|
parser->current_token->location.start,
|
|
452
600
|
parser->allocator,
|
|
453
|
-
errors
|
|
601
|
+
errors,
|
|
602
|
+
&parser->options
|
|
454
603
|
);
|
|
455
604
|
|
|
456
605
|
parser_append_literal_node_from_buffer(parser, &buffer, children, start);
|
|
457
606
|
hb_buffer_free(&buffer);
|
|
458
607
|
|
|
459
|
-
|
|
608
|
+
return ast_html_attribute_value_node_init(
|
|
460
609
|
opening_quote,
|
|
461
610
|
children,
|
|
462
611
|
NULL,
|
|
463
612
|
true,
|
|
464
613
|
opening_quote->location.start,
|
|
465
614
|
parser->current_token->location.start,
|
|
466
|
-
errors,
|
|
615
|
+
*errors,
|
|
467
616
|
parser->allocator
|
|
468
617
|
);
|
|
469
|
-
|
|
470
|
-
token_free(opening_quote, parser->allocator);
|
|
471
|
-
|
|
472
|
-
return attribute_value;
|
|
473
618
|
}
|
|
474
619
|
|
|
475
620
|
bool buffer_ends_with_whitespace = buffer.length > 0 && is_whitespace(buffer.value[buffer.length - 1]);
|
|
@@ -497,26 +642,23 @@ static AST_HTML_ATTRIBUTE_VALUE_NODE_T* parser_parse_quoted_html_attribute_value
|
|
|
497
642
|
opening_quote->location.start,
|
|
498
643
|
parser->current_token->location.start,
|
|
499
644
|
parser->allocator,
|
|
500
|
-
errors
|
|
645
|
+
errors,
|
|
646
|
+
&parser->options
|
|
501
647
|
);
|
|
502
648
|
|
|
503
649
|
parser_append_literal_node_from_buffer(parser, &buffer, children, start);
|
|
504
650
|
hb_buffer_free(&buffer);
|
|
505
651
|
|
|
506
|
-
|
|
652
|
+
return ast_html_attribute_value_node_init(
|
|
507
653
|
opening_quote,
|
|
508
654
|
children,
|
|
509
655
|
NULL,
|
|
510
656
|
true,
|
|
511
657
|
opening_quote->location.start,
|
|
512
658
|
parser->current_token->location.start,
|
|
513
|
-
errors,
|
|
659
|
+
*errors,
|
|
514
660
|
parser->allocator
|
|
515
661
|
);
|
|
516
|
-
|
|
517
|
-
token_free(opening_quote, parser->allocator);
|
|
518
|
-
|
|
519
|
-
return attribute_value;
|
|
520
662
|
}
|
|
521
663
|
}
|
|
522
664
|
|
|
@@ -536,176 +678,133 @@ static AST_HTML_ATTRIBUTE_VALUE_NODE_T* parser_parse_quoted_html_attribute_value
|
|
|
536
678
|
parser->current_token = lexer_next_token(parser->lexer);
|
|
537
679
|
}
|
|
538
680
|
|
|
539
|
-
if (token_is(parser, TOKEN_QUOTE) && opening_quote != NULL
|
|
540
|
-
&& hb_string_equals(parser->current_token->value, opening_quote->value)) {
|
|
541
|
-
lexer_state_snapshot_T saved_state = lexer_save_state(parser->lexer);
|
|
542
|
-
|
|
543
|
-
token_T* potential_closing = parser->current_token;
|
|
544
|
-
parser->current_token = lexer_next_token(parser->lexer);
|
|
545
|
-
|
|
546
|
-
if (token_is(parser, TOKEN_IDENTIFIER) || token_is(parser, TOKEN_CHARACTER)) {
|
|
547
|
-
append_unexpected_error(
|
|
548
|
-
hb_string("Unescaped quote character in attribute value"),
|
|
549
|
-
hb_string("HTML entity ('/") or different quote style"),
|
|
550
|
-
opening_quote->value,
|
|
551
|
-
potential_closing->location.start,
|
|
552
|
-
potential_closing->location.end,
|
|
553
|
-
parser->allocator,
|
|
554
|
-
errors
|
|
555
|
-
);
|
|
556
|
-
|
|
557
|
-
lexer_restore_state(parser->lexer, saved_state);
|
|
558
|
-
|
|
559
|
-
token_free(parser->current_token, parser->allocator);
|
|
560
|
-
parser->current_token = potential_closing;
|
|
561
|
-
|
|
562
|
-
hb_buffer_append_string(&buffer, parser->current_token->value);
|
|
563
|
-
token_free(parser->current_token, parser->allocator);
|
|
564
|
-
parser->current_token = lexer_next_token(parser->lexer);
|
|
565
|
-
|
|
566
|
-
while (!token_is(parser, TOKEN_EOF)
|
|
567
|
-
&& !(
|
|
568
|
-
token_is(parser, TOKEN_QUOTE) && opening_quote != NULL
|
|
569
|
-
&& hb_string_equals(parser->current_token->value, opening_quote->value)
|
|
570
|
-
)) {
|
|
571
|
-
if (token_is(parser, TOKEN_ERB_START)) {
|
|
572
|
-
parser_append_literal_node_from_buffer(parser, &buffer, children, start);
|
|
573
|
-
|
|
574
|
-
hb_array_append(children, parser_parse_erb_tag(parser));
|
|
575
|
-
|
|
576
|
-
start = parser->current_token->location.start;
|
|
577
|
-
|
|
578
|
-
continue;
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
hb_buffer_append_string(&buffer, parser->current_token->value);
|
|
582
|
-
token_free(parser->current_token, parser->allocator);
|
|
583
|
-
|
|
584
|
-
parser->current_token = lexer_next_token(parser->lexer);
|
|
585
|
-
}
|
|
586
|
-
} else {
|
|
587
|
-
token_free(parser->current_token, parser->allocator);
|
|
588
|
-
parser->current_token = potential_closing;
|
|
589
|
-
|
|
590
|
-
lexer_restore_state(parser->lexer, saved_state);
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
|
|
594
681
|
parser_append_literal_node_from_buffer(parser, &buffer, children, start);
|
|
595
682
|
hb_buffer_free(&buffer);
|
|
596
683
|
|
|
597
684
|
token_T* closing_quote = parser_consume_expected(parser, TOKEN_QUOTE, errors);
|
|
598
685
|
|
|
599
|
-
|
|
686
|
+
return ast_html_attribute_value_node_init(
|
|
600
687
|
opening_quote,
|
|
601
688
|
children,
|
|
602
689
|
closing_quote,
|
|
603
690
|
true,
|
|
604
691
|
opening_quote->location.start,
|
|
605
692
|
closing_quote->location.end,
|
|
606
|
-
errors,
|
|
693
|
+
*errors,
|
|
607
694
|
parser->allocator
|
|
608
695
|
);
|
|
696
|
+
}
|
|
609
697
|
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
return attribute_value;
|
|
698
|
+
static bool parser_attribute_value_is_missing(const parser_T* parser) {
|
|
699
|
+
return token_is_any_of(parser, TOKEN_HTML_TAG_END, TOKEN_HTML_TAG_SELF_CLOSE, TOKEN_EOF)
|
|
700
|
+
|| parser_token_starts_tag(parser);
|
|
614
701
|
}
|
|
615
702
|
|
|
616
703
|
static AST_HTML_ATTRIBUTE_VALUE_NODE_T* parser_parse_html_attribute_value(parser_T* parser) {
|
|
617
704
|
hb_array_T* children = hb_array_init(8, parser->allocator);
|
|
618
|
-
hb_array_T* errors =
|
|
705
|
+
hb_array_T* errors = NULL;
|
|
619
706
|
|
|
620
|
-
// <div id
|
|
621
|
-
if (token_is(parser,
|
|
622
|
-
AST_ERB_CONTENT_NODE_T* erb_node = parser_parse_erb_tag(parser);
|
|
623
|
-
hb_array_append(children, erb_node);
|
|
707
|
+
// <div id="home">
|
|
708
|
+
if (token_is(parser, TOKEN_QUOTE)) { return parser_parse_quoted_html_attribute_value(parser, children, &errors); }
|
|
624
709
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
)
|
|
635
|
-
|
|
710
|
+
// <div id=home> or <div id=<%= "home" %>>
|
|
711
|
+
hb_buffer_T buffer;
|
|
712
|
+
hb_buffer_init(&buffer, 128, parser->allocator);
|
|
713
|
+
position_T value_start = parser->current_token->location.start;
|
|
714
|
+
position_T value_end = value_start;
|
|
715
|
+
position_T start = value_start;
|
|
716
|
+
|
|
717
|
+
while (
|
|
718
|
+
token_is_none_of(parser, TOKEN_WHITESPACE, TOKEN_NEWLINE, TOKEN_HTML_TAG_END, TOKEN_HTML_TAG_SELF_CLOSE, TOKEN_EOF)
|
|
719
|
+
&& !parser_token_starts_tag(parser)
|
|
720
|
+
) {
|
|
721
|
+
if (token_is(parser, TOKEN_ERB_START)) {
|
|
722
|
+
parser_append_literal_node_from_buffer(parser, &buffer, children, start);
|
|
636
723
|
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
token_T* identifier = parser_consume_expected(parser, TOKEN_IDENTIFIER, errors);
|
|
640
|
-
AST_LITERAL_NODE_T* literal = ast_literal_node_init_from_token(identifier, parser->allocator);
|
|
641
|
-
token_free(identifier, parser->allocator);
|
|
724
|
+
AST_NODE_T* erb_node = parser_parse_erb_tag(parser);
|
|
725
|
+
hb_array_append(children, erb_node);
|
|
642
726
|
|
|
643
|
-
|
|
727
|
+
value_end = erb_node->location.end;
|
|
728
|
+
start = parser->current_token->location.start;
|
|
644
729
|
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
children,
|
|
648
|
-
NULL,
|
|
649
|
-
false,
|
|
650
|
-
literal->base.location.start,
|
|
651
|
-
literal->base.location.end,
|
|
652
|
-
errors,
|
|
653
|
-
parser->allocator
|
|
654
|
-
);
|
|
655
|
-
}
|
|
730
|
+
continue;
|
|
731
|
+
}
|
|
656
732
|
|
|
657
|
-
|
|
658
|
-
|
|
733
|
+
if (token_is_any_of(parser, TOKEN_QUOTE, TOKEN_BACKTICK, TOKEN_EQUALS)) {
|
|
734
|
+
append_unexpected_character_in_unquoted_attribute_value_error(
|
|
735
|
+
parser->current_token,
|
|
736
|
+
parser->current_token->location.start,
|
|
737
|
+
parser->current_token->location.end,
|
|
738
|
+
parser->allocator,
|
|
739
|
+
&errors,
|
|
740
|
+
&parser->options
|
|
741
|
+
);
|
|
742
|
+
}
|
|
659
743
|
|
|
660
|
-
if (token_is(parser, TOKEN_BACKTICK)) {
|
|
661
744
|
token_T* token = parser_advance(parser);
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
hb_string("Invalid quote character for HTML attribute"),
|
|
667
|
-
hb_string("single quote (') or double quote (\")"),
|
|
668
|
-
hb_string("a backtick"),
|
|
669
|
-
start,
|
|
670
|
-
end,
|
|
671
|
-
parser->allocator,
|
|
672
|
-
errors
|
|
673
|
-
);
|
|
745
|
+
hb_buffer_append_string(&buffer, token->value);
|
|
746
|
+
value_end = token->location.end;
|
|
747
|
+
token_free(token, parser->allocator);
|
|
748
|
+
}
|
|
674
749
|
|
|
675
|
-
|
|
676
|
-
|
|
750
|
+
parser_append_literal_node_from_buffer(parser, &buffer, children, start);
|
|
751
|
+
hb_buffer_free(&buffer);
|
|
677
752
|
|
|
678
|
-
|
|
753
|
+
return ast_html_attribute_value_node_init(
|
|
754
|
+
NULL,
|
|
755
|
+
children,
|
|
756
|
+
NULL,
|
|
757
|
+
false,
|
|
758
|
+
value_start,
|
|
759
|
+
value_end,
|
|
760
|
+
errors,
|
|
761
|
+
parser->allocator
|
|
762
|
+
);
|
|
763
|
+
}
|
|
679
764
|
|
|
680
|
-
|
|
681
|
-
|
|
765
|
+
static AST_HTML_ATTRIBUTE_NODE_T* parser_parse_html_attribute_missing_value(
|
|
766
|
+
parser_T* parser,
|
|
767
|
+
AST_HTML_ATTRIBUTE_NAME_NODE_T* attribute_name,
|
|
768
|
+
token_T* equals
|
|
769
|
+
) {
|
|
770
|
+
hb_array_T* errors = NULL;
|
|
771
|
+
hb_string_T attribute_name_string = hb_string("unknown");
|
|
682
772
|
|
|
683
|
-
|
|
773
|
+
if (hb_array_size(attribute_name->children) > 0) {
|
|
774
|
+
AST_LITERAL_NODE_T* first_child = (AST_LITERAL_NODE_T*) hb_array_get(attribute_name->children, 0);
|
|
684
775
|
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
776
|
+
if (first_child && !hb_string_is_empty(first_child->content)) { attribute_name_string = first_child->content; }
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
append_missing_attribute_value_error(
|
|
780
|
+
attribute_name_string,
|
|
781
|
+
equals->location.start,
|
|
689
782
|
parser->current_token->location.start,
|
|
690
|
-
parser->current_token->location.end,
|
|
691
783
|
parser->allocator,
|
|
692
|
-
errors
|
|
784
|
+
&errors,
|
|
785
|
+
&parser->options
|
|
693
786
|
);
|
|
694
787
|
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
AST_HTML_ATTRIBUTE_VALUE_NODE_T* value = ast_html_attribute_value_node_init(
|
|
788
|
+
AST_HTML_ATTRIBUTE_VALUE_NODE_T* empty_value = ast_html_attribute_value_node_init(
|
|
698
789
|
NULL,
|
|
699
|
-
|
|
790
|
+
hb_array_init(8, parser->allocator),
|
|
700
791
|
NULL,
|
|
701
792
|
false,
|
|
793
|
+
equals->location.end,
|
|
702
794
|
parser->current_token->location.start,
|
|
703
|
-
parser->current_token->location.end,
|
|
704
795
|
errors,
|
|
705
796
|
parser->allocator
|
|
706
797
|
);
|
|
707
798
|
|
|
708
|
-
return
|
|
799
|
+
return ast_html_attribute_node_init(
|
|
800
|
+
attribute_name,
|
|
801
|
+
equals,
|
|
802
|
+
empty_value,
|
|
803
|
+
attribute_name->base.location.start,
|
|
804
|
+
parser->current_token->location.start,
|
|
805
|
+
NULL,
|
|
806
|
+
parser->allocator
|
|
807
|
+
);
|
|
709
808
|
}
|
|
710
809
|
|
|
711
810
|
static AST_HTML_ATTRIBUTE_NODE_T* parser_parse_html_attribute(parser_T* parser) {
|
|
@@ -778,12 +877,18 @@ static AST_HTML_ATTRIBUTE_NODE_T* parser_parse_html_attribute(parser_T* parser)
|
|
|
778
877
|
|
|
779
878
|
char* arena_copy = hb_allocator_strndup(parser->allocator, equals_buffer.value, equals_buffer.length);
|
|
780
879
|
equals_with_whitespace->value = hb_string_from_data(arena_copy, equals_buffer.length);
|
|
880
|
+
equals_with_whitespace->owns_value = true;
|
|
781
881
|
|
|
782
882
|
hb_buffer_free(&equals_buffer);
|
|
783
883
|
|
|
784
884
|
equals_with_whitespace->location = (location_T) { .start = equals_start, .end = equals_end };
|
|
785
885
|
equals_with_whitespace->range = (range_T) { .from = range_start, .to = range_end };
|
|
786
886
|
|
|
887
|
+
// <div class = >
|
|
888
|
+
if (parser_attribute_value_is_missing(parser)) {
|
|
889
|
+
return parser_parse_html_attribute_missing_value(parser, attribute_name, equals_with_whitespace);
|
|
890
|
+
}
|
|
891
|
+
|
|
787
892
|
AST_HTML_ATTRIBUTE_VALUE_NODE_T* attribute_value = parser_parse_html_attribute_value(parser);
|
|
788
893
|
|
|
789
894
|
return ast_html_attribute_node_init(
|
|
@@ -816,53 +921,13 @@ static AST_HTML_ATTRIBUTE_NODE_T* parser_parse_html_attribute(parser_T* parser)
|
|
|
816
921
|
parser_consume_whitespace(parser, NULL);
|
|
817
922
|
|
|
818
923
|
// <div class= >
|
|
819
|
-
if (
|
|
820
|
-
|
|
821
|
-
hb_string_T attribute_name_string = hb_string("unknown");
|
|
822
|
-
|
|
823
|
-
if (hb_array_size(attribute_name->children) > 0) {
|
|
824
|
-
AST_LITERAL_NODE_T* first_child = (AST_LITERAL_NODE_T*) hb_array_get(attribute_name->children, 0);
|
|
825
|
-
|
|
826
|
-
if (first_child && !hb_string_is_empty(first_child->content)) { attribute_name_string = first_child->content; }
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
append_missing_attribute_value_error(
|
|
830
|
-
attribute_name_string,
|
|
831
|
-
equals->location.start,
|
|
832
|
-
parser->current_token->location.start,
|
|
833
|
-
parser->allocator,
|
|
834
|
-
errors
|
|
835
|
-
);
|
|
836
|
-
|
|
837
|
-
AST_HTML_ATTRIBUTE_VALUE_NODE_T* empty_value = ast_html_attribute_value_node_init(
|
|
838
|
-
NULL,
|
|
839
|
-
hb_array_init(8, parser->allocator),
|
|
840
|
-
NULL,
|
|
841
|
-
false,
|
|
842
|
-
equals->location.end,
|
|
843
|
-
parser->current_token->location.start,
|
|
844
|
-
errors,
|
|
845
|
-
parser->allocator
|
|
846
|
-
);
|
|
847
|
-
|
|
848
|
-
AST_HTML_ATTRIBUTE_NODE_T* attribute_node = ast_html_attribute_node_init(
|
|
849
|
-
attribute_name,
|
|
850
|
-
equals,
|
|
851
|
-
empty_value,
|
|
852
|
-
attribute_name->base.location.start,
|
|
853
|
-
parser->current_token->location.start,
|
|
854
|
-
NULL,
|
|
855
|
-
parser->allocator
|
|
856
|
-
);
|
|
857
|
-
|
|
858
|
-
token_free(equals, parser->allocator);
|
|
859
|
-
|
|
860
|
-
return attribute_node;
|
|
924
|
+
if (parser_attribute_value_is_missing(parser)) {
|
|
925
|
+
return parser_parse_html_attribute_missing_value(parser, attribute_name, equals);
|
|
861
926
|
}
|
|
862
927
|
|
|
863
928
|
AST_HTML_ATTRIBUTE_VALUE_NODE_T* attribute_value = parser_parse_html_attribute_value(parser);
|
|
864
929
|
|
|
865
|
-
|
|
930
|
+
return ast_html_attribute_node_init(
|
|
866
931
|
attribute_name,
|
|
867
932
|
equals,
|
|
868
933
|
attribute_value,
|
|
@@ -871,10 +936,6 @@ static AST_HTML_ATTRIBUTE_NODE_T* parser_parse_html_attribute(parser_T* parser)
|
|
|
871
936
|
NULL,
|
|
872
937
|
parser->allocator
|
|
873
938
|
);
|
|
874
|
-
|
|
875
|
-
token_free(equals, parser->allocator);
|
|
876
|
-
|
|
877
|
-
return attribute_node;
|
|
878
939
|
}
|
|
879
940
|
|
|
880
941
|
return ast_html_attribute_node_init(
|
|
@@ -1030,25 +1091,28 @@ static void parser_handle_whitespace_in_open_tag(parser_T* parser, hb_array_T* c
|
|
|
1030
1091
|
}
|
|
1031
1092
|
|
|
1032
1093
|
static AST_HTML_OPEN_TAG_NODE_T* parser_parse_html_open_tag(parser_T* parser) {
|
|
1033
|
-
hb_array_T* errors =
|
|
1094
|
+
hb_array_T* errors = NULL;
|
|
1034
1095
|
hb_array_T* children = hb_array_init(8, parser->allocator);
|
|
1035
1096
|
|
|
1036
|
-
token_T* tag_start = parser_consume_expected(parser, TOKEN_HTML_TAG_START, errors);
|
|
1037
|
-
token_T* tag_name = parser_consume_expected(parser, TOKEN_IDENTIFIER, errors);
|
|
1097
|
+
token_T* tag_start = parser_consume_expected(parser, TOKEN_HTML_TAG_START, &errors);
|
|
1098
|
+
token_T* tag_name = parser_consume_expected(parser, TOKEN_IDENTIFIER, &errors);
|
|
1099
|
+
|
|
1100
|
+
parser_consume_dot_notation_segments(parser, tag_name, &errors);
|
|
1038
1101
|
|
|
1039
|
-
|
|
1102
|
+
bool previous_was_quoted_value = false;
|
|
1040
1103
|
|
|
1041
1104
|
while (token_is_none_of(parser, TOKEN_HTML_TAG_END, TOKEN_HTML_TAG_SELF_CLOSE, TOKEN_EOF)) {
|
|
1042
|
-
if (
|
|
1105
|
+
if (parser_token_starts_tag(parser)) {
|
|
1043
1106
|
append_unclosed_open_tag_error(
|
|
1044
1107
|
tag_name,
|
|
1045
1108
|
tag_name->location.start,
|
|
1046
1109
|
parser->current_token->location.start,
|
|
1047
1110
|
parser->allocator,
|
|
1048
|
-
errors
|
|
1111
|
+
&errors,
|
|
1112
|
+
&parser->options
|
|
1049
1113
|
);
|
|
1050
1114
|
|
|
1051
|
-
|
|
1115
|
+
return ast_html_open_tag_node_init(
|
|
1052
1116
|
tag_start,
|
|
1053
1117
|
tag_name,
|
|
1054
1118
|
NULL,
|
|
@@ -1059,48 +1123,21 @@ static AST_HTML_OPEN_TAG_NODE_T* parser_parse_html_open_tag(parser_T* parser) {
|
|
|
1059
1123
|
errors,
|
|
1060
1124
|
parser->allocator
|
|
1061
1125
|
);
|
|
1062
|
-
|
|
1063
|
-
token_free(tag_start, parser->allocator);
|
|
1064
|
-
token_free(tag_name, parser->allocator);
|
|
1065
|
-
|
|
1066
|
-
return open_tag_node;
|
|
1067
1126
|
}
|
|
1068
1127
|
|
|
1069
1128
|
if (token_is_any_of(parser, TOKEN_WHITESPACE, TOKEN_NEWLINE)) {
|
|
1129
|
+
previous_was_quoted_value = false;
|
|
1070
1130
|
parser_handle_whitespace_in_open_tag(parser, children);
|
|
1071
1131
|
continue;
|
|
1072
1132
|
}
|
|
1073
1133
|
|
|
1074
|
-
if (parser
|
|
1075
|
-
|
|
1076
|
-
continue;
|
|
1077
|
-
}
|
|
1078
|
-
|
|
1079
|
-
if (parser->current_token->type == TOKEN_ERB_START) {
|
|
1134
|
+
if (token_is(parser, TOKEN_ERB_START)) {
|
|
1135
|
+
previous_was_quoted_value = false;
|
|
1080
1136
|
parser_handle_erb_in_open_tag(parser, children);
|
|
1081
1137
|
continue;
|
|
1082
1138
|
}
|
|
1083
1139
|
|
|
1084
|
-
if (parser
|
|
1085
|
-
hb_array_append(children, parser_parse_html_attribute(parser));
|
|
1086
|
-
continue;
|
|
1087
|
-
}
|
|
1088
|
-
|
|
1089
|
-
if (parser->current_token->type == TOKEN_COLON) {
|
|
1090
|
-
lexer_T lexer_copy = *parser->lexer;
|
|
1091
|
-
token_T* next_token = lexer_next_token(&lexer_copy);
|
|
1092
|
-
|
|
1093
|
-
if (next_token && next_token->type == TOKEN_IDENTIFIER) {
|
|
1094
|
-
token_free(next_token, parser->allocator);
|
|
1095
|
-
hb_array_append(children, parser_parse_html_attribute(parser));
|
|
1096
|
-
|
|
1097
|
-
continue;
|
|
1098
|
-
}
|
|
1099
|
-
|
|
1100
|
-
token_free(next_token, parser->allocator);
|
|
1101
|
-
}
|
|
1102
|
-
|
|
1103
|
-
if (parser->current_token->type == TOKEN_PERCENT) {
|
|
1140
|
+
if (token_is(parser, TOKEN_PERCENT)) {
|
|
1104
1141
|
lexer_T lexer_copy = *parser->lexer;
|
|
1105
1142
|
token_T* peek_token = lexer_next_token(&lexer_copy);
|
|
1106
1143
|
|
|
@@ -1109,7 +1146,7 @@ static AST_HTML_OPEN_TAG_NODE_T* parser_parse_html_open_tag(parser_T* parser) {
|
|
|
1109
1146
|
position_T stray_end = peek_token->location.end;
|
|
1110
1147
|
token_free(peek_token, parser->allocator);
|
|
1111
1148
|
|
|
1112
|
-
append_stray_erb_closing_tag_error(stray_start, stray_end, parser->allocator, errors);
|
|
1149
|
+
append_stray_erb_closing_tag_error(stray_start, stray_end, parser->allocator, &errors, &parser->options);
|
|
1113
1150
|
|
|
1114
1151
|
token_T* percent = parser_advance(parser);
|
|
1115
1152
|
token_T* gt = parser_advance(parser);
|
|
@@ -1121,22 +1158,73 @@ static AST_HTML_OPEN_TAG_NODE_T* parser_parse_html_open_tag(parser_T* parser) {
|
|
|
1121
1158
|
token_free(percent, parser->allocator);
|
|
1122
1159
|
token_free(gt, parser->allocator);
|
|
1123
1160
|
|
|
1161
|
+
previous_was_quoted_value = false;
|
|
1124
1162
|
continue;
|
|
1125
1163
|
}
|
|
1126
1164
|
|
|
1127
1165
|
token_free(peek_token, parser->allocator);
|
|
1128
1166
|
}
|
|
1129
1167
|
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1168
|
+
// <div / class="a">
|
|
1169
|
+
if (token_is(parser, TOKEN_SLASH)) {
|
|
1170
|
+
token_T* solidus = parser_advance(parser);
|
|
1171
|
+
|
|
1172
|
+
append_unexpected_solidus_in_tag_error(
|
|
1173
|
+
solidus,
|
|
1174
|
+
solidus->location.start,
|
|
1175
|
+
solidus->location.end,
|
|
1176
|
+
parser->allocator,
|
|
1177
|
+
&errors,
|
|
1178
|
+
&parser->options
|
|
1179
|
+
);
|
|
1180
|
+
|
|
1181
|
+
token_free(solidus, parser->allocator);
|
|
1182
|
+
previous_was_quoted_value = false;
|
|
1183
|
+
continue;
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
if (token_is(parser, TOKEN_ERROR)) {
|
|
1187
|
+
parser_append_unexpected_error(
|
|
1188
|
+
parser,
|
|
1189
|
+
&errors,
|
|
1190
|
+
"Unexpected Token",
|
|
1191
|
+
TOKEN_IDENTIFIER,
|
|
1192
|
+
TOKEN_AT,
|
|
1193
|
+
TOKEN_ERB_START,
|
|
1194
|
+
TOKEN_WHITESPACE,
|
|
1195
|
+
TOKEN_NEWLINE
|
|
1196
|
+
);
|
|
1197
|
+
continue;
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
// <div class="a"id="b">
|
|
1201
|
+
if (previous_was_quoted_value) {
|
|
1202
|
+
append_missing_whitespace_between_attributes_error(
|
|
1203
|
+
parser->current_token,
|
|
1204
|
+
parser->current_token->location.start,
|
|
1205
|
+
parser->current_token->location.end,
|
|
1206
|
+
parser->allocator,
|
|
1207
|
+
&errors,
|
|
1208
|
+
&parser->options
|
|
1209
|
+
);
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
// <div =foo>
|
|
1213
|
+
if (token_is(parser, TOKEN_EQUALS)) {
|
|
1214
|
+
append_unexpected_equals_sign_before_attribute_name_error(
|
|
1215
|
+
parser->current_token,
|
|
1216
|
+
parser->current_token->location.start,
|
|
1217
|
+
parser->current_token->location.end,
|
|
1218
|
+
parser->allocator,
|
|
1219
|
+
&errors,
|
|
1220
|
+
&parser->options
|
|
1221
|
+
);
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
AST_HTML_ATTRIBUTE_NODE_T* attribute = parser_parse_html_attribute(parser);
|
|
1225
|
+
hb_array_append(children, attribute);
|
|
1226
|
+
|
|
1227
|
+
previous_was_quoted_value = attribute->value != NULL && attribute->value->close_quote != NULL;
|
|
1140
1228
|
}
|
|
1141
1229
|
|
|
1142
1230
|
if (token_is(parser, TOKEN_EOF)) {
|
|
@@ -1145,10 +1233,11 @@ static AST_HTML_OPEN_TAG_NODE_T* parser_parse_html_open_tag(parser_T* parser) {
|
|
|
1145
1233
|
tag_name->location.start,
|
|
1146
1234
|
parser->current_token->location.start,
|
|
1147
1235
|
parser->allocator,
|
|
1148
|
-
errors
|
|
1236
|
+
&errors,
|
|
1237
|
+
&parser->options
|
|
1149
1238
|
);
|
|
1150
1239
|
|
|
1151
|
-
|
|
1240
|
+
return ast_html_open_tag_node_init(
|
|
1152
1241
|
tag_start,
|
|
1153
1242
|
tag_name,
|
|
1154
1243
|
NULL,
|
|
@@ -1159,11 +1248,6 @@ static AST_HTML_OPEN_TAG_NODE_T* parser_parse_html_open_tag(parser_T* parser) {
|
|
|
1159
1248
|
errors,
|
|
1160
1249
|
parser->allocator
|
|
1161
1250
|
);
|
|
1162
|
-
|
|
1163
|
-
token_free(tag_start, parser->allocator);
|
|
1164
|
-
token_free(tag_name, parser->allocator);
|
|
1165
|
-
|
|
1166
|
-
return open_tag_node;
|
|
1167
1251
|
}
|
|
1168
1252
|
|
|
1169
1253
|
bool is_self_closing = false;
|
|
@@ -1171,7 +1255,7 @@ static AST_HTML_OPEN_TAG_NODE_T* parser_parse_html_open_tag(parser_T* parser) {
|
|
|
1171
1255
|
token_T* tag_end = parser_consume_if_present(parser, TOKEN_HTML_TAG_END);
|
|
1172
1256
|
|
|
1173
1257
|
if (tag_end == NULL) {
|
|
1174
|
-
tag_end = parser_consume_expected(parser, TOKEN_HTML_TAG_SELF_CLOSE, errors);
|
|
1258
|
+
tag_end = parser_consume_expected(parser, TOKEN_HTML_TAG_SELF_CLOSE, &errors);
|
|
1175
1259
|
|
|
1176
1260
|
if (tag_end == NULL) {
|
|
1177
1261
|
token_free(tag_start, parser->allocator);
|
|
@@ -1186,7 +1270,7 @@ static AST_HTML_OPEN_TAG_NODE_T* parser_parse_html_open_tag(parser_T* parser) {
|
|
|
1186
1270
|
is_self_closing = true;
|
|
1187
1271
|
}
|
|
1188
1272
|
|
|
1189
|
-
|
|
1273
|
+
return ast_html_open_tag_node_init(
|
|
1190
1274
|
tag_start,
|
|
1191
1275
|
tag_name,
|
|
1192
1276
|
tag_end,
|
|
@@ -1197,37 +1281,50 @@ static AST_HTML_OPEN_TAG_NODE_T* parser_parse_html_open_tag(parser_T* parser) {
|
|
|
1197
1281
|
errors,
|
|
1198
1282
|
parser->allocator
|
|
1199
1283
|
);
|
|
1200
|
-
|
|
1201
|
-
token_free(tag_start, parser->allocator);
|
|
1202
|
-
token_free(tag_name, parser->allocator);
|
|
1203
|
-
token_free(tag_end, parser->allocator);
|
|
1204
|
-
|
|
1205
|
-
return open_tag_node;
|
|
1206
1284
|
}
|
|
1207
1285
|
|
|
1208
1286
|
static AST_HTML_CLOSE_TAG_NODE_T* parser_parse_html_close_tag(parser_T* parser) {
|
|
1209
|
-
hb_array_T* errors =
|
|
1287
|
+
hb_array_T* errors = NULL;
|
|
1210
1288
|
hb_array_T* children = hb_array_init(8, parser->allocator);
|
|
1211
1289
|
|
|
1212
|
-
token_T* tag_opening = parser_consume_expected(parser, TOKEN_HTML_TAG_START_CLOSE, errors);
|
|
1290
|
+
token_T* tag_opening = parser_consume_expected(parser, TOKEN_HTML_TAG_START_CLOSE, &errors);
|
|
1213
1291
|
|
|
1214
1292
|
parser_consume_whitespace(parser, children);
|
|
1215
1293
|
|
|
1216
|
-
token_T* tag_name = parser_consume_expected(parser, TOKEN_IDENTIFIER, errors);
|
|
1294
|
+
token_T* tag_name = parser_consume_expected(parser, TOKEN_IDENTIFIER, &errors);
|
|
1217
1295
|
|
|
1218
|
-
parser_consume_dot_notation_segments(parser, tag_name, errors);
|
|
1296
|
+
parser_consume_dot_notation_segments(parser, tag_name, &errors);
|
|
1297
|
+
|
|
1298
|
+
if (parser->svg_depth > 0 && hb_string_equals_case_insensitive(tag_name->value, hb_string("svg"))) {
|
|
1299
|
+
parser->svg_depth--;
|
|
1300
|
+
}
|
|
1219
1301
|
|
|
1220
1302
|
parser_consume_whitespace(parser, children);
|
|
1221
1303
|
|
|
1222
1304
|
token_T* tag_closing = parser_consume_if_present(parser, TOKEN_HTML_TAG_END);
|
|
1223
1305
|
|
|
1306
|
+
// </div/>
|
|
1307
|
+
if (tag_closing == NULL && token_is(parser, TOKEN_HTML_TAG_SELF_CLOSE) && tag_name != NULL) {
|
|
1308
|
+
tag_closing = parser_advance(parser);
|
|
1309
|
+
|
|
1310
|
+
append_end_tag_with_trailing_solidus_error(
|
|
1311
|
+
tag_name,
|
|
1312
|
+
tag_closing->location.start,
|
|
1313
|
+
tag_closing->location.end,
|
|
1314
|
+
parser->allocator,
|
|
1315
|
+
&errors,
|
|
1316
|
+
&parser->options
|
|
1317
|
+
);
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1224
1320
|
if (tag_closing == NULL) {
|
|
1225
1321
|
append_unclosed_close_tag_error(
|
|
1226
1322
|
tag_name,
|
|
1227
1323
|
tag_opening->location.start,
|
|
1228
1324
|
tag_name->location.end,
|
|
1229
1325
|
parser->allocator,
|
|
1230
|
-
errors
|
|
1326
|
+
&errors,
|
|
1327
|
+
&parser->options
|
|
1231
1328
|
);
|
|
1232
1329
|
}
|
|
1233
1330
|
|
|
@@ -1243,7 +1340,8 @@ static AST_HTML_CLOSE_TAG_NODE_T* parser_parse_html_close_tag(parser_T* parser)
|
|
|
1243
1340
|
tag_opening->location.start,
|
|
1244
1341
|
tag_closing->location.end,
|
|
1245
1342
|
parser->allocator,
|
|
1246
|
-
errors
|
|
1343
|
+
&errors,
|
|
1344
|
+
&parser->options
|
|
1247
1345
|
);
|
|
1248
1346
|
|
|
1249
1347
|
hb_allocator_dealloc(parser->allocator, expected.data);
|
|
@@ -1252,7 +1350,7 @@ static AST_HTML_CLOSE_TAG_NODE_T* parser_parse_html_close_tag(parser_T* parser)
|
|
|
1252
1350
|
|
|
1253
1351
|
position_T end_position = tag_closing != NULL ? tag_closing->location.end : tag_name->location.end;
|
|
1254
1352
|
|
|
1255
|
-
|
|
1353
|
+
return ast_html_close_tag_node_init(
|
|
1256
1354
|
tag_opening,
|
|
1257
1355
|
tag_name,
|
|
1258
1356
|
children,
|
|
@@ -1262,12 +1360,6 @@ static AST_HTML_CLOSE_TAG_NODE_T* parser_parse_html_close_tag(parser_T* parser)
|
|
|
1262
1360
|
errors,
|
|
1263
1361
|
parser->allocator
|
|
1264
1362
|
);
|
|
1265
|
-
|
|
1266
|
-
token_free(tag_opening, parser->allocator);
|
|
1267
|
-
token_free(tag_name, parser->allocator);
|
|
1268
|
-
token_free(tag_closing, parser->allocator);
|
|
1269
|
-
|
|
1270
|
-
return close_tag;
|
|
1271
1363
|
}
|
|
1272
1364
|
|
|
1273
1365
|
// TODO: this should probably be AST_HTML_ELEMENT_NODE_T with a AST_HTML_SELF_CLOSING_TAG_NODE_T
|
|
@@ -1277,7 +1369,7 @@ static AST_HTML_ELEMENT_NODE_T* parser_parse_html_self_closing_element(
|
|
|
1277
1369
|
) {
|
|
1278
1370
|
return ast_html_element_node_init(
|
|
1279
1371
|
(AST_NODE_T*) open_tag,
|
|
1280
|
-
open_tag->tag_name,
|
|
1372
|
+
token_copy(open_tag->tag_name, parser->allocator),
|
|
1281
1373
|
NULL,
|
|
1282
1374
|
NULL,
|
|
1283
1375
|
true,
|
|
@@ -1293,28 +1385,30 @@ static AST_HTML_ELEMENT_NODE_T* parser_parse_html_regular_element(
|
|
|
1293
1385
|
parser_T* parser,
|
|
1294
1386
|
AST_HTML_OPEN_TAG_NODE_T* open_tag
|
|
1295
1387
|
) {
|
|
1296
|
-
hb_array_T* errors =
|
|
1388
|
+
hb_array_T* errors = NULL;
|
|
1297
1389
|
hb_array_T* body = hb_array_init(8, parser->allocator);
|
|
1298
1390
|
|
|
1299
1391
|
parser_push_open_tag(parser, open_tag->tag_name);
|
|
1300
1392
|
|
|
1301
|
-
if (
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1393
|
+
if (parser_element_has_foreign_content(parser, open_tag->tag_name->value)) {
|
|
1394
|
+
hb_string_T tag_name = open_tag->tag_name->value;
|
|
1395
|
+
hb_string_T end_tag_name = parser_foreign_content_has_end_tag(tag_name) ? tag_name : HB_STRING_NULL;
|
|
1396
|
+
|
|
1397
|
+
parser_enter_foreign_content(parser, parser_get_foreign_content_kind(tag_name), end_tag_name);
|
|
1398
|
+
parser_parse_foreign_content(parser, body, &errors);
|
|
1305
1399
|
} else {
|
|
1306
|
-
parser_parse_in_data_state(parser, body, errors);
|
|
1400
|
+
parser_parse_in_data_state(parser, body, &errors);
|
|
1307
1401
|
}
|
|
1308
1402
|
|
|
1309
1403
|
if (!token_is(parser, TOKEN_HTML_TAG_START_CLOSE)) {
|
|
1310
|
-
return parser_handle_missing_close_tag(parser, open_tag, body, errors);
|
|
1404
|
+
return parser_handle_missing_close_tag(parser, open_tag, body, &errors);
|
|
1311
1405
|
}
|
|
1312
1406
|
|
|
1313
1407
|
AST_HTML_CLOSE_TAG_NODE_T* close_tag = parser_parse_html_close_tag(parser);
|
|
1314
1408
|
|
|
1315
1409
|
if (parser_in_svg_context(parser) == false && is_void_element(close_tag->tag_name->value)) {
|
|
1316
1410
|
hb_array_push(body, close_tag);
|
|
1317
|
-
parser_parse_in_data_state(parser, body, errors);
|
|
1411
|
+
parser_parse_in_data_state(parser, body, &errors);
|
|
1318
1412
|
close_tag = parser_parse_html_close_tag(parser);
|
|
1319
1413
|
}
|
|
1320
1414
|
|
|
@@ -1335,7 +1429,8 @@ static AST_HTML_ELEMENT_NODE_T* parser_parse_html_regular_element(
|
|
|
1335
1429
|
unclosed->location.start,
|
|
1336
1430
|
unclosed->location.end,
|
|
1337
1431
|
parser->allocator,
|
|
1338
|
-
errors
|
|
1432
|
+
&errors,
|
|
1433
|
+
&parser->options
|
|
1339
1434
|
);
|
|
1340
1435
|
token_free(unclosed, parser->allocator);
|
|
1341
1436
|
}
|
|
@@ -1344,12 +1439,12 @@ static AST_HTML_ELEMENT_NODE_T* parser_parse_html_regular_element(
|
|
|
1344
1439
|
token_T* popped_token = parser_pop_open_tag(parser);
|
|
1345
1440
|
token_free(popped_token, parser->allocator);
|
|
1346
1441
|
} else {
|
|
1347
|
-
parser_handle_mismatched_tags(parser, close_tag, errors);
|
|
1442
|
+
parser_handle_mismatched_tags(parser, close_tag, &errors);
|
|
1348
1443
|
}
|
|
1349
1444
|
|
|
1350
1445
|
return ast_html_element_node_init(
|
|
1351
1446
|
(AST_NODE_T*) open_tag,
|
|
1352
|
-
open_tag->tag_name,
|
|
1447
|
+
token_copy(open_tag->tag_name, parser->allocator),
|
|
1353
1448
|
body,
|
|
1354
1449
|
(AST_NODE_T*) close_tag,
|
|
1355
1450
|
false,
|
|
@@ -1369,12 +1464,14 @@ static AST_NODE_T* parser_parse_html_element(parser_T* parser) {
|
|
|
1369
1464
|
// <tag />
|
|
1370
1465
|
if (open_tag->is_void) { return (AST_NODE_T*) parser_parse_html_self_closing_element(parser, open_tag); }
|
|
1371
1466
|
|
|
1467
|
+
if (hb_string_equals_case_insensitive(open_tag->tag_name->value, hb_string("svg"))) { parser->svg_depth++; }
|
|
1468
|
+
|
|
1372
1469
|
// <tag>, in void element list, and not in inside an <svg> element
|
|
1373
1470
|
if (!open_tag->is_void && is_void_element(open_tag->tag_name->value) && !parser_in_svg_context(parser)) {
|
|
1374
1471
|
return (AST_NODE_T*) parser_parse_html_self_closing_element(parser, open_tag);
|
|
1375
1472
|
}
|
|
1376
1473
|
|
|
1377
|
-
if (
|
|
1474
|
+
if (parser_element_has_foreign_content(parser, open_tag->tag_name->value)) {
|
|
1378
1475
|
AST_HTML_ELEMENT_NODE_T* regular_element = parser_parse_html_regular_element(parser, open_tag);
|
|
1379
1476
|
|
|
1380
1477
|
if (regular_element != NULL) { return (AST_NODE_T*) regular_element; }
|
|
@@ -1383,18 +1480,35 @@ static AST_NODE_T* parser_parse_html_element(parser_T* parser) {
|
|
|
1383
1480
|
return (AST_NODE_T*) open_tag;
|
|
1384
1481
|
}
|
|
1385
1482
|
|
|
1386
|
-
static
|
|
1387
|
-
hb_array_T* errors =
|
|
1483
|
+
static AST_NODE_T* parser_parse_erb_tag(parser_T* parser) {
|
|
1484
|
+
hb_array_T* errors = NULL;
|
|
1388
1485
|
|
|
1389
|
-
token_T* opening_tag = parser_consume_expected(parser, TOKEN_ERB_START, errors);
|
|
1390
|
-
token_T* content = parser_consume_expected(parser, TOKEN_ERB_CONTENT, errors);
|
|
1486
|
+
token_T* opening_tag = parser_consume_expected(parser, TOKEN_ERB_START, &errors);
|
|
1487
|
+
token_T* content = parser_consume_expected(parser, TOKEN_ERB_CONTENT, &errors);
|
|
1391
1488
|
|
|
1392
1489
|
token_T* closing_tag = NULL;
|
|
1393
1490
|
position_T end_position;
|
|
1394
1491
|
|
|
1395
1492
|
if (token_is(parser, TOKEN_ERB_END)) {
|
|
1396
|
-
closing_tag = parser_consume_expected(parser, TOKEN_ERB_END, errors);
|
|
1493
|
+
closing_tag = parser_consume_expected(parser, TOKEN_ERB_END, &errors);
|
|
1397
1494
|
end_position = closing_tag->location.end;
|
|
1495
|
+
|
|
1496
|
+
bool is_well_formed = hb_string_equals(closing_tag->value, hb_string("%>"))
|
|
1497
|
+
|| hb_string_equals(closing_tag->value, hb_string("-%>"))
|
|
1498
|
+
|| hb_string_equals(closing_tag->value, hb_string("=%>"))
|
|
1499
|
+
|| hb_string_equals(closing_tag->value, hb_string("%%>"));
|
|
1500
|
+
|
|
1501
|
+
if (!is_well_formed) {
|
|
1502
|
+
append_malformed_erb_closing_tag_error(
|
|
1503
|
+
opening_tag,
|
|
1504
|
+
closing_tag,
|
|
1505
|
+
opening_tag->location.start,
|
|
1506
|
+
closing_tag->location.end,
|
|
1507
|
+
parser->allocator,
|
|
1508
|
+
&errors,
|
|
1509
|
+
&parser->options
|
|
1510
|
+
);
|
|
1511
|
+
}
|
|
1398
1512
|
} else if (token_is(parser, TOKEN_ERB_START)) {
|
|
1399
1513
|
append_nested_erb_tag_error(
|
|
1400
1514
|
opening_tag,
|
|
@@ -1403,7 +1517,8 @@ static AST_ERB_CONTENT_NODE_T* parser_parse_erb_tag(parser_T* parser) {
|
|
|
1403
1517
|
parser->current_token->location.start,
|
|
1404
1518
|
parser->current_token->location.end,
|
|
1405
1519
|
parser->allocator,
|
|
1406
|
-
errors
|
|
1520
|
+
&errors,
|
|
1521
|
+
&parser->options
|
|
1407
1522
|
);
|
|
1408
1523
|
end_position = parser->current_token->location.start;
|
|
1409
1524
|
} else {
|
|
@@ -1412,12 +1527,25 @@ static AST_ERB_CONTENT_NODE_T* parser_parse_erb_tag(parser_T* parser) {
|
|
|
1412
1527
|
opening_tag->location.start,
|
|
1413
1528
|
parser->current_token->location.start,
|
|
1414
1529
|
parser->allocator,
|
|
1415
|
-
errors
|
|
1530
|
+
&errors,
|
|
1531
|
+
&parser->options
|
|
1416
1532
|
);
|
|
1417
1533
|
end_position = parser->current_token->location.start;
|
|
1418
1534
|
}
|
|
1419
1535
|
|
|
1420
|
-
|
|
1536
|
+
if (hb_string_equals(opening_tag->value, hb_string("<%#"))) {
|
|
1537
|
+
return (AST_NODE_T*) ast_erb_comment_node_init(
|
|
1538
|
+
opening_tag,
|
|
1539
|
+
content,
|
|
1540
|
+
closing_tag,
|
|
1541
|
+
opening_tag->location.start,
|
|
1542
|
+
end_position,
|
|
1543
|
+
errors,
|
|
1544
|
+
parser->allocator
|
|
1545
|
+
);
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
return (AST_NODE_T*) ast_erb_content_node_init(
|
|
1421
1549
|
opening_tag,
|
|
1422
1550
|
content,
|
|
1423
1551
|
closing_tag,
|
|
@@ -1430,26 +1558,103 @@ static AST_ERB_CONTENT_NODE_T* parser_parse_erb_tag(parser_T* parser) {
|
|
|
1430
1558
|
errors,
|
|
1431
1559
|
parser->allocator
|
|
1432
1560
|
);
|
|
1561
|
+
}
|
|
1433
1562
|
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1563
|
+
static bool is_tag_name_character(char character) {
|
|
1564
|
+
return (character >= 'a' && character <= 'z') || (character >= 'A' && character <= 'Z')
|
|
1565
|
+
|| (character >= '0' && character <= '9') || character == '-';
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
static bool parser_scan_for_end_tag(const parser_T* parser, hb_string_T tag_name) {
|
|
1569
|
+
hb_string_T source = parser->lexer->source;
|
|
1570
|
+
|
|
1571
|
+
if (hb_string_is_empty(source) || hb_string_is_empty(tag_name)) { return false; }
|
|
1572
|
+
|
|
1573
|
+
for (uint32_t index = parser->current_token->range.from; index + 2 < source.length; index++) {
|
|
1574
|
+
if (source.data[index] != '<' || source.data[index + 1] != '/') { continue; }
|
|
1575
|
+
|
|
1576
|
+
uint32_t name_start = index + 2;
|
|
1437
1577
|
|
|
1438
|
-
|
|
1578
|
+
if (name_start + tag_name.length > source.length) { return false; }
|
|
1579
|
+
|
|
1580
|
+
hb_string_T candidate = { .data = source.data + name_start, .length = tag_name.length };
|
|
1581
|
+
|
|
1582
|
+
if (!hb_string_equals_case_insensitive(candidate, tag_name)) { continue; }
|
|
1583
|
+
|
|
1584
|
+
uint32_t after = name_start + tag_name.length;
|
|
1585
|
+
|
|
1586
|
+
if (after >= source.length || !is_tag_name_character(source.data[after])) { return true; }
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
return false;
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
static bool parser_foreign_content_end_tag_ahead(parser_T* parser, hb_string_T tag_name) {
|
|
1593
|
+
int index = parser_foreign_content_element_index(tag_name);
|
|
1594
|
+
uint32_t position = parser->current_token->range.from;
|
|
1595
|
+
|
|
1596
|
+
if (index >= 0 && position >= parser->foreign_content_absent_from[index]) { return false; }
|
|
1597
|
+
|
|
1598
|
+
if (parser_scan_for_end_tag(parser, tag_name)) { return true; }
|
|
1599
|
+
|
|
1600
|
+
if (index >= 0 && position < parser->foreign_content_absent_from[index]) {
|
|
1601
|
+
parser->foreign_content_absent_from[index] = position;
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1604
|
+
return false;
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
// <title> and <plaintext> are ordinary elements in XML documents, <title> also inside <svg>
|
|
1608
|
+
static bool parser_element_has_foreign_content(parser_T* parser, hb_string_T tag_name) {
|
|
1609
|
+
if (parser_get_foreign_content_kind(tag_name) == FOREIGN_CONTENT_NONE) { return false; }
|
|
1610
|
+
if (parser_foreign_content_is_html_only(tag_name) && parser->xml_document) { return false; }
|
|
1611
|
+
if (hb_string_equals_case_insensitive(tag_name, hb_string("title")) && parser_in_svg_context(parser)) {
|
|
1612
|
+
return false;
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
if (parser_foreign_content_has_end_tag(tag_name) && !parser_foreign_content_end_tag_ahead(parser, tag_name)) {
|
|
1616
|
+
return false;
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
return true;
|
|
1439
1620
|
}
|
|
1440
1621
|
|
|
1441
|
-
|
|
1622
|
+
// <textarea> and <title> hold text, <script> and <style> hold raw source
|
|
1623
|
+
static void parser_append_foreign_content_from_buffer(
|
|
1624
|
+
const parser_T* parser,
|
|
1625
|
+
hb_buffer_T* buffer,
|
|
1626
|
+
hb_array_T* children,
|
|
1627
|
+
position_T start
|
|
1628
|
+
) {
|
|
1629
|
+
bool is_text = parser->foreign_content_kind == FOREIGN_CONTENT_RCDATA;
|
|
1630
|
+
|
|
1631
|
+
if (!is_text || buffer->length == 0) {
|
|
1632
|
+
parser_append_literal_node_from_buffer(parser, buffer, children, start);
|
|
1633
|
+
return;
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
hb_string_T content = { .data = buffer->value, .length = (uint32_t) buffer->length };
|
|
1637
|
+
|
|
1638
|
+
hb_array_append(
|
|
1639
|
+
children,
|
|
1640
|
+
ast_html_text_node_init(content, start, parser->current_token->location.start, NULL, parser->allocator)
|
|
1641
|
+
);
|
|
1642
|
+
|
|
1643
|
+
hb_buffer_free(buffer);
|
|
1644
|
+
hb_buffer_init(buffer, 128, parser->allocator);
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
static void parser_parse_foreign_content(parser_T* parser, hb_array_T* children, hb_array_T** errors) {
|
|
1442
1648
|
hb_buffer_T content;
|
|
1443
1649
|
hb_buffer_init(&content, 1024, parser->allocator);
|
|
1444
1650
|
position_T start = parser->current_token->location.start;
|
|
1445
|
-
|
|
1446
|
-
bool has_closing_tag = !hb_string_is_empty(expected_closing_tag);
|
|
1651
|
+
bool has_closing_tag = !hb_string_is_empty(parser->foreign_content_tag_name);
|
|
1447
1652
|
|
|
1448
1653
|
while (!token_is(parser, TOKEN_EOF)) {
|
|
1449
1654
|
if (token_is(parser, TOKEN_ERB_START)) {
|
|
1450
|
-
|
|
1655
|
+
parser_append_foreign_content_from_buffer(parser, &content, children, start);
|
|
1451
1656
|
|
|
1452
|
-
|
|
1657
|
+
AST_NODE_T* erb_node = parser_parse_erb_tag(parser);
|
|
1453
1658
|
hb_array_append(children, erb_node);
|
|
1454
1659
|
|
|
1455
1660
|
start = parser->current_token->location.start;
|
|
@@ -1464,7 +1669,7 @@ static void parser_parse_foreign_content(parser_T* parser, hb_array_T* children,
|
|
|
1464
1669
|
bool is_potential_match = false;
|
|
1465
1670
|
|
|
1466
1671
|
if (next_token && next_token->type == TOKEN_IDENTIFIER && !hb_string_is_empty(next_token->value)) {
|
|
1467
|
-
is_potential_match =
|
|
1672
|
+
is_potential_match = parser_is_foreign_content_closing_tag_name(parser, next_token->value);
|
|
1468
1673
|
}
|
|
1469
1674
|
|
|
1470
1675
|
lexer_restore_state(parser->lexer, saved_state);
|
|
@@ -1472,7 +1677,7 @@ static void parser_parse_foreign_content(parser_T* parser, hb_array_T* children,
|
|
|
1472
1677
|
if (next_token) { token_free(next_token, parser->allocator); }
|
|
1473
1678
|
|
|
1474
1679
|
if (is_potential_match) {
|
|
1475
|
-
|
|
1680
|
+
parser_append_foreign_content_from_buffer(parser, &content, children, start);
|
|
1476
1681
|
parser_exit_foreign_content(parser);
|
|
1477
1682
|
|
|
1478
1683
|
hb_buffer_free(&content);
|
|
@@ -1486,18 +1691,19 @@ static void parser_parse_foreign_content(parser_T* parser, hb_array_T* children,
|
|
|
1486
1691
|
token_free(token, parser->allocator);
|
|
1487
1692
|
}
|
|
1488
1693
|
|
|
1489
|
-
|
|
1694
|
+
parser_append_foreign_content_from_buffer(parser, &content, children, start);
|
|
1490
1695
|
parser_exit_foreign_content(parser);
|
|
1491
1696
|
hb_buffer_free(&content);
|
|
1492
1697
|
}
|
|
1493
1698
|
|
|
1494
|
-
static void parser_parse_in_data_state(parser_T* parser, hb_array_T* children, hb_array_T
|
|
1699
|
+
static void parser_parse_in_data_state(parser_T* parser, hb_array_T* children, hb_array_T** errors) {
|
|
1495
1700
|
if (!parser->options.html) {
|
|
1496
1701
|
parser_parse_foreign_content(parser, children, errors);
|
|
1497
1702
|
return;
|
|
1498
1703
|
}
|
|
1499
1704
|
|
|
1500
1705
|
while (token_is_not(parser, TOKEN_EOF)) {
|
|
1706
|
+
if (parser_options_past_deadline(&parser->options)) { break; }
|
|
1501
1707
|
|
|
1502
1708
|
if (token_is(parser, TOKEN_ERB_START)) {
|
|
1503
1709
|
hb_array_append(children, parser_parse_erb_tag(parser));
|
|
@@ -1517,6 +1723,12 @@ static void parser_parse_in_data_state(parser_T* parser, hb_array_T* children, h
|
|
|
1517
1723
|
continue;
|
|
1518
1724
|
}
|
|
1519
1725
|
|
|
1726
|
+
if (token_is(parser, TOKEN_XML_PROCESSING_INSTRUCTION_START)) {
|
|
1727
|
+
hb_array_append(children, parser_parse_xml_processing_instruction(parser));
|
|
1728
|
+
parser->consecutive_error_count = 0;
|
|
1729
|
+
continue;
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1520
1732
|
if (token_is(parser, TOKEN_CDATA_START)) {
|
|
1521
1733
|
hb_array_append(children, parser_parse_cdata(parser));
|
|
1522
1734
|
parser->consecutive_error_count = 0;
|
|
@@ -1601,11 +1813,18 @@ static void parser_parse_in_data_state(parser_T* parser, hb_array_T* children, h
|
|
|
1601
1813
|
}
|
|
1602
1814
|
}
|
|
1603
1815
|
|
|
1604
|
-
static size_t find_matching_close_tag(
|
|
1816
|
+
static size_t find_matching_close_tag(
|
|
1817
|
+
hb_array_T* nodes,
|
|
1818
|
+
size_t start_index,
|
|
1819
|
+
hb_string_T tag_name,
|
|
1820
|
+
const parser_options_T* options
|
|
1821
|
+
) {
|
|
1605
1822
|
int depth = 0;
|
|
1606
1823
|
|
|
1607
|
-
for (size_t
|
|
1608
|
-
|
|
1824
|
+
for (size_t index = start_index + 1; index < hb_array_size(nodes); index++) {
|
|
1825
|
+
if (parser_options_past_deadline(options)) { return (size_t) -1; }
|
|
1826
|
+
|
|
1827
|
+
AST_NODE_T* node = (AST_NODE_T*) hb_array_get(nodes, index);
|
|
1609
1828
|
if (node == NULL) { continue; }
|
|
1610
1829
|
|
|
1611
1830
|
if (node->type == AST_HTML_OPEN_TAG_NODE) {
|
|
@@ -1616,7 +1835,7 @@ static size_t find_matching_close_tag(hb_array_T* nodes, size_t start_idx, hb_st
|
|
|
1616
1835
|
AST_HTML_CLOSE_TAG_NODE_T* close = (AST_HTML_CLOSE_TAG_NODE_T*) node;
|
|
1617
1836
|
|
|
1618
1837
|
if (hb_string_equals_case_insensitive(close->tag_name->value, tag_name)) {
|
|
1619
|
-
if (depth == 0) { return
|
|
1838
|
+
if (depth == 0) { return index; }
|
|
1620
1839
|
depth--;
|
|
1621
1840
|
}
|
|
1622
1841
|
}
|
|
@@ -1625,23 +1844,23 @@ static size_t find_matching_close_tag(hb_array_T* nodes, size_t start_idx, hb_st
|
|
|
1625
1844
|
return (size_t) -1;
|
|
1626
1845
|
}
|
|
1627
1846
|
|
|
1628
|
-
static size_t find_implicit_close_index(hb_array_T* nodes, size_t
|
|
1847
|
+
static size_t find_implicit_close_index(hb_array_T* nodes, size_t start_index, hb_string_T tag_name) {
|
|
1629
1848
|
if (!has_optional_end_tag(tag_name)) { return (size_t) -1; }
|
|
1630
1849
|
|
|
1631
|
-
for (size_t
|
|
1632
|
-
AST_NODE_T* node = (AST_NODE_T*) hb_array_get(nodes,
|
|
1850
|
+
for (size_t index = start_index + 1; index < hb_array_size(nodes); index++) {
|
|
1851
|
+
AST_NODE_T* node = (AST_NODE_T*) hb_array_get(nodes, index);
|
|
1633
1852
|
if (node == NULL) { continue; }
|
|
1634
1853
|
|
|
1635
1854
|
if (node->type == AST_HTML_OPEN_TAG_NODE) {
|
|
1636
1855
|
AST_HTML_OPEN_TAG_NODE_T* open = (AST_HTML_OPEN_TAG_NODE_T*) node;
|
|
1637
1856
|
hb_string_T next_tag_name = open->tag_name->value;
|
|
1638
1857
|
|
|
1639
|
-
if (should_implicitly_close(tag_name, next_tag_name)) { return
|
|
1858
|
+
if (should_implicitly_close(tag_name, next_tag_name)) { return index; }
|
|
1640
1859
|
} else if (node->type == AST_HTML_CLOSE_TAG_NODE) {
|
|
1641
1860
|
AST_HTML_CLOSE_TAG_NODE_T* close = (AST_HTML_CLOSE_TAG_NODE_T*) node;
|
|
1642
1861
|
hb_string_T close_tag_name = close->tag_name->value;
|
|
1643
1862
|
|
|
1644
|
-
if (parent_closes_element(tag_name, close_tag_name)) { return
|
|
1863
|
+
if (parent_closes_element(tag_name, close_tag_name)) { return index; }
|
|
1645
1864
|
}
|
|
1646
1865
|
}
|
|
1647
1866
|
|
|
@@ -1655,6 +1874,46 @@ static hb_array_T* parser_build_elements_from_tags(
|
|
|
1655
1874
|
hb_allocator_T* allocator
|
|
1656
1875
|
);
|
|
1657
1876
|
|
|
1877
|
+
static bool has_close_tag_for_name(hb_array_T* close_tag_names, hb_string_T tag_name) {
|
|
1878
|
+
for (size_t i = 0; i < hb_array_size(close_tag_names); i++) {
|
|
1879
|
+
hb_string_T* name = (hb_string_T*) hb_array_get(close_tag_names, i);
|
|
1880
|
+
if (name != NULL && hb_string_equals_case_insensitive(*name, tag_name)) { return true; }
|
|
1881
|
+
}
|
|
1882
|
+
|
|
1883
|
+
return false;
|
|
1884
|
+
}
|
|
1885
|
+
|
|
1886
|
+
static hb_array_T* collect_close_tag_names(hb_array_T* nodes, hb_allocator_T* allocator) {
|
|
1887
|
+
hb_array_T* close_tag_names = hb_array_init(16, allocator);
|
|
1888
|
+
|
|
1889
|
+
for (size_t i = 0; i < hb_array_size(nodes); i++) {
|
|
1890
|
+
AST_NODE_T* node = (AST_NODE_T*) hb_array_get(nodes, i);
|
|
1891
|
+
if (node == NULL || node->type != AST_HTML_CLOSE_TAG_NODE) { continue; }
|
|
1892
|
+
|
|
1893
|
+
AST_HTML_CLOSE_TAG_NODE_T* close_tag = (AST_HTML_CLOSE_TAG_NODE_T*) node;
|
|
1894
|
+
hb_string_T name = close_tag->tag_name->value;
|
|
1895
|
+
|
|
1896
|
+
if (!has_close_tag_for_name(close_tag_names, name)) {
|
|
1897
|
+
hb_string_T* stored = hb_allocator_alloc(allocator, sizeof(hb_string_T));
|
|
1898
|
+
*stored = name;
|
|
1899
|
+
hb_array_append(close_tag_names, stored);
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
|
|
1903
|
+
return close_tag_names;
|
|
1904
|
+
}
|
|
1905
|
+
|
|
1906
|
+
static void free_close_tag_names(hb_array_T** close_tag_names, hb_allocator_T* allocator) {
|
|
1907
|
+
if (close_tag_names == NULL || *close_tag_names == NULL) { return; }
|
|
1908
|
+
|
|
1909
|
+
for (size_t i = 0; i < hb_array_size(*close_tag_names); i++) {
|
|
1910
|
+
hb_string_T* name = (hb_string_T*) hb_array_get(*close_tag_names, i);
|
|
1911
|
+
if (name != NULL) { hb_allocator_dealloc(allocator, name); }
|
|
1912
|
+
}
|
|
1913
|
+
|
|
1914
|
+
hb_array_free(close_tag_names);
|
|
1915
|
+
}
|
|
1916
|
+
|
|
1658
1917
|
static hb_array_T* parser_build_elements_from_tags(
|
|
1659
1918
|
hb_array_T* nodes,
|
|
1660
1919
|
hb_array_T* errors,
|
|
@@ -1663,8 +1922,11 @@ static hb_array_T* parser_build_elements_from_tags(
|
|
|
1663
1922
|
) {
|
|
1664
1923
|
bool strict = options ? options->strict : false;
|
|
1665
1924
|
hb_array_T* result = hb_array_init(hb_array_size(nodes), allocator);
|
|
1925
|
+
hb_array_T* close_tag_names = collect_close_tag_names(nodes, allocator);
|
|
1666
1926
|
|
|
1667
1927
|
for (size_t index = 0; index < hb_array_size(nodes); index++) {
|
|
1928
|
+
if (parser_options_past_deadline(options)) { break; }
|
|
1929
|
+
|
|
1668
1930
|
AST_NODE_T* node = (AST_NODE_T*) hb_array_get(nodes, index);
|
|
1669
1931
|
if (node == NULL) { continue; }
|
|
1670
1932
|
|
|
@@ -1672,7 +1934,11 @@ static hb_array_T* parser_build_elements_from_tags(
|
|
|
1672
1934
|
AST_HTML_OPEN_TAG_NODE_T* open_tag = (AST_HTML_OPEN_TAG_NODE_T*) node;
|
|
1673
1935
|
hb_string_T tag_name = open_tag->tag_name->value;
|
|
1674
1936
|
|
|
1675
|
-
size_t close_index =
|
|
1937
|
+
size_t close_index = (size_t) -1;
|
|
1938
|
+
|
|
1939
|
+
if (has_close_tag_for_name(close_tag_names, tag_name)) {
|
|
1940
|
+
close_index = find_matching_close_tag(nodes, index, tag_name, options);
|
|
1941
|
+
}
|
|
1676
1942
|
|
|
1677
1943
|
if (close_index == (size_t) -1) {
|
|
1678
1944
|
size_t implicit_close_index = find_implicit_close_index(nodes, index, tag_name);
|
|
@@ -1694,7 +1960,7 @@ static hb_array_T* parser_build_elements_from_tags(
|
|
|
1694
1960
|
if (last_body_node != NULL) { end_position = last_body_node->location.end; }
|
|
1695
1961
|
}
|
|
1696
1962
|
|
|
1697
|
-
hb_array_T* element_errors =
|
|
1963
|
+
hb_array_T* element_errors = NULL;
|
|
1698
1964
|
|
|
1699
1965
|
if (strict) {
|
|
1700
1966
|
append_omitted_closing_tag_error(
|
|
@@ -1703,21 +1969,22 @@ static hb_array_T* parser_build_elements_from_tags(
|
|
|
1703
1969
|
open_tag->base.location.start,
|
|
1704
1970
|
open_tag->base.location.end,
|
|
1705
1971
|
allocator,
|
|
1706
|
-
element_errors
|
|
1972
|
+
&element_errors,
|
|
1973
|
+
options
|
|
1707
1974
|
);
|
|
1708
1975
|
}
|
|
1709
1976
|
|
|
1710
1977
|
AST_HTML_OMITTED_CLOSE_TAG_NODE_T* omitted_close_tag = ast_html_omitted_close_tag_node_init(
|
|
1711
|
-
open_tag->tag_name,
|
|
1978
|
+
token_copy(open_tag->tag_name, allocator),
|
|
1712
1979
|
end_position,
|
|
1713
1980
|
end_position,
|
|
1714
|
-
|
|
1981
|
+
NULL,
|
|
1715
1982
|
allocator
|
|
1716
1983
|
);
|
|
1717
1984
|
|
|
1718
1985
|
AST_HTML_ELEMENT_NODE_T* element = ast_html_element_node_init(
|
|
1719
1986
|
(AST_NODE_T*) open_tag,
|
|
1720
|
-
open_tag->tag_name,
|
|
1987
|
+
token_copy(open_tag->tag_name, allocator),
|
|
1721
1988
|
processed_body,
|
|
1722
1989
|
(AST_NODE_T*) omitted_close_tag,
|
|
1723
1990
|
false,
|
|
@@ -1738,7 +2005,8 @@ static hb_array_T* parser_build_elements_from_tags(
|
|
|
1738
2005
|
open_tag->base.location.start,
|
|
1739
2006
|
open_tag->base.location.end,
|
|
1740
2007
|
allocator,
|
|
1741
|
-
open_tag->base.errors
|
|
2008
|
+
&open_tag->base.errors,
|
|
2009
|
+
options
|
|
1742
2010
|
);
|
|
1743
2011
|
}
|
|
1744
2012
|
|
|
@@ -1756,11 +2024,11 @@ static hb_array_T* parser_build_elements_from_tags(
|
|
|
1756
2024
|
hb_array_T* processed_body = parser_build_elements_from_tags(body, errors, options, allocator);
|
|
1757
2025
|
hb_array_free(&body);
|
|
1758
2026
|
|
|
1759
|
-
hb_array_T* element_errors =
|
|
2027
|
+
hb_array_T* element_errors = NULL;
|
|
1760
2028
|
|
|
1761
2029
|
AST_HTML_ELEMENT_NODE_T* element = ast_html_element_node_init(
|
|
1762
2030
|
(AST_NODE_T*) open_tag,
|
|
1763
|
-
open_tag->tag_name,
|
|
2031
|
+
token_copy(open_tag->tag_name, allocator),
|
|
1764
2032
|
processed_body,
|
|
1765
2033
|
(AST_NODE_T*) close_tag,
|
|
1766
2034
|
false,
|
|
@@ -1785,7 +2053,8 @@ static hb_array_T* parser_build_elements_from_tags(
|
|
|
1785
2053
|
close_tag->base.location.start,
|
|
1786
2054
|
close_tag->base.location.end,
|
|
1787
2055
|
allocator,
|
|
1788
|
-
close_tag->base.errors
|
|
2056
|
+
&close_tag->base.errors,
|
|
2057
|
+
options
|
|
1789
2058
|
);
|
|
1790
2059
|
}
|
|
1791
2060
|
}
|
|
@@ -1796,17 +2065,19 @@ static hb_array_T* parser_build_elements_from_tags(
|
|
|
1796
2065
|
}
|
|
1797
2066
|
}
|
|
1798
2067
|
|
|
2068
|
+
free_close_tag_names(&close_tag_names, allocator);
|
|
2069
|
+
|
|
1799
2070
|
return result;
|
|
1800
2071
|
}
|
|
1801
2072
|
|
|
1802
2073
|
static AST_DOCUMENT_NODE_T* parser_parse_document(parser_T* parser) {
|
|
1803
2074
|
hb_array_T* children = hb_array_init(8, parser->allocator);
|
|
1804
|
-
hb_array_T* errors =
|
|
2075
|
+
hb_array_T* errors = NULL;
|
|
1805
2076
|
position_T start = parser->current_token->location.start;
|
|
1806
2077
|
|
|
1807
|
-
parser_parse_in_data_state(parser, children, errors);
|
|
2078
|
+
parser_parse_in_data_state(parser, children, &errors);
|
|
1808
2079
|
|
|
1809
|
-
token_T* eof = parser_consume_expected(parser, TOKEN_EOF, errors);
|
|
2080
|
+
token_T* eof = parser_consume_expected(parser, TOKEN_EOF, &errors);
|
|
1810
2081
|
|
|
1811
2082
|
AST_DOCUMENT_NODE_T* document_node =
|
|
1812
2083
|
ast_document_node_init(children, NULL, HERB_PRISM_NODE_EMPTY, start, eof->location.end, errors, parser->allocator);
|
|
@@ -1822,7 +2093,7 @@ AST_DOCUMENT_NODE_T* herb_parser_parse(parser_T* parser) {
|
|
|
1822
2093
|
|
|
1823
2094
|
static void parser_handle_whitespace(parser_T* parser, token_T* whitespace_token, hb_array_T* children) {
|
|
1824
2095
|
if (parser->options.track_whitespace) {
|
|
1825
|
-
hb_array_T* errors =
|
|
2096
|
+
hb_array_T* errors = NULL;
|
|
1826
2097
|
AST_WHITESPACE_NODE_T* whitespace_node = ast_whitespace_node_init(
|
|
1827
2098
|
whitespace_token,
|
|
1828
2099
|
whitespace_token->location.start,
|
|
@@ -1831,6 +2102,8 @@ static void parser_handle_whitespace(parser_T* parser, token_T* whitespace_token
|
|
|
1831
2102
|
parser->allocator
|
|
1832
2103
|
);
|
|
1833
2104
|
hb_array_append(children, whitespace_node);
|
|
2105
|
+
|
|
2106
|
+
return;
|
|
1834
2107
|
}
|
|
1835
2108
|
|
|
1836
2109
|
token_free(whitespace_token, parser->allocator);
|