diff --git a/src/parser.c b/src/parser.c
index 5131c0639..ffc7273f7 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -295,6 +295,11 @@ static AST_HTML_ATTRIBUTE_NAME_NODE_T* parser_parse_html_attribute_name(parser_T
TOKEN_EOF
)) {
if (token_is(parser, TOKEN_ERB_START)) {
+ const char* tag = parser->current_token->value;
+ bool is_output_tag = (tag[2] == '=');
+
+ if (!is_output_tag) { break; }
+
parser_append_literal_node_from_buffer(parser, &buffer, children, start);
AST_ERB_CONTENT_NODE_T* erb_node = parser_parse_erb_tag(parser);
diff --git a/test/parser/attributes_test.rb b/test/parser/attributes_test.rb
index 789d032a2..4c091d603 100644
--- a/test/parser/attributes_test.rb
+++ b/test/parser/attributes_test.rb
@@ -195,5 +195,66 @@ class AttributesTest < Minitest::Spec
test "Empty attribute value with closing bracket immediatly following it" do
assert_parsed_snapshot(%(
div-content
))
end
+
+ test "Conditional attribute with ERB control flow and no surrounding spaces" do
+ assert_parsed_snapshot(%(data-turbo-permanent<% end %>> ))
+ end
+
+ test "Conditional attribute with ERB control flow with surrounding spaces" do
+ assert_parsed_snapshot(%( data-turbo-permanent <% end %>> ))
+ end
+
+ test "Conditional attribute with ERB on separate line" do
+ assert_parsed_snapshot <<~HTML
+ data-menu-button<% end %>
+ class="css-truncate css-truncate-target"
+ >
+ HTML
+ end
+
+ test "Conditional attribute with value" do
+ assert_parsed_snapshot(%(data-enabled="true"<% end %>>
))
+ end
+
+ test "Multiple conditional attributes" do
+ assert_parsed_snapshot(%(data-a<% end %> <% if b? %>data-b<% end %>>
))
+ end
+
+ test "Conditional attribute with elsif and else" do
+ assert_parsed_snapshot(%(data-primary<% elsif secondary? %>data-secondary<% else %>data-default<% end %>>
))
+ end
+
+ test "Conditional attribute with unless" do
+ assert_parsed_snapshot(%(data-enabled<% end %>>
))
+ end
+
+ test "Multiple attributes in one conditional block" do
+ assert_parsed_snapshot(%(data-admin data-role="admin"<% end %>>
))
+ end
+
+ test "Conditional boolean attribute" do
+ assert_parsed_snapshot(%( disabled<% end %> type="text">))
+ end
+
+ test "Conditional attribute with output tag inside" do
+ assert_parsed_snapshot(%(data-user="<%= user.id %>"<% end %>>
))
+ end
+
+ test "ERB comment between attributes" do
+ assert_parsed_snapshot(%( data-baz="qux">
))
+ end
+
+ test "Conditional attribute with trimming tags" do
+ assert_parsed_snapshot(%(data-conditional<%- end -%>>
))
+ end
+
+ test "Empty conditional block in attributes" do
+ assert_parsed_snapshot(%(<% end %> data-other="value">
))
+ end
+
+ test "Nested conditional attributes" do
+ assert_parsed_snapshot(%(<% if inner? %>data-inner<% end %><% end %>>
))
+ end
end
end
diff --git a/test/snapshots/parser/attributes_test/test_0047_Conditional_attribute_with_ERB_control_flow_and_no_surrounding_spaces_8b8da9205eb731ac258036f24249144e.txt b/test/snapshots/parser/attributes_test/test_0047_Conditional_attribute_with_ERB_control_flow_and_no_surrounding_spaces_8b8da9205eb731ac258036f24249144e.txt
new file mode 100644
index 000000000..b28e20c8a
--- /dev/null
+++ b/test/snapshots/parser/attributes_test/test_0047_Conditional_attribute_with_ERB_control_flow_and_no_surrounding_spaces_8b8da9205eb731ac258036f24249144e.txt
@@ -0,0 +1,70 @@
+---
+source: "Parser::AttributesTest#test_0047_Conditional attribute with ERB control flow and no surrounding spaces"
+input: "data-turbo-permanent<% end %>> "
+---
+@ DocumentNode (location: (1:0)-(1:106))
+└── children: (1 item)
+ └── @ HTMLElementNode (location: (1:0)-(1:106))
+ ├── open_tag:
+ │ └── @ HTMLOpenTagNode (location: (1:0)-(1:97))
+ │ ├── tag_opening: "<" (location: (1:0)-(1:1))
+ │ ├── tag_name: "dialog" (location: (1:1)-(1:7))
+ │ ├── tag_closing: ">" (location: (1:96)-(1:97))
+ │ ├── children: (2 items)
+ │ │ ├── @ HTMLAttributeNode (location: (1:8)-(1:32))
+ │ │ │ ├── name:
+ │ │ │ │ └── @ HTMLAttributeNameNode (location: (1:8)-(1:23))
+ │ │ │ │ └── children: (1 item)
+ │ │ │ │ └── @ LiteralNode (location: (1:8)-(1:23))
+ │ │ │ │ └── content: "data-controller"
+ │ │ │ │
+ │ │ │ │
+ │ │ │ ├── equals: "=" (location: (1:23)-(1:24))
+ │ │ │ └── value:
+ │ │ │ └── @ HTMLAttributeValueNode (location: (1:24)-(1:32))
+ │ │ │ ├── open_quote: """ (location: (1:24)-(1:25))
+ │ │ │ ├── children: (1 item)
+ │ │ │ │ └── @ LiteralNode (location: (1:25)-(1:31))
+ │ │ │ │ └── content: "dialog"
+ │ │ │ │
+ │ │ │ ├── close_quote: """ (location: (1:31)-(1:32))
+ │ │ │ └── quoted: true
+ │ │ │
+ │ │ │
+ │ │ └── @ ERBIfNode (location: (1:33)-(1:96))
+ │ │ ├── tag_opening: "<%" (location: (1:33)-(1:35))
+ │ │ ├── content: " if local_assigns[:permanent] " (location: (1:35)-(1:65))
+ │ │ ├── tag_closing: "%>" (location: (1:65)-(1:67))
+ │ │ ├── statements: (1 item)
+ │ │ │ └── @ HTMLAttributeNode (location: (1:67)-(1:87))
+ │ │ │ ├── name:
+ │ │ │ │ └── @ HTMLAttributeNameNode (location: (1:67)-(1:87))
+ │ │ │ │ └── children: (1 item)
+ │ │ │ │ └── @ LiteralNode (location: (1:67)-(1:87))
+ │ │ │ │ └── content: "data-turbo-permanent"
+ │ │ │ │
+ │ │ │ │
+ │ │ │ ├── equals: ∅
+ │ │ │ └── value: ∅
+ │ │ │
+ │ │ ├── subsequent: ∅
+ │ │ └── end_node:
+ │ │ └── @ ERBEndNode (location: (1:87)-(1:96))
+ │ │ ├── tag_opening: "<%" (location: (1:87)-(1:89))
+ │ │ ├── content: " end " (location: (1:89)-(1:94))
+ │ │ └── tag_closing: "%>" (location: (1:94)-(1:96))
+ │ │
+ │ │
+ │ └── is_void: false
+ │
+ ├── tag_name: "dialog" (location: (1:1)-(1:7))
+ ├── body: []
+ ├── close_tag:
+ │ └── @ HTMLCloseTagNode (location: (1:97)-(1:106))
+ │ ├── tag_opening: "" (location: (1:97)-(1:99))
+ │ ├── tag_name: "dialog" (location: (1:99)-(1:105))
+ │ ├── children: []
+ │ └── tag_closing: ">" (location: (1:105)-(1:106))
+ │
+ ├── is_void: false
+ └── source: "HTML"
\ No newline at end of file
diff --git a/test/snapshots/parser/attributes_test/test_0048_Conditional_attribute_with_ERB_control_flow_with_surrounding_spaces_f5fb22be5ee259a7902533d5e90f2935.txt b/test/snapshots/parser/attributes_test/test_0048_Conditional_attribute_with_ERB_control_flow_with_surrounding_spaces_f5fb22be5ee259a7902533d5e90f2935.txt
new file mode 100644
index 000000000..4094a112e
--- /dev/null
+++ b/test/snapshots/parser/attributes_test/test_0048_Conditional_attribute_with_ERB_control_flow_with_surrounding_spaces_f5fb22be5ee259a7902533d5e90f2935.txt
@@ -0,0 +1,70 @@
+---
+source: "Parser::AttributesTest#test_0048_Conditional attribute with ERB control flow with surrounding spaces"
+input: " data-turbo-permanent <% end %>> "
+---
+@ DocumentNode (location: (1:0)-(1:108))
+└── children: (1 item)
+ └── @ HTMLElementNode (location: (1:0)-(1:108))
+ ├── open_tag:
+ │ └── @ HTMLOpenTagNode (location: (1:0)-(1:99))
+ │ ├── tag_opening: "<" (location: (1:0)-(1:1))
+ │ ├── tag_name: "dialog" (location: (1:1)-(1:7))
+ │ ├── tag_closing: ">" (location: (1:98)-(1:99))
+ │ ├── children: (2 items)
+ │ │ ├── @ HTMLAttributeNode (location: (1:8)-(1:32))
+ │ │ │ ├── name:
+ │ │ │ │ └── @ HTMLAttributeNameNode (location: (1:8)-(1:23))
+ │ │ │ │ └── children: (1 item)
+ │ │ │ │ └── @ LiteralNode (location: (1:8)-(1:23))
+ │ │ │ │ └── content: "data-controller"
+ │ │ │ │
+ │ │ │ │
+ │ │ │ ├── equals: "=" (location: (1:23)-(1:24))
+ │ │ │ └── value:
+ │ │ │ └── @ HTMLAttributeValueNode (location: (1:24)-(1:32))
+ │ │ │ ├── open_quote: """ (location: (1:24)-(1:25))
+ │ │ │ ├── children: (1 item)
+ │ │ │ │ └── @ LiteralNode (location: (1:25)-(1:31))
+ │ │ │ │ └── content: "dialog"
+ │ │ │ │
+ │ │ │ ├── close_quote: """ (location: (1:31)-(1:32))
+ │ │ │ └── quoted: true
+ │ │ │
+ │ │ │
+ │ │ └── @ ERBIfNode (location: (1:33)-(1:98))
+ │ │ ├── tag_opening: "<%" (location: (1:33)-(1:35))
+ │ │ ├── content: " if local_assigns[:permanent] " (location: (1:35)-(1:65))
+ │ │ ├── tag_closing: "%>" (location: (1:65)-(1:67))
+ │ │ ├── statements: (1 item)
+ │ │ │ └── @ HTMLAttributeNode (location: (1:68)-(1:88))
+ │ │ │ ├── name:
+ │ │ │ │ └── @ HTMLAttributeNameNode (location: (1:68)-(1:88))
+ │ │ │ │ └── children: (1 item)
+ │ │ │ │ └── @ LiteralNode (location: (1:68)-(1:88))
+ │ │ │ │ └── content: "data-turbo-permanent"
+ │ │ │ │
+ │ │ │ │
+ │ │ │ ├── equals: ∅
+ │ │ │ └── value: ∅
+ │ │ │
+ │ │ ├── subsequent: ∅
+ │ │ └── end_node:
+ │ │ └── @ ERBEndNode (location: (1:89)-(1:98))
+ │ │ ├── tag_opening: "<%" (location: (1:89)-(1:91))
+ │ │ ├── content: " end " (location: (1:91)-(1:96))
+ │ │ └── tag_closing: "%>" (location: (1:96)-(1:98))
+ │ │
+ │ │
+ │ └── is_void: false
+ │
+ ├── tag_name: "dialog" (location: (1:1)-(1:7))
+ ├── body: []
+ ├── close_tag:
+ │ └── @ HTMLCloseTagNode (location: (1:99)-(1:108))
+ │ ├── tag_opening: "" (location: (1:99)-(1:101))
+ │ ├── tag_name: "dialog" (location: (1:101)-(1:107))
+ │ ├── children: []
+ │ └── tag_closing: ">" (location: (1:107)-(1:108))
+ │
+ ├── is_void: false
+ └── source: "HTML"
\ No newline at end of file
diff --git a/test/snapshots/parser/attributes_test/test_0049_Conditional_attribute_with_ERB_on_separate_line_8f3997e9bb390d529e8a302cd3644924.txt b/test/snapshots/parser/attributes_test/test_0049_Conditional_attribute_with_ERB_on_separate_line_8f3997e9bb390d529e8a302cd3644924.txt
new file mode 100644
index 000000000..7043d2212
--- /dev/null
+++ b/test/snapshots/parser/attributes_test/test_0049_Conditional_attribute_with_ERB_on_separate_line_8f3997e9bb390d529e8a302cd3644924.txt
@@ -0,0 +1,77 @@
+---
+source: "Parser::AttributesTest#test_0049_Conditional attribute with ERB on separate line"
+input: |2-
+data-menu-button<% end %>
+ class="css-truncate css-truncate-target"
+>
+---
+@ DocumentNode (location: (1:0)-(5:0))
+└── children: (2 items)
+ ├── @ HTMLElementNode (location: (1:0)-(4:8))
+ │ ├── open_tag:
+ │ │ └── @ HTMLOpenTagNode (location: (1:0)-(4:1))
+ │ │ ├── tag_opening: "<" (location: (1:0)-(1:1))
+ │ │ ├── tag_name: "span" (location: (1:1)-(1:5))
+ │ │ ├── tag_closing: ">" (location: (4:0)-(4:1))
+ │ │ ├── children: (2 items)
+ │ │ │ ├── @ ERBIfNode (location: (2:2)-(2:48))
+ │ │ │ │ ├── tag_opening: "<%" (location: (2:2)-(2:4))
+ │ │ │ │ ├── content: " if @replaceable " (location: (2:4)-(2:21))
+ │ │ │ │ ├── tag_closing: "%>" (location: (2:21)-(2:23))
+ │ │ │ │ ├── statements: (1 item)
+ │ │ │ │ │ └── @ HTMLAttributeNode (location: (2:23)-(2:39))
+ │ │ │ │ │ ├── name:
+ │ │ │ │ │ │ └── @ HTMLAttributeNameNode (location: (2:23)-(2:39))
+ │ │ │ │ │ │ └── children: (1 item)
+ │ │ │ │ │ │ └── @ LiteralNode (location: (2:23)-(2:39))
+ │ │ │ │ │ │ └── content: "data-menu-button"
+ │ │ │ │ │ │
+ │ │ │ │ │ │
+ │ │ │ │ │ ├── equals: ∅
+ │ │ │ │ │ └── value: ∅
+ │ │ │ │ │
+ │ │ │ │ ├── subsequent: ∅
+ │ │ │ │ └── end_node:
+ │ │ │ │ └── @ ERBEndNode (location: (2:39)-(2:48))
+ │ │ │ │ ├── tag_opening: "<%" (location: (2:39)-(2:41))
+ │ │ │ │ ├── content: " end " (location: (2:41)-(2:46))
+ │ │ │ │ └── tag_closing: "%>" (location: (2:46)-(2:48))
+ │ │ │ │
+ │ │ │ │
+ │ │ │ └── @ HTMLAttributeNode (location: (3:2)-(3:42))
+ │ │ │ ├── name:
+ │ │ │ │ └── @ HTMLAttributeNameNode (location: (3:2)-(3:7))
+ │ │ │ │ └── children: (1 item)
+ │ │ │ │ └── @ LiteralNode (location: (3:2)-(3:7))
+ │ │ │ │ └── content: "class"
+ │ │ │ │
+ │ │ │ │
+ │ │ │ ├── equals: "=" (location: (3:7)-(3:8))
+ │ │ │ └── value:
+ │ │ │ └── @ HTMLAttributeValueNode (location: (3:8)-(3:42))
+ │ │ │ ├── open_quote: """ (location: (3:8)-(3:9))
+ │ │ │ ├── children: (1 item)
+ │ │ │ │ └── @ LiteralNode (location: (3:9)-(3:41))
+ │ │ │ │ └── content: "css-truncate css-truncate-target"
+ │ │ │ │
+ │ │ │ ├── close_quote: """ (location: (3:41)-(3:42))
+ │ │ │ └── quoted: true
+ │ │ │
+ │ │ │
+ │ │ └── is_void: false
+ │ │
+ │ ├── tag_name: "span" (location: (1:1)-(1:5))
+ │ ├── body: []
+ │ ├── close_tag:
+ │ │ └── @ HTMLCloseTagNode (location: (4:1)-(4:8))
+ │ │ ├── tag_opening: "" (location: (4:1)-(4:3))
+ │ │ ├── tag_name: "span" (location: (4:3)-(4:7))
+ │ │ ├── children: []
+ │ │ └── tag_closing: ">" (location: (4:7)-(4:8))
+ │ │
+ │ ├── is_void: false
+ │ └── source: "HTML"
+ │
+ └── @ HTMLTextNode (location: (4:8)-(5:0))
+ └── content: "\n"
\ No newline at end of file
diff --git a/test/snapshots/parser/attributes_test/test_0050_Conditional_attribute_with_value_81e52238e369e409d9df110376cc3aa3.txt b/test/snapshots/parser/attributes_test/test_0050_Conditional_attribute_with_value_81e52238e369e409d9df110376cc3aa3.txt
new file mode 100644
index 000000000..e278fcab8
--- /dev/null
+++ b/test/snapshots/parser/attributes_test/test_0050_Conditional_attribute_with_value_81e52238e369e409d9df110376cc3aa3.txt
@@ -0,0 +1,59 @@
+---
+source: "Parser::AttributesTest#test_0050_Conditional attribute with value"
+input: "data-enabled=\"true\"<% end %>>
"
+---
+@ DocumentNode (location: (1:0)-(1:57))
+└── children: (1 item)
+ └── @ HTMLElementNode (location: (1:0)-(1:57))
+ ├── open_tag:
+ │ └── @ HTMLOpenTagNode (location: (1:0)-(1:51))
+ │ ├── tag_opening: "<" (location: (1:0)-(1:1))
+ │ ├── tag_name: "div" (location: (1:1)-(1:4))
+ │ ├── tag_closing: ">" (location: (1:50)-(1:51))
+ │ ├── children: (1 item)
+ │ │ └── @ ERBIfNode (location: (1:5)-(1:50))
+ │ │ ├── tag_opening: "<%" (location: (1:5)-(1:7))
+ │ │ ├── content: " if enabled? " (location: (1:7)-(1:20))
+ │ │ ├── tag_closing: "%>" (location: (1:20)-(1:22))
+ │ │ ├── statements: (1 item)
+ │ │ │ └── @ HTMLAttributeNode (location: (1:22)-(1:41))
+ │ │ │ ├── name:
+ │ │ │ │ └── @ HTMLAttributeNameNode (location: (1:22)-(1:34))
+ │ │ │ │ └── children: (1 item)
+ │ │ │ │ └── @ LiteralNode (location: (1:22)-(1:34))
+ │ │ │ │ └── content: "data-enabled"
+ │ │ │ │
+ │ │ │ │
+ │ │ │ ├── equals: "=" (location: (1:34)-(1:35))
+ │ │ │ └── value:
+ │ │ │ └── @ HTMLAttributeValueNode (location: (1:35)-(1:41))
+ │ │ │ ├── open_quote: """ (location: (1:35)-(1:36))
+ │ │ │ ├── children: (1 item)
+ │ │ │ │ └── @ LiteralNode (location: (1:36)-(1:40))
+ │ │ │ │ └── content: "true"
+ │ │ │ │
+ │ │ │ ├── close_quote: """ (location: (1:40)-(1:41))
+ │ │ │ └── quoted: true
+ │ │ │
+ │ │ │
+ │ │ ├── subsequent: ∅
+ │ │ └── end_node:
+ │ │ └── @ ERBEndNode (location: (1:41)-(1:50))
+ │ │ ├── tag_opening: "<%" (location: (1:41)-(1:43))
+ │ │ ├── content: " end " (location: (1:43)-(1:48))
+ │ │ └── tag_closing: "%>" (location: (1:48)-(1:50))
+ │ │
+ │ │
+ │ └── is_void: false
+ │
+ ├── tag_name: "div" (location: (1:1)-(1:4))
+ ├── body: []
+ ├── close_tag:
+ │ └── @ HTMLCloseTagNode (location: (1:51)-(1:57))
+ │ ├── tag_opening: "" (location: (1:51)-(1:53))
+ │ ├── tag_name: "div" (location: (1:53)-(1:56))
+ │ ├── children: []
+ │ └── tag_closing: ">" (location: (1:56)-(1:57))
+ │
+ ├── is_void: false
+ └── source: "HTML"
\ No newline at end of file
diff --git a/test/snapshots/parser/attributes_test/test_0051_Multiple_conditional_attributes_befdf95a4fadd41e440a471f38e443da.txt b/test/snapshots/parser/attributes_test/test_0051_Multiple_conditional_attributes_befdf95a4fadd41e440a471f38e443da.txt
new file mode 100644
index 000000000..3a76f28c4
--- /dev/null
+++ b/test/snapshots/parser/attributes_test/test_0051_Multiple_conditional_attributes_befdf95a4fadd41e440a471f38e443da.txt
@@ -0,0 +1,74 @@
+---
+source: "Parser::AttributesTest#test_0051_Multiple conditional attributes"
+input: "data-a<% end %> <% if b? %>data-b<% end %>>
"
+---
+@ DocumentNode (location: (1:0)-(1:65))
+└── children: (1 item)
+ └── @ HTMLElementNode (location: (1:0)-(1:65))
+ ├── open_tag:
+ │ └── @ HTMLOpenTagNode (location: (1:0)-(1:59))
+ │ ├── tag_opening: "<" (location: (1:0)-(1:1))
+ │ ├── tag_name: "div" (location: (1:1)-(1:4))
+ │ ├── tag_closing: ">" (location: (1:58)-(1:59))
+ │ ├── children: (2 items)
+ │ │ ├── @ ERBIfNode (location: (1:5)-(1:31))
+ │ │ │ ├── tag_opening: "<%" (location: (1:5)-(1:7))
+ │ │ │ ├── content: " if a? " (location: (1:7)-(1:14))
+ │ │ │ ├── tag_closing: "%>" (location: (1:14)-(1:16))
+ │ │ │ ├── statements: (1 item)
+ │ │ │ │ └── @ HTMLAttributeNode (location: (1:16)-(1:22))
+ │ │ │ │ ├── name:
+ │ │ │ │ │ └── @ HTMLAttributeNameNode (location: (1:16)-(1:22))
+ │ │ │ │ │ └── children: (1 item)
+ │ │ │ │ │ └── @ LiteralNode (location: (1:16)-(1:22))
+ │ │ │ │ │ └── content: "data-a"
+ │ │ │ │ │
+ │ │ │ │ │
+ │ │ │ │ ├── equals: ∅
+ │ │ │ │ └── value: ∅
+ │ │ │ │
+ │ │ │ ├── subsequent: ∅
+ │ │ │ └── end_node:
+ │ │ │ └── @ ERBEndNode (location: (1:22)-(1:31))
+ │ │ │ ├── tag_opening: "<%" (location: (1:22)-(1:24))
+ │ │ │ ├── content: " end " (location: (1:24)-(1:29))
+ │ │ │ └── tag_closing: "%>" (location: (1:29)-(1:31))
+ │ │ │
+ │ │ │
+ │ │ └── @ ERBIfNode (location: (1:32)-(1:58))
+ │ │ ├── tag_opening: "<%" (location: (1:32)-(1:34))
+ │ │ ├── content: " if b? " (location: (1:34)-(1:41))
+ │ │ ├── tag_closing: "%>" (location: (1:41)-(1:43))
+ │ │ ├── statements: (1 item)
+ │ │ │ └── @ HTMLAttributeNode (location: (1:43)-(1:49))
+ │ │ │ ├── name:
+ │ │ │ │ └── @ HTMLAttributeNameNode (location: (1:43)-(1:49))
+ │ │ │ │ └── children: (1 item)
+ │ │ │ │ └── @ LiteralNode (location: (1:43)-(1:49))
+ │ │ │ │ └── content: "data-b"
+ │ │ │ │
+ │ │ │ │
+ │ │ │ ├── equals: ∅
+ │ │ │ └── value: ∅
+ │ │ │
+ │ │ ├── subsequent: ∅
+ │ │ └── end_node:
+ │ │ └── @ ERBEndNode (location: (1:49)-(1:58))
+ │ │ ├── tag_opening: "<%" (location: (1:49)-(1:51))
+ │ │ ├── content: " end " (location: (1:51)-(1:56))
+ │ │ └── tag_closing: "%>" (location: (1:56)-(1:58))
+ │ │
+ │ │
+ │ └── is_void: false
+ │
+ ├── tag_name: "div" (location: (1:1)-(1:4))
+ ├── body: []
+ ├── close_tag:
+ │ └── @ HTMLCloseTagNode (location: (1:59)-(1:65))
+ │ ├── tag_opening: "" (location: (1:59)-(1:61))
+ │ ├── tag_name: "div" (location: (1:61)-(1:64))
+ │ ├── children: []
+ │ └── tag_closing: ">" (location: (1:64)-(1:65))
+ │
+ ├── is_void: false
+ └── source: "HTML"
\ No newline at end of file
diff --git a/test/snapshots/parser/attributes_test/test_0052_Conditional_attribute_with_elsif_and_else_bb59fa557fa46906ac8d7b2ac4948269.txt b/test/snapshots/parser/attributes_test/test_0052_Conditional_attribute_with_elsif_and_else_bb59fa557fa46906ac8d7b2ac4948269.txt
new file mode 100644
index 000000000..4623ebfd6
--- /dev/null
+++ b/test/snapshots/parser/attributes_test/test_0052_Conditional_attribute_with_elsif_and_else_bb59fa557fa46906ac8d7b2ac4948269.txt
@@ -0,0 +1,86 @@
+---
+source: "Parser::AttributesTest#test_0052_Conditional attribute with elsif and else"
+input: "data-primary<% elsif secondary? %>data-secondary<% else %>data-default<% end %>>
"
+---
+@ DocumentNode (location: (1:0)-(1:108))
+└── children: (1 item)
+ └── @ HTMLElementNode (location: (1:0)-(1:108))
+ ├── open_tag:
+ │ └── @ HTMLOpenTagNode (location: (1:0)-(1:102))
+ │ ├── tag_opening: "<" (location: (1:0)-(1:1))
+ │ ├── tag_name: "div" (location: (1:1)-(1:4))
+ │ ├── tag_closing: ">" (location: (1:101)-(1:102))
+ │ ├── children: (1 item)
+ │ │ └── @ ERBIfNode (location: (1:5)-(1:101))
+ │ │ ├── tag_opening: "<%" (location: (1:5)-(1:7))
+ │ │ ├── content: " if primary? " (location: (1:7)-(1:20))
+ │ │ ├── tag_closing: "%>" (location: (1:20)-(1:22))
+ │ │ ├── statements: (1 item)
+ │ │ │ └── @ HTMLAttributeNode (location: (1:22)-(1:34))
+ │ │ │ ├── name:
+ │ │ │ │ └── @ HTMLAttributeNameNode (location: (1:22)-(1:34))
+ │ │ │ │ └── children: (1 item)
+ │ │ │ │ └── @ LiteralNode (location: (1:22)-(1:34))
+ │ │ │ │ └── content: "data-primary"
+ │ │ │ │
+ │ │ │ │
+ │ │ │ ├── equals: ∅
+ │ │ │ └── value: ∅
+ │ │ │
+ │ │ ├── subsequent:
+ │ │ │ └── @ ERBIfNode (location: (1:34)-(1:70))
+ │ │ │ ├── tag_opening: "<%" (location: (1:34)-(1:36))
+ │ │ │ ├── content: " elsif secondary? " (location: (1:36)-(1:54))
+ │ │ │ ├── tag_closing: "%>" (location: (1:54)-(1:56))
+ │ │ │ ├── statements: (1 item)
+ │ │ │ │ └── @ HTMLAttributeNode (location: (1:56)-(1:70))
+ │ │ │ │ ├── name:
+ │ │ │ │ │ └── @ HTMLAttributeNameNode (location: (1:56)-(1:70))
+ │ │ │ │ │ └── children: (1 item)
+ │ │ │ │ │ └── @ LiteralNode (location: (1:56)-(1:70))
+ │ │ │ │ │ └── content: "data-secondary"
+ │ │ │ │ │
+ │ │ │ │ │
+ │ │ │ │ ├── equals: ∅
+ │ │ │ │ └── value: ∅
+ │ │ │ │
+ │ │ │ ├── subsequent:
+ │ │ │ │ └── @ ERBElseNode (location: (1:70)-(1:92))
+ │ │ │ │ ├── tag_opening: "<%" (location: (1:70)-(1:72))
+ │ │ │ │ ├── content: " else " (location: (1:72)-(1:78))
+ │ │ │ │ ├── tag_closing: "%>" (location: (1:78)-(1:80))
+ │ │ │ │ └── statements: (1 item)
+ │ │ │ │ └── @ HTMLAttributeNode (location: (1:80)-(1:92))
+ │ │ │ │ ├── name:
+ │ │ │ │ │ └── @ HTMLAttributeNameNode (location: (1:80)-(1:92))
+ │ │ │ │ │ └── children: (1 item)
+ │ │ │ │ │ └── @ LiteralNode (location: (1:80)-(1:92))
+ │ │ │ │ │ └── content: "data-default"
+ │ │ │ │ │
+ │ │ │ │ │
+ │ │ │ │ ├── equals: ∅
+ │ │ │ │ └── value: ∅
+ │ │ │ │
+ │ │ │ │
+ │ │ │ └── end_node: ∅
+ │ │ │
+ │ │ └── end_node:
+ │ │ └── @ ERBEndNode (location: (1:92)-(1:101))
+ │ │ ├── tag_opening: "<%" (location: (1:92)-(1:94))
+ │ │ ├── content: " end " (location: (1:94)-(1:99))
+ │ │ └── tag_closing: "%>" (location: (1:99)-(1:101))
+ │ │
+ │ │
+ │ └── is_void: false
+ │
+ ├── tag_name: "div" (location: (1:1)-(1:4))
+ ├── body: []
+ ├── close_tag:
+ │ └── @ HTMLCloseTagNode (location: (1:102)-(1:108))
+ │ ├── tag_opening: "" (location: (1:102)-(1:104))
+ │ ├── tag_name: "div" (location: (1:104)-(1:107))
+ │ ├── children: []
+ │ └── tag_closing: ">" (location: (1:107)-(1:108))
+ │
+ ├── is_void: false
+ └── source: "HTML"
\ No newline at end of file
diff --git a/test/snapshots/parser/attributes_test/test_0053_Conditional_attribute_with_unless_a63ab0987a8655064d1dcbe0ac4267f7.txt b/test/snapshots/parser/attributes_test/test_0053_Conditional_attribute_with_unless_a63ab0987a8655064d1dcbe0ac4267f7.txt
new file mode 100644
index 000000000..7f2b16cf7
--- /dev/null
+++ b/test/snapshots/parser/attributes_test/test_0053_Conditional_attribute_with_unless_a63ab0987a8655064d1dcbe0ac4267f7.txt
@@ -0,0 +1,50 @@
+---
+source: "Parser::AttributesTest#test_0053_Conditional attribute with unless"
+input: "data-enabled<% end %>>
"
+---
+@ DocumentNode (location: (1:0)-(1:55))
+└── children: (1 item)
+ └── @ HTMLElementNode (location: (1:0)-(1:55))
+ ├── open_tag:
+ │ └── @ HTMLOpenTagNode (location: (1:0)-(1:49))
+ │ ├── tag_opening: "<" (location: (1:0)-(1:1))
+ │ ├── tag_name: "div" (location: (1:1)-(1:4))
+ │ ├── tag_closing: ">" (location: (1:48)-(1:49))
+ │ ├── children: (1 item)
+ │ │ └── @ ERBUnlessNode (location: (1:5)-(1:48))
+ │ │ ├── tag_opening: "<%" (location: (1:5)-(1:7))
+ │ │ ├── content: " unless disabled? " (location: (1:7)-(1:25))
+ │ │ ├── tag_closing: "%>" (location: (1:25)-(1:27))
+ │ │ ├── statements: (1 item)
+ │ │ │ └── @ HTMLAttributeNode (location: (1:27)-(1:39))
+ │ │ │ ├── name:
+ │ │ │ │ └── @ HTMLAttributeNameNode (location: (1:27)-(1:39))
+ │ │ │ │ └── children: (1 item)
+ │ │ │ │ └── @ LiteralNode (location: (1:27)-(1:39))
+ │ │ │ │ └── content: "data-enabled"
+ │ │ │ │
+ │ │ │ │
+ │ │ │ ├── equals: ∅
+ │ │ │ └── value: ∅
+ │ │ │
+ │ │ ├── else_clause: ∅
+ │ │ └── end_node:
+ │ │ └── @ ERBEndNode (location: (1:39)-(1:48))
+ │ │ ├── tag_opening: "<%" (location: (1:39)-(1:41))
+ │ │ ├── content: " end " (location: (1:41)-(1:46))
+ │ │ └── tag_closing: "%>" (location: (1:46)-(1:48))
+ │ │
+ │ │
+ │ └── is_void: false
+ │
+ ├── tag_name: "div" (location: (1:1)-(1:4))
+ ├── body: []
+ ├── close_tag:
+ │ └── @ HTMLCloseTagNode (location: (1:49)-(1:55))
+ │ ├── tag_opening: "" (location: (1:49)-(1:51))
+ │ ├── tag_name: "div" (location: (1:51)-(1:54))
+ │ ├── children: []
+ │ └── tag_closing: ">" (location: (1:54)-(1:55))
+ │
+ ├── is_void: false
+ └── source: "HTML"
\ No newline at end of file
diff --git a/test/snapshots/parser/attributes_test/test_0054_Multiple_attributes_in_one_conditional_block_ad2a48dc8c52e2e1b15ed1c970d12457.txt b/test/snapshots/parser/attributes_test/test_0054_Multiple_attributes_in_one_conditional_block_ad2a48dc8c52e2e1b15ed1c970d12457.txt
new file mode 100644
index 000000000..23ac40a88
--- /dev/null
+++ b/test/snapshots/parser/attributes_test/test_0054_Multiple_attributes_in_one_conditional_block_ad2a48dc8c52e2e1b15ed1c970d12457.txt
@@ -0,0 +1,70 @@
+---
+source: "Parser::AttributesTest#test_0054_Multiple attributes in one conditional block"
+input: "data-admin data-role=\"admin\"<% end %>>
"
+---
+@ DocumentNode (location: (1:0)-(1:64))
+└── children: (1 item)
+ └── @ HTMLElementNode (location: (1:0)-(1:64))
+ ├── open_tag:
+ │ └── @ HTMLOpenTagNode (location: (1:0)-(1:58))
+ │ ├── tag_opening: "<" (location: (1:0)-(1:1))
+ │ ├── tag_name: "div" (location: (1:1)-(1:4))
+ │ ├── tag_closing: ">" (location: (1:57)-(1:58))
+ │ ├── children: (1 item)
+ │ │ └── @ ERBIfNode (location: (1:5)-(1:57))
+ │ │ ├── tag_opening: "<%" (location: (1:5)-(1:7))
+ │ │ ├── content: " if admin? " (location: (1:7)-(1:18))
+ │ │ ├── tag_closing: "%>" (location: (1:18)-(1:20))
+ │ │ ├── statements: (2 items)
+ │ │ │ ├── @ HTMLAttributeNode (location: (1:20)-(1:30))
+ │ │ │ │ ├── name:
+ │ │ │ │ │ └── @ HTMLAttributeNameNode (location: (1:20)-(1:30))
+ │ │ │ │ │ └── children: (1 item)
+ │ │ │ │ │ └── @ LiteralNode (location: (1:20)-(1:30))
+ │ │ │ │ │ └── content: "data-admin"
+ │ │ │ │ │
+ │ │ │ │ │
+ │ │ │ │ ├── equals: ∅
+ │ │ │ │ └── value: ∅
+ │ │ │ │
+ │ │ │ └── @ HTMLAttributeNode (location: (1:31)-(1:48))
+ │ │ │ ├── name:
+ │ │ │ │ └── @ HTMLAttributeNameNode (location: (1:31)-(1:40))
+ │ │ │ │ └── children: (1 item)
+ │ │ │ │ └── @ LiteralNode (location: (1:31)-(1:40))
+ │ │ │ │ └── content: "data-role"
+ │ │ │ │
+ │ │ │ │
+ │ │ │ ├── equals: "=" (location: (1:40)-(1:41))
+ │ │ │ └── value:
+ │ │ │ └── @ HTMLAttributeValueNode (location: (1:41)-(1:48))
+ │ │ │ ├── open_quote: """ (location: (1:41)-(1:42))
+ │ │ │ ├── children: (1 item)
+ │ │ │ │ └── @ LiteralNode (location: (1:42)-(1:47))
+ │ │ │ │ └── content: "admin"
+ │ │ │ │
+ │ │ │ ├── close_quote: """ (location: (1:47)-(1:48))
+ │ │ │ └── quoted: true
+ │ │ │
+ │ │ │
+ │ │ ├── subsequent: ∅
+ │ │ └── end_node:
+ │ │ └── @ ERBEndNode (location: (1:48)-(1:57))
+ │ │ ├── tag_opening: "<%" (location: (1:48)-(1:50))
+ │ │ ├── content: " end " (location: (1:50)-(1:55))
+ │ │ └── tag_closing: "%>" (location: (1:55)-(1:57))
+ │ │
+ │ │
+ │ └── is_void: false
+ │
+ ├── tag_name: "div" (location: (1:1)-(1:4))
+ ├── body: []
+ ├── close_tag:
+ │ └── @ HTMLCloseTagNode (location: (1:58)-(1:64))
+ │ ├── tag_opening: "" (location: (1:58)-(1:60))
+ │ ├── tag_name: "div" (location: (1:60)-(1:63))
+ │ ├── children: []
+ │ └── tag_closing: ">" (location: (1:63)-(1:64))
+ │
+ ├── is_void: false
+ └── source: "HTML"
\ No newline at end of file
diff --git a/test/snapshots/parser/attributes_test/test_0055_Conditional_boolean_attribute_661703bbd4a517e45d7ccf10bb92dd41.txt b/test/snapshots/parser/attributes_test/test_0055_Conditional_boolean_attribute_661703bbd4a517e45d7ccf10bb92dd41.txt
new file mode 100644
index 000000000..1e377f5a0
--- /dev/null
+++ b/test/snapshots/parser/attributes_test/test_0055_Conditional_boolean_attribute_661703bbd4a517e45d7ccf10bb92dd41.txt
@@ -0,0 +1,64 @@
+---
+source: "Parser::AttributesTest#test_0055_Conditional boolean attribute"
+input: " disabled<% end %> type=\"text\">"
+---
+@ DocumentNode (location: (1:0)-(1:61))
+└── children: (1 item)
+ └── @ HTMLElementNode (location: (1:0)-(1:61))
+ ├── open_tag:
+ │ └── @ HTMLOpenTagNode (location: (1:0)-(1:61))
+ │ ├── tag_opening: "<" (location: (1:0)-(1:1))
+ │ ├── tag_name: "input" (location: (1:1)-(1:6))
+ │ ├── tag_closing: ">" (location: (1:60)-(1:61))
+ │ ├── children: (2 items)
+ │ │ ├── @ ERBIfNode (location: (1:7)-(1:48))
+ │ │ │ ├── tag_opening: "<%" (location: (1:7)-(1:9))
+ │ │ │ ├── content: " if should_disable? " (location: (1:9)-(1:29))
+ │ │ │ ├── tag_closing: "%>" (location: (1:29)-(1:31))
+ │ │ │ ├── statements: (1 item)
+ │ │ │ │ └── @ HTMLAttributeNode (location: (1:31)-(1:39))
+ │ │ │ │ ├── name:
+ │ │ │ │ │ └── @ HTMLAttributeNameNode (location: (1:31)-(1:39))
+ │ │ │ │ │ └── children: (1 item)
+ │ │ │ │ │ └── @ LiteralNode (location: (1:31)-(1:39))
+ │ │ │ │ │ └── content: "disabled"
+ │ │ │ │ │
+ │ │ │ │ │
+ │ │ │ │ ├── equals: ∅
+ │ │ │ │ └── value: ∅
+ │ │ │ │
+ │ │ │ ├── subsequent: ∅
+ │ │ │ └── end_node:
+ │ │ │ └── @ ERBEndNode (location: (1:39)-(1:48))
+ │ │ │ ├── tag_opening: "<%" (location: (1:39)-(1:41))
+ │ │ │ ├── content: " end " (location: (1:41)-(1:46))
+ │ │ │ └── tag_closing: "%>" (location: (1:46)-(1:48))
+ │ │ │
+ │ │ │
+ │ │ └── @ HTMLAttributeNode (location: (1:49)-(1:60))
+ │ │ ├── name:
+ │ │ │ └── @ HTMLAttributeNameNode (location: (1:49)-(1:53))
+ │ │ │ └── children: (1 item)
+ │ │ │ └── @ LiteralNode (location: (1:49)-(1:53))
+ │ │ │ └── content: "type"
+ │ │ │
+ │ │ │
+ │ │ ├── equals: "=" (location: (1:53)-(1:54))
+ │ │ └── value:
+ │ │ └── @ HTMLAttributeValueNode (location: (1:54)-(1:60))
+ │ │ ├── open_quote: """ (location: (1:54)-(1:55))
+ │ │ ├── children: (1 item)
+ │ │ │ └── @ LiteralNode (location: (1:55)-(1:59))
+ │ │ │ └── content: "text"
+ │ │ │
+ │ │ ├── close_quote: """ (location: (1:59)-(1:60))
+ │ │ └── quoted: true
+ │ │
+ │ │
+ │ └── is_void: false
+ │
+ ├── tag_name: "input" (location: (1:1)-(1:6))
+ ├── body: []
+ ├── close_tag: ∅
+ ├── is_void: true
+ └── source: "HTML"
\ No newline at end of file
diff --git a/test/snapshots/parser/attributes_test/test_0056_Conditional_attribute_with_output_tag_inside_2e2b58a4804aa16c21405c4371206b2a.txt b/test/snapshots/parser/attributes_test/test_0056_Conditional_attribute_with_output_tag_inside_2e2b58a4804aa16c21405c4371206b2a.txt
new file mode 100644
index 000000000..75a89e9c6
--- /dev/null
+++ b/test/snapshots/parser/attributes_test/test_0056_Conditional_attribute_with_output_tag_inside_2e2b58a4804aa16c21405c4371206b2a.txt
@@ -0,0 +1,63 @@
+---
+source: "Parser::AttributesTest#test_0056_Conditional attribute with output tag inside"
+input: "data-user=\"<%= user.id %>\"<% end %>>
"
+---
+@ DocumentNode (location: (1:0)-(1:60))
+└── children: (1 item)
+ └── @ HTMLElementNode (location: (1:0)-(1:60))
+ ├── open_tag:
+ │ └── @ HTMLOpenTagNode (location: (1:0)-(1:54))
+ │ ├── tag_opening: "<" (location: (1:0)-(1:1))
+ │ ├── tag_name: "div" (location: (1:1)-(1:4))
+ │ ├── tag_closing: ">" (location: (1:53)-(1:54))
+ │ ├── children: (1 item)
+ │ │ └── @ ERBIfNode (location: (1:5)-(1:53))
+ │ │ ├── tag_opening: "<%" (location: (1:5)-(1:7))
+ │ │ ├── content: " if user " (location: (1:7)-(1:16))
+ │ │ ├── tag_closing: "%>" (location: (1:16)-(1:18))
+ │ │ ├── statements: (1 item)
+ │ │ │ └── @ HTMLAttributeNode (location: (1:18)-(1:44))
+ │ │ │ ├── name:
+ │ │ │ │ └── @ HTMLAttributeNameNode (location: (1:18)-(1:27))
+ │ │ │ │ └── children: (1 item)
+ │ │ │ │ └── @ LiteralNode (location: (1:18)-(1:27))
+ │ │ │ │ └── content: "data-user"
+ │ │ │ │
+ │ │ │ │
+ │ │ │ ├── equals: "=" (location: (1:27)-(1:28))
+ │ │ │ └── value:
+ │ │ │ └── @ HTMLAttributeValueNode (location: (1:28)-(1:44))
+ │ │ │ ├── open_quote: """ (location: (1:28)-(1:29))
+ │ │ │ ├── children: (1 item)
+ │ │ │ │ └── @ ERBContentNode (location: (1:29)-(1:43))
+ │ │ │ │ ├── tag_opening: "<%=" (location: (1:29)-(1:32))
+ │ │ │ │ ├── content: " user.id " (location: (1:32)-(1:41))
+ │ │ │ │ ├── tag_closing: "%>" (location: (1:41)-(1:43))
+ │ │ │ │ ├── parsed: true
+ │ │ │ │ └── valid: true
+ │ │ │ │
+ │ │ │ ├── close_quote: """ (location: (1:43)-(1:44))
+ │ │ │ └── quoted: true
+ │ │ │
+ │ │ │
+ │ │ ├── subsequent: ∅
+ │ │ └── end_node:
+ │ │ └── @ ERBEndNode (location: (1:44)-(1:53))
+ │ │ ├── tag_opening: "<%" (location: (1:44)-(1:46))
+ │ │ ├── content: " end " (location: (1:46)-(1:51))
+ │ │ └── tag_closing: "%>" (location: (1:51)-(1:53))
+ │ │
+ │ │
+ │ └── is_void: false
+ │
+ ├── tag_name: "div" (location: (1:1)-(1:4))
+ ├── body: []
+ ├── close_tag:
+ │ └── @ HTMLCloseTagNode (location: (1:54)-(1:60))
+ │ ├── tag_opening: "" (location: (1:54)-(1:56))
+ │ ├── tag_name: "div" (location: (1:56)-(1:59))
+ │ ├── children: []
+ │ └── tag_closing: ">" (location: (1:59)-(1:60))
+ │
+ ├── is_void: false
+ └── source: "HTML"
\ No newline at end of file
diff --git a/test/snapshots/parser/attributes_test/test_0057_ERB_comment_between_attributes_0e265aed6fa4a1f4adc75b32f35bd862.txt b/test/snapshots/parser/attributes_test/test_0057_ERB_comment_between_attributes_0e265aed6fa4a1f4adc75b32f35bd862.txt
new file mode 100644
index 000000000..ff83721b1
--- /dev/null
+++ b/test/snapshots/parser/attributes_test/test_0057_ERB_comment_between_attributes_0e265aed6fa4a1f4adc75b32f35bd862.txt
@@ -0,0 +1,73 @@
+---
+source: "Parser::AttributesTest#test_0057_ERB comment between attributes"
+input: " data-baz=\"qux\">
"
+---
+@ DocumentNode (location: (1:0)-(1:66))
+└── children: (1 item)
+ └── @ HTMLElementNode (location: (1:0)-(1:66))
+ ├── open_tag:
+ │ └── @ HTMLOpenTagNode (location: (1:0)-(1:60))
+ │ ├── tag_opening: "<" (location: (1:0)-(1:1))
+ │ ├── tag_name: "div" (location: (1:1)-(1:4))
+ │ ├── tag_closing: ">" (location: (1:59)-(1:60))
+ │ ├── children: (3 items)
+ │ │ ├── @ HTMLAttributeNode (location: (1:5)-(1:19))
+ │ │ │ ├── name:
+ │ │ │ │ └── @ HTMLAttributeNameNode (location: (1:5)-(1:13))
+ │ │ │ │ └── children: (1 item)
+ │ │ │ │ └── @ LiteralNode (location: (1:5)-(1:13))
+ │ │ │ │ └── content: "data-foo"
+ │ │ │ │
+ │ │ │ │
+ │ │ │ ├── equals: "=" (location: (1:13)-(1:14))
+ │ │ │ └── value:
+ │ │ │ └── @ HTMLAttributeValueNode (location: (1:14)-(1:19))
+ │ │ │ ├── open_quote: """ (location: (1:14)-(1:15))
+ │ │ │ ├── children: (1 item)
+ │ │ │ │ └── @ LiteralNode (location: (1:15)-(1:18))
+ │ │ │ │ └── content: "bar"
+ │ │ │ │
+ │ │ │ ├── close_quote: """ (location: (1:18)-(1:19))
+ │ │ │ └── quoted: true
+ │ │ │
+ │ │ │
+ │ │ ├── @ ERBContentNode (location: (1:20)-(1:44))
+ │ │ │ ├── tag_opening: "<%#" (location: (1:20)-(1:23))
+ │ │ │ ├── content: " This is a comment " (location: (1:23)-(1:42))
+ │ │ │ ├── tag_closing: "%>" (location: (1:42)-(1:44))
+ │ │ │ ├── parsed: false
+ │ │ │ └── valid: true
+ │ │ │
+ │ │ └── @ HTMLAttributeNode (location: (1:45)-(1:59))
+ │ │ ├── name:
+ │ │ │ └── @ HTMLAttributeNameNode (location: (1:45)-(1:53))
+ │ │ │ └── children: (1 item)
+ │ │ │ └── @ LiteralNode (location: (1:45)-(1:53))
+ │ │ │ └── content: "data-baz"
+ │ │ │
+ │ │ │
+ │ │ ├── equals: "=" (location: (1:53)-(1:54))
+ │ │ └── value:
+ │ │ └── @ HTMLAttributeValueNode (location: (1:54)-(1:59))
+ │ │ ├── open_quote: """ (location: (1:54)-(1:55))
+ │ │ ├── children: (1 item)
+ │ │ │ └── @ LiteralNode (location: (1:55)-(1:58))
+ │ │ │ └── content: "qux"
+ │ │ │
+ │ │ ├── close_quote: """ (location: (1:58)-(1:59))
+ │ │ └── quoted: true
+ │ │
+ │ │
+ │ └── is_void: false
+ │
+ ├── tag_name: "div" (location: (1:1)-(1:4))
+ ├── body: []
+ ├── close_tag:
+ │ └── @ HTMLCloseTagNode (location: (1:60)-(1:66))
+ │ ├── tag_opening: "" (location: (1:60)-(1:62))
+ │ ├── tag_name: "div" (location: (1:62)-(1:65))
+ │ ├── children: []
+ │ └── tag_closing: ">" (location: (1:65)-(1:66))
+ │
+ ├── is_void: false
+ └── source: "HTML"
\ No newline at end of file
diff --git a/test/snapshots/parser/attributes_test/test_0058_Conditional_attribute_with_trimming_tags_80b50d0bc25df0f6805558f541ff8d08.txt b/test/snapshots/parser/attributes_test/test_0058_Conditional_attribute_with_trimming_tags_80b50d0bc25df0f6805558f541ff8d08.txt
new file mode 100644
index 000000000..1bca4a956
--- /dev/null
+++ b/test/snapshots/parser/attributes_test/test_0058_Conditional_attribute_with_trimming_tags_80b50d0bc25df0f6805558f541ff8d08.txt
@@ -0,0 +1,50 @@
+---
+source: "Parser::AttributesTest#test_0058_Conditional attribute with trimming tags"
+input: "data-conditional<%- end -%>>
"
+---
+@ DocumentNode (location: (1:0)-(1:59))
+└── children: (1 item)
+ └── @ HTMLElementNode (location: (1:0)-(1:59))
+ ├── open_tag:
+ │ └── @ HTMLOpenTagNode (location: (1:0)-(1:53))
+ │ ├── tag_opening: "<" (location: (1:0)-(1:1))
+ │ ├── tag_name: "div" (location: (1:1)-(1:4))
+ │ ├── tag_closing: ">" (location: (1:52)-(1:53))
+ │ ├── children: (1 item)
+ │ │ └── @ ERBIfNode (location: (1:5)-(1:52))
+ │ │ ├── tag_opening: "<%-" (location: (1:5)-(1:8))
+ │ │ ├── content: " if condition " (location: (1:8)-(1:22))
+ │ │ ├── tag_closing: "-%>" (location: (1:22)-(1:25))
+ │ │ ├── statements: (1 item)
+ │ │ │ └── @ HTMLAttributeNode (location: (1:25)-(1:41))
+ │ │ │ ├── name:
+ │ │ │ │ └── @ HTMLAttributeNameNode (location: (1:25)-(1:41))
+ │ │ │ │ └── children: (1 item)
+ │ │ │ │ └── @ LiteralNode (location: (1:25)-(1:41))
+ │ │ │ │ └── content: "data-conditional"
+ │ │ │ │
+ │ │ │ │
+ │ │ │ ├── equals: ∅
+ │ │ │ └── value: ∅
+ │ │ │
+ │ │ ├── subsequent: ∅
+ │ │ └── end_node:
+ │ │ └── @ ERBEndNode (location: (1:41)-(1:52))
+ │ │ ├── tag_opening: "<%-" (location: (1:41)-(1:44))
+ │ │ ├── content: " end " (location: (1:44)-(1:49))
+ │ │ └── tag_closing: "-%>" (location: (1:49)-(1:52))
+ │ │
+ │ │
+ │ └── is_void: false
+ │
+ ├── tag_name: "div" (location: (1:1)-(1:4))
+ ├── body: []
+ ├── close_tag:
+ │ └── @ HTMLCloseTagNode (location: (1:53)-(1:59))
+ │ ├── tag_opening: "" (location: (1:53)-(1:55))
+ │ ├── tag_name: "div" (location: (1:55)-(1:58))
+ │ ├── children: []
+ │ └── tag_closing: ">" (location: (1:58)-(1:59))
+ │
+ ├── is_void: false
+ └── source: "HTML"
\ No newline at end of file
diff --git a/test/snapshots/parser/attributes_test/test_0059_Empty_conditional_block_in_attributes_2b453534ea13ee20fab205fee722364a.txt b/test/snapshots/parser/attributes_test/test_0059_Empty_conditional_block_in_attributes_2b453534ea13ee20fab205fee722364a.txt
new file mode 100644
index 000000000..59c0b2c96
--- /dev/null
+++ b/test/snapshots/parser/attributes_test/test_0059_Empty_conditional_block_in_attributes_2b453534ea13ee20fab205fee722364a.txt
@@ -0,0 +1,70 @@
+---
+source: "Parser::AttributesTest#test_0059_Empty conditional block in attributes"
+input: "<% end %> data-other=\"value\">
"
+---
+@ DocumentNode (location: (1:0)-(1:66))
+└── children: (1 item)
+ └── @ HTMLElementNode (location: (1:0)-(1:66))
+ ├── open_tag:
+ │ └── @ HTMLOpenTagNode (location: (1:0)-(1:60))
+ │ ├── tag_opening: "<" (location: (1:0)-(1:1))
+ │ ├── tag_name: "div" (location: (1:1)-(1:4))
+ │ ├── tag_closing: ">" (location: (1:59)-(1:60))
+ │ ├── children: (3 items)
+ │ │ ├── @ HTMLAttributeNode (location: (1:5)-(1:16))
+ │ │ │ ├── name:
+ │ │ │ │ └── @ HTMLAttributeNameNode (location: (1:5)-(1:16))
+ │ │ │ │ └── children: (1 item)
+ │ │ │ │ └── @ LiteralNode (location: (1:5)-(1:16))
+ │ │ │ │ └── content: "data-static"
+ │ │ │ │
+ │ │ │ │
+ │ │ │ ├── equals: ∅
+ │ │ │ └── value: ∅
+ │ │ │
+ │ │ ├── @ ERBIfNode (location: (1:17)-(1:40))
+ │ │ │ ├── tag_opening: "<%" (location: (1:17)-(1:19))
+ │ │ │ ├── content: " if false " (location: (1:19)-(1:29))
+ │ │ │ ├── tag_closing: "%>" (location: (1:29)-(1:31))
+ │ │ │ ├── statements: []
+ │ │ │ ├── subsequent: ∅
+ │ │ │ └── end_node:
+ │ │ │ └── @ ERBEndNode (location: (1:31)-(1:40))
+ │ │ │ ├── tag_opening: "<%" (location: (1:31)-(1:33))
+ │ │ │ ├── content: " end " (location: (1:33)-(1:38))
+ │ │ │ └── tag_closing: "%>" (location: (1:38)-(1:40))
+ │ │ │
+ │ │ │
+ │ │ └── @ HTMLAttributeNode (location: (1:41)-(1:59))
+ │ │ ├── name:
+ │ │ │ └── @ HTMLAttributeNameNode (location: (1:41)-(1:51))
+ │ │ │ └── children: (1 item)
+ │ │ │ └── @ LiteralNode (location: (1:41)-(1:51))
+ │ │ │ └── content: "data-other"
+ │ │ │
+ │ │ │
+ │ │ ├── equals: "=" (location: (1:51)-(1:52))
+ │ │ └── value:
+ │ │ └── @ HTMLAttributeValueNode (location: (1:52)-(1:59))
+ │ │ ├── open_quote: """ (location: (1:52)-(1:53))
+ │ │ ├── children: (1 item)
+ │ │ │ └── @ LiteralNode (location: (1:53)-(1:58))
+ │ │ │ └── content: "value"
+ │ │ │
+ │ │ ├── close_quote: """ (location: (1:58)-(1:59))
+ │ │ └── quoted: true
+ │ │
+ │ │
+ │ └── is_void: false
+ │
+ ├── tag_name: "div" (location: (1:1)-(1:4))
+ ├── body: []
+ ├── close_tag:
+ │ └── @ HTMLCloseTagNode (location: (1:60)-(1:66))
+ │ ├── tag_opening: "" (location: (1:60)-(1:62))
+ │ ├── tag_name: "div" (location: (1:62)-(1:65))
+ │ ├── children: []
+ │ └── tag_closing: ">" (location: (1:65)-(1:66))
+ │
+ ├── is_void: false
+ └── source: "HTML"
\ No newline at end of file
diff --git a/test/snapshots/parser/attributes_test/test_0060_Nested_conditional_attributes_f995c179776fa746db8f0a5e80590c75.txt b/test/snapshots/parser/attributes_test/test_0060_Nested_conditional_attributes_f995c179776fa746db8f0a5e80590c75.txt
new file mode 100644
index 000000000..661b16394
--- /dev/null
+++ b/test/snapshots/parser/attributes_test/test_0060_Nested_conditional_attributes_f995c179776fa746db8f0a5e80590c75.txt
@@ -0,0 +1,63 @@
+---
+source: "Parser::AttributesTest#test_0060_Nested conditional attributes"
+input: "<% if inner? %>data-inner<% end %><% end %>>
"
+---
+@ DocumentNode (location: (1:0)-(1:70))
+└── children: (1 item)
+ └── @ HTMLElementNode (location: (1:0)-(1:70))
+ ├── open_tag:
+ │ └── @ HTMLOpenTagNode (location: (1:0)-(1:64))
+ │ ├── tag_opening: "<" (location: (1:0)-(1:1))
+ │ ├── tag_name: "div" (location: (1:1)-(1:4))
+ │ ├── tag_closing: ">" (location: (1:63)-(1:64))
+ │ ├── children: (1 item)
+ │ │ └── @ ERBIfNode (location: (1:5)-(1:63))
+ │ │ ├── tag_opening: "<%" (location: (1:5)-(1:7))
+ │ │ ├── content: " if outer? " (location: (1:7)-(1:18))
+ │ │ ├── tag_closing: "%>" (location: (1:18)-(1:20))
+ │ │ ├── statements: (1 item)
+ │ │ │ └── @ ERBIfNode (location: (1:20)-(1:54))
+ │ │ │ ├── tag_opening: "<%" (location: (1:20)-(1:22))
+ │ │ │ ├── content: " if inner? " (location: (1:22)-(1:33))
+ │ │ │ ├── tag_closing: "%>" (location: (1:33)-(1:35))
+ │ │ │ ├── statements: (1 item)
+ │ │ │ │ └── @ HTMLAttributeNode (location: (1:35)-(1:45))
+ │ │ │ │ ├── name:
+ │ │ │ │ │ └── @ HTMLAttributeNameNode (location: (1:35)-(1:45))
+ │ │ │ │ │ └── children: (1 item)
+ │ │ │ │ │ └── @ LiteralNode (location: (1:35)-(1:45))
+ │ │ │ │ │ └── content: "data-inner"
+ │ │ │ │ │
+ │ │ │ │ │
+ │ │ │ │ ├── equals: ∅
+ │ │ │ │ └── value: ∅
+ │ │ │ │
+ │ │ │ ├── subsequent: ∅
+ │ │ │ └── end_node:
+ │ │ │ └── @ ERBEndNode (location: (1:45)-(1:54))
+ │ │ │ ├── tag_opening: "<%" (location: (1:45)-(1:47))
+ │ │ │ ├── content: " end " (location: (1:47)-(1:52))
+ │ │ │ └── tag_closing: "%>" (location: (1:52)-(1:54))
+ │ │ │
+ │ │ │
+ │ │ ├── subsequent: ∅
+ │ │ └── end_node:
+ │ │ └── @ ERBEndNode (location: (1:54)-(1:63))
+ │ │ ├── tag_opening: "<%" (location: (1:54)-(1:56))
+ │ │ ├── content: " end " (location: (1:56)-(1:61))
+ │ │ └── tag_closing: "%>" (location: (1:61)-(1:63))
+ │ │
+ │ │
+ │ └── is_void: false
+ │
+ ├── tag_name: "div" (location: (1:1)-(1:4))
+ ├── body: []
+ ├── close_tag:
+ │ └── @ HTMLCloseTagNode (location: (1:64)-(1:70))
+ │ ├── tag_opening: "" (location: (1:64)-(1:66))
+ │ ├── tag_name: "div" (location: (1:66)-(1:69))
+ │ ├── children: []
+ │ └── tag_closing: ">" (location: (1:69)-(1:70))
+ │
+ ├── is_void: false
+ └── source: "HTML"
\ No newline at end of file