phml.core.formats.html_format
1from copy import deepcopy 2from typing import Optional 3 4from phml.core.nodes import AST, NODE 5from phml.core.virtual_python import VirtualPython 6from phml.utilities.locate.find import find_all 7from phml.utilities.transform import remove_nodes 8 9from .compile import ASTRenderer, apply_conditions, apply_python 10from .format import Format 11from .parse import parse_hypertest_markup 12 13from phml.types.config import Config 14 15 16def parse_markup(data: str, class_name: str, auto_close: bool = True) -> AST: 17 """Parse a string as a markup document.""" 18 return parse_hypertest_markup(data, class_name, auto_close) 19 20 21class HTMLFormat(Format): 22 """Logic for parsing and compiling html files.""" 23 24 extension: list[str] = ["html", "htm"] 25 26 @classmethod 27 def parse(cls, data: str, auto_close: bool = True) -> str: 28 return parse_markup(data, cls.__name__, auto_close) 29 30 @classmethod 31 def compile( 32 cls, 33 ast: AST, 34 config: Config, 35 components: Optional[dict[str, dict[str, list | NODE]]] = None, 36 **kwargs, 37 ) -> AST: 38 """Compile and process the given ast and return the resulting ast.""" 39 40 components = components or {} 41 src = deepcopy(ast) 42 43 # 1. Search for all python elements and get source info. 44 # - Remove when done 45 virtual_python = VirtualPython() 46 47 for python_block in find_all(src, {"tag": "python"}): 48 if ( 49 len(python_block.children) == 1 50 and python_block.children[0].type == "text" 51 ): 52 virtual_python += VirtualPython( 53 python_block.children[0].normalized(), 54 context={**kwargs} 55 ) 56 57 remove_nodes(src, ["element", {"tag": "python"}]) 58 59 # 2. Replace specific element node with given replacement components 60 # replace_components(src, components, virtual_python, **kwargs) 61 62 # 3. Search each element and find @if, @elif, and @else 63 # - Execute those statements 64 65 apply_conditions(src, config, virtual_python, components, **kwargs) 66 67 for python_block in find_all(src, {"tag": "python"}): 68 if ( 69 len(python_block.children) == 1 70 and python_block.children[0].type == "text" 71 ): 72 virtual_python += VirtualPython( 73 python_block.children[0].normalized(), 74 context={**kwargs} 75 ) 76 77 remove_nodes(src, ["element", {"tag": "python"}]) 78 79 # 4. Search for python blocks and process them. 80 81 apply_python(src, virtual_python, **kwargs) 82 remove_nodes(src, {"tag": "slot"}) 83 84 return src 85 86 @classmethod 87 def render( 88 cls, 89 ast: AST, 90 config: Config, 91 components: Optional[dict[str, dict[str, list | NODE]]] = None, 92 indent: int = 4, 93 **kwargs, 94 ) -> str: 95 indent = indent or 4 96 components = components or {} 97 src = ast 98 99 # 1. Search for all python elements and get source info. 100 # - Remove when done 101 virtual_python = VirtualPython() 102 103 for python_block in find_all(src, {"tag": "python"}): 104 if len(python_block.children) == 1: 105 if python_block.children[0].type == "text": 106 virtual_python += VirtualPython(python_block.children[0].normalized()) 107 108 remove_nodes(src, ["element", {"tag": "python"}]) 109 110 # 2. Replace specific element node with given replacement components 111 # replace_components(src, components, virtual_python, **kwargs) 112 113 # 3. Search each element and find @if, @elif, and @else 114 # - Execute those statements 115 116 apply_conditions(src, config, virtual_python, components, **kwargs) 117 118 for python_block in find_all(src, {"tag": "python"}): 119 if len(python_block.children) == 1: 120 if python_block.children[0].type == "text": 121 virtual_python += VirtualPython(python_block.children[0].normalized()) 122 123 remove_nodes(src, ["element", {"tag": "python"}]) 124 125 # 4. Search for python blocks and process them. 126 127 apply_python(src, virtual_python, **kwargs) 128 remove_nodes(src, {"tag": "slot"}) 129 130 return ASTRenderer(src, indent).compile()
17def parse_markup(data: str, class_name: str, auto_close: bool = True) -> AST: 18 """Parse a string as a markup document.""" 19 return parse_hypertest_markup(data, class_name, auto_close)
Parse a string as a markup document.
22class HTMLFormat(Format): 23 """Logic for parsing and compiling html files.""" 24 25 extension: list[str] = ["html", "htm"] 26 27 @classmethod 28 def parse(cls, data: str, auto_close: bool = True) -> str: 29 return parse_markup(data, cls.__name__, auto_close) 30 31 @classmethod 32 def compile( 33 cls, 34 ast: AST, 35 config: Config, 36 components: Optional[dict[str, dict[str, list | NODE]]] = None, 37 **kwargs, 38 ) -> AST: 39 """Compile and process the given ast and return the resulting ast.""" 40 41 components = components or {} 42 src = deepcopy(ast) 43 44 # 1. Search for all python elements and get source info. 45 # - Remove when done 46 virtual_python = VirtualPython() 47 48 for python_block in find_all(src, {"tag": "python"}): 49 if ( 50 len(python_block.children) == 1 51 and python_block.children[0].type == "text" 52 ): 53 virtual_python += VirtualPython( 54 python_block.children[0].normalized(), 55 context={**kwargs} 56 ) 57 58 remove_nodes(src, ["element", {"tag": "python"}]) 59 60 # 2. Replace specific element node with given replacement components 61 # replace_components(src, components, virtual_python, **kwargs) 62 63 # 3. Search each element and find @if, @elif, and @else 64 # - Execute those statements 65 66 apply_conditions(src, config, virtual_python, components, **kwargs) 67 68 for python_block in find_all(src, {"tag": "python"}): 69 if ( 70 len(python_block.children) == 1 71 and python_block.children[0].type == "text" 72 ): 73 virtual_python += VirtualPython( 74 python_block.children[0].normalized(), 75 context={**kwargs} 76 ) 77 78 remove_nodes(src, ["element", {"tag": "python"}]) 79 80 # 4. Search for python blocks and process them. 81 82 apply_python(src, virtual_python, **kwargs) 83 remove_nodes(src, {"tag": "slot"}) 84 85 return src 86 87 @classmethod 88 def render( 89 cls, 90 ast: AST, 91 config: Config, 92 components: Optional[dict[str, dict[str, list | NODE]]] = None, 93 indent: int = 4, 94 **kwargs, 95 ) -> str: 96 indent = indent or 4 97 components = components or {} 98 src = ast 99 100 # 1. Search for all python elements and get source info. 101 # - Remove when done 102 virtual_python = VirtualPython() 103 104 for python_block in find_all(src, {"tag": "python"}): 105 if len(python_block.children) == 1: 106 if python_block.children[0].type == "text": 107 virtual_python += VirtualPython(python_block.children[0].normalized()) 108 109 remove_nodes(src, ["element", {"tag": "python"}]) 110 111 # 2. Replace specific element node with given replacement components 112 # replace_components(src, components, virtual_python, **kwargs) 113 114 # 3. Search each element and find @if, @elif, and @else 115 # - Execute those statements 116 117 apply_conditions(src, config, virtual_python, components, **kwargs) 118 119 for python_block in find_all(src, {"tag": "python"}): 120 if len(python_block.children) == 1: 121 if python_block.children[0].type == "text": 122 virtual_python += VirtualPython(python_block.children[0].normalized()) 123 124 remove_nodes(src, ["element", {"tag": "python"}]) 125 126 # 4. Search for python blocks and process them. 127 128 apply_python(src, virtual_python, **kwargs) 129 remove_nodes(src, {"tag": "slot"}) 130 131 return ASTRenderer(src, indent).compile()
Logic for parsing and compiling html files.
extension: list[str] = ['html', 'htm']
The extension or extensions for the file format. When writing to a file and extensions is a list then the first extensions in the list is used for the file extension.
@classmethod
def
parse(cls, data: str, auto_close: bool = True) -> str:
27 @classmethod 28 def parse(cls, data: str, auto_close: bool = True) -> str: 29 return parse_markup(data, cls.__name__, auto_close)
Parse the given data into a phml.core.nodes.AST.
@classmethod
def
compile( cls, ast: phml.core.nodes.AST.AST, config: dict[typing.Literal['enabled'], dict[typing.Literal['html', 'markdown'], bool]], components: Optional[dict[str, dict[str, list | 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]]] = None, **kwargs) -> phml.core.nodes.AST.AST:
31 @classmethod 32 def compile( 33 cls, 34 ast: AST, 35 config: Config, 36 components: Optional[dict[str, dict[str, list | NODE]]] = None, 37 **kwargs, 38 ) -> AST: 39 """Compile and process the given ast and return the resulting ast.""" 40 41 components = components or {} 42 src = deepcopy(ast) 43 44 # 1. Search for all python elements and get source info. 45 # - Remove when done 46 virtual_python = VirtualPython() 47 48 for python_block in find_all(src, {"tag": "python"}): 49 if ( 50 len(python_block.children) == 1 51 and python_block.children[0].type == "text" 52 ): 53 virtual_python += VirtualPython( 54 python_block.children[0].normalized(), 55 context={**kwargs} 56 ) 57 58 remove_nodes(src, ["element", {"tag": "python"}]) 59 60 # 2. Replace specific element node with given replacement components 61 # replace_components(src, components, virtual_python, **kwargs) 62 63 # 3. Search each element and find @if, @elif, and @else 64 # - Execute those statements 65 66 apply_conditions(src, config, virtual_python, components, **kwargs) 67 68 for python_block in find_all(src, {"tag": "python"}): 69 if ( 70 len(python_block.children) == 1 71 and python_block.children[0].type == "text" 72 ): 73 virtual_python += VirtualPython( 74 python_block.children[0].normalized(), 75 context={**kwargs} 76 ) 77 78 remove_nodes(src, ["element", {"tag": "python"}]) 79 80 # 4. Search for python blocks and process them. 81 82 apply_python(src, virtual_python, **kwargs) 83 remove_nodes(src, {"tag": "slot"}) 84 85 return src
Compile and process the given ast and return the resulting ast.
@classmethod
def
render( cls, ast: phml.core.nodes.AST.AST, config: dict[typing.Literal['enabled'], dict[typing.Literal['html', 'markdown'], bool]], components: Optional[dict[str, dict[str, list | 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]]] = None, indent: int = 4, **kwargs) -> str:
87 @classmethod 88 def render( 89 cls, 90 ast: AST, 91 config: Config, 92 components: Optional[dict[str, dict[str, list | NODE]]] = None, 93 indent: int = 4, 94 **kwargs, 95 ) -> str: 96 indent = indent or 4 97 components = components or {} 98 src = ast 99 100 # 1. Search for all python elements and get source info. 101 # - Remove when done 102 virtual_python = VirtualPython() 103 104 for python_block in find_all(src, {"tag": "python"}): 105 if len(python_block.children) == 1: 106 if python_block.children[0].type == "text": 107 virtual_python += VirtualPython(python_block.children[0].normalized()) 108 109 remove_nodes(src, ["element", {"tag": "python"}]) 110 111 # 2. Replace specific element node with given replacement components 112 # replace_components(src, components, virtual_python, **kwargs) 113 114 # 3. Search each element and find @if, @elif, and @else 115 # - Execute those statements 116 117 apply_conditions(src, config, virtual_python, components, **kwargs) 118 119 for python_block in find_all(src, {"tag": "python"}): 120 if len(python_block.children) == 1: 121 if python_block.children[0].type == "text": 122 virtual_python += VirtualPython(python_block.children[0].normalized()) 123 124 remove_nodes(src, ["element", {"tag": "python"}]) 125 126 # 4. Search for python blocks and process them. 127 128 apply_python(src, virtual_python, **kwargs) 129 remove_nodes(src, {"tag": "slot"}) 130 131 return ASTRenderer(src, indent).compile()
Compile the given phml.core.nodes.AST into string of a given format.