python-fragments 0.22__py3-none-any.whl → 0.26__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.
- fragments/ast_nodes.py +50 -4
- fragments/grammar.py +15 -5
- fragments/html/elements.py +2 -1
- {python_fragments-0.22.dist-info → python_fragments-0.26.dist-info}/METADATA +1 -1
- {python_fragments-0.22.dist-info → python_fragments-0.26.dist-info}/RECORD +8 -8
- {python_fragments-0.22.dist-info → python_fragments-0.26.dist-info}/WHEEL +0 -0
- {python_fragments-0.22.dist-info → python_fragments-0.26.dist-info}/entry_points.txt +0 -0
- {python_fragments-0.22.dist-info → python_fragments-0.26.dist-info}/top_level.txt +0 -0
fragments/ast_nodes.py
CHANGED
|
@@ -241,7 +241,7 @@ class ASTComponent:
|
|
|
241
241
|
source_start: int = field(compare=False)
|
|
242
242
|
source_end: int = field(compare=False)
|
|
243
243
|
|
|
244
|
-
name:
|
|
244
|
+
name: "ASTComponentName"
|
|
245
245
|
arguments: dict[str, "ASTComponentArgument"]
|
|
246
246
|
children: Sequence["ASTHTMLChild"]
|
|
247
247
|
|
|
@@ -253,7 +253,8 @@ class ASTComponent:
|
|
|
253
253
|
|
|
254
254
|
def transpile(self, transpiled_start: int) -> None:
|
|
255
255
|
self.transpiled_start = transpiled_start
|
|
256
|
-
|
|
256
|
+
self.name.transpile(self.transpiled_start)
|
|
257
|
+
transpiled_start = self.name.transpiled_end + 2
|
|
257
258
|
for child in self.children:
|
|
258
259
|
child.transpile(transpiled_start)
|
|
259
260
|
transpiled_start = child.transpiled_end + 1
|
|
@@ -262,7 +263,7 @@ class ASTComponent:
|
|
|
262
263
|
children = ",".join(child.transpiled_content for child in self.children)
|
|
263
264
|
|
|
264
265
|
if len(self.arguments) == 0:
|
|
265
|
-
self.transpiled_content = self.__template__.format(self.name, children, "")
|
|
266
|
+
self.transpiled_content = self.__template__.format(self.name.transpiled_content, children, "")
|
|
266
267
|
self.transpiled_end = self.transpiled_start + len(self.transpiled_content)
|
|
267
268
|
return
|
|
268
269
|
|
|
@@ -272,10 +273,13 @@ class ASTComponent:
|
|
|
272
273
|
transpiled_start = attribute.transpiled_end + 1
|
|
273
274
|
|
|
274
275
|
attributes = ",".join(attribute.transpiled_content for attribute in self.arguments.values())
|
|
275
|
-
self.transpiled_content = self.__template__.format(self.name, children, attributes)
|
|
276
|
+
self.transpiled_content = self.__template__.format(self.name.transpiled_content, children, attributes)
|
|
276
277
|
self.transpiled_end = self.transpiled_start + len(self.transpiled_content)
|
|
277
278
|
|
|
278
279
|
def map_offset(self, offset: int) -> int | None:
|
|
280
|
+
if self.name.source_start < offset < self.name.source_end:
|
|
281
|
+
return self.name.map_offset(offset)
|
|
282
|
+
|
|
279
283
|
for attribute in self.arguments.values():
|
|
280
284
|
if attribute.source_start <= offset <= attribute.source_end:
|
|
281
285
|
return attribute.map_offset(offset)
|
|
@@ -287,6 +291,9 @@ class ASTComponent:
|
|
|
287
291
|
return None
|
|
288
292
|
|
|
289
293
|
def unmap_offset(self, offset: int) -> int | None:
|
|
294
|
+
if self.name.transpiled_start < offset < self.name.transpiled_end:
|
|
295
|
+
return self.name.unmap_offset(offset)
|
|
296
|
+
|
|
290
297
|
for attribute in self.arguments.values():
|
|
291
298
|
if attribute.transpiled_start <= offset <= attribute.transpiled_end:
|
|
292
299
|
return attribute.unmap_offset(offset)
|
|
@@ -298,6 +305,37 @@ class ASTComponent:
|
|
|
298
305
|
return None
|
|
299
306
|
|
|
300
307
|
|
|
308
|
+
@dataclass(slots=True)
|
|
309
|
+
class ASTComponentName:
|
|
310
|
+
source_start: int = field(compare=False)
|
|
311
|
+
source_end: int = field(compare=False)
|
|
312
|
+
|
|
313
|
+
name: str
|
|
314
|
+
|
|
315
|
+
transpiled_content: str = field(init=False)
|
|
316
|
+
transpiled_start: int = field(init=False)
|
|
317
|
+
transpiled_end: int = field(init=False)
|
|
318
|
+
|
|
319
|
+
def transpile(self, offset: int) -> None:
|
|
320
|
+
self.transpiled_start = offset
|
|
321
|
+
self.transpiled_content = self.name
|
|
322
|
+
self.transpiled_end = offset + len(self.name)
|
|
323
|
+
|
|
324
|
+
def map_offset(self, offset: int) -> int | None:
|
|
325
|
+
if self.source_start <= offset <= self.source_end:
|
|
326
|
+
specific_offset = offset - self.source_start
|
|
327
|
+
return self.transpiled_start + specific_offset
|
|
328
|
+
|
|
329
|
+
return None
|
|
330
|
+
|
|
331
|
+
def unmap_offset(self, offset: int) -> int | None:
|
|
332
|
+
if self.transpiled_start <= offset <= self.transpiled_end:
|
|
333
|
+
specific_offset = offset - self.transpiled_start
|
|
334
|
+
return self.source_start + specific_offset
|
|
335
|
+
|
|
336
|
+
return None
|
|
337
|
+
|
|
338
|
+
|
|
301
339
|
@dataclass(slots=True)
|
|
302
340
|
class ASTComponentArgument:
|
|
303
341
|
source_start: int = field(compare=False)
|
|
@@ -327,6 +365,10 @@ class ASTComponentArgument:
|
|
|
327
365
|
self.transpiled_end = self.transpiled_start + len(self.transpiled_content)
|
|
328
366
|
|
|
329
367
|
def map_offset(self, offset: int) -> int | None:
|
|
368
|
+
if self.source_start <= offset <= self.source_start + len(self.name):
|
|
369
|
+
specific_offset = offset - self.source_start
|
|
370
|
+
return self.transpiled_start + specific_offset
|
|
371
|
+
|
|
330
372
|
if self.interpolation is None:
|
|
331
373
|
return None
|
|
332
374
|
|
|
@@ -336,6 +378,10 @@ class ASTComponentArgument:
|
|
|
336
378
|
return None
|
|
337
379
|
|
|
338
380
|
def unmap_offset(self, offset: int) -> int | None:
|
|
381
|
+
if self.transpiled_start <= offset <= self.transpiled_start + len(self.name):
|
|
382
|
+
specific_offset = offset - self.transpiled_start
|
|
383
|
+
return self.source_start + specific_offset
|
|
384
|
+
|
|
339
385
|
if self.interpolation is None:
|
|
340
386
|
return None
|
|
341
387
|
|
fragments/grammar.py
CHANGED
|
@@ -4,6 +4,7 @@ import re
|
|
|
4
4
|
from fragments.ast_nodes import (
|
|
5
5
|
ASTComponent,
|
|
6
6
|
ASTComponentArgument,
|
|
7
|
+
ASTComponentName,
|
|
7
8
|
ASTControlNode,
|
|
8
9
|
ASTFragment,
|
|
9
10
|
ASTHTMLAttribute,
|
|
@@ -140,7 +141,7 @@ def expect_component(source: Source) -> tuple[Source, ASTComponent | ASTControlN
|
|
|
140
141
|
"""An pseudo-element that actually resolves into a user-defined function call."""
|
|
141
142
|
source_start = source.offset
|
|
142
143
|
source = expect_string(source, "<")
|
|
143
|
-
source, name =
|
|
144
|
+
source, name = expect_component_name(source)
|
|
144
145
|
source, _ = source.eat_whitespace()
|
|
145
146
|
|
|
146
147
|
arguments: dict[str, ASTComponentArgument] = {}
|
|
@@ -170,12 +171,12 @@ def expect_component(source: Source) -> tuple[Source, ASTComponent | ASTControlN
|
|
|
170
171
|
source = expect_string(source, ">")
|
|
171
172
|
source, children = expect_children(source)
|
|
172
173
|
source = expect_string(source, "</")
|
|
173
|
-
source, closing_name =
|
|
174
|
+
source, closing_name = expect_component_name(source)
|
|
174
175
|
source, _ = source.eat_whitespace()
|
|
175
176
|
source = expect_string(source, ">")
|
|
176
177
|
|
|
177
|
-
if name != closing_name:
|
|
178
|
-
raise ParsingError(f"Element closed ({closing_name
|
|
178
|
+
if name.name != closing_name.name:
|
|
179
|
+
raise ParsingError(f"Element closed ({closing_name.name}) is not the same as currently opened element ({name.name})", source.offset)
|
|
179
180
|
|
|
180
181
|
return source, ASTControlNode[ASTComponent].wrap_child(
|
|
181
182
|
ASTComponent(source_start=source_start, source_end=source.offset, name=name, arguments=arguments, children=children),
|
|
@@ -184,6 +185,13 @@ def expect_component(source: Source) -> tuple[Source, ASTComponent | ASTControlN
|
|
|
184
185
|
)
|
|
185
186
|
|
|
186
187
|
|
|
188
|
+
def expect_component_name(source: Source) -> tuple[Source, ASTComponentName]:
|
|
189
|
+
"""An identifier corresponding with a Python function."""
|
|
190
|
+
source_start = source.offset
|
|
191
|
+
source, name = expect_regex(source, r"[A-Z][a-zA-Z0-9_]*", "component name")
|
|
192
|
+
return source, ASTComponentName(source_start, source.offset, name)
|
|
193
|
+
|
|
194
|
+
|
|
187
195
|
def expect_html_comment(source: Source) -> tuple[Source, ASTHTMLComment]:
|
|
188
196
|
source_start = source.offset
|
|
189
197
|
source = expect_string(source, "<!--")
|
|
@@ -261,7 +269,9 @@ def expect_children(source: Source) -> tuple[Source, list[ASTHTMLChild]]:
|
|
|
261
269
|
while not source.remaining().startswith("</"):
|
|
262
270
|
source, child = expect_child(source)
|
|
263
271
|
children.append(child)
|
|
264
|
-
|
|
272
|
+
source_after_whitespace, _ = source.eat_whitespace()
|
|
273
|
+
if not source_after_whitespace.remaining().startswith("{{"):
|
|
274
|
+
source = source_after_whitespace
|
|
265
275
|
return source, children
|
|
266
276
|
|
|
267
277
|
|
fragments/html/elements.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import json
|
|
2
2
|
from typing import Any
|
|
3
3
|
from fragments.types import Children
|
|
4
|
+
import html
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
def sequence(children: Children) -> str:
|
|
@@ -46,7 +47,7 @@ def attribute_to_string(name: str, value: Any) -> str:
|
|
|
46
47
|
value = list(value)
|
|
47
48
|
|
|
48
49
|
if isinstance(value, dict) or isinstance(value, list):
|
|
49
|
-
value = json.dumps(value)
|
|
50
|
+
value = html.escape(json.dumps(value))
|
|
50
51
|
|
|
51
52
|
if isinstance(value, bool):
|
|
52
53
|
value = str(value).lower()
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
fragments/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
fragments/ast_nodes.py,sha256=
|
|
2
|
+
fragments/ast_nodes.py,sha256=LKj73eO04I01_po8F2vNT8yCziECt8bMS1Vfo12V70Y,19988
|
|
3
3
|
fragments/cli.py,sha256=9P9fvurRlROstWUh-tjneFt9IrVvgxcBEd3pn0wL_CE,1292
|
|
4
|
-
fragments/grammar.py,sha256=
|
|
4
|
+
fragments/grammar.py,sha256=5JzDukLFxhyxWOWUJQFzKNsfm0RTtSjF678vOLjDLW4,12887
|
|
5
5
|
fragments/loader.py,sha256=7nlsXVjCpRRmd939UJQqd9NWbE2-3ZtbO0aFfz3zCs8,980
|
|
6
6
|
fragments/source.py,sha256=cbDzLOlFy2C6xZe-ZWcroieGG-7PLTdLJi003aIdegg,1000
|
|
7
7
|
fragments/transpiler.py,sha256=O4pusCuv_Hbms2J0AP3tun-uNkXfb27RBUugr_0dIVA,316
|
|
8
8
|
fragments/types.py,sha256=tPD0YHT5rOaZMfrXWDz6W0HEQwu4EJyfVNR-pd_CX0A,152
|
|
9
9
|
fragments/html/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
-
fragments/html/elements.py,sha256=
|
|
10
|
+
fragments/html/elements.py,sha256=admLd2C9hcxdSjAwA9XvS7BbxMfregzwb_4AuBtOF_0,1898
|
|
11
11
|
fragments/lsp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
12
|
fragments/lsp/based_proxy.py,sha256=pFH-70H7uvy8yqxmq2s3jOmHw_CrAUHzyqiQXmDpJEI,3746
|
|
13
13
|
fragments/lsp/file_state.py,sha256=mghS-hcvZyPb8n9Ufypteu9DDZfv9Ktin-3C7GYxBh0,3292
|
|
@@ -32,8 +32,8 @@ fragments/lsp/pyright_notification_handlers/__init__.py,sha256=47DEQpj8HBSa-_TIm
|
|
|
32
32
|
fragments/lsp/pyright_notification_handlers/capability.py,sha256=1xH6SttTtWKAovCfx8WeJApRI4rrVlZDGCWHtlyGTUE,868
|
|
33
33
|
fragments/lsp/pyright_notification_handlers/configuration.py,sha256=Qomq8tCVcBg15MYDPby-PeRp4kJe7k8o6-2VRAYQ0hI,1009
|
|
34
34
|
fragments/lsp/pyright_notification_handlers/diagnostics.py,sha256=n_YZ8k8PHKcpHrgmTYTU2-pKi0P_v_WC1irqtAcs_iI,1107
|
|
35
|
-
python_fragments-0.
|
|
36
|
-
python_fragments-0.
|
|
37
|
-
python_fragments-0.
|
|
38
|
-
python_fragments-0.
|
|
39
|
-
python_fragments-0.
|
|
35
|
+
python_fragments-0.26.dist-info/METADATA,sha256=3es1e7oJTxa5wcarNEWlor8W4oRTuzz3zmAOFMwBnX0,1545
|
|
36
|
+
python_fragments-0.26.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
37
|
+
python_fragments-0.26.dist-info/entry_points.txt,sha256=9xVMCpt9OucM3W3fh0UnEeErKEyI6CNIFqfQCIuGmi8,96
|
|
38
|
+
python_fragments-0.26.dist-info/top_level.txt,sha256=4r1SNnHOK3BVhAT_KgV8MRq9kiV23yK_rnuTAEl5oRg,10
|
|
39
|
+
python_fragments-0.26.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|