diff --git a/backend/app/sanitize.py b/backend/app/sanitize.py index bd86fb3..a479cfb 100644 --- a/backend/app/sanitize.py +++ b/backend/app/sanitize.py @@ -44,6 +44,64 @@ def _is_junk_paragraph(node: Any) -> bool: ) +def _lift_lists_flat(node: Any) -> list[Any]: + """گره را به دنباله‌ای از گره‌های نرمال تبدیل می‌کند — نقل‌قول‌های داخل + آیتم فهرست به سطح خود فهرست می‌آیند تا خط مسی همهٔ نقل‌قول‌ها یک‌خط شود.""" + if not isinstance(node, dict): + return [node] + flat_content: list[Any] = [] + for child in node.get("content") or []: + flat_content.extend(_lift_lists_flat(child)) + node["content"] = flat_content + + if node.get("type") not in ("bulletList", "orderedList"): + return [node] + + rebuilt: list[Any] = [] + pending_items: list[Any] = [] + for li in node.get("content") or []: + if not isinstance(li, dict) or li.get("type") != "listItem": + pending_items.append(li) + continue + parts: list[list[Any]] = [[]] + for child in li.get("content") or []: + if isinstance(child, dict) and child.get("type") == "blockquote": + parts.append(child) + parts.append([]) + else: + parts[-1].append(child) + if len(parts) == 1: + pending_items.append(li) + continue + if parts[0]: + li["content"] = parts[0] + pending_items.append(li) + for part in parts[1:]: + if isinstance(part, dict) and part.get("type") == "blockquote": + if pending_items: + rebuilt.append({**node, "content": pending_items}) + pending_items = [] + rebuilt.append(part) + else: + pending_items.extend(part) + if pending_items: + rebuilt.append({**node, "content": pending_items}) + return rebuilt + + +def _lift_doc(doc: Any) -> Any: + lifted = _lift_lists_flat(doc) + if len(lifted) == 1 and isinstance(lifted[0], dict) and lifted[0].get("type") == "doc": + return lifted[0] + content: list[Any] = [] + for part in lifted: + if isinstance(part, dict) and part.get("type") == "doc": + content.extend(part.get("content") or []) + else: + content.append(part) + return {"type": "doc", "content": content} + + def _walk(node: Any) -> Any: if isinstance(node, list): return [_walk(item) for item in node] @@ -73,4 +131,5 @@ def sanitize_doc(doc: Any) -> Any: """سند TipTap را درجا پاک می‌کند (سایر ساختارها دست‌نخورده برمی‌گردند).""" if not isinstance(doc, dict): return doc - return _walk(doc) + walked = _walk(doc) + return _lift_doc(walked)