python-liquid 2.3.6__py3-none-any.whl → 3.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- liquid/__about__.py +1 -0
- liquid/__init__.py +161 -187
- liquid/_base_tag.py +66 -0
- liquid/{utils/chain_map.py → _chain_map.py} +18 -19
- liquid/_context.py +465 -0
- liquid/_drop.py +108 -0
- liquid/_filter.py +174 -0
- liquid/_io.py +18 -0
- liquid/_lax_parser_mixin.py +100 -0
- liquid/_lexer.py +93 -0
- liquid/_lexer_extended.py +623 -0
- liquid/_lexer_legacy.py +536 -0
- liquid/_loader.py +84 -0
- liquid/{utils/lru_cache.py → _lru_cache.py} +28 -36
- liquid/_markup.py +253 -0
- liquid/_messages.py +292 -0
- liquid/_missing.py +3 -0
- liquid/_nothing.py +28 -0
- liquid/_parser.py +460 -0
- liquid/_parser_extended.py +293 -0
- liquid/_parser_legacy.py +819 -0
- liquid/_resource_limits.py +50 -0
- liquid/_slice.py +41 -0
- liquid/_static_analysis.py +503 -0
- liquid/_strftime.py +186 -0
- liquid/_template.py +536 -0
- liquid/drops/__init__.py +20 -0
- liquid/drops/forloop.py +78 -0
- liquid/drops/iterable.py +25 -0
- liquid/drops/range.py +76 -0
- liquid/drops/self_.py +45 -0
- liquid/drops/tablerowloop.py +142 -0
- liquid/drops/undefined.py +228 -0
- liquid/environment.py +717 -551
- liquid/exceptions.py +67 -214
- liquid/expressions.py +1184 -0
- liquid/filters/__init__.py +134 -0
- liquid/filters/abs.py +7 -0
- liquid/filters/append.py +5 -0
- liquid/filters/at_least.py +9 -0
- liquid/filters/at_most.py +9 -0
- liquid/filters/babel.py +560 -0
- liquid/filters/base64.py +26 -0
- liquid/filters/capitalize.py +5 -0
- liquid/filters/ceil.py +8 -0
- liquid/filters/compact.py +25 -0
- liquid/filters/concat.py +11 -0
- liquid/filters/date.py +27 -0
- liquid/filters/default.py +25 -0
- liquid/filters/divided_by.py +21 -0
- liquid/filters/downcase.py +5 -0
- liquid/filters/escape.py +56 -0
- liquid/filters/find.py +56 -0
- liquid/filters/first.py +19 -0
- liquid/filters/floor.py +8 -0
- liquid/filters/html.py +23 -0
- liquid/filters/index.py +12 -0
- liquid/filters/join.py +13 -0
- liquid/filters/json_.py +30 -0
- liquid/filters/last.py +17 -0
- liquid/filters/map.py +5 -0
- liquid/filters/minus.py +13 -0
- liquid/filters/modulo.py +18 -0
- liquid/filters/newline_to_br.py +16 -0
- liquid/filters/plus.py +13 -0
- liquid/filters/prepend.py +5 -0
- liquid/filters/reject.py +19 -0
- liquid/filters/remove.py +36 -0
- liquid/filters/replace.py +32 -0
- liquid/filters/reverse.py +5 -0
- liquid/filters/round.py +35 -0
- liquid/filters/size.py +25 -0
- liquid/filters/slice.py +39 -0
- liquid/filters/sort.py +148 -0
- liquid/filters/split.py +34 -0
- liquid/filters/squish.py +9 -0
- liquid/filters/strip.py +13 -0
- liquid/filters/strip_html.py +19 -0
- liquid/filters/strip_newlines.py +17 -0
- liquid/filters/sum.py +21 -0
- liquid/filters/times.py +13 -0
- liquid/filters/translate.py +380 -0
- liquid/filters/truncate.py +39 -0
- liquid/filters/uniq.py +11 -0
- liquid/filters/upcase.py +5 -0
- liquid/filters/url.py +18 -0
- liquid/filters/where.py +18 -0
- liquid/loaders/__init__.py +17 -0
- liquid/loaders/caching_file_system_loader.py +64 -0
- liquid/loaders/choice_loader.py +93 -0
- liquid/loaders/dict_loader.py +56 -0
- liquid/{builtin/loaders → loaders}/file_system_loader.py +51 -55
- liquid/{builtin/loaders → loaders}/mixins.py +39 -51
- liquid/loaders/package_loader.py +110 -0
- liquid/tags/__init__.py +61 -0
- liquid/tags/assign.py +68 -0
- liquid/tags/capture.py +83 -0
- liquid/tags/case.py +199 -0
- liquid/tags/comment.py +56 -0
- liquid/tags/cycle.py +131 -0
- liquid/tags/decrement.py +55 -0
- liquid/tags/doc.py +56 -0
- liquid/tags/echo.py +65 -0
- liquid/tags/else_.py +53 -0
- liquid/tags/error.py +51 -0
- liquid/tags/extends.py +448 -0
- liquid/tags/for_.py +421 -0
- liquid/tags/if_.py +156 -0
- liquid/tags/ifchanged.py +69 -0
- liquid/tags/include.py +223 -0
- liquid/tags/increment.py +55 -0
- liquid/tags/inline_comment.py +70 -0
- liquid/tags/liquid.py +56 -0
- liquid/tags/macro.py +281 -0
- liquid/tags/output.py +58 -0
- liquid/tags/raw.py +60 -0
- liquid/tags/render.py +245 -0
- liquid/tags/tablerow.py +254 -0
- liquid/tags/template_comment.py +56 -0
- liquid/tags/translate.py +316 -0
- liquid/tags/unless.py +121 -0
- liquid/tags/with_.py +83 -0
- liquid/tokens.py +370 -0
- {python_liquid-2.3.6.dist-info → python_liquid-3.0.0.dist-info}/METADATA +32 -39
- python_liquid-3.0.0.dist-info/RECORD +128 -0
- {python_liquid-2.3.6.dist-info → python_liquid-3.0.0.dist-info}/WHEEL +1 -1
- {python_liquid-2.3.6.dist-info → python_liquid-3.0.0.dist-info}/licenses/LICENSE +1 -1
- liquid/analyze_tags.py +0 -214
- liquid/ast.py +0 -252
- liquid/builtin/__init__.py +0 -203
- liquid/builtin/content.py +0 -41
- liquid/builtin/drops/__init__.py +0 -3
- liquid/builtin/drops/drops.py +0 -13
- liquid/builtin/expressions/__init__.py +0 -47
- liquid/builtin/expressions/_tokenize.py +0 -186
- liquid/builtin/expressions/arguments.py +0 -207
- liquid/builtin/expressions/filtered.py +0 -387
- liquid/builtin/expressions/logical.py +0 -672
- liquid/builtin/expressions/loop.py +0 -275
- liquid/builtin/expressions/path.py +0 -163
- liquid/builtin/expressions/primitive.py +0 -417
- liquid/builtin/filters/__init__.py +0 -0
- liquid/builtin/filters/array.py +0 -329
- liquid/builtin/filters/extra.py +0 -83
- liquid/builtin/filters/math.py +0 -129
- liquid/builtin/filters/misc.py +0 -137
- liquid/builtin/filters/string.py +0 -416
- liquid/builtin/illegal.py +0 -28
- liquid/builtin/loaders/__init__.py +0 -0
- liquid/builtin/loaders/caching_file_system_loader.py +0 -61
- liquid/builtin/loaders/choice_loader.py +0 -94
- liquid/builtin/loaders/dict_loader.py +0 -64
- liquid/builtin/loaders/package_loader.py +0 -132
- liquid/builtin/output.py +0 -74
- liquid/builtin/tags/__init__.py +0 -0
- liquid/builtin/tags/assign_tag.py +0 -75
- liquid/builtin/tags/capture_tag.py +0 -98
- liquid/builtin/tags/case_tag.py +0 -287
- liquid/builtin/tags/comment_tag.py +0 -77
- liquid/builtin/tags/cycle_tag.py +0 -132
- liquid/builtin/tags/decrement_tag.py +0 -59
- liquid/builtin/tags/doc_tag.py +0 -68
- liquid/builtin/tags/echo_tag.py +0 -45
- liquid/builtin/tags/for_tag.py +0 -337
- liquid/builtin/tags/if_tag.py +0 -209
- liquid/builtin/tags/ifchanged_tag.py +0 -94
- liquid/builtin/tags/include_tag.py +0 -251
- liquid/builtin/tags/increment_tag.py +0 -60
- liquid/builtin/tags/inline_comment_tag.py +0 -47
- liquid/builtin/tags/liquid_tag.py +0 -183
- liquid/builtin/tags/render_tag.py +0 -371
- liquid/builtin/tags/tablerow_tag.py +0 -320
- liquid/builtin/tags/unless_tag.py +0 -218
- liquid/context.py +0 -615
- liquid/expression.py +0 -41
- liquid/extra/__init__.py +0 -98
- liquid/extra/filters/__init__.py +0 -33
- liquid/extra/filters/_json.py +0 -33
- liquid/extra/filters/array.py +0 -60
- liquid/extra/filters/babel.py +0 -552
- liquid/extra/filters/html.py +0 -32
- liquid/extra/filters/translate.py +0 -448
- liquid/extra/tags/__init__.py +0 -17
- liquid/extra/tags/_with.py +0 -80
- liquid/extra/tags/extends_tag.py +0 -576
- liquid/extra/tags/macro_tag.py +0 -270
- liquid/extra/tags/snippet_tag.py +0 -107
- liquid/extra/tags/translate_tag.py +0 -388
- liquid/filter.py +0 -230
- liquid/future/__init__.py +0 -3
- liquid/future/environment.py +0 -30
- liquid/future/filters/__init__.py +0 -1
- liquid/future/tags/__init__.py +0 -1
- liquid/lex.py +0 -260
- liquid/limits.py +0 -66
- liquid/loader.py +0 -141
- liquid/messages.py +0 -357
- liquid/mode.py +0 -12
- liquid/output.py +0 -35
- liquid/parser.py +0 -119
- liquid/span.py +0 -35
- liquid/static_analysis.py +0 -443
- liquid/stream.py +0 -148
- liquid/stringify.py +0 -31
- liquid/tag.py +0 -47
- liquid/template.py +0 -658
- liquid/token.py +0 -145
- liquid/undefined.py +0 -218
- liquid/utils/__init__.py +0 -15
- liquid/utils/html.py +0 -57
- liquid/utils/text.py +0 -28
- python_liquid-2.3.6.dist-info/RECORD +0 -96
liquid/extra/tags/macro_tag.py
DELETED
|
@@ -1,270 +0,0 @@
|
|
|
1
|
-
"""The built-in `macro` and `call` tags."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import itertools
|
|
6
|
-
from dataclasses import dataclass
|
|
7
|
-
from typing import TYPE_CHECKING
|
|
8
|
-
from typing import Iterable
|
|
9
|
-
from typing import Optional
|
|
10
|
-
from typing import TextIO
|
|
11
|
-
from typing import Union
|
|
12
|
-
|
|
13
|
-
from liquid.ast import BlockNode
|
|
14
|
-
from liquid.ast import Node
|
|
15
|
-
from liquid.builtin.expressions import Identifier
|
|
16
|
-
from liquid.builtin.expressions import KeywordArgument
|
|
17
|
-
from liquid.builtin.expressions import Parameter
|
|
18
|
-
from liquid.builtin.expressions import parse_arguments
|
|
19
|
-
from liquid.builtin.expressions import parse_name
|
|
20
|
-
from liquid.parser import get_parser
|
|
21
|
-
from liquid.tag import Tag
|
|
22
|
-
from liquid.token import TOKEN_TAG
|
|
23
|
-
from liquid.undefined import Undefined
|
|
24
|
-
from liquid.undefined import is_undefined
|
|
25
|
-
|
|
26
|
-
if TYPE_CHECKING:
|
|
27
|
-
from liquid import Expression
|
|
28
|
-
from liquid import RenderContext
|
|
29
|
-
from liquid import Token
|
|
30
|
-
from liquid import TokenStream
|
|
31
|
-
from liquid.builtin.expressions import PositionalArgument
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
@dataclass
|
|
35
|
-
class Macro:
|
|
36
|
-
"""A macro's arguments and associated block."""
|
|
37
|
-
|
|
38
|
-
args: dict[str, Parameter]
|
|
39
|
-
block: BlockNode
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
@dataclass
|
|
43
|
-
class BoundArgs:
|
|
44
|
-
"""Expressions bound to the evaluation of a `call` tag."""
|
|
45
|
-
|
|
46
|
-
args: dict[str, Optional[Expression]]
|
|
47
|
-
excess_args: list[Expression]
|
|
48
|
-
excess_kwargs: dict[str, Expression]
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
class MacroNode(Node):
|
|
52
|
-
"""The built-in _macro_ tag."""
|
|
53
|
-
|
|
54
|
-
__slots__ = ("name", "args", "block")
|
|
55
|
-
|
|
56
|
-
def __init__(
|
|
57
|
-
self,
|
|
58
|
-
token: Token,
|
|
59
|
-
name: str,
|
|
60
|
-
args: dict[str, Parameter],
|
|
61
|
-
block: BlockNode,
|
|
62
|
-
):
|
|
63
|
-
super().__init__(token)
|
|
64
|
-
self.name = name
|
|
65
|
-
self.args = args
|
|
66
|
-
self.block = block
|
|
67
|
-
self.blank = True
|
|
68
|
-
|
|
69
|
-
def __str__(self) -> str:
|
|
70
|
-
args = " " + ", ".join(str(p) for p in self.args.values()) if self.args else ""
|
|
71
|
-
return f"{{% macro {self.name}{args} %}}{self.block}{{% endmacro %}}"
|
|
72
|
-
|
|
73
|
-
def render_to_output(self, context: RenderContext, _buffer: TextIO) -> int:
|
|
74
|
-
"""Render the node to the output buffer."""
|
|
75
|
-
# Macro tags don't render or evaluate anything, just store their arguments list
|
|
76
|
-
# and block on the render context so it can be called later by a `call` tag.
|
|
77
|
-
context.tag_namespace["macros"][self.name] = Macro(
|
|
78
|
-
args=self.args, block=self.block
|
|
79
|
-
)
|
|
80
|
-
return 0
|
|
81
|
-
|
|
82
|
-
def expressions(self) -> Iterable[Expression]:
|
|
83
|
-
"""Return this node's expressions."""
|
|
84
|
-
yield from (arg.value for arg in self.args.values() if arg.value)
|
|
85
|
-
|
|
86
|
-
def children(
|
|
87
|
-
self,
|
|
88
|
-
static_context: RenderContext, # noqa: ARG002
|
|
89
|
-
*,
|
|
90
|
-
include_partials: bool = True, # noqa: ARG002
|
|
91
|
-
) -> Iterable[Node]:
|
|
92
|
-
"""Return this node's children."""
|
|
93
|
-
yield self.block
|
|
94
|
-
|
|
95
|
-
def block_scope(self) -> Iterable[Identifier]:
|
|
96
|
-
"""Return variables this node adds to the node's block scope."""
|
|
97
|
-
yield Identifier("args", token=self.token)
|
|
98
|
-
yield Identifier("kwargs", token=self.token)
|
|
99
|
-
yield from (Identifier(p.name, token=p.token) for p in self.args.values())
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
class MacroTag(Tag):
|
|
103
|
-
"""The built-in _macro_ tag."""
|
|
104
|
-
|
|
105
|
-
name = "macro"
|
|
106
|
-
node_class = MacroNode
|
|
107
|
-
|
|
108
|
-
def parse(self, stream: TokenStream) -> Node:
|
|
109
|
-
"""Parse tokens from _stream_ into an AST node."""
|
|
110
|
-
token = stream.eat(TOKEN_TAG)
|
|
111
|
-
tokens = stream.into_inner(tag=token)
|
|
112
|
-
name = parse_name(self.env, tokens)
|
|
113
|
-
args = Parameter.parse(self.env, tokens)
|
|
114
|
-
block = get_parser(self.env).parse_block(stream, ("endmacro",))
|
|
115
|
-
stream.expect(TOKEN_TAG, "endmacro")
|
|
116
|
-
return self.node_class(token, name, args, block)
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
class CallNode(Node):
|
|
120
|
-
"""The built-in _call_ tag."""
|
|
121
|
-
|
|
122
|
-
__slots__ = ("name", "args", "kwargs")
|
|
123
|
-
disabled_tags = ["include", "block"]
|
|
124
|
-
|
|
125
|
-
def __init__(
|
|
126
|
-
self,
|
|
127
|
-
token: Token,
|
|
128
|
-
name: str,
|
|
129
|
-
args: list[PositionalArgument],
|
|
130
|
-
kwargs: list[KeywordArgument],
|
|
131
|
-
) -> None:
|
|
132
|
-
super().__init__(token)
|
|
133
|
-
self.name = name
|
|
134
|
-
self.args = args
|
|
135
|
-
self.kwargs = kwargs
|
|
136
|
-
self.blank = False
|
|
137
|
-
|
|
138
|
-
def __str__(self) -> str:
|
|
139
|
-
args = " " + ", ".join(
|
|
140
|
-
[*(str(arg) for arg in self.args), *(str(arg) for arg in self.kwargs)]
|
|
141
|
-
)
|
|
142
|
-
return f"{{% call {self.name}{args} %}}"
|
|
143
|
-
|
|
144
|
-
def render_to_output(self, context: RenderContext, buffer: TextIO) -> int:
|
|
145
|
-
"""Render the node to the output buffer."""
|
|
146
|
-
macro: Union[Macro, Undefined] = context.tag_namespace["macros"].get(
|
|
147
|
-
self.name, context.env.undefined(self.name, token=self.token)
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
if isinstance(macro, Undefined):
|
|
151
|
-
return buffer.write(str(macro))
|
|
152
|
-
|
|
153
|
-
args = self.macro_args(macro)
|
|
154
|
-
|
|
155
|
-
namespace: dict[str, object] = {
|
|
156
|
-
"args": [expr.evaluate(context) for expr in args.excess_args],
|
|
157
|
-
"kwargs": {
|
|
158
|
-
name: expr.evaluate(context)
|
|
159
|
-
for name, expr in args.excess_kwargs.items()
|
|
160
|
-
},
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
for name, expr in args.args.items():
|
|
164
|
-
if expr is None:
|
|
165
|
-
namespace[name] = context.env.undefined(name, token=self.token)
|
|
166
|
-
else:
|
|
167
|
-
namespace[name] = expr.evaluate(context)
|
|
168
|
-
|
|
169
|
-
macro_context = context.copy(
|
|
170
|
-
namespace=namespace,
|
|
171
|
-
disabled_tags=self.disabled_tags,
|
|
172
|
-
carry_loop_iterations=True,
|
|
173
|
-
)
|
|
174
|
-
|
|
175
|
-
return macro.block.render(macro_context, buffer)
|
|
176
|
-
|
|
177
|
-
async def render_to_output_async(
|
|
178
|
-
self,
|
|
179
|
-
context: RenderContext,
|
|
180
|
-
buffer: TextIO,
|
|
181
|
-
) -> int:
|
|
182
|
-
"""Render the node to the output buffer."""
|
|
183
|
-
macro: Union[Macro, Undefined] = context.tag_namespace["macros"].get(
|
|
184
|
-
self.name, context.env.undefined(self.name, token=self.token)
|
|
185
|
-
)
|
|
186
|
-
|
|
187
|
-
if is_undefined(macro):
|
|
188
|
-
return buffer.write(str(macro))
|
|
189
|
-
|
|
190
|
-
assert isinstance(macro, Macro)
|
|
191
|
-
args = self.macro_args(macro)
|
|
192
|
-
|
|
193
|
-
namespace: dict[str, object] = {
|
|
194
|
-
"args": [await expr.evaluate_async(context) for expr in args.excess_args],
|
|
195
|
-
"kwargs": {
|
|
196
|
-
name: await expr.evaluate_async(context)
|
|
197
|
-
for name, expr in args.excess_kwargs.items()
|
|
198
|
-
},
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
for name, expr in args.args.items():
|
|
202
|
-
if expr is None:
|
|
203
|
-
namespace[name] = context.env.undefined(name, token=self.token)
|
|
204
|
-
else:
|
|
205
|
-
namespace[name] = await expr.evaluate_async(context)
|
|
206
|
-
|
|
207
|
-
macro_context = context.copy(
|
|
208
|
-
namespace=namespace,
|
|
209
|
-
disabled_tags=self.disabled_tags,
|
|
210
|
-
carry_loop_iterations=True,
|
|
211
|
-
)
|
|
212
|
-
|
|
213
|
-
return await macro.block.render_async(macro_context, buffer)
|
|
214
|
-
|
|
215
|
-
def macro_args(self, macro: Macro) -> BoundArgs:
|
|
216
|
-
"""Bind this call's arguments to macro parameter names."""
|
|
217
|
-
args: dict[str, Optional[Expression]] = {
|
|
218
|
-
name: param.value for name, param in macro.args.items()
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
excess_args: list[Expression] = []
|
|
222
|
-
excess_kwargs: dict[str, Expression] = {}
|
|
223
|
-
|
|
224
|
-
# Bind positional arguments to names. If there are more positional arguments
|
|
225
|
-
# than names defined in the macro, they'll be stored in `excess_args`.
|
|
226
|
-
#
|
|
227
|
-
# We're effectively pushing kwargs to the end if they appear before positional
|
|
228
|
-
# arguments.
|
|
229
|
-
for name, expr in itertools.zip_longest(macro.args, self.args, fillvalue=None):
|
|
230
|
-
if name is None:
|
|
231
|
-
assert expr is not None
|
|
232
|
-
excess_args.append(expr.value)
|
|
233
|
-
continue
|
|
234
|
-
|
|
235
|
-
if expr is None:
|
|
236
|
-
break
|
|
237
|
-
|
|
238
|
-
args[name] = expr.value
|
|
239
|
-
|
|
240
|
-
for arg in self.kwargs:
|
|
241
|
-
if arg.name in macro.args:
|
|
242
|
-
# This has the potential to override a positional argument.
|
|
243
|
-
args[arg.name] = arg.value
|
|
244
|
-
else:
|
|
245
|
-
excess_kwargs[arg.name] = arg.value
|
|
246
|
-
|
|
247
|
-
return BoundArgs(
|
|
248
|
-
args=args, excess_args=excess_args, excess_kwargs=excess_kwargs
|
|
249
|
-
)
|
|
250
|
-
|
|
251
|
-
def expressions(self) -> Iterable[Expression]:
|
|
252
|
-
"""Return this node's expressions."""
|
|
253
|
-
yield from (arg.value for arg in self.args if arg.value)
|
|
254
|
-
yield from (arg.value for arg in self.kwargs if arg.value)
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
class CallTag(Tag):
|
|
258
|
-
"""The built-in _call_ tag."""
|
|
259
|
-
|
|
260
|
-
name = "call"
|
|
261
|
-
node_class = CallNode
|
|
262
|
-
block = False
|
|
263
|
-
|
|
264
|
-
def parse(self, stream: TokenStream) -> Node:
|
|
265
|
-
"""Parse tokens from _stream_ into an AST node."""
|
|
266
|
-
token = stream.eat(TOKEN_TAG)
|
|
267
|
-
tokens = stream.into_inner(tag=token, eat=False)
|
|
268
|
-
name = parse_name(self.env, tokens)
|
|
269
|
-
args, kwargs = parse_arguments(self.env, tokens)
|
|
270
|
-
return self.node_class(token, name, args, kwargs)
|
liquid/extra/tags/snippet_tag.py
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
"""The built-in _snippet_ tag.
|
|
2
|
-
|
|
3
|
-
New in Python Liquid version 2.2.0.
|
|
4
|
-
New in Shopify/liquid version 5.10.0.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from __future__ import annotations
|
|
8
|
-
|
|
9
|
-
from typing import TYPE_CHECKING
|
|
10
|
-
from typing import TextIO
|
|
11
|
-
|
|
12
|
-
from liquid.ast import BlockNode
|
|
13
|
-
from liquid.ast import Node
|
|
14
|
-
from liquid.builtin.expressions import parse_identifier
|
|
15
|
-
from liquid.parser import get_parser
|
|
16
|
-
from liquid.tag import Tag
|
|
17
|
-
from liquid.template import BoundTemplate
|
|
18
|
-
from liquid.token import TOKEN_EOF
|
|
19
|
-
from liquid.token import TOKEN_TAG
|
|
20
|
-
from liquid.token import Token
|
|
21
|
-
|
|
22
|
-
if TYPE_CHECKING:
|
|
23
|
-
from collections.abc import Iterable
|
|
24
|
-
|
|
25
|
-
from liquid.builtin.expressions import Identifier
|
|
26
|
-
from liquid.context import RenderContext
|
|
27
|
-
from liquid.stream import TokenStream
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class SnippetNode(Node):
|
|
31
|
-
"""The built-in _snippet_ tag."""
|
|
32
|
-
|
|
33
|
-
__slots__ = ("name", "block")
|
|
34
|
-
|
|
35
|
-
def __init__(self, token: Token, name: Identifier, block: BlockNode):
|
|
36
|
-
super().__init__(token)
|
|
37
|
-
self.name = name
|
|
38
|
-
self.block = block
|
|
39
|
-
|
|
40
|
-
def __str__(self) -> str:
|
|
41
|
-
return f"{{% snippet {self.name} %}}{self.block}{{% endsnippet %}}"
|
|
42
|
-
|
|
43
|
-
def render_to_output(self, context: RenderContext, buffer: TextIO) -> int: # noqa: ARG002
|
|
44
|
-
"""Render the node to the output buffer."""
|
|
45
|
-
# Don't render anything, just bind the block to its name.
|
|
46
|
-
context.assign(
|
|
47
|
-
self.name,
|
|
48
|
-
SnippetDrop(
|
|
49
|
-
context.env,
|
|
50
|
-
self.block.nodes,
|
|
51
|
-
context.template.name,
|
|
52
|
-
context.template.path,
|
|
53
|
-
),
|
|
54
|
-
)
|
|
55
|
-
return 0
|
|
56
|
-
|
|
57
|
-
def children(
|
|
58
|
-
self,
|
|
59
|
-
static_context: RenderContext, # noqa: ARG002
|
|
60
|
-
*,
|
|
61
|
-
include_partials: bool = True, # noqa: ARG002
|
|
62
|
-
) -> Iterable[Node]:
|
|
63
|
-
"""Return this node's children."""
|
|
64
|
-
# Snippets are only visited when rendered so we get accurate variable
|
|
65
|
-
# scope analysis.
|
|
66
|
-
static_context.assign(
|
|
67
|
-
self.name,
|
|
68
|
-
SnippetDrop(
|
|
69
|
-
static_context.env,
|
|
70
|
-
self.block.nodes,
|
|
71
|
-
static_context.template.name,
|
|
72
|
-
static_context.template.path,
|
|
73
|
-
),
|
|
74
|
-
)
|
|
75
|
-
return []
|
|
76
|
-
|
|
77
|
-
def template_scope(self) -> Iterable[Identifier]:
|
|
78
|
-
"""Return variables this node adds to the template local scope."""
|
|
79
|
-
yield self.name
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
class SnippetTag(Tag):
|
|
83
|
-
"""The built-in _snippet_ tag."""
|
|
84
|
-
|
|
85
|
-
block = True
|
|
86
|
-
name = "snippet"
|
|
87
|
-
end = "endsnippet"
|
|
88
|
-
node_class = SnippetNode
|
|
89
|
-
|
|
90
|
-
ENDSNIPPETBLOCK = frozenset((end, TOKEN_EOF))
|
|
91
|
-
|
|
92
|
-
def parse(self, stream: TokenStream) -> SnippetNode:
|
|
93
|
-
"""Parse tokens from _stream_ into an AST node."""
|
|
94
|
-
token = stream.eat(TOKEN_TAG)
|
|
95
|
-
tokens = stream.into_inner(tag=token)
|
|
96
|
-
name = parse_identifier(self.env, tokens)
|
|
97
|
-
tokens.expect_eos()
|
|
98
|
-
block = get_parser(self.env).parse_block(stream, self.ENDSNIPPETBLOCK)
|
|
99
|
-
stream.expect(TOKEN_TAG, value=self.end)
|
|
100
|
-
return self.node_class(token, name, block)
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
class SnippetDrop(BoundTemplate):
|
|
104
|
-
"""An template suitable for storing in a render context."""
|
|
105
|
-
|
|
106
|
-
def __str__(self) -> str:
|
|
107
|
-
return "SnippetDrop"
|