from typing import List, Tuple, Union def MakeAttrs(css:str|Tuple[str, ...]|None, id:str|None, attributes: dict[str, str | None]|None) -> str: if not attributes: attributes = {} if css: attributes['class'] = " ".join(css) if isinstance(css, (list, tuple)) else css if id: attributes['id'] = id attrList: List[str] = [] for key, value in attributes.items(): if value: attrList.append(f'{key}="{value}"') return " " + " ".join(attrList) class Leaf(): name:str = "" def __init__(self, name:str|None = None): if name: self.name = name self.attrs = None def props(self, css:str|Tuple[str, ...]|None, id:str|None, attributes: dict[str, str | None]|None): clone = self.__class__(self.name) clone.attrs = MakeAttrs(css, id, attributes) return clone def __call__(self, css:str|None = None, id:str|None = None): return self.props(css, id, {}) def __repr__(self) -> str: return f'<{self.name}{self.attrs or ""}/>' class Branch(Leaf): name:str = "" def __init__(self, name:str|None = None): if name: self.name = name self.attrs = None def __repr__(self) -> str: return f'<{self.name}{self.attrs or ""}>' def __getitem__(self, key:Union[str, 'Branch', Leaf, Tuple[Union[str, 'Branch', Leaf], ...]]) -> str: if isinstance(key, tuple): children = f'\n'.join(str(k) for k in key) else: children = str(key) return f'<{self.name}{self.attrs or ""}>\n{children}\n' class IMGTag(Leaf): name = "img" def __call__(self, css:str|None = None, id:str|None = None, src:str|None = None): return self.props(css, id, {"src":src}) class ATag(Branch): name = "a" def __call__(self, css:str|None = None, id:str|None = None, href:str|None = None, target:str|None = None): return self.props(css, id, {"href":href, "target":target}) IMG = IMGTag() A = ATag() BR = Leaf("br") HR = Leaf("hr") DIV = Branch("div") P = Branch("p") SPAN = Branch("span") EM = Branch("EM") H1 = Branch("h1") H2 = Branch("h2") H3 = Branch("h3") H4 = Branch("h4") SECTION = Branch("section") MAIN = Branch("main")