kordoc 3.10.0 → 3.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/dist/{-3B5FDXW2.js → -LPEXY73L.js} +5 -5
  2. package/dist/{chunk-ZQOGTAT5.cjs → chunk-7UXZTZBJ.cjs} +2 -2
  3. package/dist/{chunk-ZQOGTAT5.cjs.map → chunk-7UXZTZBJ.cjs.map} +1 -1
  4. package/dist/{chunk-MZA7AXHN.js → chunk-GFS4QWB6.js} +2 -2
  5. package/dist/{chunk-PNXOUDS7.js → chunk-I6CX2RK4.js} +2 -2
  6. package/dist/{chunk-5TK4X4JQ.js → chunk-RMGYE4LT.js} +5 -5
  7. package/dist/{chunk-FU25KFFZ.js → chunk-UR34PYAC.js} +3 -3
  8. package/dist/chunk-UR34PYAC.js.map +1 -0
  9. package/dist/{chunk-5DL6VCIJ.js → chunk-YXEE3DEQ.js} +2 -2
  10. package/dist/cli.js +7 -7
  11. package/dist/index.cjs +119 -119
  12. package/dist/index.cjs.map +1 -1
  13. package/dist/index.js +3 -3
  14. package/dist/index.js.map +1 -1
  15. package/dist/mcp.js +5 -5
  16. package/dist/{parser-DKIA66MN.js → parser-664URIIW.js} +2 -2
  17. package/dist/{parser-6B7BUSX3.cjs → parser-AT22HMF5.cjs} +14 -14
  18. package/dist/{parser-6B7BUSX3.cjs.map → parser-AT22HMF5.cjs.map} +1 -1
  19. package/dist/{parser-VCJTQVAH.js → parser-LJOS7VZM.js} +3 -3
  20. package/dist/render-XWOEGE3U.js +9 -0
  21. package/dist/{watch-MQTMNUSB.js → watch-CZF6NA2V.js} +5 -5
  22. package/package.json +1 -1
  23. package/dist/chunk-FU25KFFZ.js.map +0 -1
  24. package/dist/render-4I72JOAR.js +0 -9
  25. /package/dist/{-3B5FDXW2.js.map → -LPEXY73L.js.map} +0 -0
  26. /package/dist/{chunk-MZA7AXHN.js.map → chunk-GFS4QWB6.js.map} +0 -0
  27. /package/dist/{chunk-PNXOUDS7.js.map → chunk-I6CX2RK4.js.map} +0 -0
  28. /package/dist/{chunk-5TK4X4JQ.js.map → chunk-RMGYE4LT.js.map} +0 -0
  29. /package/dist/{chunk-5DL6VCIJ.js.map → chunk-YXEE3DEQ.js.map} +0 -0
  30. /package/dist/{parser-DKIA66MN.js.map → parser-664URIIW.js.map} +0 -0
  31. /package/dist/{parser-VCJTQVAH.js.map → parser-LJOS7VZM.js.map} +0 -0
  32. /package/dist/{render-4I72JOAR.js.map → render-XWOEGE3U.js.map} +0 -0
  33. /package/dist/{watch-MQTMNUSB.js.map → watch-CZF6NA2V.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/render/svg-render.ts","../src/hwpx/parser-shared.ts","../src/render/layout.ts","../src/hwpx/text-metrics.ts","../src/render/head-styles.ts"],"sourcesContent":["/**\n * 레이아웃 보존 렌더 — HWPX 조판 캐시(lineseg·cellAddr·hp:pos)를 SVG 절대배치로 그린다.\n *\n * 조판 엔진 없음: 한컴이 저장 시 기록한 좌표를 그대로 사용한다. 따라서\n * 한컴(또는 조판 캐시를 기록하는 편집기)에서 저장한 파일만 렌더 가능 —\n * markdownToHwpx 산출물엔 linesegarray가 없어 KordocError를 던진다.\n *\n * 좌표 산식(실측 검증 — .claude/plans/render-poc/findings.md):\n * - 단위 HWPUNIT(1/7200in), pt = /100. 최상위 문단 lineseg = 본문영역 로컬,\n * 셀 문단 = 셀 로컬. PARA 밀어내기 개체 anchor = 호스트vp − (omTop+h+omBottom) 역산.\n * - horzsize는 줄 \"영역\" 폭(텍스트 폭 아님) — 마지막 줄이 아닌 줄은 원본 줄바꿈에\n * 맞춰 textLength로 고정하고, 마지막 줄만 paraPr 정렬(LEFT 자연폭/CENTER/RIGHT/배분)을 적용.\n * - 좌표 속성엔 uint32로 저장된 음수가 섞여 있다(toInt32 필수).\n * - 표 열은 span 제약 경계 전파로, 행은 rs=1 max + 콘텐츠 초과 성장으로 푼다.\n *\n * 범위: 1페이지(section0) 한정, 수식·그리기개체 도형은 미지원(경고 수집).\n */\n\nimport JSZip from \"jszip\"\nimport { KordocError } from \"../utils.js\"\nimport { createXmlParser, findChildByLocalName, MAX_DECOMPRESS_SIZE } from \"../hwpx/parser-shared.js\"\nimport { toInt32, solveBoundaries, solveRowHeights, type SpanConstraint } from \"./layout.js\"\nimport { measureTextWidth } from \"../hwpx/text-metrics.js\"\nimport { parseRenderStyles, DEFAULT_CHAR, type RenderStyles, type RenderBorderEdge } from \"./head-styles.js\"\n\nexport interface RenderSvgOptions {\n /** 이미지 1장당 허용 최대 바이트 (기본 40MB) */\n maxImageBytes?: number\n}\n\nexport interface RenderSvgResult {\n svg: string\n /** 페이지 크기 (pt) */\n width: number\n height: number\n warnings: string[]\n stats: { texts: number; images: number; tables: number }\n}\n\n// ─── XML 헬퍼 ─────────────────────────────────────\n\nfunction ln(el: Element): string {\n return (el.tagName || \"\").replace(/^[^:]+:/, \"\")\n}\n\nfunction elements(el: Element): Element[] {\n const out: Element[] = []\n const children = el.childNodes\n if (!children) return out\n for (let i = 0; i < children.length; i++) {\n if (children[i].nodeType === 1) out.push(children[i] as Element)\n }\n return out\n}\n\nfunction num(el: Element | null, attr: string, fallback = 0): number {\n return el ? toInt32(el.getAttribute(attr) ?? undefined, fallback) : fallback\n}\n\nfunction findFirst(el: Element, name: string, depth = 0): Element | null {\n if (depth > 64) return null\n for (const ch of elements(el)) {\n if (ln(ch) === name) return ch\n const found = findFirst(ch, name, depth + 1)\n if (found) return found\n }\n return null\n}\n\nfunction escapeXml(s: string): string {\n return s.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\").replace(/\"/g, \"&quot;\")\n}\n\n// ─── 내부 모델 ────────────────────────────────────\n\ninterface PageGeom { PW: number; PH: number; ML: number; MT: number; BODY_W: number; BODY_H: number }\n\ninterface Seg { textpos: number; vertpos: number; horzpos: number; horzsize: number; textheight: number; baseline: number }\n\ninterface ParaChar { ch: string; prId: string | null }\n\n/** 렌더 대상 개체 태그 — 이 외(도형류)는 경고 후 생략 */\nconst OBJ_TAGS = new Set([\"tbl\", \"pic\", \"container\", \"equation\", \"rect\", \"ellipse\", \"polygon\", \"curv\", \"line\", \"arc\", \"ole\", \"textart\"])\n\ninterface ParaObj { el: Element; tag: string; index: number; inline: boolean; width: number; height: number }\n\ninterface ParaModel { chars: ParaChar[]; segs: Seg[]; objs: ParaObj[]; paraPrId: string | null }\n\ninterface Ctx {\n svg: string[]\n geom: PageGeom\n styles: RenderStyles\n images: Map<string, { dataUri: string; orgW?: number; orgH?: number }>\n warnings: string[]\n warned: Set<string>\n stats: { texts: number; images: number; tables: number }\n}\n\nconst pt = (u: number): string => String(Math.round(u) / 100)\n\nfunction warnOnce(ctx: Ctx, key: string, msg: string): void {\n if (ctx.warned.has(key)) return\n ctx.warned.add(key)\n ctx.warnings.push(msg)\n}\n\n// ─── 문단 모델 구축 ────────────────────────────────\n\nfunction textOfT(t: Element): string {\n // hp:t 내부 텍스트 노드만 (markpen 등 자식 요소의 텍스트 포함)\n let s = \"\"\n const walk = (n: Node, d: number): void => {\n if (d > 32) return\n const kids = n.childNodes\n if (!kids) return\n for (let i = 0; i < kids.length; i++) {\n const c = kids[i]\n if (c.nodeType === 3) s += c.textContent ?? \"\"\n else if (c.nodeType === 1) walk(c, d + 1)\n }\n }\n walk(t, 0)\n return s\n}\n\nfunction buildPara(p: Element): ParaModel {\n const chars: ParaChar[] = []\n const objs: ParaObj[] = []\n let segs: Seg[] = []\n for (const runEl of elements(p)) {\n const tag = ln(runEl)\n if (tag === \"run\") {\n const prId = runEl.getAttribute(\"charPrIDRef\")\n for (const ch of elements(runEl)) {\n const cn = ln(ch)\n if (cn === \"t\") {\n for (const c of textOfT(ch)) chars.push({ ch: c, prId })\n } else if (OBJ_TAGS.has(cn)) {\n const sz = findChildByLocalName(ch, \"sz\")\n const pos = findChildByLocalName(ch, \"pos\")\n objs.push({\n el: ch, tag: cn, index: chars.length,\n inline: pos?.getAttribute(\"treatAsChar\") === \"1\",\n width: num(sz, \"width\"), height: num(sz, \"height\"),\n })\n }\n }\n } else if (tag === \"linesegarray\") {\n segs = elements(runEl).filter(s => ln(s) === \"lineseg\").map(s => ({\n textpos: num(s, \"textpos\"), vertpos: num(s, \"vertpos\"), horzpos: num(s, \"horzpos\"),\n horzsize: num(s, \"horzsize\"), textheight: num(s, \"textheight\", 1000), baseline: num(s, \"baseline\", 850),\n }))\n }\n }\n return { chars, segs, objs, paraPrId: p.getAttribute(\"paraPrIDRef\") }\n}\n\n// ─── 줄 렌더 (run별 charPr + 정렬) ──────────────────\n\ninterface LinePlan {\n seg: Seg\n /** 줄 시작 x 보정 (정렬) */\n xoff: number\n /** 텍스트 조각 폭 스케일 */\n scale: number\n start: number\n end: number\n}\n\nfunction charW(c: ParaChar, styles: RenderStyles): number {\n const st = (c.prId != null ? styles.charPr.get(c.prId) : undefined) ?? DEFAULT_CHAR\n return measureTextWidth(c.ch, st.height, st.ratio, { spacingPct: st.spacing })\n}\n\n/** 줄 자연폭 = 텍스트 조각 + 인라인 개체 폭 (개체 폭은 스케일 불변) */\nfunction lineNaturalWidth(m: ParaModel, styles: RenderStyles, start: number, end: number): { text: number; obj: number } {\n let text = 0\n for (let i = start; i < end && i < m.chars.length; i++) text += charW(m.chars[i], styles)\n let obj = 0\n for (const o of m.objs) if (o.inline && o.index >= start && o.index < end) obj += o.width\n return { text, obj }\n}\n\nfunction planLines(m: ParaModel, styles: RenderStyles): LinePlan[] {\n const align = (m.paraPrId != null ? styles.paraAlign.get(m.paraPrId) : undefined) ?? \"JUSTIFY\"\n const plans: LinePlan[] = []\n for (let i = 0; i < m.segs.length; i++) {\n const seg = m.segs[i]\n const start = seg.textpos\n const end = i + 1 < m.segs.length ? m.segs[i + 1].textpos : Math.max(m.chars.length, start)\n const nat = lineNaturalWidth(m, styles, start, end)\n const isLast = i === m.segs.length - 1\n let xoff = 0\n let scale = 1\n const avail = seg.horzsize - nat.obj\n if (nat.text > 0 && (!isLast || align === \"DISTRIBUTE\" || align === \"DISTRIBUTE_SPACE\")) {\n // 줄바꿈이 고정된 중간 줄·배분정렬 — 줄 영역 폭에 맞춰 고정 (원본 조판 재현)\n scale = avail > 0 ? avail / nat.text : 1\n } else if (nat.text + nat.obj > 0 && isLast) {\n const w = nat.text + nat.obj\n if (align === \"CENTER\") xoff = Math.max(0, (seg.horzsize - w) / 2)\n else if (align === \"RIGHT\") xoff = Math.max(0, seg.horzsize - w)\n }\n if (!Number.isFinite(scale) || scale <= 0) scale = 1\n scale = Math.min(4, Math.max(0.25, scale))\n plans.push({ seg, xoff, scale, start, end })\n }\n return plans\n}\n\n/** 줄 안 [start, upto) 구간의 전진폭 (텍스트×스케일 + 인라인 개체) */\nfunction advanceTo(m: ParaModel, styles: RenderStyles, plan: LinePlan, upto: number): number {\n let x = 0\n for (let i = plan.start; i < upto && i < m.chars.length; i++) x += charW(m.chars[i], styles) * plan.scale\n for (const o of m.objs) if (o.inline && o.index >= plan.start && o.index < upto) x += o.width\n return x\n}\n\n// ─── 문단 드로잉 ───────────────────────────────────\n\nfunction drawPara(p: Element, ox: number, oy: number, areaW: number, ctx: Ctx, depth: number): void {\n if (depth > 16) { warnOnce(ctx, \"depth\", \"중첩 깊이 16 초과 — 이하 생략\"); return }\n const m = buildPara(p)\n if (m.segs.length === 0) {\n // 조판 캐시 없는 문단 — 개체만이라도 문단 원점에 배치\n for (const o of m.objs) drawObject(o, ox, oy, 0, areaW, ctx, depth)\n return\n }\n const plans = planLines(m, ctx.styles)\n const baseV = m.segs[0].vertpos\n\n for (const plan of plans) {\n const { seg } = plan\n // charPr 단위 조각으로 분할\n let i = plan.start\n let cursor = ox + seg.horzpos + plan.xoff\n const y = oy + seg.vertpos + seg.baseline\n while (i < plan.end && i < m.chars.length) {\n const prId = m.chars[i].prId\n let j = i\n let piece = \"\"\n while (j < plan.end && j < m.chars.length && m.chars[j].prId === prId) { piece += m.chars[j].ch; j++ }\n // 이 조각 구간에 걸친 인라인 개체 폭 반영을 위해 개체 경계에서도 절단\n for (const o of m.objs) {\n if (o.inline && o.index > i && o.index < j) { piece = piece.slice(0, o.index - i); j = o.index; break }\n }\n // 연속 공백(2+) 경계 절단 — 공백 폭 오차(한컴 0.5em 고정 vs 뷰어 폰트)를\n // 공백 구간에 가둔다 (공무원 스페이스 정렬 원문에서 글자 벌어짐 방지)\n {\n const cut = piece.search(/ {2,}/)\n if (cut > 0) { piece = piece.slice(0, cut); j = i + cut }\n else if (cut === 0) {\n const runEnd = piece.match(/^ +/)![0].length\n piece = piece.slice(0, runEnd); j = i + runEnd\n }\n }\n const st = (prId != null ? ctx.styles.charPr.get(prId) : undefined) ?? DEFAULT_CHAR\n const w = measureTextWidth(piece, st.height, st.ratio, { spacingPct: st.spacing }) * plan.scale\n if (piece.trim().length > 0) {\n const attrs: string[] = [`x=\"${pt(cursor)}\"`, `y=\"${pt(y)}\"`, `font-size=\"${pt(st.height)}\"`]\n if ([...piece].length > 1 && w > 50) {\n attrs.push(`textLength=\"${pt(w)}\"`, `lengthAdjust=\"${plan.scale < 1 ? \"spacingAndGlyphs\" : \"spacing\"}\"`)\n }\n if (st.bold) attrs.push(`font-weight=\"bold\"`)\n if (st.italic) attrs.push(`font-style=\"italic\"`)\n if (st.underline) attrs.push(`text-decoration=\"underline\"`)\n if (st.color) attrs.push(`fill=\"${escapeXml(st.color)}\"`)\n ctx.svg.push(`<text ${attrs.join(\" \")}>${escapeXml(piece)}</text>`)\n ctx.stats.texts++\n }\n cursor += w\n // 개체 경계에서 끊었으면 개체 폭만큼 전진\n for (const o of m.objs) if (o.inline && o.index === j) cursor += o.width\n i = j\n }\n }\n\n // 개체 배치 — 인라인은 소속 줄 위치, 앵커는 hp:pos 해석\n for (const o of m.objs) {\n if (o.inline) {\n let plan = plans[0]\n for (const pl of plans) if (pl.start <= o.index && (o.index < pl.end || pl === plans[plans.length - 1])) plan = pl\n const x = ox + plan.seg.horzpos + plan.xoff + advanceTo(m, ctx.styles, plan, o.index)\n // 개체가 줄보다 낮으면 baseline 위에 얹고, 줄을 채우는 개체(th==h)는 줄 상단\n const yTop = oy + plan.seg.vertpos + Math.max(0, plan.seg.baseline - o.height)\n drawObject(o, x, yTop, baseV, areaW, ctx, depth)\n } else {\n const { x, y } = anchorObject(o, ox, oy, baseV, areaW, ctx)\n drawObject(o, x, y, baseV, areaW, ctx, depth)\n }\n }\n}\n\n/** hp:pos 기준계 해석 → 개체 좌상단 절대좌표 (tac=0) */\nfunction anchorObject(o: ParaObj, ox: number, oy: number, baseV: number, areaW: number, ctx: Ctx): { x: number; y: number } {\n const { PW, PH, ML, MT, BODY_W, BODY_H } = ctx.geom\n const pos = findChildByLocalName(o.el, \"pos\")\n const om = findChildByLocalName(o.el, \"outMargin\")\n const omT = num(om, \"top\"), omB = num(om, \"bottom\")\n const w = o.width, h = o.height\n if (!pos) return { x: ox, y: oy + baseV }\n const vo = num(pos, \"vertOffset\")\n const ho = num(pos, \"horzOffset\")\n const vrel = pos.getAttribute(\"vertRelTo\") ?? \"PARA\"\n const hrel = pos.getAttribute(\"horzRelTo\") ?? \"PARA\"\n const va = pos.getAttribute(\"vertAlign\") ?? \"TOP\"\n const ha = pos.getAttribute(\"horzAlign\") ?? \"LEFT\"\n const wrap = o.el.getAttribute(\"textWrap\") ?? \"TOP_AND_BOTTOM\"\n\n let y: number\n if (vrel === \"PAPER\") {\n y = va === \"BOTTOM\" ? PH - h - vo : va === \"CENTER\" ? (PH - h) / 2 + vo : vo\n } else if (vrel === \"PAGE\") {\n y = va === \"BOTTOM\" ? MT + BODY_H - h - vo : va === \"CENTER\" ? MT + (BODY_H - h) / 2 + vo : MT + vo\n } else if (wrap === \"TOP_AND_BOTTOM\") {\n // PARA 밀어내기 역산 — 호스트 문단 vp가 개체(여백 포함)만큼 밀렸다는 모델 (실측 일치).\n // 음수면 밀지 않은 개체(빈 호스트 줄 등)로 보고 현재 흐름 y 사용.\n const pushed = baseV - (omT + h + omB)\n const anchor = pushed >= -100 ? pushed : baseV\n y = oy + anchor + omT + vo\n } else {\n // BEHIND_TEXT/IN_FRONT/SQUARE — 문단을 밀지 않는 개체는 문단 원점 흐름 배치\n y = oy + baseV + vo\n }\n\n let x: number\n if (hrel === \"PAGE\") {\n x = ha === \"RIGHT\" ? ML + BODY_W - w - ho : ha === \"CENTER\" ? ML + (BODY_W - w) / 2 + ho : ML + ho\n } else if (hrel === \"PAPER\") {\n x = ha === \"RIGHT\" ? PW - w - ho : ha === \"CENTER\" ? (PW - w) / 2 + ho : ho\n } else {\n // PARA/COLUMN — 현재 텍스트 영역 기준 (셀 안이면 셀 내부 폭. COLUMN을 페이지\n // 단으로 읽으면 셀 안 개체가 페이지 왼쪽으로 튄다 — 사진대지 우측 셀 실측)\n x = ha === \"RIGHT\" ? ox + areaW - w - ho : ha === \"CENTER\" ? ox + (areaW - w) / 2 + ho : ox + ho\n }\n return { x, y }\n}\n\nfunction drawObject(o: ParaObj, x: number, y: number, baseV: number, areaW: number, ctx: Ctx, depth: number): void {\n if (o.tag === \"tbl\") drawTable(o.el, x, y, ctx, depth + 1)\n else if (o.tag === \"pic\") drawPic(o.el, x, y, ctx)\n else if (o.tag === \"container\") {\n // 그리기개체 묶음 — 자식 개체를 컨테이너 원점 기준으로 재귀 배치\n for (const ch of elements(o.el)) {\n const tag = ln(ch)\n if (!OBJ_TAGS.has(tag)) continue\n const sz = findChildByLocalName(ch, \"sz\")\n const off = findChildByLocalName(ch, \"offset\")\n const sub: ParaObj = { el: ch, tag, index: 0, inline: true, width: num(sz, \"width\"), height: num(sz, \"height\") }\n drawObject(sub, x + num(off, \"x\"), y + num(off, \"y\"), baseV, areaW, ctx, depth + 1)\n }\n } else if (o.tag === \"equation\") {\n warnOnce(ctx, \"equation\", \"수식 개체는 렌더 미지원 — 생략\")\n } else {\n warnOnce(ctx, `shape:${o.tag}`, `도형 개체(${o.tag}) 렌더 미지원 — 생략`)\n }\n}\n\n// ─── 표 ───────────────────────────────────────────\n\ninterface CellModel {\n el: Element\n ca: number; ra: number; cs: number; rs: number\n w: number; h: number\n bfId: string | null\n sub: Element | null\n marginL: number; marginR: number; marginT: number; marginB: number\n}\n\n/** 셀 콘텐츠 세로 범위 — 줄(vp+th)과 PARA 앵커 개체(anchor+h) 최대값 */\nfunction cellContentExtent(cell: CellModel, ctx: Ctx): number {\n if (!cell.sub) return 0\n let ext = 0\n for (const p of elements(cell.sub)) {\n if (ln(p) !== \"p\") continue\n const m = buildPara(p)\n for (const s of m.segs) ext = Math.max(ext, s.vertpos + s.textheight)\n const baseV = m.segs[0]?.vertpos ?? 0\n for (const o of m.objs) {\n if (o.inline) continue\n const pos = findChildByLocalName(o.el, \"pos\")\n if ((pos?.getAttribute(\"vertRelTo\") ?? \"PARA\") !== \"PARA\") continue\n const om = findChildByLocalName(o.el, \"outMargin\")\n const pushed = baseV - (num(om, \"top\") + o.height + num(om, \"bottom\"))\n const anchor = pushed >= -100 ? pushed : baseV\n ext = Math.max(ext, anchor + num(om, \"top\") + num(pos, \"vertOffset\") + o.height)\n }\n }\n return ext\n}\n\nfunction edgeLine(x1: number, y1: number, x2: number, y2: number, e: RenderBorderEdge): string {\n const dash = /DASH|DOT/.test(e.type) ? ` stroke-dasharray=\"${e.type.includes(\"DOT\") ? \"1,1.5\" : \"3,1.5\"}\"` : \"\"\n return `<line x1=\"${pt(x1)}\" y1=\"${pt(y1)}\" x2=\"${pt(x2)}\" y2=\"${pt(y2)}\" stroke=\"${escapeXml(e.color)}\" stroke-width=\"${e.widthPt.toFixed(2)}\"${dash}/>`\n}\n\nfunction drawTable(tbl: Element, tx: number, ty: number, ctx: Ctx, depth: number): void {\n if (depth > 16) { warnOnce(ctx, \"depth\", \"중첩 깊이 16 초과 — 이하 생략\"); return }\n ctx.stats.tables++\n const tblSz = findChildByLocalName(tbl, \"sz\")\n const inMargin = findChildByLocalName(tbl, \"inMargin\")\n const defL = num(inMargin, \"left\", 141), defR = num(inMargin, \"right\", 141)\n const defT = num(inMargin, \"top\", 141), defB = num(inMargin, \"bottom\", 141)\n\n const cells: CellModel[] = []\n for (const tr of elements(tbl)) {\n if (ln(tr) !== \"tr\") continue\n for (const tc of elements(tr)) {\n if (ln(tc) !== \"tc\") continue\n const addr = findChildByLocalName(tc, \"cellAddr\")\n const span = findChildByLocalName(tc, \"cellSpan\")\n const csz = findChildByLocalName(tc, \"cellSz\")\n const cm = findChildByLocalName(tc, \"cellMargin\")\n if (!addr || !csz) continue\n cells.push({\n el: tc,\n ca: num(addr, \"colAddr\"), ra: num(addr, \"rowAddr\"),\n cs: Math.max(1, num(span, \"colSpan\", 1)), rs: Math.max(1, num(span, \"rowSpan\", 1)),\n w: num(csz, \"width\"), h: num(csz, \"height\"),\n bfId: tc.getAttribute(\"borderFillIDRef\"),\n sub: findChildByLocalName(tc, \"subList\"),\n marginL: cm ? num(cm, \"left\", defL) : defL, marginR: cm ? num(cm, \"right\", defR) : defR,\n marginT: cm ? num(cm, \"top\", defT) : defT, marginB: cm ? num(cm, \"bottom\", defB) : defB,\n })\n }\n }\n if (cells.length === 0 || cells.length > 4096) return\n\n const nCols = Math.max(...cells.map(c => c.ca + c.cs))\n const nRows = Math.max(...cells.map(c => c.ra + c.rs))\n const colCons: SpanConstraint[] = cells.map(c => ({ a: c.ca, b: c.ca + c.cs, size: c.w }))\n const colX = solveBoundaries(colCons, nCols, num(tblSz, \"width\") || undefined)\n const rowH = solveRowHeights(\n cells.map(c => ({ rowAddr: c.ra, rowSpan: c.rs, height: c.h, contentH: c.rs === 1 ? cellContentExtent(c, ctx) : undefined })),\n nRows,\n )\n const rowY: number[] = [0]\n for (let r = 0; r < nRows; r++) rowY.push(rowY[r] + rowH[r])\n\n // 1패스: 배경 → 2패스: 콘텐츠 → 3패스: 테두리 (테두리가 배경/콘텐츠 위)\n const geom = cells.map(c => ({\n c,\n x: tx + colX[c.ca], y: ty + rowY[c.ra],\n w: colX[Math.min(c.ca + c.cs, nCols)] - colX[c.ca],\n h: rowY[Math.min(c.ra + c.rs, nRows)] - rowY[c.ra],\n }))\n for (const g of geom) {\n const bf = g.c.bfId != null ? ctx.styles.borderFill.get(g.c.bfId) : undefined\n if (bf?.fill) ctx.svg.push(`<rect x=\"${pt(g.x)}\" y=\"${pt(g.y)}\" width=\"${pt(g.w)}\" height=\"${pt(g.h)}\" fill=\"${escapeXml(bf.fill)}\"/>`)\n }\n for (const g of geom) {\n const { c } = g\n if (!c.sub) continue\n const innerH = g.h - c.marginT - c.marginB\n const extent = cellContentExtent(c, ctx)\n const va = c.sub.getAttribute(\"vertAlign\") ?? \"TOP\"\n let yoff = 0\n if (va === \"CENTER\") yoff = Math.max(0, (innerH - extent) / 2)\n else if (va === \"BOTTOM\") yoff = Math.max(0, innerH - extent)\n for (const p of elements(c.sub)) {\n if (ln(p) !== \"p\") continue\n drawPara(p, g.x + c.marginL, g.y + c.marginT + yoff, g.w - c.marginL - c.marginR, ctx, depth + 1)\n }\n }\n for (const g of geom) {\n const bf = g.c.bfId != null ? ctx.styles.borderFill.get(g.c.bfId) : undefined\n if (!bf) continue\n if (bf.top) ctx.svg.push(edgeLine(g.x, g.y, g.x + g.w, g.y, bf.top))\n if (bf.bottom) ctx.svg.push(edgeLine(g.x, g.y + g.h, g.x + g.w, g.y + g.h, bf.bottom))\n if (bf.left) ctx.svg.push(edgeLine(g.x, g.y, g.x, g.y + g.h, bf.left))\n if (bf.right) ctx.svg.push(edgeLine(g.x + g.w, g.y, g.x + g.w, g.y + g.h, bf.right))\n }\n}\n\n// ─── 이미지 ───────────────────────────────────────\n\nfunction drawPic(pic: Element, x: number, y: number, ctx: Ctx): void {\n const sz = findChildByLocalName(pic, \"sz\")\n const w = num(sz, \"width\", 5669), h = num(sz, \"height\", 5669)\n const img = findFirst(pic, \"img\")\n const ref = img?.getAttribute(\"binaryItemIDRef\")\n const loaded = ref != null ? ctx.images.get(ref) : undefined\n if (!loaded) {\n ctx.svg.push(`<rect x=\"${pt(x)}\" y=\"${pt(y)}\" width=\"${pt(w)}\" height=\"${pt(h)}\" fill=\"#eee\" stroke=\"#c00\" stroke-width=\"0.5\"/>`)\n warnOnce(ctx, `img:${ref}`, `이미지 바이너리 누락: ${ref ?? \"(ref 없음)\"}`)\n return\n }\n ctx.stats.images++\n const orgSz = findChildByLocalName(pic, \"orgSz\")\n const clip = findChildByLocalName(pic, \"imgClip\")\n const orgW = num(orgSz, \"width\"), orgH = num(orgSz, \"height\")\n const cl = num(clip, \"left\"), ct = num(clip, \"top\")\n const cr = num(clip, \"right\", orgW), cb = num(clip, \"bottom\", orgH)\n const cropped = orgW > 0 && orgH > 0 && clip != null && (cl > 0 || ct > 0 || cr < orgW || cb < orgH) && cr > cl && cb > ct\n if (cropped) {\n // 원본 좌표계 viewBox로 크롭 창을 내고, 이미지는 원본 크기로 깐다\n ctx.svg.push(\n `<svg x=\"${pt(x)}\" y=\"${pt(y)}\" width=\"${pt(w)}\" height=\"${pt(h)}\" viewBox=\"${pt(cl)} ${pt(ct)} ${pt(cr - cl)} ${pt(cb - ct)}\" preserveAspectRatio=\"none\">` +\n `<image x=\"0\" y=\"0\" width=\"${pt(orgW)}\" height=\"${pt(orgH)}\" preserveAspectRatio=\"none\" href=\"${loaded.dataUri}\"/></svg>`,\n )\n } else {\n ctx.svg.push(`<image x=\"${pt(x)}\" y=\"${pt(y)}\" width=\"${pt(w)}\" height=\"${pt(h)}\" preserveAspectRatio=\"none\" href=\"${loaded.dataUri}\"/>`)\n }\n}\n\nfunction sniffMime(name: string, bytes: Uint8Array): string {\n const lower = name.toLowerCase()\n if (lower.endsWith(\".png\") || (bytes.length > 4 && bytes[0] === 0x89 && bytes[1] === 0x50)) return \"image/png\"\n if (lower.endsWith(\".bmp\") || (bytes.length > 2 && bytes[0] === 0x42 && bytes[1] === 0x4d)) return \"image/bmp\"\n if (lower.endsWith(\".gif\")) return \"image/gif\"\n if (lower.endsWith(\".svg\")) return \"image/svg+xml\"\n return \"image/jpeg\"\n}\n\n// ─── 엔트리 ───────────────────────────────────────\n\n/**\n * HWPX(한컴 저장본) → 레이아웃 보존 SVG (1페이지).\n * 조판 캐시(linesegarray)가 없는 파일(예: markdownToHwpx 산출물)은 KordocError.\n */\nexport async function renderHwpxToSvg(input: ArrayBuffer | Uint8Array, options?: RenderSvgOptions): Promise<RenderSvgResult> {\n const maxImg = options?.maxImageBytes ?? 40 * 1024 * 1024\n let zip: JSZip\n try {\n zip = await JSZip.loadAsync(input)\n } catch {\n throw new KordocError(\"HWPX(ZIP) 형식이 아닙니다 — 렌더는 HWPX만 지원\")\n }\n const secFile = zip.file(\"Contents/section0.xml\") ??\n zip.file(/Contents\\/section\\d+\\.xml$/i).sort((a, b) => a.name.localeCompare(b.name))[0]\n if (!secFile) throw new KordocError(\"Contents/section0.xml 없음 — HWPX가 아니거나 손상됨\")\n const secXml = await secFile.async(\"string\")\n if (secXml.length > MAX_DECOMPRESS_SIZE) throw new KordocError(\"섹션 XML이 허용 크기를 초과\")\n if (!secXml.includes(\"linesegarray\")) {\n throw new KordocError(\"조판 캐시(linesegarray) 없음 — 한컴에서 저장한 HWPX만 렌더 가능\")\n }\n\n const warnings: string[] = []\n const headFile = zip.file(\"Contents/header.xml\") ?? zip.file(\"Contents/head.xml\")\n const styles: RenderStyles = headFile\n ? parseRenderStyles(await headFile.async(\"string\"))\n : { charPr: new Map(), paraAlign: new Map(), borderFill: new Map() }\n if (!headFile) warnings.push(\"header.xml 없음 — 기본 스타일로 렌더\")\n\n // BinData 매니페스트 (id → href) — content.hpf 우선, 파일명 휴리스틱 폴백\n const binmap = new Map<string, string>()\n const hpf = zip.file(/content\\.hpf$/i)[0]\n if (hpf) {\n const man = await hpf.async(\"string\")\n for (const m of man.matchAll(/<[^>]*\\bid=\"([^\"]+)\"[^>]*\\bhref=\"(BinData\\/[^\"]+)\"[^>]*>/g)) binmap.set(m[1], m[2])\n for (const m of man.matchAll(/<[^>]*\\bhref=\"(BinData\\/[^\"]+)\"[^>]*\\bid=\"([^\"]+)\"[^>]*>/g)) binmap.set(m[2], m[1])\n }\n // 참조된 이미지만 선로딩 (섹션 문자열 정규식 — DOM 워크 전에 async 구간 종료)\n const images = new Map<string, { dataUri: string }>()\n const refs = new Set<string>()\n for (const m of secXml.matchAll(/binaryItemIDRef=\"([^\"]+)\"/g)) refs.add(m[1])\n for (const ref of refs) {\n let href = binmap.get(ref)\n if (!href) {\n const cand = zip.file(new RegExp(`BinData/.*${ref.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")}`, \"i\"))[0]\n href = cand?.name\n }\n if (!href) continue\n const f = zip.file(href) ?? zip.file(\"Contents/\" + href)\n if (!f) continue\n const bytes = await f.async(\"uint8array\")\n if (bytes.length > maxImg) {\n warnings.push(`이미지 ${href} ${(bytes.length / 1048576).toFixed(1)}MB — 한도 초과로 생략`)\n continue\n }\n images.set(ref, { dataUri: `data:${sniffMime(href, bytes)};base64,${Buffer.from(bytes).toString(\"base64\")}` })\n }\n\n const doc = createXmlParser().parseFromString(secXml, \"text/xml\")\n const root = doc.documentElement as unknown as Element\n if (!root) throw new KordocError(\"섹션 XML 파싱 실패\")\n\n const pagePr = findFirst(root, \"pagePr\")\n const margin = pagePr ? findChildByLocalName(pagePr, \"margin\") : null\n const PW = num(pagePr, \"width\", 59528), PH = num(pagePr, \"height\", 84188)\n const ML = num(margin, \"left\", 8504)\n const MT = num(margin, \"top\", 5668) + num(margin, \"header\", 0)\n const BODY_H = PH - MT - num(margin, \"bottom\", 4252) - num(margin, \"footer\", 0)\n const BODY_W = PW - ML - num(margin, \"right\", 8504)\n\n const ctx: Ctx = {\n svg: [], geom: { PW, PH, ML, MT, BODY_W, BODY_H }, styles, images,\n warnings, warned: new Set(), stats: { texts: 0, images: 0, tables: 0 },\n }\n\n // 최상위 문단 — 1페이지 분량만 (본문영역을 벗어난 문단은 이후 페이지)\n for (const p of elements(root)) {\n if (ln(p) !== \"p\") continue\n const segs = findChildByLocalName(p, \"linesegarray\")\n const first = segs ? elements(segs)[0] : null\n if (first && num(first, \"vertpos\") > BODY_H) continue\n drawPara(p, ML, MT, BODY_W, ctx, 0)\n }\n\n // width/height는 pt 단위 명시 — 단위 없는 px로 두면 A4 실물(96dpi 기준)보다 25% 작게 보인다\n const svg = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 ${pt(PW)} ${pt(PH)}\" width=\"${pt(PW)}pt\" height=\"${pt(PH)}pt\" font-family=\"'HCR Batang','함초롬바탕','Hancom Batang',AppleMyungjo,'Noto Serif CJK KR',serif\" xml:space=\"preserve\">\\n` +\n `<rect width=\"100%\" height=\"100%\" fill=\"white\"/>\\n${ctx.svg.join(\"\\n\")}\\n</svg>`\n return { svg, width: Math.round(PW) / 100, height: Math.round(PH) / 100, warnings, stats: ctx.stats }\n}\n","/**\n * HWPX 파서 공유 상수/타입/유틸 (parser.ts에서 분리).\n * ZIP 한도, 섹션 공유 상태(SectionShared), walk 컨텍스트(WalkCtx), XML 유틸.\n */\n\nimport { DOMParser } from \"@xmldom/xmldom\"\nimport { KordocError } from \"../utils.js\"\nimport type { CellContext, IRBlock, ParseWarning } from \"../types.js\"\n// WalkCtx.styleMap 타입 참조 — 타입 전용이라 styles.ts와의 순환은 컴파일 시 소거됨\nimport type { HwpxStyleMap } from \"./styles.js\"\n\nexport const MAX_DECOMPRESS_SIZE = 100 * 1024 * 1024\n/** 손상 ZIP 복구 시 최대 엔트리 수 */\nexport const MAX_ZIP_ENTRIES = 500\n\n/** colSpan/rowSpan을 안전한 범위로 클램핑 */\nexport function clampSpan(val: number, max: number): number {\n return Math.max(1, Math.min(val, max))\n}\n\n/** XML DOM 재귀 최대 깊이 — 악성 파일의 스택 오버플로 방지.\n * 좌표계가 다른 hwp5 MAX_NEST_DEPTH(8, 표 중첩 단계)·filler/소스맵 16\n * (표 중첩 단계)과 달리 이건 \"XML 요소\" 깊이라 표 1단이 여러 depth를\n * 소모한다 — 상수 통일 금지 (의미가 다름) */\nexport const MAX_XML_DEPTH = 200\n\n/** 셀 컨텍스트 확장 — 중첩표/이미지/다중문단 블록과 제목셀 여부를 IRCell로 전달 (v3.0) */\nexport interface CellCtxEx extends CellContext {\n blocks?: IRBlock[]\n /** 중첩표/이미지 등 구조 콘텐츠 존재 — true일 때만 IRCell.blocks로 attach */\n hasStructure?: boolean\n isHeader?: boolean\n}\n\nexport interface TableState {\n rows: CellContext[][]\n currentRow: CellContext[]\n cell: CellCtxEx | null\n /** hp:caption 텍스트 — IRTable.caption으로 전달 (v3.0) */\n caption?: string\n}\n\n/** 섹션 간 공유 상태 — 자동번호 카운터, 머리말/꼬리말, 변경추적 */\nexport interface SectionShared {\n /** numbering id → 레벨별(1..10) 카운터. 0 = 미사용(start값으로 초기화) */\n numState: Map<string, number[]>\n pageText: { headers: string[]; footers: string[] }\n track: { deleteDepth: number; warned: boolean }\n}\n\nexport function createSectionShared(): SectionShared {\n return { numState: new Map(), pageText: { headers: [], footers: [] }, track: { deleteDepth: 0, warned: false } }\n}\n\n/** walk 함수들이 공유하는 파싱 컨텍스트 — 개별 optional 파라미터를 하나로 묶어 시그니처 안정화 */\nexport interface WalkCtx {\n styleMap?: HwpxStyleMap\n warnings?: ParseWarning[]\n sectionNum?: number\n shared: SectionShared\n /** secPr outlineShapeIDRef — 개요(OUTLINE) 문단이 사용하는 numbering id */\n outlineNumId?: string\n}\n\n/** xmldom DOMParser 생성 — onError 콜백으로 malformed XML 경고 수집 */\nexport function createXmlParser(warnings?: ParseWarning[]): DOMParser {\n return new DOMParser({\n onError(level: \"warn\" | \"error\" | \"fatalError\", msg: string) {\n if (level === \"fatalError\") throw new KordocError(`XML 파싱 실패: ${msg}`)\n warnings?.push({ code: \"MALFORMED_XML\", message: `XML ${level === \"warn\" ? \"경고\" : \"오류\"}: ${msg}` })\n },\n })\n}\n\n/** 수집된 머리말/꼬리말을 본문 앞/뒤 문단으로 배치 */\nexport function applyPageText(blocks: IRBlock[], shared: SectionShared): void {\n const { headers, footers } = shared.pageText\n if (headers.length > 0) {\n blocks.unshift(...headers.map(t => ({ type: \"paragraph\" as const, text: t, pageNumber: 1 })))\n }\n if (footers.length > 0) {\n blocks.push(...footers.map(t => ({ type: \"paragraph\" as const, text: t })))\n }\n}\n\n/** 자식 중 지정된 localName(접두사 제거)을 가진 첫 번째 Element 반환 */\nexport function findChildByLocalName(parent: Element, name: string): Element | null {\n const children = parent.childNodes\n if (!children) return null\n for (let i = 0; i < children.length; i++) {\n const ch = children[i] as Element\n if (ch.nodeType !== 1) continue\n const tag = (ch.tagName || ch.localName || \"\").replace(/^[^:]+:/, \"\")\n if (tag === name) return ch\n }\n return null\n}\n\n/** 노드 내 모든 텍스트를 재귀적으로 추출 */\nexport function extractTextFromNode(node: Node): string {\n let result = \"\"\n const children = node.childNodes\n if (!children) return result\n for (let i = 0; i < children.length; i++) {\n const child = children[i]\n if (child.nodeType === 3) result += child.textContent || \"\"\n else if (child.nodeType === 1) result += extractTextFromNode(child)\n }\n return result.trim()\n}\n","/**\n * 레이아웃 보존 렌더 — 순수 계산 유틸 (XML 무접촉).\n * 좌표 산식은 .claude/plans/render-poc/findings.md에서 실측 검증된 모델.\n * 단위: HWPUNIT(1/7200in), pt 변환은 /100.\n */\n\n/** HWPX 좌표 속성은 uint32로 저장된 음수가 섞여 있다 (예: vertOffset=4294967103 = -193) */\nexport function toInt32(v: string | undefined, fallback = 0): number {\n if (v == null || v === \"\") return fallback\n const n = Number(v)\n if (!Number.isFinite(n)) return fallback\n return n > 0x7fffffff ? n - 0x100000000 : n\n}\n\n/** 셀 하나가 주는 경계 제약: boundary[a] + size = boundary[b] */\nexport interface SpanConstraint {\n a: number\n b: number\n size: number\n}\n\n/**\n * 표 열 경계 솔버 — 경계 전파.\n * 결재문서 트레일러처럼 41열 그리드에 span-1 셀이 거의 없어도,\n * x[ca+cs] = x[ca] + w 제약을 고정점까지 전파하면 전 경계가 풀린다 (실측 검증).\n * 미해결 경계는 인접 확정 경계 사이 균등 보간.\n */\nexport function solveBoundaries(constraints: SpanConstraint[], count: number, total?: number): number[] {\n const x = new Array<number | undefined>(count + 1).fill(undefined)\n x[0] = 0\n if (total != null && total > 0) x[count] = total\n let changed = true\n let guard = 0\n while (changed && guard++ < count + 8) {\n changed = false\n for (const c of constraints) {\n if (c.a < 0 || c.b > count || c.a >= c.b) continue\n const xa = x[c.a]\n const xb = x[c.b]\n if (xa != null && xb == null) {\n x[c.b] = xa + c.size\n changed = true\n } else if (xb != null && xa == null) {\n x[c.a] = xb - c.size\n changed = true\n }\n }\n }\n // 잔여 미해결 경계 — 좌우 확정 경계 사이 균등 보간\n let i = 0\n while (i <= count) {\n if (x[i] != null) { i++; continue }\n let lo = i - 1\n let hi = i\n while (hi <= count && x[hi] == null) hi++\n const loV = x[lo] as number\n const hiV = hi <= count ? (x[hi] as number) : loV + (hi - lo) * 1000\n const n = hi - lo\n for (let k = 1; k < n; k++) x[lo + k] = loV + ((hiV - loV) * k) / n\n if (hi > count) x[count] = hiV\n i = hi\n }\n // 단조 보정 (모순 제약 방어)\n const out = x as number[]\n for (let k = 1; k <= count; k++) if (out[k] < out[k - 1]) out[k] = out[k - 1]\n return out\n}\n\n/**\n * 표 행 높이 솔버 — rowSpan=1 셀의 max가 기본, rowSpan>1은 잔여 균등분배.\n * h=1 더미 셀(헤어라인 행 장식)이 섞이므로 열과 달리 max 방식이 안전.\n * grow: 셀 콘텐츠(사진 등)가 설계 높이를 넘으면 초과분만큼 행이 자란다 —\n * 사진대지 실측: 설계 16441 + 사진 22209 → 행 22209, 표 sz 합치 정확 일치.\n */\nexport function solveRowHeights(\n cells: { rowAddr: number; rowSpan: number; height: number; contentH?: number }[],\n rowCount: number,\n): number[] {\n const h = new Array<number>(rowCount).fill(0)\n for (const c of cells) {\n if (c.rowSpan === 1 && c.rowAddr >= 0 && c.rowAddr < rowCount) {\n h[c.rowAddr] = Math.max(h[c.rowAddr], c.height)\n }\n }\n // rowSpan>1 셀 — 포함 행 중 미확정(0) 행에 잔여 균등분배\n for (const c of cells) {\n if (c.rowSpan <= 1) continue\n const rows: number[] = []\n for (let r = c.rowAddr; r < Math.min(c.rowAddr + c.rowSpan, rowCount); r++) rows.push(r)\n const known = rows.reduce((s, r) => s + h[r], 0)\n const missing = rows.filter(r => h[r] === 0)\n if (missing.length > 0 && c.height > known) {\n const each = (c.height - known) / missing.length\n for (const r of missing) h[r] = each\n }\n }\n // 콘텐츠 초과 성장 (rowSpan=1 셀만 — 사진 셀 케이스)\n for (const c of cells) {\n if (c.rowSpan === 1 && c.contentH != null && c.rowAddr >= 0 && c.rowAddr < rowCount) {\n if (c.contentH > h[c.rowAddr]) h[c.rowAddr] = c.contentH\n }\n }\n return h\n}\n\n// 자연폭 계산은 hwpx/text-metrics.ts의 함초롬바탕 실측 advance 테이블(measureTextWidth)을 재사용한다.\n","/**\n * 한글 조판 텍스트 폭 계산 — 함초롬바탕(HCR Batang) 실측 advance 테이블\n *\n * 공문서 표준 본문 글꼴인 함초롬바탕 정품 TTF(한컴 공개 배포)의 hmtx advance를\n * upem=1000 기준으로 추출한 값이다. Bold도 advance가 Regular와 완전히 동일함을\n * 전수 확인했다(한컴이 굵기 간 폭을 통일해 제작). 한글 음절 11,172자 전수 = 970,\n * 한자 = 1000, 전각형·원문자·도형·화살표·단위기호 = 970으로 균일하다.\n *\n * 단위: em×1000. 실제 폭(HWPUNIT) = w/1000 × charPr.height × ratio(장평)/100.\n * (1em = 글자크기 = charPr.height HWPUNIT — 1pt = 100 HWPUNIT이므로)\n *\n * 공백: HWP는 charPr useFontSpace=0(기본)일 때 글꼴의 space advance(0.30em) 대신\n * 반각 고정폭(0.50em)을 쓴다 — kordoc 생성 문서는 모두 useFontSpace=0이므로\n * 기본 SPACE_EM=500. (글꼴값을 쓰려면 measure 옵션 fontSpace로 300 지정)\n *\n * 다른 글꼴(맑은 고딕 등)도 한글=전각 균일·숫자≈0.55em의 동일 부류 구조라\n * 이 테이블로 근사한다(오차 수 % 이내 — 공문서 본문은 어차피 함초롬바탕 관행).\n */\n\n/** ASCII 0x20~0x7E advance (em×1000). 0x20은 useFontSpace=1일 때의 글꼴값(300) */\nconst ASCII_W = [\n 300, 320, 320, 610, 610, 830, 724, 320, 320, 320, 550, 550, 320, 550, 320, 550, // 0x20-0x2F\n 550, 550, 550, 550, 550, 550, 550, 550, 550, 550, 320, 320, 550, 550, 550, 550, // 0x30-0x3F\n 830, 706, 605, 685, 719, 627, 617, 683, 734, 305, 315, 660, 605, 839, 734, 732, // 0x40-0x4F\n 603, 705, 660, 627, 664, 731, 706, 910, 705, 705, 626, 320, 550, 320, 550, 550, // 0x50-0x5F\n 320, 569, 597, 552, 597, 536, 356, 562, 635, 287, 288, 582, 287, 907, 635, 588, // 0x60-0x6F\n 597, 579, 478, 496, 356, 635, 563, 720, 542, 543, 486, 320, 320, 320, 550, 0, // 0x70-0x7E(+DEL)\n]\n\n/** 개별 실측 예외 기호 (em×1000) */\nconst SYM_W: Record<number, number> = {\n 0xa0: 300, 0xa3: 568, 0xa5: 707, 0xa7: 498, 0xab: 440, 0xac: 564, 0xb0: 291,\n 0xb1: 798, 0xb6: 606, 0xb7: 320, 0xbb: 440, 0xd7: 617, 0xf7: 678,\n 0x2013: 625, 0x2014: 875, 0x2015: 875, 0x2018: 320, 0x2019: 320, 0x201c: 480, 0x201d: 480,\n 0x2020: 558, 0x2021: 438, 0x2025: 640, 0x2026: 960, 0x2030: 988, 0x2032: 335, 0x2033: 474,\n 0x203b: 770, 0x20ac: 656, 0x261c: 1012, 0x261e: 1012,\n}\n\n/** 코드포인트의 advance(em×1000). 미상 문자는 CJK권 970 / 라틴권 550 폴백 */\nexport function charWidthEm1000(cp: number): number {\n if (cp >= 0x20 && cp <= 0x7e) return ASCII_W[cp - 0x20]\n const sym = SYM_W[cp]\n if (sym !== undefined) return sym\n if (cp >= 0xac00 && cp <= 0xd7a3) return 970 // 한글 음절 (전수 균일 확인)\n if (cp >= 0x1100 && cp <= 0x11ff) return 970 // 옛한글 자모\n if (cp >= 0x3131 && cp <= 0x318e) return 970 // 호환 자모 (ㆍ 포함)\n if ((cp >= 0x4e00 && cp <= 0x9fff) || (cp >= 0xf900 && cp <= 0xfaff)) return 1000 // 한자\n if ((cp >= 0x3008 && cp <= 0x3011) || (cp >= 0x3014 && cp <= 0x301b)) return 500 // 「」『』〈〉《》〔〕【】\n if (cp === 0x3000) return 970 // 전각 공백\n if (cp >= 0x2190 && cp <= 0x22ff) return 970 // 화살표·수학 기호\n if (cp >= 0x2460 && cp <= 0x24ff) return 970 // 원문자 ①⑴\n if (cp >= 0x25a0 && cp <= 0x26ff) return 970 // 도형 □○◆★\n if (cp >= 0x3200 && cp <= 0x33ff) return 970 // 괄호한글 ㉮·단위 ㎡㎏\n if (cp >= 0xff01 && cp <= 0xff60) return 970 // 전각형 !~\n return cp >= 0x2e80 ? 970 : 550\n}\n\n/** HWP 공백 폭(em×1000) — useFontSpace=0(기본): 반각 고정 500 / =1: 글꼴값 300 */\nexport const SPACE_EM_FIXED = 500\nexport const SPACE_EM_FONT = 300\n\nexport interface MeasureOptions {\n /** 공백 폭(em×1000). 기본 SPACE_EM_FIXED(500) = useFontSpace 0 */\n spaceEm?: number\n /** 자간(charPr spacing %) — 글자폭의 %가 문자마다 추가 */\n spacingPct?: number\n}\n\n/**\n * 텍스트 폭(HWPUNIT). height=charPr height(pt×100), ratioPct=장평 %.\n * 결과는 float — 호출부에서 비교 시 ±0.5 HWPUNIT 오차 허용 권장.\n */\nexport function measureTextWidth(\n text: string,\n height: number,\n ratioPct: number,\n opts?: MeasureOptions,\n): number {\n const spaceEm = opts?.spaceEm ?? SPACE_EM_FIXED\n const spacing = opts?.spacingPct ?? 0\n let em = 0\n for (const ch of text) {\n const cp = ch.codePointAt(0)!\n const w = cp === 0x20 ? spaceEm : charWidthEm1000(cp)\n em += w * (1 + spacing / 100)\n }\n return (em / 1000) * height * (ratioPct / 100)\n}\n\n// ─── 줄바꿈 시뮬레이션 (한컴 조판 모델 — 실측 linesegarray 98% 일치 검증) ───\n//\n// 검증: bench/verify-linebreak.mjs — 서울 정보소통광장 실제 결재문서의 linesegarray\n// (한컴 계열 조판기가 계산한 줄 시작 오프셋)와 대조. 고정폭 글꼴 버킷에서 98%\n// (56/57 줄바꿈점, 미스는 코퍼스 좌표계 노이즈) 일치. 이 과정에서 확정된 규칙:\n// - 공백 폭 = 0.5em 고정(useFontSpace=0), 장평·자간 모두 공백에도 적용\n// - 자간 = 글자폭 × (1+spacing/100)\n// - 줄 끝 공백은 hang (줄바꿈을 유발하지 않음)\n// - 금칙: 시작금칙(닫는 부호 줄머리 금지)은 직전 글자 1개를 동반해 다음 줄로\n// (밀어내기), 끝금칙(여는 괄호 줄끝 금지)은 그 글자를 다음 줄로 내림\n\n/** 줄머리 금지(시작금칙) 문자 — 한컴 기본 */\nconst FORBID_START = new Set([...\"!%),.:;?]}¢°′″℃〉》」』】〕!%),.:;?]}₩~…·、。〃\"])\n/** 줄끝 금지(끝금칙) 문자 — 한컴 기본 */\nconst FORBID_END = new Set([...\"$([{£¥〈《「『【〔$([{₩\"])\n\nexport type WrapMode = \"keep\" | \"charAll\"\n\nexport interface WrapResult {\n /** 줄 수 */\n lines: number\n /** 각 줄의 시작 오프셋(UTF-16) — [0, …] */\n starts: number[]\n /** 마지막 줄 텍스트 폭(HWPUNIT) */\n lastLineWidth: number\n}\n\n/**\n * 문단 줄바꿈 시뮬레이션.\n * mode 'keep' = breakNonLatinWord=KEEP_WORD(어절 단위, 공문서 모드·Windows 한글),\n * mode 'charAll' = 글자 단위(BREAK_WORD·macOS 한글·전자결재 변환기의 실동작).\n * 한 어절이 줄보다 길면 keep에서도 글자 단위로 강제 분해(한컴 동일).\n *\n * @param text 문단 전체 텍스트(항목 부호 포함)\n * @param firstWidth 첫 줄 가용 폭(HWPUNIT)\n * @param contWidth 둘째 줄부터 가용 폭(HWPUNIT) — 내어쓰기 반영\n * @param height charPr height (pt×100)\n * @param ratioPct 장평 %\n */\nexport function simulateWrap(\n text: string,\n firstWidth: number,\n contWidth: number,\n height: number,\n ratioPct: number,\n mode: WrapMode = \"keep\",\n opts?: MeasureOptions,\n): WrapResult {\n const EPS = 0.5\n const spaceEm = opts?.spaceEm ?? SPACE_EM_FIXED\n const spacing = opts?.spacingPct ?? 0\n const k = (height * ratioPct) / 100 / 1000\n const cwCp = (cp: number): number =>\n (cp === 0x20 ? spaceEm : charWidthEm1000(cp)) * (1 + spacing / 100) * k\n const charW = (ch: string): number => cwCp(ch.codePointAt(0)!)\n const rangeW = (from: number, to: number): number => {\n let w = 0\n for (const ch of text.slice(from, to)) w += charW(ch)\n return w\n }\n\n const units = text.match(mode === \"keep\" ? / +|[^ ]+/g : / +|[^ ]/g) ?? []\n\n const starts = [0]\n let lineW = 0\n let avail = firstWidth\n let pos = 0\n const lineStart = (): number => starts[starts.length - 1]\n\n /** 유닛(시작 unitPos, 폭 w)이 안 들어갈 때 줄바꿈 + 금칙 보정 */\n const breakBefore = (unitPos: number, w: number): void => {\n let bp = unitPos\n const u = text[unitPos]\n // 시작금칙: 줄머리 금지 문자면 직전 글자 1개를 함께 내린다 (밀어내기)\n if (u !== undefined && FORBID_START.has(u) && bp - 1 > lineStart() && text[bp - 1] !== \" \") bp--\n // 끝금칙: 남는 줄 끝이 여는 괄호류면 그 글자(들)도 함께 내린다\n while (bp - 1 > lineStart() && FORBID_END.has(text[bp - 1])) bp--\n if (bp <= lineStart()) bp = unitPos\n starts.push(bp)\n avail = contWidth\n lineW = rangeW(bp, unitPos) + w\n }\n\n for (const u of units) {\n if (u[0] === \" \") {\n lineW += charW(\" \") * u.length // 줄 끝 공백은 hang\n pos += u.length\n continue\n }\n const w = rangeW(pos, pos + u.length)\n if (lineW + w <= avail + EPS) {\n lineW += w\n pos += u.length\n continue\n }\n if (lineW === 0 || w > contWidth + EPS) {\n // 빈 줄이거나 다음 줄에도 안 들어가는 초장 유닛 — 글자 단위 강제 분해\n let sub = 0\n for (const ch of u) {\n const c = charW(ch)\n if (lineW + c > avail + EPS && lineW > 0) breakBefore(pos + sub, 0)\n lineW += c\n sub += ch.length\n }\n pos += u.length\n continue\n }\n breakBefore(pos, w)\n pos += u.length\n }\n return { lines: starts.length, starts, lastLineWidth: lineW }\n}\n\n/** @deprecated simulateWrap(text, …, 'keep') 별칭 — 하위 호환 */\nexport function simulateWrapKeepWord(\n text: string,\n firstWidth: number,\n contWidth: number,\n height: number,\n ratioPct: number,\n opts?: MeasureOptions,\n): WrapResult {\n return simulateWrap(text, firstWidth, contWidth, height, ratioPct, \"keep\", opts)\n}\n\n/**\n * 한두 글자(짧은 꼬리)가 다음 줄로 넘어간 문단을 장평 축소로 한 줄 줄일 수 있는지\n * 탐색. baseRatio에서 줄 수 N≥2일 때 r=baseRatio-1…minRatio를 내려가며 처음으로\n * 줄 수가 줄어드는(가장 큰) r을 반환. 불가능하면 null.\n * (실무 관행: 공무원이 문단 장평을 95→92 등으로 줄여 orphan을 위로 당기는 조작의 자동화.\n * keep 모드로 판정 — 글자 단위 조판은 항상 keep 이하의 줄 수라 함께 만족된다.)\n */\nexport function fitRatioForFewerLines(\n text: string,\n firstWidth: number,\n contWidth: number,\n height: number,\n baseRatio: number,\n minRatio: number,\n opts?: MeasureOptions,\n): number | null {\n const base = simulateWrap(text, firstWidth, contWidth, height, baseRatio, \"keep\", opts)\n if (base.lines < 2) return null\n for (let r = baseRatio - 1; r >= minRatio; r--) {\n const sim = simulateWrap(text, firstWidth, contWidth, height, r, \"keep\", opts)\n if (sim.lines < base.lines) return r\n }\n return null\n}\n","/**\n * 레이아웃 보존 렌더 — header.xml 스타일 테이블 (charPr/paraPr/borderFill).\n * 파서 IR과 무관하게 렌더에 필요한 속성만 추출한다.\n */\n\nimport { createXmlParser, findChildByLocalName } from \"../hwpx/parser-shared.js\"\n\nexport interface RenderCharStyle {\n /** 글자 크기 (1/100pt — 1000 = 10pt) */\n height: number\n bold: boolean\n italic: boolean\n underline: boolean\n /** #RRGGBB — 검정이면 undefined */\n color?: string\n /** 장평 % */\n ratio: number\n /** 자간 % */\n spacing: number\n}\n\nexport type ParaAlign = \"JUSTIFY\" | \"LEFT\" | \"RIGHT\" | \"CENTER\" | \"DISTRIBUTE\" | \"DISTRIBUTE_SPACE\"\n\nexport interface RenderBorderEdge {\n /** SOLID/DASH/DOT… — NONE은 edge 자체를 생략 */\n type: string\n /** pt 단위 굵기 */\n widthPt: number\n color: string\n}\n\nexport interface RenderBorderFill {\n left?: RenderBorderEdge\n right?: RenderBorderEdge\n top?: RenderBorderEdge\n bottom?: RenderBorderEdge\n /** 배경색 #RRGGBB (없으면 undefined) */\n fill?: string\n}\n\nexport interface RenderStyles {\n charPr: Map<string, RenderCharStyle>\n paraAlign: Map<string, ParaAlign>\n borderFill: Map<string, RenderBorderFill>\n}\n\nexport const DEFAULT_CHAR: RenderCharStyle = { height: 1000, bold: false, italic: false, underline: false, ratio: 100, spacing: 0 }\n\n/** \"0.12 mm\" / \"0.5 mm\" → pt */\nfunction borderWidthPt(v: string | null | undefined): number {\n const n = parseFloat(v ?? \"\")\n if (!Number.isFinite(n)) return 0.34\n return n * 2.834645 // mm → pt\n}\n\nfunction parseEdge(el: Element | null): RenderBorderEdge | undefined {\n if (!el) return undefined\n const type = el.getAttribute(\"type\") ?? \"NONE\"\n if (type === \"NONE\") return undefined\n return { type, widthPt: borderWidthPt(el.getAttribute(\"width\")), color: el.getAttribute(\"color\") ?? \"#000000\" }\n}\n\n/** header.xml(구버전 head.xml) → 렌더용 스타일 맵 */\nexport function parseRenderStyles(headXml: string): RenderStyles {\n const styles: RenderStyles = { charPr: new Map(), paraAlign: new Map(), borderFill: new Map() }\n const doc = createXmlParser().parseFromString(headXml, \"text/xml\")\n const root = doc.documentElement as unknown as Element | null\n if (!root) return styles\n\n const walk = (el: Element): void => {\n const tag = (el.tagName || \"\").replace(/^[^:]+:/, \"\")\n if (tag === \"charPr\") {\n const id = el.getAttribute(\"id\")\n if (id != null) {\n const ratioEl = findChildByLocalName(el, \"ratio\")\n const spacingEl = findChildByLocalName(el, \"spacing\")\n const underlineEl = findChildByLocalName(el, \"underline\")\n const textColor = el.getAttribute(\"textColor\")\n styles.charPr.set(id, {\n height: Number(el.getAttribute(\"height\")) || 1000,\n bold: findChildByLocalName(el, \"bold\") != null,\n italic: findChildByLocalName(el, \"italic\") != null,\n underline: underlineEl != null && (underlineEl.getAttribute(\"type\") ?? \"NONE\") !== \"NONE\",\n color: textColor && textColor !== \"#000000\" && textColor.toLowerCase() !== \"none\" ? textColor : undefined,\n ratio: Number(ratioEl?.getAttribute(\"hangul\")) || 100,\n spacing: Number(spacingEl?.getAttribute(\"hangul\")) || 0,\n })\n }\n } else if (tag === \"paraPr\") {\n const id = el.getAttribute(\"id\")\n if (id != null) {\n const align = findChildByLocalName(el, \"align\")\n styles.paraAlign.set(id, (align?.getAttribute(\"horizontal\") as ParaAlign) || \"JUSTIFY\")\n }\n } else if (tag === \"borderFill\") {\n const id = el.getAttribute(\"id\")\n if (id != null) {\n const bf: RenderBorderFill = {\n left: parseEdge(findChildByLocalName(el, \"leftBorder\")),\n right: parseEdge(findChildByLocalName(el, \"rightBorder\")),\n top: parseEdge(findChildByLocalName(el, \"topBorder\")),\n bottom: parseEdge(findChildByLocalName(el, \"bottomBorder\")),\n }\n const fillBrush = findChildByLocalName(el, \"fillBrush\")\n const winBrush = fillBrush ? findChildByLocalName(fillBrush, \"winBrush\") : null\n const face = winBrush?.getAttribute(\"faceColor\")\n if (face && face.toLowerCase() !== \"none\") bf.fill = face\n styles.borderFill.set(id, bf)\n }\n }\n const children = el.childNodes\n for (let i = 0; i < children.length; i++) {\n const ch = children[i]\n if (ch.nodeType === 1) walk(ch as Element)\n }\n }\n walk(root)\n return styles\n}\n"],"mappings":"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","names":["charW"]}
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  sanitizeHref
4
- } from "./chunk-MZA7AXHN.js";
4
+ } from "./chunk-GFS4QWB6.js";
5
5
 
