- JSONRenderer(slim=True): null·기본값·빈 attributes 필드 제거 - EmojiMarkupRenderer: CTTree → 이모지 마크업 텍스트 왕복 변환 지원 - title_mark / section_marks 커스터마이징 가능 - names_per_line 옵션으로 줄당 이름 수 제한 - EmojiMarkupParser: 구분자를 생성자 파라미터로 주입 가능 - section_marks 길이 제한 없음 (임의 깊이 섹션 지원) - 긴 마커 우선 매칭으로 prefix 충돌 방지 - 테스트 39개 추가 (커스텀 구분자·렌더러·slim 검증) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
59 lines
1.7 KiB
Python
59 lines
1.7 KiB
Python
"""
|
|
ctstruct/renderers/json_renderer.py
|
|
CTTree → JSON 렌더러
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from typing import Any
|
|
from ..tree import CTTree
|
|
from .base import BaseRenderer
|
|
|
|
|
|
class JSONRenderer(BaseRenderer):
|
|
"""
|
|
CTTree 를 JSON 문자열로 직렬화.
|
|
|
|
Args:
|
|
indent: 들여쓰기 공백 수 (기본 2)
|
|
ensure_ascii: ASCII 강제 인코딩 여부 (기본 False)
|
|
slim: True 이면 null·기본값 필드를 제거해 출력을 간소화
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
indent: int = 2,
|
|
ensure_ascii: bool = False,
|
|
slim: bool = False,
|
|
) -> None:
|
|
self.indent = indent
|
|
self.ensure_ascii = ensure_ascii
|
|
self.slim = slim
|
|
|
|
def render(self, tree: CTTree) -> str:
|
|
data = tree.to_dict()
|
|
if self.slim:
|
|
data = self._strip(data)
|
|
return json.dumps(data, indent=self.indent, ensure_ascii=self.ensure_ascii)
|
|
|
|
# ── slim 헬퍼 ─────────────────────────────────────────────
|
|
|
|
@staticmethod
|
|
def _strip(obj: Any) -> Any:
|
|
"""None·기본값 필드를 재귀적으로 제거."""
|
|
if isinstance(obj, list):
|
|
return [JSONRenderer._strip(v) for v in obj]
|
|
if isinstance(obj, dict):
|
|
result: dict[str, Any] = {}
|
|
for k, v in obj.items():
|
|
if v is None:
|
|
continue
|
|
if k == "data_type" and v == "unset":
|
|
continue
|
|
if k == "attributes" and v == {}:
|
|
continue
|
|
result[k] = JSONRenderer._strip(v)
|
|
return result
|
|
return obj
|