phml.builder
phml.utilities.builder
This module serves as a utility to make building elements and ast's easier.
1"""phml.utilities.builder 2 3This module serves as a utility to make building elements and ast's easier. 4""" 5 6from __future__ import annotations 7 8from typing import Optional 9 10from phml.core.nodes import NODE, Comment, DocType, Element, Root, Text 11 12__all__ = ["p"] 13 14 15def __process_children(node, children: list[str | list | int | NODE]): 16 for child in children: 17 if isinstance(child, str): 18 node.children.append(Text(child, node)) 19 elif isinstance(child, (float, int)): 20 node.children.append(Text(str(child), node)) 21 elif isinstance(child, NODE): 22 child.parent = node 23 node.children.append(child) 24 elif isinstance(child, list): 25 for nested_child in child: 26 if isinstance(nested_child, str): 27 node.children.append(Text(nested_child, node)) 28 elif isinstance(nested_child, (float, int)): 29 node.children.append(Text(str(nested_child), node)) 30 elif isinstance(nested_child, NODE): 31 nested_child.parent = node 32 node.children.append(nested_child) 33 else: 34 raise TypeError( 35 f"Unkown type <{type(nested_child).__name__}> in {child}:\ 36 {nested_child}" 37 ) 38 39 40def p( # pylint: disable=[invalid-name,keyword-arg-before-vararg] 41 selector: Optional[str] = None, 42 *args: str | list | dict | int | NODE, 43): 44 """Generic factory for creating phml nodes.""" 45 46 # Get all children | non dict objects 47 children = [child for child in args if isinstance(child, (str, list, int, NODE))] 48 49 # Get all properties | dict objects 50 props = [prop for prop in args if isinstance(prop, dict)] 51 52 if selector is not None: 53 # Is a comment 54 if isinstance(selector, str) and selector.startswith("<!--"): 55 return Comment(selector.replace("<!--", "").replace("-->", "")) 56 57 # Is a text node 58 if ( 59 isinstance(selector, str) 60 and (len(selector.split(" ")) > 1 or len(selector.split("\n")) > 1) 61 and len(args) == 0 62 ): 63 return Text(selector) 64 65 if not isinstance(selector, str): 66 args = [selector, *args] 67 selector = None 68 69 children = [child for child in args if isinstance(child, (str, list, int, NODE))] 70 return parse_root(children) 71 return parse_node(selector, props, children) 72 73 return parse_root(children) 74 75 76def parse_root(children: list): 77 """From the given information return a built root node.""" 78 79 node = Root() 80 __process_children(node, children) 81 return node 82 83 84def parse_node(selector: str, props: dict, children: list): 85 """From the provided selector, props, and children build an element node.""" 86 from phml.utilities import parse_specifiers # pylint: disable=import-outside-toplevel 87 88 node = parse_specifiers(selector) 89 if not isinstance(node[0], dict) or len(node[0]["attributes"]) > 0: 90 raise TypeError("Selector must be of the format `tag?[#id]?[.classes...]?`") 91 92 node = node[0] 93 94 node["tag"] = "div" if node["tag"] == "*" else node["tag"] 95 96 if node["tag"].lower() == "doctype": 97 str_children = [child for child in children if isinstance(child, str)] 98 if len(str_children) > 0: 99 return DocType(str_children[0]) 100 return DocType() 101 102 if node["tag"].lower().strip() == "text": 103 return Text( 104 " ".join([str(child) for child in children if isinstance(child, (str, int, float))]) 105 ) 106 107 if node["tag"].lower().strip() == "comment": 108 return Comment( 109 " ".join([str(child) for child in children if isinstance(child, (str, int, float))]) 110 ) 111 112 properties = {} 113 for prop in props: 114 properties.update(prop) 115 116 if len(node["classList"]) > 0: 117 properties["class"] = "" if "class" not in properties else properties["class"] 118 properties["class"] += " ".join(node["classList"]) 119 if node["id"] is not None: 120 properties["id"] = node["id"] 121 122 element = Element( 123 node["tag"], 124 properties=properties, 125 startend=len(children) == 0, 126 ) 127 128 __process_children(element, children) 129 return element
def
p( selector: Optional[str] = None, *args: str | list | dict | int | phml.core.nodes.nodes.Root | phml.core.nodes.nodes.Element | phml.core.nodes.nodes.Text | phml.core.nodes.nodes.Comment | phml.core.nodes.nodes.DocType | phml.core.nodes.nodes.Parent | phml.core.nodes.nodes.Node | phml.core.nodes.nodes.Literal):
41def p( # pylint: disable=[invalid-name,keyword-arg-before-vararg] 42 selector: Optional[str] = None, 43 *args: str | list | dict | int | NODE, 44): 45 """Generic factory for creating phml nodes.""" 46 47 # Get all children | non dict objects 48 children = [child for child in args if isinstance(child, (str, list, int, NODE))] 49 50 # Get all properties | dict objects 51 props = [prop for prop in args if isinstance(prop, dict)] 52 53 if selector is not None: 54 # Is a comment 55 if isinstance(selector, str) and selector.startswith("<!--"): 56 return Comment(selector.replace("<!--", "").replace("-->", "")) 57 58 # Is a text node 59 if ( 60 isinstance(selector, str) 61 and (len(selector.split(" ")) > 1 or len(selector.split("\n")) > 1) 62 and len(args) == 0 63 ): 64 return Text(selector) 65 66 if not isinstance(selector, str): 67 args = [selector, *args] 68 selector = None 69 70 children = [child for child in args if isinstance(child, (str, list, int, NODE))] 71 return parse_root(children) 72 return parse_node(selector, props, children) 73 74 return parse_root(children)
Generic factory for creating phml nodes.