6
6
  // src/shared/pua.ts
7
7
  var BMP_SYMBOL_MAP = {
@@ -532,4 +532,4 @@ export {
532
532
  HEADING_RATIO_H2,
533
533
  HEADING_RATIO_H3
534
534
  };
535
- //# sourceMappingURL=chunk-5DL6VCIJ.js.map
535
+ //# sourceMappingURL=chunk-YXEE3DEQ.js.map
package/dist/cli.js CHANGED
@@ -6,21 +6,21 @@ import {
6
6
  fillHwpx,
7
7
  markdownToHwpx,
8
8
  parse
9
- } from "./chunk-5TK4X4JQ.js";
9
+ } from "./chunk-RMGYE4LT.js";
10
10
  import {
11
11
  detectFormat,
12
12
  detectZipFormat
13
13
  } from "./chunk-MEPHGCPQ.js";
14
- import "./chunk-FU25KFFZ.js";
14
+ import "./chunk-UR34PYAC.js";
15
15
  import {
16
16
  blocksToMarkdown
17
- } from "./chunk-5DL6VCIJ.js";
17
+ } from "./chunk-YXEE3DEQ.js";
18
18
  import "./chunk-MOL7MDBG.js";
19
19
  import {
20
20
  VERSION,
21
21
  sanitizeError,
22
22
  toArrayBuffer
23
- } from "./chunk-MZA7AXHN.js";
23
+ } from "./chunk-GFS4QWB6.js";
24
24
 
