phml.builder

phml.utils.builder

This module serves as a utility to make building elements and ast's easier.

  1"""phml.utils.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.nodes import All_Nodes, Comment, DocType, Element, Root, Text
 11
 12__all__ = ["p"]
 13
 14
 15def __process_children(node, children: list[str | list | int | All_Nodes]):
 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, All_Nodes):
 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, All_Nodes):
 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 | int | All_Nodes,
 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, All_Nodes))]
 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, All_Nodes))]
 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.utils 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 | int | phml.nodes.root.Root | phml.nodes.element.Element | phml.nodes.text.Text | phml.nodes.comment.Comment | phml.nodes.doctype.DocType | phml.nodes.parent.Parent | phml.nodes.node.Node | phml.nodes.literal.Literal):
41def p(  # pylint: disable=[invalid-name,keyword-arg-before-vararg]
42    selector: Optional[str] = None,
43    *args: str | list | int | All_Nodes,
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, All_Nodes))]
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, All_Nodes))]
71            return parse_root(children)
72        return parse_node(selector, props, children)
73
74    return parse_root(children)

Generic factory for creating phml nodes.