from pathlib import Path from log import Logger import re PLUGINS_DIR = Path(__file__).parent / "plugins" HTML_DIR = Path(__file__).parent / "../html" MARKDOWN_DIR = Path(__file__).parent / ".." / "markdown" class Actions: def _safe_read_file(self, path): """Safe file reading with path validation""" try: p = Path(path) # Prevent directory traversal if ".." in str(p.parts): raise ValueError("Path traversal not allowed") return p.read_text(encoding="utf-8") except Exception as e: Logger.log_lua_error(f"Error reading file {path}: {e}") return None @staticmethod def _safe_write_file(self, path, content): """Safe file writing with path validation""" try: p = Path(path) # Prevent directory traversal if ".." in str(p.parts): raise ValueError("Path traversal not allowed") p.write_text(content, encoding="utf-8") return True except Exception as e: Logger.log_lua_error(f"Error writing file {path}: {e}") return False # HTML/Markdown content operations @staticmethod def _read_content(self, base_dir, filename): """Read content from HTML or Markdown directory""" try: path = base_dir / filename if not path.is_relative_to(base_dir): raise ValueError("Invalid path") if path.exists(): return path.read_text(encoding="utf-8") return None except Exception as e: Logger.log_lua_error(f"Error reading {filename}: {e}") return None @staticmethod def _write_content(self, base_dir, filename, content): """Write content to HTML or Markdown directory""" try: path = base_dir / filename if not path.is_relative_to(base_dir): raise ValueError("Invalid path") path.write_text(content, encoding="utf-8") return True except Exception as e: Logger.log_lua_error(f"Error writing {filename}: {e}") return False @staticmethod def _list_files(self, base_dir, extension): """List files with given extension""" try: return [f.name for f in base_dir.glob(f"*{extension}")] except Exception as e: Logger.log_lua_error(f"Error listing files: {e}") return [] # HTML manipulation helpers @staticmethod def _html_find_tag(self, html, tag): """Find first occurrence of HTML tag""" pattern = f"<{tag}[^>]*>.*?" match = re.search(pattern, html, re.DOTALL | re.IGNORECASE) return match.group(0) if match else None @staticmethod def _html_replace_tag(self, html, tag, new_content): """Replace HTML tag content""" pattern = f"(<{tag}[^>]*>).*?()" return re.sub(pattern, f"\\1{new_content}\\2", html, flags=re.DOTALL | re.IGNORECASE) @staticmethod def _html_insert_before(self, html, marker, content): """Insert content before a marker""" return html.replace(marker, content + marker) @staticmethod def _html_insert_after(self, html, marker, content): """Insert content after a marker""" return html.replace(marker, marker + content) @staticmethod def _html_wrap_content(self, html, tag, wrapper_tag, attrs=""): """Wrap tag content with another tag""" pattern = f"(<{tag}[^>]*>)(.*?)()" def replacer(match): open_tag, content, close_tag = match.groups() return f"{open_tag}<{wrapper_tag} {attrs}>{content}{close_tag}" return re.sub(pattern, replacer, html, flags=re.DOTALL | re.IGNORECASE) # Markdown manipulation helpers @staticmethod def _md_add_header(self, markdown, level, text): """Add header to markdown""" prefix = "#" * level return f"{prefix} {text}\n\n{markdown}" @staticmethod def _md_replace_section(self, markdown, header, new_content): """Replace markdown section""" # Find section starting with header pattern = f"(#{1,6}\\s+{re.escape(header)}.*?)(?=#{1,6}\\s+|$)" return re.sub(pattern, f"## {header}\n\n{new_content}\n\n", markdown, flags=re.DOTALL) @staticmethod def _md_append_content(self, markdown, content): """Append content to markdown""" return markdown.rstrip() + "\n\n" + content # JSON conversion helpers @staticmethod def _table_to_json(self, lua_table): """Convert Lua table to JSON string""" import json try: # Convert lupa table to Python dict py_dict = dict(lua_table) return json.dumps(py_dict) except Exception as e: Logger.log_lua_error(f"Error converting table to JSON: {e}") return "{}" @staticmethod def _json_to_table(self, json_str): """Convert JSON string to Lua table""" import json try: return json.loads(json_str) except Exception as e: Logger.log_lua_error(f"Error parsing JSON: {e}") return {}