markup_fmt
markup_fmt copied to clipboard
Fail to format conditional open/close tag pairs
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 ?
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.
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)
That will be nice.
Do you have any pointers about where I should look to do such change ?
Maybe the parser. We can try parsing as normal elements, but fall back to text node if it fails.
I'll try to find if I can figure this out, will keep you posted. Thanks
Struggling a bit with this one, if you find some time to look at it, it would be awesome @g-plane