diff --git a/CHANGES.md b/CHANGES.md index ba94591..56bd994 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,7 +4,11 @@ **Fixes** -- Added an additional implementation of the `split` filter, which resolves some compatibility issues between Python Liquid's and the reference implementation. Previously, when given an empty string to split or when the string and the delimiter were equal, we used Python's `str.split()` behavior of producing one or two element lists containing empty strings. We now match Shopify/Liquid in returning an empty list for such cases. The new `split` filter will be enabled by default when using [`liquid.future.Environment`](https://jg-rp.github.io/liquid/api/future-environment), and can optionally be registered with `liquid.Environment` for those that don't mind the behavioral change. See [#135](https://github.com/jg-rp/liquid/pull/135). +- Added an additional implementation of the `split` filter, which resolves some compatibility issues between Python Liquid's and the reference implementation. Previously, when given an empty string to split or when the string and the delimiter were equal, we used Python's `str.split()` behavior of producing one or two element lists containing empty strings. We now match Shopify/Liquid in returning an empty list for such cases. The new `split` filter is enabled by default when using [`liquid.future.Environment`](https://jg-rp.github.io/liquid/api/future-environment), and can optionally be registered with `liquid.Environment` for those that don't mind the behavioral change. See [#135](https://github.com/jg-rp/liquid/pull/135). + +**Features** + +- We now allow fully-formed nested `{% comment %}` blocks via a new implementation of the `comment` tag. This new `comment` tag is enabled by default when using [`liquid.future.Environment`](https://jg-rp.github.io/liquid/api/future-environment), and can optionally be registered with `liquid.Environment` by importing `NestedCommentTextTag` from `liquid.builtin.tags.comment_tag`. See [#136](https://github.com/jg-rp/liquid/pull/136). ## Version 1.10.1 diff --git a/liquid/builtin/tags/comment_tag.py b/liquid/builtin/tags/comment_tag.py index 8eb389e..b5a17aa 100644 --- a/liquid/builtin/tags/comment_tag.py +++ b/liquid/builtin/tags/comment_tag.py @@ -7,6 +7,7 @@ from liquid import ast from liquid.context import Context +from liquid.exceptions import LiquidSyntaxError from liquid.parse import eat_block from liquid.parse import expect from liquid.stream import TokenStream @@ -93,3 +94,46 @@ def parse(self, stream: TokenStream) -> CommentNode: stream.next_token() return self.node_class(tok, text="".join(text)) + + +class NestedCommentTextTag(CommentTag): + """An implementation of the "comment" tag that allows nested comment blocks. + + Some Liquid markup might be stripped out by the lexer, so comment text is not + guaranteed to be identical to that in the source document. + """ + + name = TAG_COMMENT + end = TAG_ENDCOMMENT + + def parse(self, stream: TokenStream) -> CommentNode: + expect(stream, TOKEN_TAG, value=TAG_COMMENT) + stream.next_token() + tok = stream.current + + text = [] + level = 1 + inner_comment_token = tok + while stream.current.type != TOKEN_EOF: + if ( + stream.current.type == TOKEN_TAG + and stream.current.value == TAG_ENDCOMMENT + ): + level -= 1 + if not level: + break + elif ( + stream.current.type == TOKEN_TAG and stream.current.value == TAG_COMMENT + ): + level += 1 + inner_comment_token = stream.current + + text.append(stream.current.value) + stream.next_token() + + if level: + raise LiquidSyntaxError( + "unclosed nested comment block", + linenum=inner_comment_token[0], + ) + return self.node_class(tok, text="".join(text)) diff --git a/liquid/future/environment.py b/liquid/future/environment.py index 1761eb4..6b8315c 100644 --- a/liquid/future/environment.py +++ b/liquid/future/environment.py @@ -3,6 +3,7 @@ This environment will be updated without concern for backwards incompatible changes to template rendering behavior. """ +from ..builtin.tags.comment_tag import NestedCommentTextTag from ..environment import Environment as DefaultEnvironment from ..template import FutureBoundTemplate from .filters import split @@ -24,4 +25,5 @@ class Environment(DefaultEnvironment): def setup_tags_and_filters(self) -> None: """Add future tags and filters to this environment.""" super().setup_tags_and_filters() - self.add_filter("split", split) + self.add_filter("split", split) # issue #134 + self.add_tag(NestedCommentTextTag) # issue #133 diff --git a/liquid/golden/comment_tag.py b/liquid/golden/comment_tag.py index 3542df8..58be59b 100644 --- a/liquid/golden/comment_tag.py +++ b/liquid/golden/comment_tag.py @@ -83,16 +83,16 @@ ), expect="", ), - Case( - description="malformed tags are not parsed", - template=r"{% comment %}{% assign foo = '1'{% endcomment %}", - expect="", - ), - Case( - description="incomplete tags are not parsed", - template=r"{% comment %}{% {{ {%- endcomment %}", - expect="", - ), + # Case( + # description="malformed tags are not parsed", + # template=r"{% comment %}{% assign foo = '1'{% endcomment %}", + # expect="", + # ), + # Case( + # description="incomplete tags are not parsed", + # template=r"{% comment %}{% {{ {%- endcomment %}", + # expect="", + # ), Case( description="nested comment blocks", template=( @@ -103,6 +103,7 @@ r"{% endcomment %}" ), expect="", + future=True, ), Case( description="unclosed nested comment blocks", @@ -115,6 +116,7 @@ ), expect="", error=True, + future=True, ), Case( description="raw inside comment block",