diff options
| author | Asko Nõmm <asko@nmm.ee> | 2024-12-27 22:55:13 +0200 |
|---|---|---|
| committer | Asko Nõmm <asko@nmm.ee> | 2024-12-27 22:55:13 +0200 |
| commit | c539b8f72b9d47453a09febe91ec551e11252f80 (patch) | |
| tree | 07ae5dfa42e3d28e8a45acbd7fdfa7b887abd671 | |
bump
| -rw-r--r-- | .gitignore | 13 | ||||
| -rw-r--r-- | .python-version | 1 | ||||
| -rw-r--r-- | README.md | 5 | ||||
| -rw-r--r-- | hello.py | 9 | ||||
| -rw-r--r-- | htmtl/__init__.py | 1 | ||||
| -rw-r--r-- | htmtl/htmtl.py | 151 | ||||
| -rw-r--r-- | pyproject.toml | 19 |
7 files changed, 199 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..185c342 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +# Python-generated files +__pycache__/ +*.py[oc] +build/ +dist/ +wheels/ +*.egg-info + +# Virtual environments +.venv + +# Other +.idea/ diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..24ee5b1 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.13 diff --git a/README.md b/README.md new file mode 100644 index 0000000..0d94bda --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# HTMTL + +HTMTL (HyperText Markup _Templating_ Language) is a templating language that uses HTML attributes for its rendering logic. +It is both a subset and superset of HTML, meaning that valid HTML is also valid HTMTL and valid HTMTL is also valid HTML, allowing +you to use any editor without needing any additional plugins.
\ No newline at end of file diff --git a/hello.py b/hello.py new file mode 100644 index 0000000..504affe --- /dev/null +++ b/hello.py @@ -0,0 +1,9 @@ +from htmtl import Htmtl + + +def main(): + Htmtl("<div>Hello World<span>asdasd<a>asd</a></span></div>").toHtml() + + +if __name__ == "__main__": + main() diff --git a/htmtl/__init__.py b/htmtl/__init__.py new file mode 100644 index 0000000..7a91412 --- /dev/null +++ b/htmtl/__init__.py @@ -0,0 +1 @@ +from .htmtl import Htmtl
\ No newline at end of file diff --git a/htmtl/htmtl.py b/htmtl/htmtl.py new file mode 100644 index 0000000..4a50043 --- /dev/null +++ b/htmtl/htmtl.py @@ -0,0 +1,151 @@ +from __future__ import annotations +from typing import Dict, Any, Tuple, Callable, Optional + + +class Node: + name: str + attributes: Dict[str, str] + children: list[Node] + + def __init__(self, name: str, attributes: Dict[str, str], children: list[Node]): + self.name = name + self.attributes = attributes + self.children = [] + + +class IRBlockPosNode: + name: str + coords: Tuple[int, int] + moved: bool + children: list[IRBlockPosNode] + + def __init__(self, name: str, coords: Tuple[int, int]): + self.name = name + self.coords = coords + + +class IRBlockNode: + name: str + children: list[IRBlockNode] + + def __init__(self, name: str, children: list[IRBlockNode]): + self.name = name + self.moved = False + self.children = children + + +class Htmtl: + __template: str = "" + __ir_block_pos_nodes: list[IRBlockPosNode] = [] + __ir_block_nodes: list[IRBlockNode] = [] + __block_elements = [ + "div", "span", "a" + ] + __inline_elements = [ + "img" + ] + + def __init__(self, template: str): + self.__template = template + self.__ir_block_pos_nodes = [] + self.__ir_block_nodes = [] + self.__parse_ir_block_pos_nodes() + self.__join_ir_block_pos_nodes() + self.__parse_ir_block_nodes() + + def __parse_ir_block_pos_nodes(self): + start = None + end = None + + for idx, part in enumerate(self.__template): + if part == "<": + start = idx + + if part == ">": + end = idx + 1 + + if start is not None and end is not None: + tag = self.__template[start:end] + + if tag.startswith("</"): + self.__maybe_close_ir_block_pos_node(tag, end) + start = None + end = None + continue + + name = tag[1:-1].split(" ")[0].strip() + + if name in self.__block_elements: + self.__ir_block_pos_nodes.append( + IRBlockPosNode(name=name, coords=(end, 0)) + ) + + start = None + end = None + + def __maybe_close_ir_block_pos_node(self, tag: str, coord: int): + el_name = tag[2:-1].split(' ')[0].strip() + match = self.__find_last_match(self.__ir_block_pos_nodes, lambda node: node.name == el_name) + + if match is not None: + [idx, last_ir_pos_node] = match + last_ir_pos_node.coords = (last_ir_pos_node.coords[0], coord) + self.__ir_block_pos_nodes[idx] = last_ir_pos_node + + def __join_ir_block_pos_nodes(self): + processed_coords = set() + + for node in self.__ir_block_pos_nodes: + if node.coords in processed_coords: + continue + + ir_block_pos_nodes_within = self.__find_block_pos_nodes_in_coords(node.coords) + node.children = self.__recursively_build_ir_block_pos_node_children(ir_block_pos_nodes_within, processed_coords) + + self.__ir_block_pos_nodes = [ + node for node in self.__ir_block_pos_nodes if node.coords not in processed_coords + ] + + def __recursively_build_ir_block_pos_node_children(self, child_nodes: list[Tuple[int, IRBlockPosNode]], processed_coords: set): + children = [] + + for idx, child_node in child_nodes: + if child_node.coords in processed_coords: + continue + + processed_coords.add(child_node.coords) + child_node_children = self.__find_block_pos_nodes_in_coords(child_node.coords) + child_node.children = self.__recursively_build_ir_block_pos_node_children(child_node_children, processed_coords) + children.append(child_node) + + return children + + def __find_block_pos_nodes_in_coords(self, coords: Tuple[int, int]) -> list[Tuple[int, IRBlockPosNode]]: + found_block_position_nodes = [] + [start, end] = coords + + for idx, ir_block_position_node in enumerate(self.__ir_block_pos_nodes): + [iter_start, iter_end] = ir_block_position_node.coords + + if iter_start > start and iter_end < end: + found_block_position_nodes.append((idx, ir_block_position_node)) + + return found_block_position_nodes + + def __parse_ir_block_nodes(self): + pass + + @staticmethod + def __find_last_match(arr: list[Any], condition: Callable[[Any], bool]) -> Optional[Tuple[int, Any]]: + idx = len(arr) + + for item in reversed(arr): + idx -= 1 + + if condition(item): + return idx, item + + return None + + def toHtml(self): + pass diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..b058883 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,19 @@ +[project] +name = "htmtl" +version = "0.1.0" +description = "A templating language that is both a superset and subset of HTML." +readme = "README.md" +requires-python = ">=3.10" +authors = [ + { name = "Asko Nõmm", email = "asko@nmm.ee" } +] +dependencies = [] +classifiers = [ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Development Status :: 1 - Planning" +] + +[tool.black] +line-length = 100 |
