feat: initial CTStruct framework
- CTNode: 트리 기본 단위 (전위/후위/BFS 순회, 탐색, 분리) - CTTree: 트리 컨테이너 (빌더 API, TOC, filter/map/merge) - NodeType: 구조/블록/인라인/메타 노드 타입 Enum - MarkdownParser: Markdown → CTTree 파서 - MarkdownRenderer: CTTree → Markdown 렌더러 - JSONRenderer: CTTree → JSON 직렬화 - 27개 단위/통합 테스트 전체 통과
This commit is contained in:
243
docs/ARCHITECTURE.md
Normal file
243
docs/ARCHITECTURE.md
Normal file
@@ -0,0 +1,243 @@
|
||||
# CTStruct 아키텍처 문서
|
||||
|
||||
## 1. 개요
|
||||
|
||||
CTStruct(Contextual Text Structure)는 다양한 텍스트 포맷을 **단일 트리 자료구조**로 표현하고,
|
||||
파서와 렌더러를 플러그인처럼 교체할 수 있도록 설계된 Python 라이브러리입니다.
|
||||
|
||||
---
|
||||
|
||||
## 2. 설계 목표
|
||||
|
||||
| 목표 | 설명 |
|
||||
|------|------|
|
||||
| **통일성** | Markdown, JSON, 일반 텍스트 등 모든 포맷이 동일한 CTTree API로 조작됨 |
|
||||
| **확장성** | 새 파서·렌더러를 `BaseParser` / `BaseRenderer` 상속으로 추가 가능 |
|
||||
| **불변 변환** | `filter()`, `map()` 은 원본 트리를 변경하지 않고 새 트리 반환 |
|
||||
| **의존성 최소화** | 표준 라이브러리만 사용, 외부 패키지 없음 |
|
||||
| **타입 안전성** | `NodeType` Enum 으로 잘못된 타입 사용 방지 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 핵심 구성요소
|
||||
|
||||
### 3.1 NodeType (types.py)
|
||||
|
||||
```
|
||||
NodeType
|
||||
├── 구조 노드: ROOT, DOCUMENT, SECTION
|
||||
├── 블록 노드: HEADING, PARAGRAPH, LIST, LIST_ITEM,
|
||||
│ TABLE, TABLE_ROW, TABLE_CELL,
|
||||
│ CODE_BLOCK, BLOCKQUOTE, DIVIDER
|
||||
├── 인라인 노드: TEXT, BOLD, ITALIC, CODE, LINK, IMAGE
|
||||
└── 메타 노드: METADATA, ANNOTATION, CUSTOM
|
||||
```
|
||||
|
||||
`NodeType` 은 Python `Enum` 으로 구현되어 있으며,
|
||||
노드의 **의미적 역할**을 정의합니다.
|
||||
|
||||
---
|
||||
|
||||
### 3.2 CTNode (node.py)
|
||||
|
||||
트리의 기본 단위. `dataclass` 로 구현되어 있습니다.
|
||||
|
||||
```
|
||||
CTNode
|
||||
├── node_id : str # 고유 식별자 (8자리 hex)
|
||||
├── node_type : NodeType # 의미적 타입
|
||||
├── content : str | None # 직접 보유 텍스트
|
||||
├── attributes : dict # 메타정보 (level, lang, …)
|
||||
├── parent : CTNode | None
|
||||
└── children : list[CTNode]
|
||||
```
|
||||
|
||||
#### 주요 메서드
|
||||
|
||||
| 메서드 | 설명 |
|
||||
|--------|------|
|
||||
| `append(child)` | 자식 추가 (체이닝 지원) |
|
||||
| `prepend(child)` | 맨 앞 삽입 |
|
||||
| `insert(i, child)` | 지정 위치 삽입 |
|
||||
| `remove(child)` | 자식 제거 |
|
||||
| `detach()` | 부모에서 자신을 분리 |
|
||||
| `walk(order)` | `"pre"` / `"post"` / `"bfs"` 순회 |
|
||||
| `find(type)` | 타입별 하위 노드 검색 |
|
||||
| `ancestors()` | 부모 방향 이터레이터 |
|
||||
| `text_content()` | 모든 하위 텍스트 추출 |
|
||||
| `pretty()` | 트리 시각화 문자열 |
|
||||
|
||||
---
|
||||
|
||||
### 3.3 CTTree (tree.py)
|
||||
|
||||
루트 노드를 감싸는 컨테이너. 문서 단위의 고수준 API를 제공합니다.
|
||||
|
||||
```
|
||||
CTTree
|
||||
└── root: CTNode (NodeType.ROOT)
|
||||
```
|
||||
|
||||
#### 빌더 API (정적 메서드)
|
||||
|
||||
```python
|
||||
CTTree.make_heading(text, level)
|
||||
CTTree.make_paragraph(text)
|
||||
CTTree.make_code_block(code, language)
|
||||
CTTree.make_list(items, ordered)
|
||||
CTTree.make_table(headers, rows)
|
||||
```
|
||||
|
||||
#### 탐색 API
|
||||
|
||||
```python
|
||||
tree.find(NodeType.HEADING) # 타입별 검색
|
||||
tree.find_by_id("a1b2c3d4") # ID 검색
|
||||
tree.headings() # 헤딩 목록
|
||||
tree.toc() # 목차 생성
|
||||
tree.walk(order) # 전체 순회
|
||||
```
|
||||
|
||||
#### 변환 API (원본 불변)
|
||||
|
||||
```python
|
||||
tree.filter(predicate) # 조건 필터링 → 새 CTTree
|
||||
tree.map(transform) # 변환 적용 → 새 CTTree
|
||||
tree.merge(other) # 다른 트리 병합 (in-place)
|
||||
```
|
||||
|
||||
#### 직렬화
|
||||
|
||||
```python
|
||||
d = tree.to_dict() # Python dict
|
||||
tree = CTTree.from_dict(d) # dict → CTTree
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.4 파서 (parsers/)
|
||||
|
||||
```
|
||||
BaseParser (추상)
|
||||
└── parse(text: str) → CTTree
|
||||
└── MarkdownParser
|
||||
├── frontmatter 파싱 (--- key: value ---)
|
||||
├── ATX 헤딩 (# ~ ######)
|
||||
├── 섹션 자동 분류 (H1 기준)
|
||||
├── 코드 블록 (``` … ```)
|
||||
├── 목록 (-, *, 1.)
|
||||
├── 인용구 (>)
|
||||
├── 구분선 (---)
|
||||
└── 문단 (multi-line 연결)
|
||||
```
|
||||
|
||||
**커스텀 파서 작성:**
|
||||
|
||||
```python
|
||||
from ctstruct.parsers import BaseParser
|
||||
from ctstruct import CTTree, CTNode, NodeType
|
||||
|
||||
class MyParser(BaseParser):
|
||||
def parse(self, text: str) -> CTTree:
|
||||
tree = CTTree()
|
||||
for line in text.splitlines():
|
||||
tree.add(NodeType.PARAGRAPH, line)
|
||||
return tree
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.5 렌더러 (renderers/)
|
||||
|
||||
```
|
||||
BaseRenderer (추상)
|
||||
└── render(tree: CTTree) → str
|
||||
├── MarkdownRenderer → Markdown 텍스트
|
||||
└── JSONRenderer → JSON 문자열
|
||||
```
|
||||
|
||||
**커스텀 렌더러 작성:**
|
||||
|
||||
```python
|
||||
from ctstruct.renderers import BaseRenderer
|
||||
from ctstruct import CTTree, NodeType
|
||||
|
||||
class PlainTextRenderer(BaseRenderer):
|
||||
def render(self, tree: CTTree) -> str:
|
||||
lines = []
|
||||
for node in tree.walk():
|
||||
if node.content:
|
||||
lines.append(node.content)
|
||||
return "\n".join(lines)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 데이터 흐름
|
||||
|
||||
```
|
||||
┌──────────────┐ parse() ┌──────────────┐
|
||||
│ 텍스트 입력 │ ──────────► │ CTTree │
|
||||
│ (Markdown, │ │ │
|
||||
│ JSON, etc) │ │ ┌────────┐ │ render() ┌──────────────┐
|
||||
└──────────────┘ │ │CTNode │ │ ────────────► │ 텍스트 출력 │
|
||||
│ │ ├child │ │ │ (Markdown, │
|
||||
│ │ ├child │ │ │ JSON, etc) │
|
||||
│ │ └child │ │ └──────────────┘
|
||||
│ └────────┘ │
|
||||
│ │
|
||||
│ filter() │
|
||||
│ map() │ ──► 새 CTTree
|
||||
│ merge() │
|
||||
└──────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 노드 속성 규약
|
||||
|
||||
각 노드 타입별 `attributes` 딕셔너리의 키 규약:
|
||||
|
||||
| NodeType | 속성 키 | 타입 | 설명 |
|
||||
|----------|---------|------|------|
|
||||
| `HEADING` | `level` | `int` (1-6) | 헤딩 레벨 |
|
||||
| `CODE_BLOCK` | `language` | `str` | 코드 언어 |
|
||||
| `LIST` | `style` | `"ordered"` / `"unordered"` / `"task"` | 목록 스타일 |
|
||||
| `LIST_ITEM` | `checked` | `bool` | 태스크 목록 체크 여부 |
|
||||
| `TABLE_CELL` | `align` | `"left"` / `"center"` / `"right"` | 정렬 |
|
||||
| `TABLE_CELL` | `is_header` | `bool` | 헤더 셀 여부 |
|
||||
| `LINK` | `href` | `str` | URL |
|
||||
| `IMAGE` | `src` | `str` | 이미지 경로 |
|
||||
| `IMAGE` | `alt` | `str` | 대체 텍스트 |
|
||||
| `METADATA` | (자유형식) | — | frontmatter 키-값 |
|
||||
|
||||
---
|
||||
|
||||
## 6. 확장 계획
|
||||
|
||||
| 단계 | 기능 |
|
||||
|------|------|
|
||||
| v0.2 | `PlainTextParser` — 들여쓰기/구분자 기반 텍스트 파싱 |
|
||||
| v0.2 | `HTMLRenderer` — CTTree → HTML 변환 |
|
||||
| v0.3 | `JSONParser` — JSON 구조 → CTTree |
|
||||
| v0.3 | `YAMLParser` — YAML → CTTree |
|
||||
| v0.4 | `XPathQuery` — 트리 경로 쿼리 언어 |
|
||||
| v0.5 | 스트리밍 파서 — 대용량 문서 처리 |
|
||||
| v1.0 | 완전한 CommonMark 호환 Markdown 파서 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 의존성
|
||||
|
||||
```
|
||||
Python >= 3.10
|
||||
표준 라이브러리: uuid, re, json, copy, abc, dataclasses, enum
|
||||
```
|
||||
|
||||
개발 도구 (선택):
|
||||
```
|
||||
pytest — 테스트
|
||||
pytest-cov — 커버리지
|
||||
ruff — 린터
|
||||
mypy — 타입 검사
|
||||
```
|
||||
Reference in New Issue
Block a user