diff --git a/curlylint/ast.py b/curlylint/ast.py
index a4ec33f..8581d6a 100644
--- a/curlylint/ast.py
+++ b/curlylint/ast.py
@@ -197,25 +197,10 @@ def __str__(self):
@attr.s(frozen=True)
class JinjaOptionalContainer(Jinja):
- first_opening_if = attr.ib() # JinjaTag
- opening_tag = attr.ib() # OpeningTag
- first_closing_if = attr.ib() # JinjaTag
- content = attr.ib() # Interpolated
- second_opening_if = attr.ib() # JinjaTag
- closing_tag = attr.ib() # ClosingTag
- second_closing_if = attr.ib() # JinjaTag
+ nodes = attr.ib(factory=list)
def __str__(self):
- nodes = [
- self.first_opening_if,
- self.opening_tag,
- self.first_closing_if,
- self.content,
- self.second_opening_if,
- self.closing_tag,
- self.second_closing_if,
- ]
- return "".join(str(n) for n in nodes)
+ return "".join(str(n) for n in self.nodes)
@attr.s(frozen=True)
diff --git a/curlylint/parse.py b/curlylint/parse.py
index f66a8fa..5451f0e 100644
--- a/curlylint/parse.py
+++ b/curlylint/parse.py
@@ -522,16 +522,7 @@ def make_raw_text_element_parser(config, tag_name, jinja):
def _combine_optional_container(locations, nodes):
- return JinjaOptionalContainer(
- first_opening_if=nodes[0],
- opening_tag=nodes[1],
- first_closing_if=nodes[2],
- content=nodes[3],
- second_opening_if=nodes[4],
- closing_tag=nodes[5],
- second_closing_if=nodes[6],
- **locations,
- )
+ return JinjaOptionalContainer(nodes=nodes, **locations)
# Awkward hack to handle optional HTML containers, for example:
@@ -544,10 +535,21 @@ def _combine_optional_container(locations, nodes):
#
# {% endif %}
#
-# Currently, this only works with `if` statements and the two conditions
-# must be exactly the same.
+# OR
+#
+# {% if a %}
+#
+# {% else %}
+#
+# {% endif %}
+# foo
+#
+#
+# Currently, this only works with `if` statements. The two conditions
+# must be exactly the same in the first case.
def make_jinja_optional_container_parser(config, content, jinja):
jinja_if = make_jinja_tag_parser(P.string("if"))
+ jinja_else = make_jinja_tag_parser(P.string("else"))
jinja_endif = make_jinja_tag_parser(P.string("endif"))
opening_tag = make_opening_tag_parser(config, jinja, allow_slash=False)
@@ -582,7 +584,39 @@ def opt_container_impl():
c_second_if_node,
]
- return locate(opt_container_impl).combine(_combine_optional_container)
+ @P.generate
+ def ifelse_opt_container_impl():
+ o_if_node = yield jinja_if.skip(whitespace)
+ o_first_tag_node = yield opening_tag.skip(whitespace)
+ o_else_node = yield jinja_else.skip(whitespace)
+ o_last_tag_node = yield opening_tag.skip(whitespace)
+ if o_last_tag_node.name != o_first_tag_node.name:
+ yield P.fail(
+ "Expected '" + o_first_tag_node.name + "' to be in else block"
+ )
+ return
+ o_endif_node = yield jinja_endif.skip(whitespace)
+ html_tag_name = o_first_tag_node.name
+ if isinstance(html_tag_name, str):
+ closing_tag = make_closing_tag_parser(P.string(html_tag_name))
+ else:
+ assert isinstance(html_tag_name, Jinja)
+ closing_tag = make_closing_tag_parser(jinja)
+ content_nodes = yield content
+ c_tag_node = yield closing_tag
+ return [
+ o_if_node,
+ o_first_tag_node,
+ o_else_node,
+ o_last_tag_node,
+ o_endif_node,
+ content_nodes,
+ c_tag_node,
+ ]
+
+ return locate(opt_container_impl).combine(
+ _combine_optional_container
+ ) | locate(ifelse_opt_container_impl).combine(_combine_optional_container)
def make_jinja_parser(config, content):
diff --git a/curlylint/parse_test.py b/curlylint/parse_test.py
index 3527c10..7fff2c6 100644
--- a/curlylint/parse_test.py
+++ b/curlylint/parse_test.py
@@ -325,6 +325,36 @@ def test_optional_container():
src = '{% if a %}
{% endif %}cd{% if a %}{% endif %}'
assert src == str(content.parse(src))
+ src = "{% if a %}
{% else %}
{% endif %}
"
+ assert src == str(content.parse(src))
+
+ src = "{% if a %}
{% else %}
{% endif %}
"
+ assert src == str(content.parse(src))
+
+ src = (
+ "{% if a %}
{% else %}
{% endif %}
{% if a %}
"
+ "{% endif %}foobar{% if a %}
{% endif %}"
+ )
+ assert src == str(content.parse(src))
+
+ src = (
+ "{% if a %}
{% endif %}foobar{% if a %}
{% endif %}{% if a %}"
+ "
{% else %}
{% endif %}
"
+ )
+ assert src == str(content.parse(src))
+
+ src = (
+ "{% if a %}
{% endif %}foobar{% if a %}
{% endif %}{% if a %}"
+ "
{% else %}
"
+ )
+ assert src == str(content.parse(src))
+
+ src = (
+ "{% if a %}
{% endif %}foobar{% if a %}
{% endif %}{% if a %}"
+ "
{% else %}
"
+ )
+ assert src == str(content.parse(src))
+
src = """
{% if a %}
{% endif %}
c d