Files
CTStruct/ctstruct/renderers/json_renderer.py
gm a68a79411f feat: slim JSON, EmojiMarkupRenderer, configurable delimiters
- 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>
2026-06-01 18:30:13 +09:00

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