Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parsing issues with yield? #51

Closed
AliOsm opened this issue May 10, 2024 · 14 comments
Closed

Parsing issues with yield? #51

AliOsm opened this issue May 10, 2024 · 14 comments

Comments

@AliOsm
Copy link

AliOsm commented May 10, 2024

I have the following ERB template:

<section>
  <div class="flex flex-col pb-4 mx-auto">
    <div class="w-full bg-white rounded-lg shadow sm:max-w-lg md:mt-0 xl:p-0 dark:bg-gray-800 dark:border dark:border-gray-700">
      <div class="p-6 space-y-4 sm:p-8 md:space-y-6">
        <%= yield %>
      </div>
    </div>
  </div>
</section>

When I save it, erb-formatter VSCode extension shows the following:

Failed in line 8 ==> ERROR: Unmatched close tag, tried with ["div", "</div>"], but ["%erb%", "yield"] was on the stack

But in other templates like the following one:

<%# locals: (text:, url:, args: {}) %>

<%= link_to url, **{ class: "flex items-center text-sm font-medium text-primary-600 dark:text-primary-500 hover:underline", **args } do %>
  <%= yield %>

    <%= text %>
  <% end %>

No issues happens and the formatter works, but the formatting is not correct, I'm pasting the formatted template.

I think erb-formatter has some issues with yield with used with HTML tags.

@AliOsm
Copy link
Author

AliOsm commented May 10, 2024

The same issue happens with this template also:

<div id="flash">
  <% flash.each do |type, message| %>
    <% next unless message.is_a?(String) %>

    <% case type %>
    <% when "alert" %>
      <%= render("shared/alert_flash", message: message) %>
    <% when "notice" %>
      <%= render("shared/notice_flash", message: message) %>
    <% end %>
  <% end %>
</div>

The error is:

Failed in line 12 ==> ERROR: Unmatched close tag, tried with ["div", "</div>"], but ["%erb%", "flash.each do |type, message|"] was on the stack

@AliOsm
Copy link
Author

AliOsm commented May 10, 2024

For this template:

<section>
  <div class="flex flex-col pb-4 mx-auto">
    <div class="w-full bg-white rounded-lg shadow sm:max-w-lg md:mt-0 xl:p-0 dark:bg-gray-800 dark:border dark:border-gray-700">
      <div class="p-6 space-y-4 sm:p-8 md:space-y-6">
        <%= yield %>
      </div>
    </div>
  </div>
</section>

Adding <% end %> after the yield line fixes the issue, but the page is not rendering any more :3

@IbraheemTuffaha
Copy link
Contributor

I'm facing the same issue
I tried closing the yield tag with an end tag and the formatter is working
But as you said, the code no longer renders, instead of gives an error :)

@IbraheemTuffaha
Copy link
Contributor

IbraheemTuffaha commented May 13, 2024

I dug a bit into the code and I found this case statement:

case ruby_code
when RUBY_CLOSE_BLOCK
full_erb_tag = "#{erb_open}#{ruby_code} #{erb_close}"
tag_stack_pop('%erb%', ruby_code)
html << (erb_pre_match.match?(/\s+\z/) ? indented(full_erb_tag) : full_erb_tag)
when RUBY_REOPEN_BLOCK
full_erb_tag = "#{erb_open}#{ruby_code} #{erb_close}"
tag_stack_pop('%erb%', ruby_code)
html << (erb_pre_match.match?(/\s+\z/) ? indented(full_erb_tag) : full_erb_tag)
tag_stack_push('%erb%', ruby_code)
when RUBY_OPEN_BLOCK
full_erb_tag = "#{erb_open}#{ruby_code} #{erb_close}"
html << (erb_pre_match.match?(/\s+\z/) ? indented(full_erb_tag) : full_erb_tag)
tag_stack_push('%erb%', ruby_code)
else
ruby_code = format_ruby(ruby_code, autoclose: false)
full_erb_tag = "#{erb_open}#{ruby_code} #{erb_close}"
html << (erb_pre_match.match?(/\s+\z/) ? indented(full_erb_tag) : full_erb_tag)
end

