Coverage for phml\compiler\steps\embedded.py: 100%

16 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2023-04-06 14:03 -0500

1from html import escape 

2from typing import Any 

3 

4from phml.embedded import exec_embedded, exec_embedded_blocks 

5from phml.helpers import build_recursive_context 

6from phml.nodes import Element, Literal, Parent 

7 

8from .base import comp_step 

9 

10ESCAPE_OPTIONS = { 

11 "quote": False, 

12} 

13 

14 

15def _process_attributes(node: Element, context: dict[str, Any]): 

16 context = build_recursive_context(node, context) 

17 for attribute in list(node.attributes.keys()): 

18 if attribute.startswith(":"): 

19 result = exec_embedded( 

20 str(node[attribute]).strip(), 

21 f"<{node.tag} {attribute}='{node[attribute]}'>", 

22 **context, 

23 ) 

24 if result is not None: 

25 node.pop(attribute, None) 

26 if isinstance(result, str): 

27 node[attribute.lstrip(":")] = escape(result, **ESCAPE_OPTIONS) 

28 else: 

29 node[attribute.lstrip(":")] = result 

30 else: 

31 if isinstance(node[attribute], str): 

32 value = exec_embedded_blocks( 

33 str(node.attributes[attribute]).strip(), 

34 f"<{node.tag} {attribute}='{node.attributes[attribute]}'>", 

35 **context, 

36 ) 

37 if value is not None: 

38 node[attribute] = escape(value, **ESCAPE_OPTIONS) 

39 

40 

41@comp_step 

42def step_execute_embedded_python(node: Parent, _, context: dict[str, Any]): 

43 """Step to process embedded python inside of attributes and text nodes.""" 

44 for child in node: 

45 if isinstance(child, Element): 

46 _process_attributes( 

47 child, 

48 build_recursive_context(child, context), 

49 ) 

50 elif Literal.is_text(child) and "{{" in child.content: 

51 child.content = escape( 

52 exec_embedded_blocks( 

53 child.content.strip(), 

54 f"Text in <{node.tag}> at {node.position!r}", 

55 **build_recursive_context(child, context), 

56 ), 

57 **ESCAPE_OPTIONS, 

58 )