markup_fmt icon indicating copy to clipboard operation
markup_fmt copied to clipboard

Fail to format conditional open/close tag pairs

Open UnknownPlatypus opened this issue 10 months ago • 7 comments
trafficstars

markup_fmt curently fails to parse when some opening / close html pair are conditional.

This is not that uncommon, for example if you want to have an element that is conditionally collapsible, it would look like this, but it fails to parse:

<div>
  {% if is_collapsible %}<details><summary>{% endif %}
  <h2 class="inline-heading">
    {{ heading }}
  </h2>
  {% if is_collapsible %}</summary>{% endif %}

  {{ content }}

  {% if is_collapsible %}</details>{% endif %}
</div>

With that you end up with one the the two following valid html snippets:

<div>
  <h2 class="inline-heading">
    {{ heading }}
  </h2>
  {{ content }}
</div>

<div>
  <details><summary>
  <h2 class="inline-heading">
    {{ heading }}
  </h2>
  </summary>
  {{ content }}
  </details>
</div>
I've also seen this for conditional wrapping of inputs in a fieldset
{% if use_fieldset %}<fieldset>{% endif %}
  {% for field in fields %}
    {{ field.errors }}
    {{ field }}
  {% endfor %}
{% if use_fieldset %}</fieldset>{% endif %}
Or conditional wrapping of input in a label tag (important for checkboxes interactivity for ex)
<div>
  {% if widget.wrap_label %}
    <label {% if widget.attrs.id %}for="{{ widget.attrs.id }}"{% endif %}>
  {% endif %}

  <input type="{{ widget.type }}" name="{{ widget.name }}">

  {% if widget.wrap_label %}
    {{ widget.label }}</label>
  {% endif %}
</div>

Same for conditional optgroup etc

More generally, if you want to wrap some html into another tag conditionally, you will end up with this issue.

I'm not sure how to solve this, any good ideas @g-plane ?

UnknownPlatypus avatar Jan 15 '25 19:01 UnknownPlatypus

You're right. It's too hard and complicated to solve.

Out of the implementation, I personally discourage such code. This can't be easily understood, and neither Vue and Svelte nor other front-end template syntaxes support this case.

g-plane avatar Jan 16 '25 02:01 g-plane

I personally discourage such code

Same, it's hard to grasp.

But I tried running markup_fmt in the wild and found a bunch of these actually. The sad part is that even if a very tiny part of a template used that, the whole template cannot be parsed.

I was thinking maybe we could just output a text node in case there is incomplete HTML inside a if block ? That way we still validate the overall structure and ignore anything in these weird if blocks ? (but even that seems hard)

UnknownPlatypus avatar Jan 17 '25 11:01 UnknownPlatypus

That will be nice.

g-plane avatar Jan 17 '25 11:01 g-plane

Do you have any pointers about where I should look to do such change ?

UnknownPlatypus avatar Jan 17 '25 15:01 UnknownPlatypus

Maybe the parser. We can try parsing as normal elements, but fall back to text node if it fails.

g-plane avatar Jan 17 '25 15:01 g-plane

I'll try to find if I can figure this out, will keep you posted. Thanks

UnknownPlatypus avatar Jan 17 '25 15:01 UnknownPlatypus

Struggling a bit with this one, if you find some time to look at it, it would be awesome @g-plane

UnknownPlatypus avatar Jan 18 '25 13:01 UnknownPlatypus