So the issue here is that the yield tag should be handled in else I believe, but it's being handled in when RUBY_OPEN_BLOCK
I tried replicating the code in else into a when right at the start, where this one checks if the tag starts with yield:

 when /\Ayield\b/ 
   ruby_code = format_ruby(ruby_code, autoclose: false) 
   full_erb_tag = "#{erb_open}#{ruby_code} #{erb_close}" 
   html << (erb_pre_match.match?(/\s+\z/) ? indented(full_erb_tag) : full_erb_tag) 

So final code looked like this:

 case ruby_code 
 when /\Ayield\b/ 
   ruby_code = format_ruby(ruby_code, autoclose: false) 
   full_erb_tag = "#{erb_open}#{ruby_code} #{erb_close}" 
   html << (erb_pre_match.match?(/\s+\z/) ? indented(full_erb_tag) : full_erb_tag) 
 when RUBY_CLOSE_BLOCK 
   full_erb_tag = "#{erb_open}#{ruby_code} #{erb_close}" 
   ...

The formatter seemed to start working correctly
I'm not sure if this solution is generic enough to cover all cases though
Also, I'm sure it's not the cleanest way to handle this case for sure :)

@IbraheemTuffaha
Copy link
Contributor

I'm facing a similar issue when there's a ruby code with next unless:

<% flash.each do |type, message| %>
  <% next unless message.is_a?(String) %>
  <div ... >
    ...
  </div>
<% end %>

For some reason, erb-formatter thinks that the next unless statement is an opening tag and pushed the whole div inside one tab

@edusurf10
Copy link

what solution for this problem?

@lakim
Copy link

lakim commented Jun 14, 2024

I have the same issue with yield.
It's very weird, because I thought it was working before. But when I install previous versions up to 0.5.0, I have the same error.

@elia
Copy link
Member

elia commented Jun 14, 2024

@IbraheemTuffaha could you please send a PR with your solution? I can't fix it right now, and I'm happy to accept it, even if it's not "optimal" and only improves the situation. 🙏

@lakim
Copy link

lakim commented Jun 14, 2024

I've tried your branch @IbraheemTuffaha and I confirm that it fixes my issue. 🙏

@anthmatic
Copy link

anthmatic commented Jun 18, 2024

Just wanted to add that I'm also having the same issue with when tags:

<% when "something" %>

causes this error:

Failed in line 37 ==> ERROR: Unmatched close tag, tried with ["div", "</div>"], but ["%erb%", "when \\"something\\""] was on the stack

@IbraheemTuffaha
Copy link
Contributor

Just wanted to add that I'm also having the same issue with when tags:

<% when "something" %>

causes this error:

Failed in line 37 ==> ERROR: Unmatched close tag, tried with ["div", "</div>"], but ["%erb%", "when \\"something\\""] was on the stack

@anthmatic
It should be correctly handled here:

when RUBY_REOPEN_BLOCK

Which is defined here:
RUBY_REOPEN_BLOCK = /\A(else|elsif\b(.*)|when\b(.*))\z/

Are you sure you closed the whole case statement properly?

<% case var %>
<% when "bar" %>
  ...
<% when "foo" %>
  ...
<% end %>

@lakim
Copy link

lakim commented Jun 23, 2024

Just wanted to add that I'm also having the same issue with when tags:

<% when "something" %>

causes this error:

Failed in line 37 ==> ERROR: Unmatched close tag, tried with ["div", "</div>"], but ["%erb%", "when \\"something\\""] was on the stack

I also had issues with case/when, and this was the only syntax that worked:

<% case var
   when "bar" %>
  ...
<% when "foo" %>
  ...
<% end %>

But it now seems to work with @IbraheemTuffaha 's PR.

@elia do you think you can merge it?

@IbraheemTuffaha
Copy link
Contributor

Should be closed now after #53 is merged?

@elia
Copy link
Member

elia commented Jun 24, 2024

Fixed by #53

@elia elia closed this as completed Jun 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants