diff --git a/src/core/templating.py b/src/core/templating.py new file mode 100644 index 0000000..78fcd52 --- /dev/null +++ b/src/core/templating.py @@ -0,0 +1,77 @@ +import re +import uuid +import time +import random +from datetime import datetime +from typing import Any, Dict, Optional +import jinja2 + + +class TemplatingEngine: + def __init__(self): + self.env = jinja2.Environment( + loader=jinja2.DictLoader({}), + autoescape=True, + trim_blocks=True, + lstrip_blocks=True + ) + self._setup_filters() + self._setup_globals() + + def _setup_filters(self): + self.env.filters["uuid"] = lambda: str(uuid.uuid4()) + self.env.filters["upper"] = lambda x: x.upper() + self.env.filters["lower"] = lambda x: x.lower() + self.env.filters["default"] = lambda x, d="": x if x else d + self.env.filters["first"] = lambda x: x[0] if x else None + self.env.filters["last"] = lambda x: x[-1] if x else None + self.env.filters["length"] = len + self.env.filters["random"] = lambda x: random.choice(x) if x else None + + def _setup_globals(self): + self.env.globals["timestamp"] = lambda: int(time.time()) + self.env.globals["datetime"] = lambda: datetime.now().isoformat() + self.env.globals["uuid"] = lambda: str(uuid.uuid4()) + self.env.globals["random_int"] = lambda min_val=0, max_val=100: random.randint(min_val, max_val) + self.env.globals["random_string"] = lambda length=10: "".join(random.choices("abcdefghijklmnopqrstuvwxyz", k=length)) + self.env.globals["now"] = lambda: datetime.now().strftime("%Y-%m-%d %H:%M:%S") + + def render_template(self, template_str: str, context: Dict[str, Any]) -> str: + try: + template = self.env.from_string(template_str) + return template.render(**context) + except jinja2.TemplateError as e: + raise ValueError(f"Template rendering failed: {e}") + + def render_dict(self, data: Any, context: Dict[str, Any]) -> Any: + if isinstance(data, str): + return self.render_template(data, context) + elif isinstance(data, dict): + return {k: self.render_dict(v, context) for k, v in data.items()} + elif isinstance(data, list): + return [self.render_dict(item, context) for item in data] + else: + return data + + def build_context( + self, + path_params: Optional[Dict[str, str]] = None, + query_params: Optional[Dict[str, str]] = None, + headers: Optional[Dict[str, str]] = None, + body: Optional[Any] = None, + extra: Optional[Dict[str, Any]] = None + ) -> Dict[str, Any]: + context = { + "request": { + "path": path_params or {}, + "query": query_params or {}, + "headers": headers or {}, + "body": body or {} + }, + "uuid": str(uuid.uuid4()), + "timestamp": int(time.time()), + "datetime": datetime.now().isoformat() + } + if extra: + context.update(extra) + return context