Files
Aislo/resources/knowledge/original/_pipeline/fix_box_tables.py
T
eomsangdonandClaude Opus 5 4cb9b15939 style: 저장소 전체 포맷터 일괄 적용 (prettier·biome·ruff)
파일마다 포맷 폭이 달라(≈80 대 100) 한 줄만 고쳐도 포맷터가 무관한 줄을 대량
재포맷했음. 사용자 지시로 전체를 한 번에 맞춤. 코드 동작 변경 없음 — 포맷만.

- 프론트엔드 `.ts/.css/.html` → 저장소 prettier (`.prettierrc`, printWidth 100)
- `B07_DesignDetail/openwebcad/**` → 자체 biome (tab 들여쓰기·single quote·lineWidth 100).
  `biome format` 만 사용 — `biome lint --write` 는 포맷 아닌 코드 수정까지 하므로 제외
- 파이썬 → `ruff format` (엔진 코드는 이미 정합, resources·scratch 스크립트 24개만 변경)

두 포맷터가 서로 되돌리지 않도록 `.prettierignore` 신규 — openwebcad 와 빌드·산출물
폴더를 prettier 대상에서 뺌. `.prettierrc` 에 `endOfLine: "auto"` 추가 — 기본값 `lf` 가
`core.autocrlf=true` 로 받은 CRLF 파일을 매번 전부 다시 써서 `--list-different` 가
실제 포맷 차이를 가리고 있었음.

검증: `tsc --noEmit` 통과(루트·openwebcad 둘 다), pytest 349 passed / 17 skipped /
0 failed, CAD vitest 87건 중 81 passed / 6 failed(laptop-sub 기준선과 동일, 회귀 없음).
포맷터 재실행 시 prettier·biome 모두 변경 0건.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 07:08:24 +09:00

107 lines
3.5 KiB
Python

# -*- coding: utf-8 -*-
"""ASCII 박스표(┌┬┐│├┼┤└┴┘─)를 정식 마크다운 표로 변환.
법령 조문의 <img> 안에 있던 박스 드로잉 표가 이미지 로컬화 후 텍스트로 남는데,
│로 열을 구분하므로 md 표로 복원한다. 각 표에는 대응 ![그림]도 이미 있다.
"""
import re, sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
BORDER = set("┌┬┐├┼┤└┴┘─━┏┳┓┣╋┫┗┻┛│┃ \t")
VBAR = "│┃|"
QP = re.compile(r"^\s*>+\s?") # 인용블록 접두 '> '
def unq(l):
return QP.sub("", l)
def is_border(l):
s = unq(l).strip()
return bool(s) and all(c in BORDER for c in s) and any(c in "─━┼┬┴┌┐└┘├┤" for c in s)
def is_data(l):
return any(c in "│┃" for c in unq(l))
def split_cells(l):
s = unq(l).strip().strip("│┃")
return [c.strip() for c in re.split(r"[│┃]", s)]
def convert_block(lines):
rows = [split_cells(l) for l in lines if is_data(l)]
rows = [r for r in rows if any(c for c in r)]
if len(rows) < 2:
return None
w = max(len(r) for r in rows)
if w < 2:
return None
rows = [r + [""] * (w - len(r)) for r in rows]
esc = lambda c: c.replace("|", "\\|")
out = ["| " + " | ".join(esc(c) for c in rows[0]) + " |", "|" + "|".join(["---"] * w) + "|"]
for r in rows[1:]:
out.append("| " + " | ".join(esc(c) for c in r) + " |")
return out
def fix(md_path):
lines = md_path.read_text(encoding="utf-8").split("\n")
out = []
i, n = 0, len(lines)
changed = 0
infence = False
while i < n:
if lines[i].lstrip().startswith("```"):
infence = not infence
out.append(lines[i])
i += 1
continue
# 박스표 블록 시작: border 또는 data(│ 포함) 연속 (펜스 밖에서만)
if not infence and (
is_border(lines[i]) or (is_data(lines[i]) and not lines[i].lstrip().startswith("|"))
):
j = i
block = []
while j < n and (
is_border(lines[j]) or (is_data(lines[j]) and not lines[j].lstrip().startswith("|"))
):
block.append(lines[j])
j += 1
data_rows = [b for b in block if is_data(b)]
md = convert_block(block)
# 열이 일정한 진짜 표만 md 표로. 아니면(수식 등) 코드펜스로 정렬 보존.
widths = {len(split_cells(b)) for b in data_rows}
if md and len(data_rows) >= 2 and len(widths) == 1:
out += ["", *md, ""]
changed += 1
i = j
continue
if len(data_rows) >= 1 or any(is_border(b) for b in block):
trimmed = [b.rstrip() for b in block if b.strip()]
if trimmed:
out += ["", "```text", *trimmed, "```", ""]
changed += 1
i = j
continue
out.append(lines[i])
i += 1
if changed:
md_path.write_text("\n".join(out), encoding="utf-8")
return changed
if __name__ == "__main__":
total = 0
for md in ROOT.rglob("*.md"):
if "임도기술교본" in str(md) or "_pipeline" in str(md):
continue
c = fix(md)
if c:
total += c
print(f" {c}개 표 {md.parent.parent.name[:26]}/{md.name}")
print(f"\n박스표 → md표 변환 {total}개")