25
25
  // src/cli.ts
26
26
  import { readFileSync, writeFileSync, mkdirSync, statSync } from "fs";
@@ -118,7 +118,7 @@ program.name("kordoc").description("\uBAA8\uB450 \uD30C\uC2F1\uD574\uBC84\uB9AC\
118
118
  }
119
119
  });
120
120
  program.command("watch <dir>").description("\uB514\uB809\uD1A0\uB9AC \uAC10\uC2DC \u2014 \uC0C8 \uBB38\uC11C \uC790\uB3D9 \uBCC0\uD658").option("--webhook <url>", "\uACB0\uACFC \uC804\uC1A1 \uC6F9\uD6C5 URL").option("-d, --out-dir <dir>", "\uBCC0\uD658 \uACB0\uACFC \uCD9C\uB825 \uB514\uB809\uD1A0\uB9AC").option("-p, --pages <range>", "\uD398\uC774\uC9C0/\uC139\uC158 \uBC94\uC704").option("--format <type>", "\uCD9C\uB825 \uD615\uC2DD: markdown \uB610\uB294 json", "markdown").option("--silent", "\uC9C4\uD589 \uBA54\uC2DC\uC9C0 \uC228\uAE30\uAE30").action(async (dir, opts) => {
121
- const { watchDirectory } = await import("./watch-MQTMNUSB.js");
121
+ const { watchDirectory } = await import("./watch-CZF6NA2V.js");
122
122
  await watchDirectory({
123
123
  dir,
124
124
  outDir: opts.outDir,
@@ -269,7 +269,7 @@ program.command("fill <template>").description("\uC11C\uC2DD \uBB38\uC11C\uC758
269
269
  });
270
270
  program.command("patch <original> <edited>").description("\uC11C\uC2DD \uBCF4\uC874 \uB77C\uC6B4\uB4DC\uD2B8\uB9BD \uD328\uCE58 \u2014 \uD3B8\uC9D1\uB41C \uB9C8\uD06C\uB2E4\uC6B4\uC744 \uC6D0\uBCF8 HWPX/HWP\uC5D0 in-place \uBC18\uC601 (kordoc patch \uC6D0\uBCF8.hwpx \uD3B8\uC9D1.md -o \uCD9C\uB825.hwpx)").option("-o, --output <path>", "\uCD9C\uB825 \uACBD\uB85C (\uAE30\uBCF8: <\uC6D0\uBCF8>.patched.hwpx|.hwp)").option("--no-verify", "\uD328\uCE58 \uD6C4 \uC7AC\uD30C\uC2F1 \uC790\uB3D9 \uAC80\uC99D \uC0DD\uB7B5").option("--silent", "\uC9C4\uD589 \uBA54\uC2DC\uC9C0 \uC228\uAE30\uAE30").action(async (original, edited, opts) => {
271
271
  try {
272
- const { patchHwpx, patchHwp, detectFormat: detectFormat2 } = await import("./-3B5FDXW2.js");
272
+ const { patchHwpx, patchHwp, detectFormat: detectFormat2 } = await import("./-LPEXY73L.js");
273
273
  const rootOpts = program.opts();
274
274
  const output = opts.output ?? rootOpts.output;
275
275
  const silent = opts.silent ?? rootOpts.silent;
@@ -362,7 +362,7 @@ program.command("render <file>").description("\uB808\uC774\uC544\uC6C3 \uBCF4\uC
362
362
  const rootOpts = program.opts();
363
363
  const output = opts.output ?? rootOpts.output;
364
364
  const silent = opts.silent ?? rootOpts.silent;
365
- const { renderHwpxToSvg } = await import("./render-4I72JOAR.js");
365
+ const { renderHwpxToSvg } = await import("./render-XWOEGE3U.js");
366
366
  const absPath = resolve(file);
367
367
  const buffer = readFileSync(absPath);
368
368
  const result = await renderHwpxToSvg(toArrayBuffer(buffer));