Skip to content

Parser: Allow inline case/when and case/in in strict mode#1263

Merged
marcoroth merged 1 commit into
mainfrom
ERBCaseWithConditionsError-strict
Mar 1, 2026
Merged

Parser: Allow inline case/when and case/in in strict mode#1263
marcoroth merged 1 commit into
mainfrom
ERBCaseWithConditionsError-strict

Conversation

@marcoroth

@marcoroth marcoroth commented Mar 1, 2026

Copy link
Copy Markdown
Owner

This pull request updates the parser to provide backwards compatibility for <% case @foo when :bar %> (case/when or case/in in a single ERB tag) by gating the ERBCaseWithConditionsError behind strict mode.

This syntax is valid Erubi and, for backwards compatibility reasons, we should also make this also work in Herb. With this change, non-strict now mode accepts this syntax and now correctly compiles it by splitting a the single ERB Node into multiple AST nodes by creating a new synthetic ERBWhenNode or ERBCaseInNode node.

The following template:

<% case count
   in 1 %>
  One
<% in 2 %>
  Two
<% end %>

Now gets parsed as this in non-strict mode:

@ DocumentNode (location: (1:0)-(7:0))
└── children: (2 items)
    ├── @ ERBCaseMatchNode (location: (1:0)-(6:9))
       ├── tag_opening: "<%" (location: (1:0)-(1:2))
       ├── content: " case count
          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"

In strict mode it will still produce a ERBCaseWithConditionsError.

Before this change, it was parsed as:

@ 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` 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 count
          in 1 " (location: (1:2)-(2:8))
       ├── tag_closing: "%>" (location: (2:8)-(2:10))
       ├── children: (1 item)
          └── @ HTMLTextNode (location: (2:10)-(4:0))
              └── content: "\n  One\n"
       
       ├── conditions: (1 item)
          └── @ 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"

Resolves #1252
Related #1112

@pkg-pr-new

pkg-pr-new Bot commented Mar 1, 2026

Copy link
Copy Markdown
npx https://pkg.pr.new/@herb-tools/formatter@1263
npx https://pkg.pr.new/@herb-tools/language-server@1263
npx https://pkg.pr.new/@herb-tools/linter@1263

commit: 9f9a9e5

@github-actions

github-actions Bot commented Mar 1, 2026

Copy link
Copy Markdown

🌿 Interactive Playground and Documentation Preview

A preview deployment has been built for this pull request. Try out the changes live in the interactive playground:


🌱 Grown from commit 9f9a9e5


✅ Preview deployment has been cleaned up.

@marcoroth marcoroth merged commit d807f21 into main Mar 1, 2026
32 checks passed
@marcoroth marcoroth deleted the ERBCaseWithConditionsError-strict branch March 1, 2026 10:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Engine: Case statement with when/in in single ERB tag not backward compatible with ActionView

1 participant