Repository navigation
feat(markdown): Markdown → HWPX 쓰기(from_markdown)와 깨끗한 새 문서 모드 - #670
Conversation
…-document mode `hwpx.tools.markdown_import.from_markdown(markdown, style=...)` builds a new document from the Markdown models write most reliably: # to #### headings, paragraphs, -/*/1. lists nested by indentation (applied as Hancom lists), pipe tables with a bold, shaded header row, and **bold**/*italic* inline. Anything else is written as plain text; unknown Markdown never raises. `doc.text.append_markdown(...)` adds the same to an existing document. `MarkdownStyle` is a genre-neutral, overridable look; genre presets belong to the application layer. `HwpxDocument.new(inherit_style=False)` makes a clean document in which `add_paragraph` starts from the base shapes instead of copying the last paragraph, so a heading's outline or a list's numbering does not follow into the next paragraph. `add_paragraph(inherit_style=None)` now follows the document; the default document still inherits. Closes #669 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rt module MarkdownStyle now raises HwpxValueError (text-markdown-style-invalid), keeping the untyped-error census flat, and tools/markdown_import.py gets its explicit ownership exception, so the boundary ratchet classifies it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
airmang
left a comment
There was a problem hiding this comment.
head adc60bf / base d1c7d0a1da5b083339616f19edd9c0dd4a805dfb를 검토했습니다. 새 파서·작성기와 new/add_paragraph의 상속 기본 호환성, namespace/문서 변경을 읽었고 tests/test_markdown_import.py 21개가 통과했습니다. 정확한 head CI 7,669 passed/18 skipped/1 xfailed 및 Ruff/mypy/Pyright 로그도 확인했습니다. 다만 공개 from_markdown 호출에서 코드 블록과 제목의 원문이 사라지는 두 P2를 재현해 병합을 보류합니다. 자기 PR이므로 COMMENT로 기록합니다.
| body.append(lines[i]) | ||
| i += 1 | ||
| i += 1 # the closing fence (or the end) | ||
| yield _Paragraph("\n".join(body)) |
There was a problem hiding this comment.
[P2] fenced code의 본문은 인라인 Markdown을 다시 해석하지 않게 구분해 주세요. 여기서 일반 _Paragraph로 내보내면 _Writer.paragraph→write_runs→parse_inline을 타서 코드의 기호가 사라집니다. 공개 API from_markdown('text\n**literal** and [label](url)\n')의 문단 텍스트가 'literal and label'가 아니라 'literal and label'이고 literal에는 굵게까지 적용됩니다. 코드 예제의 실제 문자열/구문을 바꾸는 결과이므로 코드 블록 타입 또는 plain-text 작성 경로를 두고, 별표·링크·
를 포함한 코드의 저장/재열기 원문 보존 회귀를 추가해 주세요.
| header: bool | ||
|
|
||
|
|
||
| _HEADING = re.compile(r"^\s{0,3}(#{1,6})\s+(.*?)\s*#*\s*$") |
There was a problem hiding this comment.
[P2] 공백 없이 제목에 붙은 #는 글자로 보존해 주세요. 끝부분의 \s*#*는 닫는 ATX 표지 앞 공백을 요구하지 않아 공개 from_markdown('# C#')가 제목 'C'를 만듭니다. '# topic#'도 마지막 글자가 사라집니다. 닫는 # 묶음은 앞에 공백이 있는 경우만 제거하고 '# C#'와 '# 제목 ###'를 함께 검증해 주세요.
Both sides added one entry to the same lists; keep both: - errors.py / docs/error-codes.md: text-markdown-style-invalid next to text-outline-budget and text-block-unknown (count 200) - module-ownership.json: tools/markdown_import.py and _document/text_blocks.py - test_product_boundary: classifiedFiles 186 (+1 each) - editor-surface-inventory: both rows; auto section regenerated (43 areas) - CHANGELOG: both Unreleased entries Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
airmang
left a comment
There was a problem hiding this comment.
최신 head 재검토: 이전 검토 SHA와 비교해 markdown_import.py 및 해당 테스트의 변경이 없음을 확인했습니다. 두 공개 API 재현에서 '# C#'→'C', fenced 'literal and label'→'literal and label'가 여전히 발생합니다. CI 13개 성공(7687 passed,18 skipped,1 xfailed 및 정적 검사 통과)은 확인했지만 기존 두 미해결 스레드의 원문 손실 결함 때문에 병합을 보류합니다. 중복 inline 지적은 추가하지 않습니다.
Closes #669
무엇을 바꾸나
1. Markdown → HWPX
hwpx.tools.markdown_import.from_markdown(markdown, style=None)— 흔히 쓰는 Markdown 부분 집합으로 새 문서를 만든다.doc.text.append_markdown(markdown, style=None)— 이미 있는 문서 끝에 덧붙인다.#~####제목: 굵게·크기, 개요 번호는 붙이지 않는다.#####·######은####처럼 그린다.\는 줄 바꿈이다.-/*/+글머리표와1./1)번호 목록: 들여쓰기로 수준을 나누고doc.styles.apply_list_format으로 한/글 목록을 적용한다. 시작 번호를 지키고, 앞 문단 바로 뒤에 와도 목록으로 읽는다.|표:|---|구분선 위 행은 굵게·음영 머리글로 그린다. 짧은 행은 빈 칸으로 채우고, 칸 안<br>은 줄 바꿈이다.**굵게**·__굵게__,*기울임*,***둘 다***.`코드`와[글](주소)는 글자만 남기고,\이스케이프를 따른다.MarkdownStyle(frozen dataclass)로 바꾼다. 기본값:#16pt,##12pt,###11pt,####10pt(모두 굵게), 머리글 음영#D9D9D9. 제목 위·아래 간격과 본문 크기, 글머리표 문자도 이 객체로 정한다.add_paragraph·add_run·add_table·set_cell_shading·styles.ensure_run·apply_list_format·apply_paragraph_format)만 쓰며, 새 의존성도 없다.2. 깨끗한 새 문서 모드
add_paragraph의 기본값은 마지막 문단의paraPrIDRef/styleIDRef/charPrIDRef를 물려받는다. 그래서add_heading이나 목록 바로 뒤에 붙인 문단이 개요·목록 번호를 함께 받았다.HwpxDocument.new(inherit_style=False)로 만든 문서에서는add_paragraph가 바탕글 모양에서 시작한다. 호출할 때inherit_style=True를 주면 전처럼 물려받는다.add_paragraph(inherit_style=None)의None은 "문서 설정을 따름"이다. 기본 문서는 전처럼 물려받으므로 기존 동작은 바뀌지 않는다.배치 결정
official공문,notice가정통신문 등)은 core에 넣지 않았다. 계층 가드레일상 장르·기관 판단은 응용 계층(automation/skill)의 몫이다. core는 장르 중립 기본 모양과 덮어쓸 수 있는MarkdownStyle만 제공하고, 프리셋은 automation이 이 스타일을 만들어 넘기면 된다.HwpxDocument.from_markdown을 제안했다. 하지만 6.x 루트 표면이 예산 한도(35/35, 1-in-1-out)에 차 있어 생성자를 모듈 함수로 두었다.mail_merge·document_merge처럼hwpx.tools모듈 진입점이다. 루트 칸을 하나 비워 옮기는 것은 별도 결정으로 남긴다.계약·문서
markdown-import영역을 등재했다(namespace 없음, 모듈 진입점). support-matrix에는Create(experimental)행을 더하고 편집기 표면 인벤토리를 다시 생성했다.new·add_paragraph의 시그니처 변경만 반영된다(멤버 수는 그대로).[Unreleased] > 추가와docs/usage.md「Markdown으로 문서 만들기」(실행되는 standalone 예제)를 추가했다.검증
tests/test_markdown_import.py21건이 통과했다. 각 구성 요소(인라인 파싱, 제목·문단·목록 수준·번호 시작·표 머리글 음영과 굵게)를 확인한다. 개요·목록 번호 누수가 없는지, 저장·재열기 텍스트가 같은지,validate_editor_open_safety가 ok인지, 모르는 Markdown이 오류를 내지 않는지, 기존 문서에 덧붙이기와 상속 기본/깨끗한 모드도 확인한다.test_size_ratchet,test_namespace_hygiene,test_capabilities_surface,test_contract_docs_sync,test_document_facade_surface,test_engine_surface_6_0,test_stable_surface,test_golden_api,test_editor_surface_inventory,test_documentation_code_fences)가 모두 통과했다.add_paragraph/inherit_style/스타일·목록·제목 관련 테스트 480건이 통과했다.ruff check --select E9,F .과scripts/check_public_hygiene.py가 통과했다.Create(experimental)로 두었다.validate()에서head:bullets스키마 순서 경고 1건이 나온다. 기존apply_list_format에서도 똑같이 나는 경고라 이 PR과는 무관하다.🤖 Generated with Claude Code