diff --git a/bin/force_update_snapshots b/bin/force_update_snapshots
index 33666760a..69f4b40cf 100755
--- a/bin/force_update_snapshots
+++ b/bin/force_update_snapshots
@@ -2,7 +2,7 @@
set -e # Exit on error
-FORCE_UPDATE_SNAPSHOTS=true bundle exec rake test
+FORCE_UPDATE_SNAPSHOTS=true bundle exec rake test:all
echo ""
echo "Force updated snapshots!"
diff --git a/config.yml b/config.yml
index 9718ca6d8..2363d9a77 100644
--- a/config.yml
+++ b/config.yml
@@ -164,7 +164,7 @@ errors:
- name: ERBCaseWithConditionsError
message:
- template: "A `case` statement with `when`/`in` in a single ERB tag cannot be formatted. Use separate tags for `case` and its conditions."
+ template: "A `case` statement with `when`/`in` conditions in a single ERB tag cannot be reliably parsed, compiled, and formatted. Use separate ERB tags for `case` and its conditions (e.g., `<% case x %>` followed by `<% when y %>`)."
arguments: []
fields: []
diff --git a/lib/herb/engine/compiler.rb b/lib/herb/engine/compiler.rb
index 818f96a3b..6d47d1790 100644
--- a/lib/herb/engine/compiler.rb
+++ b/lib/herb/engine/compiler.rb
@@ -194,7 +194,9 @@ def visit_erb_content_node(node)
end
def visit_erb_control_node(node, &_block)
- apply_trim(node, node.content.value.strip)
+ if node.content
+ apply_trim(node, node.content.value.strip)
+ end
yield if block_given?
end
diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c
index 7880640e8..0dd761e1c 100644
--- a/src/analyze/analyze.c
+++ b/src/analyze/analyze.c
@@ -57,6 +57,8 @@ static analyzed_ruby_T* herb_analyze_ruby(hb_string_T source) {
}
static bool analyze_erb_content(const AST_NODE_T* node, void* data) {
+ const parser_options_T* options = (const parser_options_T*) data;
+
if (node->type == AST_ERB_CONTENT_NODE) {
AST_ERB_CONTENT_NODE_T* erb_content_node = (AST_ERB_CONTENT_NODE_T*) node;
@@ -78,9 +80,7 @@ static bool analyze_erb_content(const AST_NODE_T* node, void* data) {
);
}
- if (!analyzed->valid
- && ((analyzed->case_node_count > 0 && analyzed->when_node_count > 0)
- || (analyzed->case_match_node_count > 0 && analyzed->in_node_count > 0))) {
+ if (options && options->strict && !analyzed->valid && has_inline_case_condition(analyzed)) {
append_erb_case_with_conditions_error(
erb_content_node->base.location.start,
erb_content_node->base.location.end,
@@ -279,6 +279,10 @@ static size_t process_case_structure(
hb_array_T* in_conditions = hb_array_init(8);
hb_array_T* non_when_non_in_children = hb_array_init(8);
+ analyzed_ruby_T* analyzed = erb_node->analyzed_ruby;
+ bool has_inline_when = has_case_node(analyzed) && has_when_node(analyzed);
+ bool has_inline_in = has_case_match_node(analyzed) && has_in_node(analyzed);
+
index++;
const control_type_t prelude_stop[] = { CONTROL_TYPE_WHEN, CONTROL_TYPE_IN, CONTROL_TYPE_END };
@@ -290,6 +294,33 @@ static size_t process_case_structure(
sizeof(prelude_stop) / sizeof(prelude_stop[0])
);
+ // Create a synthetic when/in node for inline when/in (e.g., <% case variable when "a" %>),
+ if (has_inline_when || has_inline_in) {
+ hb_array_T* statements = non_when_non_in_children;
+ non_when_non_in_children = hb_array_init(8);
+
+ position_T start_position =
+ erb_node->tag_closing ? erb_node->tag_closing->location.end : erb_node->content->location.end;
+ position_T end_position = start_position;
+
+ if (hb_array_size(statements) > 0) {
+ AST_NODE_T* last_child = hb_array_last(statements);
+ end_position = last_child->location.end;
+ }
+
+ if (has_inline_when) {
+ AST_NODE_T* synthetic_node = (AST_NODE_T*)
+ ast_erb_when_node_init(NULL, NULL, NULL, NULL, statements, start_position, end_position, hb_array_init(0));
+
+ hb_array_append(when_conditions, synthetic_node);
+ } else {
+ AST_NODE_T* synthetic_node = (AST_NODE_T*)
+ ast_erb_in_node_init(NULL, NULL, NULL, NULL, statements, start_position, end_position, hb_array_init(0));
+
+ hb_array_append(in_conditions, synthetic_node);
+ }
+ }
+
while (index < hb_array_size(array)) {
AST_ERB_CONTENT_NODE_T* next_erb = get_erb_content_at(array, index);
@@ -754,8 +785,8 @@ hb_array_T* rewrite_node_array(AST_NODE_T* node, hb_array_T* array, analyze_ruby
return new_array;
}
-void herb_analyze_parse_tree(AST_DOCUMENT_NODE_T* document, const char* source, bool strict) {
- herb_visit_node((AST_NODE_T*) document, analyze_erb_content, NULL);
+void herb_analyze_parse_tree(AST_DOCUMENT_NODE_T* document, const char* source, const parser_options_T* options) {
+ herb_visit_node((AST_NODE_T*) document, analyze_erb_content, (void*) options);
analyze_ruby_context_T* context = malloc(sizeof(analyze_ruby_context_T));
@@ -784,7 +815,7 @@ void herb_analyze_parse_tree(AST_DOCUMENT_NODE_T* document, const char* source,
herb_analyze_parse_errors(document, source);
- herb_parser_match_html_tags_post_analyze(document, strict);
+ herb_parser_match_html_tags_post_analyze(document, options);
hb_array_free(&context->ruby_context_stack);
diff --git a/src/analyze/helpers.c b/src/analyze/helpers.c
index e75d35f29..1cb8d44a2 100644
--- a/src/analyze/helpers.c
+++ b/src/analyze/helpers.c
@@ -6,79 +6,84 @@
#include "../include/util/string.h"
bool has_if_node(analyzed_ruby_T* analyzed) {
- return analyzed->if_node_count > 0;
+ return analyzed && analyzed->if_node_count > 0;
}
bool has_elsif_node(analyzed_ruby_T* analyzed) {
- return analyzed->elsif_node_count > 0;
+ return analyzed && analyzed->elsif_node_count > 0;
}
bool has_else_node(analyzed_ruby_T* analyzed) {
- return analyzed->else_node_count > 0;
+ return analyzed && analyzed->else_node_count > 0;
}
bool has_end(analyzed_ruby_T* analyzed) {
- return analyzed->end_count > 0;
+ return analyzed && analyzed->end_count > 0;
}
bool has_block_node(analyzed_ruby_T* analyzed) {
- return analyzed->block_node_count > 0;
+ return analyzed && analyzed->block_node_count > 0;
}
bool has_block_closing(analyzed_ruby_T* analyzed) {
- return analyzed->block_closing_count > 0;
+ return analyzed && analyzed->block_closing_count > 0;
}
bool has_case_node(analyzed_ruby_T* analyzed) {
- return analyzed->case_node_count > 0;
+ return analyzed && analyzed->case_node_count > 0;
}
bool has_case_match_node(analyzed_ruby_T* analyzed) {
- return analyzed->case_match_node_count > 0;
+ return analyzed && analyzed->case_match_node_count > 0;
}
bool has_when_node(analyzed_ruby_T* analyzed) {
- return analyzed->when_node_count > 0;
+ return analyzed && analyzed->when_node_count > 0;
}
bool has_in_node(analyzed_ruby_T* analyzed) {
- return analyzed->in_node_count > 0;
+ return analyzed && analyzed->in_node_count > 0;
}
bool has_for_node(analyzed_ruby_T* analyzed) {
- return analyzed->for_node_count > 0;
+ return analyzed && analyzed->for_node_count > 0;
}
bool has_while_node(analyzed_ruby_T* analyzed) {
- return analyzed->while_node_count > 0;
+ return analyzed && analyzed->while_node_count > 0;
}
bool has_until_node(analyzed_ruby_T* analyzed) {
- return analyzed->until_node_count > 0;
+ return analyzed && analyzed->until_node_count > 0;
}
bool has_begin_node(analyzed_ruby_T* analyzed) {
- return analyzed->begin_node_count > 0;
+ return analyzed && analyzed->begin_node_count > 0;
}
bool has_rescue_node(analyzed_ruby_T* analyzed) {
- return analyzed->rescue_node_count > 0;
+ return analyzed && analyzed->rescue_node_count > 0;
}
bool has_ensure_node(analyzed_ruby_T* analyzed) {
- return analyzed->ensure_node_count > 0;
+ return analyzed && analyzed->ensure_node_count > 0;
}
bool has_unless_node(analyzed_ruby_T* analyzed) {
- return analyzed->unless_node_count > 0;
+ return analyzed && analyzed->unless_node_count > 0;
}
bool has_yield_node(analyzed_ruby_T* analyzed) {
- return analyzed->yield_node_count > 0;
+ return analyzed && analyzed->yield_node_count > 0;
}
bool has_then_keyword(analyzed_ruby_T* analyzed) {
- return analyzed->then_keyword_count > 0;
+ return analyzed && analyzed->then_keyword_count > 0;
+}
+
+bool has_inline_case_condition(analyzed_ruby_T* analyzed) {
+ return (has_case_node(analyzed) && has_when_node(analyzed))
+ || (has_case_match_node(analyzed) && has_in_node(analyzed));
}
bool has_error_message(analyzed_ruby_T* analyzed, const char* message) {
diff --git a/src/herb.c b/src/herb.c
index ad2b7e78e..0edc94cfc 100644
--- a/src/herb.c
+++ b/src/herb.c
@@ -44,7 +44,7 @@ HERB_EXPORTED_FUNCTION AST_DOCUMENT_NODE_T* herb_parse(const char* source, const
herb_parser_deinit(&parser);
- if (parser_options.analyze) { herb_analyze_parse_tree(document, source, parser_options.strict); }
+ if (parser_options.analyze) { herb_analyze_parse_tree(document, source, &parser_options); }
return document;
}
diff --git a/src/include/analyze/analyze.h b/src/include/analyze/analyze.h
index 12e961718..6cda94f11 100644
--- a/src/include/analyze/analyze.h
+++ b/src/include/analyze/analyze.h
@@ -3,6 +3,7 @@
#include "analyzed_ruby.h"
#include "../ast_nodes.h"
+#include "../parser.h"
#include "../util/hb_array.h"
typedef struct ANALYZE_RUBY_CONTEXT_STRUCT {
@@ -39,7 +40,7 @@ typedef struct {
} invalid_erb_context_T;
void herb_analyze_parse_errors(AST_DOCUMENT_NODE_T* document, const char* source);
-void herb_analyze_parse_tree(AST_DOCUMENT_NODE_T* document, const char* source, bool strict);
+void herb_analyze_parse_tree(AST_DOCUMENT_NODE_T* document, const char* source, const parser_options_T* options);
hb_array_T* rewrite_node_array(AST_NODE_T* node, hb_array_T* array, analyze_ruby_context_T* context);
bool transform_erb_nodes(const AST_NODE_T* node, void* data);
diff --git a/src/include/analyze/helpers.h b/src/include/analyze/helpers.h
index a815d93ec..6443015ff 100644
--- a/src/include/analyze/helpers.h
+++ b/src/include/analyze/helpers.h
@@ -26,6 +26,7 @@ bool has_ensure_node(analyzed_ruby_T* analyzed);
bool has_unless_node(analyzed_ruby_T* analyzed);
bool has_yield_node(analyzed_ruby_T* analyzed);
bool has_then_keyword(analyzed_ruby_T* analyzed);
+bool has_inline_case_condition(analyzed_ruby_T* analyzed);
bool has_error_message(analyzed_ruby_T* anlayzed, const char* message);
diff --git a/src/include/parser.h b/src/include/parser.h
index 81b34d8d2..6ac11f05f 100644
--- a/src/include/parser.h
+++ b/src/include/parser.h
@@ -23,7 +23,7 @@ typedef struct PARSER_OPTIONS_STRUCT {
typedef struct MATCH_TAGS_CONTEXT_STRUCT {
hb_array_T* errors;
- bool strict;
+ const parser_options_T* options;
} match_tags_context_T;
extern const parser_options_T HERB_DEFAULT_PARSER_OPTIONS;
@@ -45,10 +45,10 @@ void herb_parser_init(parser_T* parser, lexer_T* lexer, parser_options_T options
AST_DOCUMENT_NODE_T* herb_parser_parse(parser_T* parser);
-void herb_parser_match_html_tags_post_analyze(AST_DOCUMENT_NODE_T* document, bool strict);
+void herb_parser_match_html_tags_post_analyze(AST_DOCUMENT_NODE_T* document, const parser_options_T* options);
void herb_parser_deinit(parser_T* parser);
-void match_tags_in_node_array(hb_array_T* nodes, hb_array_T* errors, bool strict);
+void match_tags_in_node_array(hb_array_T* nodes, hb_array_T* errors, const parser_options_T* options);
bool match_tags_visitor(const AST_NODE_T* node, void* data);
#endif
diff --git a/src/parser.c b/src/parser.c
index f82b355a3..f27f9e606 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -1536,9 +1536,18 @@ static size_t find_implicit_close_index(hb_array_T* nodes, size_t start_idx, hb_
return hb_array_size(nodes);
}
-static hb_array_T* parser_build_elements_from_tags(hb_array_T* nodes, hb_array_T* errors, bool strict);
-
-static hb_array_T* parser_build_elements_from_tags(hb_array_T* nodes, hb_array_T* errors, bool strict) {
+static hb_array_T* parser_build_elements_from_tags(
+ hb_array_T* nodes,
+ hb_array_T* errors,
+ const parser_options_T* options
+);
+
+static hb_array_T* parser_build_elements_from_tags(
+ hb_array_T* nodes,
+ hb_array_T* errors,
+ const parser_options_T* options
+) {
+ bool strict = options ? options->strict : false;
hb_array_T* result = hb_array_init(hb_array_size(nodes));
for (size_t index = 0; index < hb_array_size(nodes); index++) {
@@ -1561,7 +1570,7 @@ static hb_array_T* parser_build_elements_from_tags(hb_array_T* nodes, hb_array_T
hb_array_append(body, hb_array_get(nodes, j));
}
- hb_array_T* processed_body = parser_build_elements_from_tags(body, errors, strict);
+ hb_array_T* processed_body = parser_build_elements_from_tags(body, errors, options);
hb_array_free(&body);
position_T end_position = open_tag->base.location.end;
@@ -1622,7 +1631,7 @@ static hb_array_T* parser_build_elements_from_tags(hb_array_T* nodes, hb_array_T
hb_array_append(body, hb_array_get(nodes, j));
}
- hb_array_T* processed_body = parser_build_elements_from_tags(body, errors, strict);
+ hb_array_T* processed_body = parser_build_elements_from_tags(body, errors, options);
hb_array_free(&body);
hb_array_T* element_errors = hb_array_init(8);
@@ -1728,10 +1737,10 @@ void herb_parser_deinit(parser_T* parser) {
}
}
-void match_tags_in_node_array(hb_array_T* nodes, hb_array_T* errors, bool strict) {
+void match_tags_in_node_array(hb_array_T* nodes, hb_array_T* errors, const parser_options_T* options) {
if (nodes == NULL || hb_array_size(nodes) == 0) { return; }
- hb_array_T* processed = parser_build_elements_from_tags(nodes, errors, strict);
+ hb_array_T* processed = parser_build_elements_from_tags(nodes, errors, options);
nodes->size = 0;
@@ -1741,7 +1750,7 @@ void match_tags_in_node_array(hb_array_T* nodes, hb_array_T* errors, bool strict
hb_array_free(&processed);
- match_tags_context_T context = { .errors = errors, .strict = strict };
+ match_tags_context_T context = { .errors = errors, .options = options };
for (size_t i = 0; i < hb_array_size(nodes); i++) {
AST_NODE_T* node = (AST_NODE_T*) hb_array_get(nodes, i);
@@ -1751,8 +1760,8 @@ void match_tags_in_node_array(hb_array_T* nodes, hb_array_T* errors, bool strict
}
}
-void herb_parser_match_html_tags_post_analyze(AST_DOCUMENT_NODE_T* document, bool strict) {
+void herb_parser_match_html_tags_post_analyze(AST_DOCUMENT_NODE_T* document, const parser_options_T* options) {
if (document == NULL) { return; }
- match_tags_in_node_array(document->children, document->base.errors, strict);
+ match_tags_in_node_array(document->children, document->base.errors, options);
}
diff --git a/templates/src/parser_match_tags.c.erb b/templates/src/parser_match_tags.c.erb
index 237d98949..27184bab1 100644
--- a/templates/src/parser_match_tags.c.erb
+++ b/templates/src/parser_match_tags.c.erb
@@ -25,7 +25,7 @@ bool match_tags_visitor(const AST_NODE_T* node, void* data) {
<%- array_fields.each do |field| -%>
if (<%= node.human %>-><%= field.name %> != NULL) {
- match_tags_in_node_array(<%= node.human %>-><%= field.name %>, context->errors, context->strict);
+ match_tags_in_node_array(<%= node.human %>-><%= field.name %>, context->errors, context->options);
}
<%- end -%>
<%- single_node_fields.each do |field| -%>
diff --git a/test/engine/evaluation/case_test.rb b/test/engine/evaluation/case_test.rb
new file mode 100644
index 000000000..4986c1483
--- /dev/null
+++ b/test/engine/evaluation/case_test.rb
@@ -0,0 +1,91 @@
+# frozen_string_literal: true
+
+require_relative "../../test_helper"
+require_relative "../../snapshot_utils"
+require_relative "../../../lib/herb/engine"
+
+module Engine
+ class CaseTest < Minitest::Spec
+ include SnapshotUtils
+
+ test "case when in same ERB tag" do
+ template = <<~ERB
+ <% case status when "pending" %>
+ Pending
+ <% when "approved" %>
+ Approved
+ <% else %>
+ Unknown
+ <% end %>
+ ERB
+
+ error = assert_raises(Herb::Engine::CompilationError) do
+ Herb::Engine.new(template, strict: true)
+ end
+
+ assert_includes error.message, "ERBCaseWithConditions"
+
+ assert_evaluated_snapshot(template, { status: "pending" }, { escape: false, strict: false })
+ assert_evaluated_snapshot(template, { status: "approved" }, { escape: false, strict: false })
+ assert_evaluated_snapshot(template, { status: "other" }, { escape: false, strict: false })
+ end
+
+ test "case in pattern in same ERB tag" do
+ template = <<~ERB
+ <% case count in 1 %>
+ One
+ <% in 2 %>
+ Two
+ <% else %>
+ Other
+ <% end %>
+ ERB
+
+ error = assert_raises(Herb::Engine::CompilationError) do
+ Herb::Engine.new(template, strict: true)
+ end
+
+ assert_includes error.message, "ERBCaseWithConditions"
+ end
+
+ test "case when on newline in same ERB tag" do
+ template = <<~ERB
+ <% case status
+ when "pending" %>
+ Pending
+ <% when "approved" %>
+ Approved
+ <% end %>
+ ERB
+
+ error = assert_raises(Herb::Engine::CompilationError) do
+ Herb::Engine.new(template, strict: true)
+ end
+
+ assert_includes error.message, "ERBCaseWithConditions"
+
+ assert_evaluated_snapshot(template, { status: "pending" }, { escape: false, strict: false })
+ assert_evaluated_snapshot(template, { status: "approved" }, { escape: false, strict: false })
+ end
+
+ test "case in on newline in same ERB tag" do
+ template = <<~ERB
+ <% case count
+ in 1 %>
+ One
+ <% in 2 %>
+ Two
+ <% end %>
+ ERB
+
+ error = assert_raises(Herb::Engine::CompilationError) do
+ Herb::Engine.new(template, strict: true)
+ end
+
+ assert_includes error.message, "ERBCaseWithConditions"
+
+ assert_evaluated_snapshot(template, { count: 1 }, { escape: false, strict: false })
+ assert_evaluated_snapshot(template, { count: 2 }, { escape: false, strict: false })
+ end
+ end
+end
diff --git a/test/engine/evaluation/heredoc_test.rb b/test/engine/evaluation/heredoc_test.rb
new file mode 100644
index 000000000..39163ae13
--- /dev/null
+++ b/test/engine/evaluation/heredoc_test.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+require_relative "../../test_helper"
+require_relative "../../snapshot_utils"
+require_relative "../../../lib/herb/engine"
+
+module Engine
+ class HeredocTest < Minitest::Spec
+ include SnapshotUtils
+
+ test "heredoc in code tag" do
+ template = <<~ERB
+ <%
+ text = <<~TEXT
+ Hello, world!
+ TEXT
+ %>
+ <%= text %>
+ ERB
+
+ assert_evaluated_snapshot(template, {}, { escape: false })
+ end
+ end
+end
diff --git a/test/engine/evaluation_test.rb b/test/engine/evaluation_test.rb
index ed75e1391..d5a4c858b 100644
--- a/test/engine/evaluation_test.rb
+++ b/test/engine/evaluation_test.rb
@@ -484,18 +484,5 @@ class EvaluationTest < Minitest::Spec
assert_evaluated_snapshot(template, { some_condition: false }, { escape: false })
end
-
- test "heredoc in code tag" do
- template = <<~ERB
- <%
- text = <<~TEXT
- Hello, world!
- TEXT
- %>
- <%= text %>
- ERB
-
- assert_evaluated_snapshot(template, {}, { escape: false })
- end
end
end
diff --git a/test/parser/multiple_control_flow_test.rb b/test/parser/multiple_control_flow_test.rb
index c4914bbc8..97c9cb2aa 100644
--- a/test/parser/multiple_control_flow_test.rb
+++ b/test/parser/multiple_control_flow_test.rb
@@ -363,23 +363,57 @@ class MultipleControlFlowTest < Minitest::Spec
end
test "case and when in same ERB tag" do
- assert_parsed_snapshot(<<~ERB)
+ template = <<~ERB
<% case variable when "a" %>
A
<% when "b" %>
B
<% end %>
ERB
+
+ assert_parsed_snapshot(template, strict: true)
+ assert_parsed_snapshot(template, strict: false)
end
test "case in pattern in same ERB tag" do
- assert_parsed_snapshot(<<~ERB)
+ template = <<~ERB
<% case value in 1 %>
One
<% in 2 %>
Two
<% end %>
ERB
+
+ assert_parsed_snapshot(template, strict: true)
+ assert_parsed_snapshot(template, strict: false)
+ end
+
+ test "case and when on newline in same ERB tag" do
+ template = <<~ERB
+ <% case variable
+ when "a" %>
+ A
+ <% when "b" %>
+ B
+ <% end %>
+ ERB
+
+ assert_parsed_snapshot(template, strict: true)
+ assert_parsed_snapshot(template, strict: false)
+ end
+
+ test "case in pattern on newline in same ERB tag" do
+ template = <<~ERB
+ <% case value
+ in 1 %>
+ One
+ <% in 2 %>
+ Two
+ <% end %>
+ ERB
+
+ assert_parsed_snapshot(template, strict: true)
+ assert_parsed_snapshot(template, strict: false)
end
end
end
diff --git a/test/snapshots/engine/case_test/test_0001_case_when_in_same_ERB_tag_23aed430da2e0530eba76d6ff44d4f48.txt b/test/snapshots/engine/case_test/test_0001_case_when_in_same_ERB_tag_23aed430da2e0530eba76d6ff44d4f48.txt
new file mode 100644
index 000000000..5b0b0a5a2
--- /dev/null
+++ b/test/snapshots/engine/case_test/test_0001_case_when_in_same_ERB_tag_23aed430da2e0530eba76d6ff44d4f48.txt
@@ -0,0 +1,5 @@
+---
+source: "Engine::CaseTest#test_0001_case when in same ERB tag"
+input: "{source: \"<% case status when \\\"pending\\\" %>\\n Pending\\n<% when \\\"approved\\\" %>\\n Approved\\n<% else %>\\n Unknown\\n<% end %>\\n\", locals: {status: \"pending\"}, options: {escape: false, strict: false}}"
+---
+ Pending
diff --git a/test/snapshots/engine/case_test/test_0001_case_when_in_same_ERB_tag_6ca15c3a9293976c06d3d4e1421980f9.txt b/test/snapshots/engine/case_test/test_0001_case_when_in_same_ERB_tag_6ca15c3a9293976c06d3d4e1421980f9.txt
new file mode 100644
index 000000000..6a98a89c3
--- /dev/null
+++ b/test/snapshots/engine/case_test/test_0001_case_when_in_same_ERB_tag_6ca15c3a9293976c06d3d4e1421980f9.txt
@@ -0,0 +1,5 @@
+---
+source: "Engine::CaseTest#test_0001_case when in same ERB tag"
+input: "{source: \"<% case status when \\\"pending\\\" %>\\n Pending\\n<% when \\\"approved\\\" %>\\n Approved\\n<% else %>\\n Unknown\\n<% end %>\\n\", locals: {status: \"approved\"}, options: {escape: false, strict: false}}"
+---
+ Approved
diff --git a/test/snapshots/engine/case_test/test_0001_case_when_in_same_ERB_tag_9b671780f0459813359368a1df6afaff.txt b/test/snapshots/engine/case_test/test_0001_case_when_in_same_ERB_tag_9b671780f0459813359368a1df6afaff.txt
new file mode 100644
index 000000000..8d21f45c0
--- /dev/null
+++ b/test/snapshots/engine/case_test/test_0001_case_when_in_same_ERB_tag_9b671780f0459813359368a1df6afaff.txt
@@ -0,0 +1,5 @@
+---
+source: "Engine::CaseTest#test_0001_case when in same ERB tag"
+input: "{source: \"<% case status when \\\"pending\\\" %>\\n Pending\\n<% when \\\"approved\\\" %>\\n Approved\\n<% else %>\\n Unknown\\n<% end %>\\n\", locals: {status: \"other\"}, options: {escape: false, strict: false}}"
+---
+ Unknown
diff --git a/test/snapshots/engine/case_test/test_0003_case_when_on_newline_in_same_ERB_tag_811ef7173169870133e367deaede4fe4.txt b/test/snapshots/engine/case_test/test_0003_case_when_on_newline_in_same_ERB_tag_811ef7173169870133e367deaede4fe4.txt
new file mode 100644
index 000000000..9a3f716dd
--- /dev/null
+++ b/test/snapshots/engine/case_test/test_0003_case_when_on_newline_in_same_ERB_tag_811ef7173169870133e367deaede4fe4.txt
@@ -0,0 +1,5 @@
+---
+source: "Engine::CaseTest#test_0003_case when on newline in same ERB tag"
+input: "{source: \"<% case status\\n when \\\"pending\\\" %>\\n Pending\\n<% when \\\"approved\\\" %>\\n Approved\\n<% end %>\\n\", locals: {status: \"approved\"}, options: {escape: false, strict: false}}"
+---
+ Approved
diff --git a/test/snapshots/engine/case_test/test_0003_case_when_on_newline_in_same_ERB_tag_ab777e9f2c3de2a5939a0bc885c8d74c.txt b/test/snapshots/engine/case_test/test_0003_case_when_on_newline_in_same_ERB_tag_ab777e9f2c3de2a5939a0bc885c8d74c.txt
new file mode 100644
index 000000000..1bbfc8c06
--- /dev/null
+++ b/test/snapshots/engine/case_test/test_0003_case_when_on_newline_in_same_ERB_tag_ab777e9f2c3de2a5939a0bc885c8d74c.txt
@@ -0,0 +1,5 @@
+---
+source: "Engine::CaseTest#test_0003_case when on newline in same ERB tag"
+input: "{source: \"<% case status\\n when \\\"pending\\\" %>\\n Pending\\n<% when \\\"approved\\\" %>\\n Approved\\n<% end %>\\n\", locals: {status: \"pending\"}, options: {escape: false, strict: false}}"
+---
+ Pending
diff --git a/test/snapshots/engine/case_test/test_0004_case_in_on_newline_in_same_ERB_tag_0a592ed5a885b7022e49432c323b8991.txt b/test/snapshots/engine/case_test/test_0004_case_in_on_newline_in_same_ERB_tag_0a592ed5a885b7022e49432c323b8991.txt
new file mode 100644
index 000000000..21efc17c5
--- /dev/null
+++ b/test/snapshots/engine/case_test/test_0004_case_in_on_newline_in_same_ERB_tag_0a592ed5a885b7022e49432c323b8991.txt
@@ -0,0 +1,5 @@
+---
+source: "Engine::CaseTest#test_0004_case in on newline in same ERB tag"
+input: "{source: \"<% case count\\n in 1 %>\\n One\\n<% in 2 %>\\n Two\\n<% end %>\\n\", locals: {count: 1}, options: {escape: false, strict: false}}"
+---
+ One
diff --git a/test/snapshots/engine/case_test/test_0004_case_in_on_newline_in_same_ERB_tag_efdcbb5c5c9196a57d4695520c828efc.txt b/test/snapshots/engine/case_test/test_0004_case_in_on_newline_in_same_ERB_tag_efdcbb5c5c9196a57d4695520c828efc.txt
new file mode 100644
index 000000000..90ab63bea
--- /dev/null
+++ b/test/snapshots/engine/case_test/test_0004_case_in_on_newline_in_same_ERB_tag_efdcbb5c5c9196a57d4695520c828efc.txt
@@ -0,0 +1,5 @@
+---
+source: "Engine::CaseTest#test_0004_case in on newline in same ERB tag"
+input: "{source: \"<% case count\\n in 1 %>\\n One\\n<% in 2 %>\\n Two\\n<% end %>\\n\", locals: {count: 2}, options: {escape: false, strict: false}}"
+---
+ Two
diff --git a/test/snapshots/engine/evaluation_test/test_0039_heredoc_in_code_tag_89436ef132cfca5077afe91beb8082b8.txt b/test/snapshots/engine/heredoc_test/test_0001_heredoc_in_code_tag_89436ef132cfca5077afe91beb8082b8.txt
similarity index 71%
rename from test/snapshots/engine/evaluation_test/test_0039_heredoc_in_code_tag_89436ef132cfca5077afe91beb8082b8.txt
rename to test/snapshots/engine/heredoc_test/test_0001_heredoc_in_code_tag_89436ef132cfca5077afe91beb8082b8.txt
index fed1e294b..0147d18fe 100644
--- a/test/snapshots/engine/evaluation_test/test_0039_heredoc_in_code_tag_89436ef132cfca5077afe91beb8082b8.txt
+++ b/test/snapshots/engine/heredoc_test/test_0001_heredoc_in_code_tag_89436ef132cfca5077afe91beb8082b8.txt
@@ -1,5 +1,5 @@
---
-source: "Engine::EvaluationTest#test_0039_heredoc in code tag"
+source: "Engine::HeredocTest#test_0001_heredoc in code tag"
input: "{source: \"<%\\n text = <<~TEXT\\n Hello, world!\\n TEXT\\n%>\\n<%= text %>\\n\", locals: {}, options: {escape: false}}"
---
Hello, world!
diff --git a/test/snapshots/parser/multiple_control_flow_test/test_0041_case_and_when_in_same_ERB_tag_82797abe9bddf29a367f8ebcc420eaba-08996694f7ff1e6e34277dc32f646630.txt b/test/snapshots/parser/multiple_control_flow_test/test_0041_case_and_when_in_same_ERB_tag_82797abe9bddf29a367f8ebcc420eaba-08996694f7ff1e6e34277dc32f646630.txt
new file mode 100644
index 000000000..09584cd75
--- /dev/null
+++ b/test/snapshots/parser/multiple_control_flow_test/test_0041_case_and_when_in_same_ERB_tag_82797abe9bddf29a367f8ebcc420eaba-08996694f7ff1e6e34277dc32f646630.txt
@@ -0,0 +1,52 @@
+---
+source: "Parser::MultipleControlFlowTest#test_0041_case and when in same ERB tag"
+input: |2-
+<% case variable when "a" %>
+ A
+<% when "b" %>
+ B
+<% end %>
+options: {strict: true}
+---
+@ DocumentNode (location: (1:0)-(6:0))
+└── children: (2 items)
+ ├── @ ERBCaseNode (location: (1:0)-(5:9))
+ │ ├── errors: (1 error)
+ │ │ └── @ ERBCaseWithConditionsError (location: (1:0)-(1:28))
+ │ │ └── message: "A `case` statement with `when`/`in` conditions in a single ERB tag cannot be reliably parsed, compiled, and formatted. Use separate ERB tags for `case` and its conditions (e.g., `<% case x %>` followed by `<% when y %>`)."
+ │ │
+ │ ├── tag_opening: "<%" (location: (1:0)-(1:2))
+ │ ├── content: " case variable when "a" " (location: (1:2)-(1:26))
+ │ ├── tag_closing: "%>" (location: (1:26)-(1:28))
+ │ ├── children: []
+ │ ├── conditions: (2 items)
+ │ │ ├── @ ERBWhenNode (location: (1:28)-(3:0))
+ │ │ │ ├── tag_opening: ∅
+ │ │ │ ├── content: ∅
+ │ │ │ ├── tag_closing: ∅
+ │ │ │ ├── then_keyword: ∅
+ │ │ │ └── statements: (1 item)
+ │ │ │ └── @ HTMLTextNode (location: (1:28)-(3:0))
+ │ │ │ └── content: "\n A\n"
+ │ │ │
+ │ │ │
+ │ │ └── @ ERBWhenNode (location: (3:0)-(3:14))
+ │ │ ├── tag_opening: "<%" (location: (3:0)-(3:2))
+ │ │ ├── content: " when "b" " (location: (3:2)-(3:12))
+ │ │ ├── tag_closing: "%>" (location: (3:12)-(3:14))
+ │ │ ├── then_keyword: ∅
+ │ │ └── statements: (1 item)
+ │ │ └── @ HTMLTextNode (location: (3:14)-(5:0))
+ │ │ └── content: "\n B\n"
+ │ │
+ │ │
+ │ ├── else_clause: ∅
+ │ └── end_node:
+ │ └── @ ERBEndNode (location: (5:0)-(5:9))
+ │ ├── tag_opening: "<%" (location: (5:0)-(5:2))
+ │ ├── content: " end " (location: (5:2)-(5:7))
+ │ └── tag_closing: "%>" (location: (5:7)-(5:9))
+ │
+ │
+ └── @ HTMLTextNode (location: (5:9)-(6:0))
+ └── content: "\n"
\ No newline at end of file
diff --git a/test/snapshots/parser/multiple_control_flow_test/test_0041_case_and_when_in_same_ERB_tag_82797abe9bddf29a367f8ebcc420eaba.txt b/test/snapshots/parser/multiple_control_flow_test/test_0041_case_and_when_in_same_ERB_tag_82797abe9bddf29a367f8ebcc420eaba-2ffd01e26b8c99a6c7a6dad67c9489dc.txt
similarity index 71%
rename from test/snapshots/parser/multiple_control_flow_test/test_0041_case_and_when_in_same_ERB_tag_82797abe9bddf29a367f8ebcc420eaba.txt
rename to test/snapshots/parser/multiple_control_flow_test/test_0041_case_and_when_in_same_ERB_tag_82797abe9bddf29a367f8ebcc420eaba-2ffd01e26b8c99a6c7a6dad67c9489dc.txt
index 58b9869c4..19e7e7b5c 100644
--- a/test/snapshots/parser/multiple_control_flow_test/test_0041_case_and_when_in_same_ERB_tag_82797abe9bddf29a367f8ebcc420eaba.txt
+++ b/test/snapshots/parser/multiple_control_flow_test/test_0041_case_and_when_in_same_ERB_tag_82797abe9bddf29a367f8ebcc420eaba-2ffd01e26b8c99a6c7a6dad67c9489dc.txt
@@ -6,22 +6,26 @@ input: |2-
<% when "b" %>
B
<% end %>
+options: {strict: false}
---
@ DocumentNode (location: (1:0)-(6:0))
└── children: (2 items)
├── @ ERBCaseNode (location: (1:0)-(5:9))
- │ ├── errors: (1 error)
- │ │ └── @ ERBCaseWithConditionsError (location: (1:0)-(1:28))
- │ │ └── message: "A `case` statement with `when`/`in` in a single ERB tag cannot be formatted. Use separate tags for `case` and its conditions."
- │ │
│ ├── tag_opening: "<%" (location: (1:0)-(1:2))
│ ├── content: " case variable when "a" " (location: (1:2)-(1:26))
│ ├── tag_closing: "%>" (location: (1:26)-(1:28))
- │ ├── children: (1 item)
- │ │ └── @ HTMLTextNode (location: (1:28)-(3:0))
- │ │ └── content: "\n A\n"
- │ │
- │ ├── conditions: (1 item)
+ │ ├── children: []
+ │ ├── conditions: (2 items)
+ │ │ ├── @ ERBWhenNode (location: (1:28)-(3:0))
+ │ │ │ ├── tag_opening: ∅
+ │ │ │ ├── content: ∅
+ │ │ │ ├── tag_closing: ∅
+ │ │ │ ├── then_keyword: ∅
+ │ │ │ └── statements: (1 item)
+ │ │ │ └── @ HTMLTextNode (location: (1:28)-(3:0))
+ │ │ │ └── content: "\n A\n"
+ │ │ │
+ │ │ │
│ │ └── @ ERBWhenNode (location: (3:0)-(3:14))
│ │ ├── tag_opening: "<%" (location: (3:0)-(3:2))
│ │ ├── content: " when "b" " (location: (3:2)-(3:12))
diff --git a/test/snapshots/parser/multiple_control_flow_test/test_0042_case_in_pattern_in_same_ERB_tag_5655a054015224a72ca2f5d378f9b966-08996694f7ff1e6e34277dc32f646630.txt b/test/snapshots/parser/multiple_control_flow_test/test_0042_case_in_pattern_in_same_ERB_tag_5655a054015224a72ca2f5d378f9b966-08996694f7ff1e6e34277dc32f646630.txt
new file mode 100644
index 000000000..bfdb501c4
--- /dev/null
+++ b/test/snapshots/parser/multiple_control_flow_test/test_0042_case_in_pattern_in_same_ERB_tag_5655a054015224a72ca2f5d378f9b966-08996694f7ff1e6e34277dc32f646630.txt
@@ -0,0 +1,52 @@
+---
+source: "Parser::MultipleControlFlowTest#test_0042_case in pattern in same ERB tag"
+input: |2-
+<% case value in 1 %>
+ One
+<% in 2 %>
+ Two
+<% end %>
+options: {strict: true}
+---
+@ DocumentNode (location: (1:0)-(6:0))
+└── children: (2 items)
+ ├── @ ERBCaseMatchNode (location: (1:0)-(5:9))
+ │ ├── errors: (1 error)
+ │ │ └── @ ERBCaseWithConditionsError (location: (1:0)-(1:21))
+ │ │ └── message: "A `case` statement with `when`/`in` conditions in a single ERB tag cannot be reliably parsed, compiled, and formatted. Use separate ERB tags for `case` and its conditions (e.g., `<% case x %>` followed by `<% when y %>`)."
+ │ │
+ │ ├── tag_opening: "<%" (location: (1:0)-(1:2))
+ │ ├── content: " case value in 1 " (location: (1:2)-(1:19))
+ │ ├── tag_closing: "%>" (location: (1:19)-(1:21))
+ │ ├── children: []
+ │ ├── conditions: (2 items)
+ │ │ ├── @ ERBInNode (location: (1:21)-(3:0))
+ │ │ │ ├── tag_opening: ∅
+ │ │ │ ├── content: ∅
+ │ │ │ ├── tag_closing: ∅
+ │ │ │ ├── then_keyword: ∅
+ │ │ │ └── statements: (1 item)
+ │ │ │ └── @ HTMLTextNode (location: (1:21)-(3:0))
+ │ │ │ └── content: "\n One\n"
+ │ │ │
+ │ │ │
+ │ │ └── @ ERBInNode (location: (3:0)-(3:10))
+ │ │ ├── tag_opening: "<%" (location: (3:0)-(3:2))
+ │ │ ├── content: " in 2 " (location: (3:2)-(3:8))
+ │ │ ├── tag_closing: "%>" (location: (3:8)-(3:10))
+ │ │ ├── then_keyword: ∅
+ │ │ └── statements: (1 item)
+ │ │ └── @ HTMLTextNode (location: (3:10)-(5:0))
+ │ │ └── content: "\n Two\n"
+ │ │
+ │ │
+ │ ├── else_clause: ∅
+ │ └── end_node:
+ │ └── @ ERBEndNode (location: (5:0)-(5:9))
+ │ ├── tag_opening: "<%" (location: (5:0)-(5:2))
+ │ ├── content: " end " (location: (5:2)-(5:7))
+ │ └── tag_closing: "%>" (location: (5:7)-(5:9))
+ │
+ │
+ └── @ HTMLTextNode (location: (5:9)-(6:0))
+ └── content: "\n"
\ No newline at end of file
diff --git a/test/snapshots/parser/multiple_control_flow_test/test_0042_case_in_pattern_in_same_ERB_tag_5655a054015224a72ca2f5d378f9b966.txt b/test/snapshots/parser/multiple_control_flow_test/test_0042_case_in_pattern_in_same_ERB_tag_5655a054015224a72ca2f5d378f9b966-2ffd01e26b8c99a6c7a6dad67c9489dc.txt
similarity index 71%
rename from test/snapshots/parser/multiple_control_flow_test/test_0042_case_in_pattern_in_same_ERB_tag_5655a054015224a72ca2f5d378f9b966.txt
rename to test/snapshots/parser/multiple_control_flow_test/test_0042_case_in_pattern_in_same_ERB_tag_5655a054015224a72ca2f5d378f9b966-2ffd01e26b8c99a6c7a6dad67c9489dc.txt
index a8fbbd0a2..35a6fa0d7 100644
--- a/test/snapshots/parser/multiple_control_flow_test/test_0042_case_in_pattern_in_same_ERB_tag_5655a054015224a72ca2f5d378f9b966.txt
+++ b/test/snapshots/parser/multiple_control_flow_test/test_0042_case_in_pattern_in_same_ERB_tag_5655a054015224a72ca2f5d378f9b966-2ffd01e26b8c99a6c7a6dad67c9489dc.txt
@@ -6,22 +6,26 @@ input: |2-
<% in 2 %>
Two
<% end %>
+options: {strict: false}
---
@ DocumentNode (location: (1:0)-(6:0))
└── children: (2 items)
├── @ ERBCaseMatchNode (location: (1:0)-(5:9))
- │ ├── errors: (1 error)
- │ │ └── @ ERBCaseWithConditionsError (location: (1:0)-(1:21))
- │ │ └── message: "A `case` statement with `when`/`in` in a single ERB tag cannot be formatted. Use separate tags for `case` and its conditions."
- │ │
│ ├── tag_opening: "<%" (location: (1:0)-(1:2))
│ ├── content: " case value in 1 " (location: (1:2)-(1:19))
│ ├── tag_closing: "%>" (location: (1:19)-(1:21))
- │ ├── children: (1 item)
- │ │ └── @ HTMLTextNode (location: (1:21)-(3:0))
- │ │ └── content: "\n One\n"
- │ │
- │ ├── conditions: (1 item)
+ │ ├── children: []
+ │ ├── conditions: (2 items)
+ │ │ ├── @ ERBInNode (location: (1:21)-(3:0))
+ │ │ │ ├── tag_opening: ∅
+ │ │ │ ├── content: ∅
+ │ │ │ ├── tag_closing: ∅
+ │ │ │ ├── then_keyword: ∅
+ │ │ │ └── statements: (1 item)
+ │ │ │ └── @ HTMLTextNode (location: (1:21)-(3:0))
+ │ │ │ └── content: "\n One\n"
+ │ │ │
+ │ │ │
│ │ └── @ ERBInNode (location: (3:0)-(3:10))
│ │ ├── tag_opening: "<%" (location: (3:0)-(3:2))
│ │ ├── content: " in 2 " (location: (3:2)-(3:8))
diff --git a/test/snapshots/parser/multiple_control_flow_test/test_0043_case_and_when_on_newline_in_same_ERB_tag_0560399f6147186ba24ad4f6c9f5df6f-08996694f7ff1e6e34277dc32f646630.txt b/test/snapshots/parser/multiple_control_flow_test/test_0043_case_and_when_on_newline_in_same_ERB_tag_0560399f6147186ba24ad4f6c9f5df6f-08996694f7ff1e6e34277dc32f646630.txt
new file mode 100644
index 000000000..58e4c32f4
--- /dev/null
+++ b/test/snapshots/parser/multiple_control_flow_test/test_0043_case_and_when_on_newline_in_same_ERB_tag_0560399f6147186ba24ad4f6c9f5df6f-08996694f7ff1e6e34277dc32f646630.txt
@@ -0,0 +1,54 @@
+---
+source: "Parser::MultipleControlFlowTest#test_0043_case and when on newline in same ERB tag"
+input: |2-
+<% case variable
+ when "a" %>
+ A
+<% when "b" %>
+ B
+<% end %>
+options: {strict: true}
+---
+@ DocumentNode (location: (1:0)-(7:0))
+└── children: (2 items)
+ ├── @ ERBCaseNode (location: (1:0)-(6:9))
+ │ ├── errors: (1 error)
+ │ │ └── @ ERBCaseWithConditionsError (location: (1:0)-(2:14))
+ │ │ └── message: "A `case` statement with `when`/`in` conditions in a single ERB tag cannot be reliably parsed, compiled, and formatted. Use separate ERB tags for `case` and its conditions (e.g., `<% case x %>` followed by `<% when y %>`)."
+ │ │
+ │ ├── tag_opening: "<%" (location: (1:0)-(1:2))
+ │ ├── content: " case variable
+ │ when "a" " (location: (1:2)-(2:12))
+ │ ├── tag_closing: "%>" (location: (2:12)-(2:14))
+ │ ├── children: []
+ │ ├── conditions: (2 items)
+ │ │ ├── @ ERBWhenNode (location: (2:14)-(4:0))
+ │ │ │ ├── tag_opening: ∅
+ │ │ │ ├── content: ∅
+ │ │ │ ├── tag_closing: ∅
+ │ │ │ ├── then_keyword: ∅
+ │ │ │ └── statements: (1 item)
+ │ │ │ └── @ HTMLTextNode (location: (2:14)-(4:0))
+ │ │ │ └── content: "\n A\n"
+ │ │ │
+ │ │ │
+ │ │ └── @ ERBWhenNode (location: (4:0)-(4:14))
+ │ │ ├── tag_opening: "<%" (location: (4:0)-(4:2))
+ │ │ ├── content: " when "b" " (location: (4:2)-(4:12))
+ │ │ ├── tag_closing: "%>" (location: (4:12)-(4:14))
+ │ │ ├── then_keyword: ∅
+ │ │ └── statements: (1 item)
+ │ │ └── @ HTMLTextNode (location: (4:14)-(6:0))
+ │ │ └── content: "\n B\n"
+ │ │
+ │ │
+ │ ├── else_clause: ∅
+ │ └── end_node:
+ │ └── @ ERBEndNode (location: (6:0)-(6:9))
+ │ ├── tag_opening: "<%" (location: (6:0)-(6:2))
+ │ ├── content: " end " (location: (6:2)-(6:7))
+ │ └── tag_closing: "%>" (location: (6:7)-(6:9))
+ │
+ │
+ └── @ HTMLTextNode (location: (6:9)-(7:0))
+ └── content: "\n"
\ No newline at end of file
diff --git a/test/snapshots/parser/multiple_control_flow_test/test_0043_case_and_when_on_newline_in_same_ERB_tag_0560399f6147186ba24ad4f6c9f5df6f-2ffd01e26b8c99a6c7a6dad67c9489dc.txt b/test/snapshots/parser/multiple_control_flow_test/test_0043_case_and_when_on_newline_in_same_ERB_tag_0560399f6147186ba24ad4f6c9f5df6f-2ffd01e26b8c99a6c7a6dad67c9489dc.txt
new file mode 100644
index 000000000..fc43443e5
--- /dev/null
+++ b/test/snapshots/parser/multiple_control_flow_test/test_0043_case_and_when_on_newline_in_same_ERB_tag_0560399f6147186ba24ad4f6c9f5df6f-2ffd01e26b8c99a6c7a6dad67c9489dc.txt
@@ -0,0 +1,50 @@
+---
+source: "Parser::MultipleControlFlowTest#test_0043_case and when on newline in same ERB tag"
+input: |2-
+<% case variable
+ when "a" %>
+ A
+<% when "b" %>
+ B
+<% end %>
+options: {strict: false}
+---
+@ DocumentNode (location: (1:0)-(7:0))
+└── children: (2 items)
+ ├── @ ERBCaseNode (location: (1:0)-(6:9))
+ │ ├── tag_opening: "<%" (location: (1:0)-(1:2))
+ │ ├── content: " case variable
+ │ when "a" " (location: (1:2)-(2:12))
+ │ ├── tag_closing: "%>" (location: (2:12)-(2:14))
+ │ ├── children: []
+ │ ├── conditions: (2 items)
+ │ │ ├── @ ERBWhenNode (location: (2:14)-(4:0))
+ │ │ │ ├── tag_opening: ∅
+ │ │ │ ├── content: ∅
+ │ │ │ ├── tag_closing: ∅
+ │ │ │ ├── then_keyword: ∅
+ │ │ │ └── statements: (1 item)
+ │ │ │ └── @ HTMLTextNode (location: (2:14)-(4:0))
+ │ │ │ └── content: "\n A\n"
+ │ │ │
+ │ │ │
+ │ │ └── @ ERBWhenNode (location: (4:0)-(4:14))
+ │ │ ├── tag_opening: "<%" (location: (4:0)-(4:2))
+ │ │ ├── content: " when "b" " (location: (4:2)-(4:12))
+ │ │ ├── tag_closing: "%>" (location: (4:12)-(4:14))
+ │ │ ├── then_keyword: ∅
+ │ │ └── statements: (1 item)
+ │ │ └── @ HTMLTextNode (location: (4:14)-(6:0))
+ │ │ └── content: "\n B\n"
+ │ │
+ │ │
+ │ ├── else_clause: ∅
+ │ └── end_node:
+ │ └── @ ERBEndNode (location: (6:0)-(6:9))
+ │ ├── tag_opening: "<%" (location: (6:0)-(6:2))
+ │ ├── content: " end " (location: (6:2)-(6:7))
+ │ └── tag_closing: "%>" (location: (6:7)-(6:9))
+ │
+ │
+ └── @ HTMLTextNode (location: (6:9)-(7:0))
+ └── content: "\n"
\ No newline at end of file
diff --git a/test/snapshots/parser/multiple_control_flow_test/test_0044_case_in_pattern_on_newline_in_same_ERB_tag_469f7105ed227c9918b8e8e22644591c-08996694f7ff1e6e34277dc32f646630.txt b/test/snapshots/parser/multiple_control_flow_test/test_0044_case_in_pattern_on_newline_in_same_ERB_tag_469f7105ed227c9918b8e8e22644591c-08996694f7ff1e6e34277dc32f646630.txt
new file mode 100644
index 000000000..b0595388f
--- /dev/null
+++ b/test/snapshots/parser/multiple_control_flow_test/test_0044_case_in_pattern_on_newline_in_same_ERB_tag_469f7105ed227c9918b8e8e22644591c-08996694f7ff1e6e34277dc32f646630.txt
@@ -0,0 +1,54 @@
+---
+source: "Parser::MultipleControlFlowTest#test_0044_case in pattern on newline in same ERB tag"
+input: |2-
+<% case value
+ in 1 %>
+ One
+<% in 2 %>
+ Two
+<% end %>
+options: {strict: true}
+---
+@ DocumentNode (location: (1:0)-(7:0))
+└── children: (2 items)
+ ├── @ ERBCaseMatchNode (location: (1:0)-(6:9))
+ │ ├── errors: (1 error)
+ │ │ └── @ ERBCaseWithConditionsError (location: (1:0)-(2:10))
+ │ │ └── message: "A `case` statement with `when`/`in` conditions in a single ERB tag cannot be reliably parsed, compiled, and formatted. Use separate ERB tags for `case` and its conditions (e.g., `<% case x %>` followed by `<% when y %>`)."
+ │ │
+ │ ├── tag_opening: "<%" (location: (1:0)-(1:2))
+ │ ├── content: " case value
+ │ in 1 " (location: (1:2)-(2:8))
+ │ ├── tag_closing: "%>" (location: (2:8)-(2:10))
+ │ ├── children: []
+ │ ├── conditions: (2 items)
+ │ │ ├── @ ERBInNode (location: (2:10)-(4:0))
+ │ │ │ ├── tag_opening: ∅
+ │ │ │ ├── content: ∅
+ │ │ │ ├── tag_closing: ∅
+ │ │ │ ├── then_keyword: ∅
+ │ │ │ └── statements: (1 item)
+ │ │ │ └── @ HTMLTextNode (location: (2:10)-(4:0))
+ │ │ │ └── content: "\n One\n"
+ │ │ │
+ │ │ │
+ │ │ └── @ ERBInNode (location: (4:0)-(4:10))
+ │ │ ├── tag_opening: "<%" (location: (4:0)-(4:2))
+ │ │ ├── content: " in 2 " (location: (4:2)-(4:8))
+ │ │ ├── tag_closing: "%>" (location: (4:8)-(4:10))
+ │ │ ├── then_keyword: ∅
+ │ │ └── statements: (1 item)
+ │ │ └── @ HTMLTextNode (location: (4:10)-(6:0))
+ │ │ └── content: "\n Two\n"
+ │ │
+ │ │
+ │ ├── else_clause: ∅
+ │ └── end_node:
+ │ └── @ ERBEndNode (location: (6:0)-(6:9))
+ │ ├── tag_opening: "<%" (location: (6:0)-(6:2))
+ │ ├── content: " end " (location: (6:2)-(6:7))
+ │ └── tag_closing: "%>" (location: (6:7)-(6:9))
+ │
+ │
+ └── @ HTMLTextNode (location: (6:9)-(7:0))
+ └── content: "\n"
\ No newline at end of file
diff --git a/test/snapshots/parser/multiple_control_flow_test/test_0044_case_in_pattern_on_newline_in_same_ERB_tag_469f7105ed227c9918b8e8e22644591c-2ffd01e26b8c99a6c7a6dad67c9489dc.txt b/test/snapshots/parser/multiple_control_flow_test/test_0044_case_in_pattern_on_newline_in_same_ERB_tag_469f7105ed227c9918b8e8e22644591c-2ffd01e26b8c99a6c7a6dad67c9489dc.txt
new file mode 100644
index 000000000..492936029
--- /dev/null
+++ b/test/snapshots/parser/multiple_control_flow_test/test_0044_case_in_pattern_on_newline_in_same_ERB_tag_469f7105ed227c9918b8e8e22644591c-2ffd01e26b8c99a6c7a6dad67c9489dc.txt
@@ -0,0 +1,50 @@
+---
+source: "Parser::MultipleControlFlowTest#test_0044_case in pattern on newline in same ERB tag"
+input: |2-
+<% case value
+ in 1 %>
+ One
+<% in 2 %>
+ Two
+<% end %>
+options: {strict: false}
+---
+@ DocumentNode (location: (1:0)-(7:0))
+└── children: (2 items)
+ ├── @ ERBCaseMatchNode (location: (1:0)-(6:9))
+ │ ├── tag_opening: "<%" (location: (1:0)-(1:2))
+ │ ├── content: " case value
+ │ in 1 " (location: (1:2)-(2:8))
+ │ ├── tag_closing: "%>" (location: (2:8)-(2:10))
+ │ ├── children: []
+ │ ├── conditions: (2 items)
+ │ │ ├── @ ERBInNode (location: (2:10)-(4:0))
+ │ │ │ ├── tag_opening: ∅
+ │ │ │ ├── content: ∅
+ │ │ │ ├── tag_closing: ∅
+ │ │ │ ├── then_keyword: ∅
+ │ │ │ └── statements: (1 item)
+ │ │ │ └── @ HTMLTextNode (location: (2:10)-(4:0))
+ │ │ │ └── content: "\n One\n"
+ │ │ │
+ │ │ │
+ │ │ └── @ ERBInNode (location: (4:0)-(4:10))
+ │ │ ├── tag_opening: "<%" (location: (4:0)-(4:2))
+ │ │ ├── content: " in 2 " (location: (4:2)-(4:8))
+ │ │ ├── tag_closing: "%>" (location: (4:8)-(4:10))
+ │ │ ├── then_keyword: ∅
+ │ │ └── statements: (1 item)
+ │ │ └── @ HTMLTextNode (location: (4:10)-(6:0))
+ │ │ └── content: "\n Two\n"
+ │ │
+ │ │
+ │ ├── else_clause: ∅
+ │ └── end_node:
+ │ └── @ ERBEndNode (location: (6:0)-(6:9))
+ │ ├── tag_opening: "<%" (location: (6:0)-(6:2))
+ │ ├── content: " end " (location: (6:2)-(6:7))
+ │ └── tag_closing: "%>" (location: (6:7)-(6:9))
+ │
+ │
+ └── @ HTMLTextNode (location: (6:9)-(7:0))
+ └── content: "\n"
\ No newline at end of file