kordoc 4.14.0 → 4.14.2

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 (135) hide show
  1. package/README.md +18 -2
  2. package/dist/{-SLX6IB6Y.js → -AQKXLFIM.js} +10 -10
  3. package/dist/{chunk-WAPKUYGP.cjs → chunk-247ANM72.cjs} +11 -11
  4. package/dist/chunk-247ANM72.cjs.map +1 -0
  5. package/dist/{chunk-EOTAPX2M.js → chunk-3DUADAY2.js} +3 -3
  6. package/dist/{chunk-B7MOYHVR.cjs → chunk-422427XJ.cjs} +6 -6
  7. package/dist/chunk-422427XJ.cjs.map +1 -0
  8. package/dist/{chunk-HG5LXXCC.js → chunk-7IAQ4HOK.js} +1 -1
  9. package/dist/{chunk-XVIJLHCW.js.map → chunk-7IAQ4HOK.js.map} +1 -1
  10. package/dist/{chunk-JIQWI7S2.js → chunk-A7QC2ZVP.js} +3 -3
  11. package/dist/{chunk-HCHA3Y2T.js → chunk-C7FQBSON.js} +2 -2
  12. package/dist/chunk-DCZVOIEO.cjs.map +1 -1
  13. package/dist/{chunk-7VUHZFGQ.js → chunk-DOGPOY4B.js} +2 -2
  14. package/dist/{chunk-6T6MB5ON.js → chunk-EDNJLUSE.js} +2 -2
  15. package/dist/{chunk-EMQZX5QQ.js → chunk-EISO3POT.js} +301 -124
  16. package/dist/chunk-EISO3POT.js.map +1 -0
  17. package/dist/{chunk-LCGAO5LF.js → chunk-EP7KOI2V.js} +3 -3
  18. package/dist/{chunk-WRIHDGGY.cjs → chunk-EQZI77PP.cjs} +3 -3
  19. package/dist/chunk-EQZI77PP.cjs.map +1 -0
  20. package/dist/{chunk-XVIJLHCW.js → chunk-FOJZNMMK.js} +1 -1
  21. package/dist/{chunk-HG5LXXCC.js.map → chunk-FOJZNMMK.js.map} +1 -1
  22. package/dist/{chunk-PLXNW3J4.js → chunk-GDW4YP7K.js} +2 -2
  23. package/dist/chunk-GS7T56RP.cjs.map +1 -1
  24. package/dist/{chunk-ANKDK5DF.cjs → chunk-HR2XNERB.cjs} +2 -2
  25. package/dist/chunk-HR2XNERB.cjs.map +1 -0
  26. package/dist/{chunk-3U3PJGVO.js → chunk-ILU76UF3.js} +13 -2
  27. package/dist/chunk-ILU76UF3.js.map +1 -0
  28. package/dist/{chunk-J3SM7VLM.js → chunk-JQEFP45L.js} +2 -2
  29. package/dist/{chunk-M5NRJMA4.js → chunk-KVWV4ULP.js} +3 -3
  30. package/dist/{chunk-COUGOFT3.cjs → chunk-L7DMSMAG.cjs} +1 -1
  31. package/dist/chunk-L7DMSMAG.cjs.map +1 -0
  32. package/dist/{chunk-GMX6EKCY.js → chunk-NS55SM7A.js} +2 -2
  33. package/dist/{chunk-XH34WJKB.js → chunk-QC5T6D4J.js} +2 -2
  34. package/dist/{chunk-STLNL53H.cjs → chunk-QOMNEWCQ.cjs} +4 -4
  35. package/dist/chunk-QOMNEWCQ.cjs.map +1 -0
  36. package/dist/{chunk-CDQJKMZ5.js → chunk-TNCKOL2O.js} +2 -2
  37. package/dist/{chunk-HH7T6SMB.js → chunk-TSFS5VKD.js} +3072 -1721
  38. package/dist/chunk-TSFS5VKD.js.map +1 -0
  39. package/dist/{chunk-RCTWZYAM.js → chunk-UET462HB.js} +2 -2
  40. package/dist/{chunk-A2JDWBKG.js → chunk-VQ5W4MYO.js} +2 -2
  41. package/dist/{chunk-ZWTEE63A.js → chunk-ZWD734EY.js} +2 -2
  42. package/dist/{chunk-UBNJXMYX.js → chunk-ZWOFQRIB.js} +14 -6
  43. package/dist/chunk-ZWOFQRIB.js.map +1 -0
  44. package/dist/chunks-SX77P5CV.js +10 -0
  45. package/dist/cli.js +1066 -1038
  46. package/dist/cli.js.map +1 -1
  47. package/dist/{formula-VSZIJZXP.js → formula-5S7WWXGH.js} +4 -4
  48. package/dist/{formula-VYDTA27M.js → formula-JGFTXWYT.js} +3 -3
  49. package/dist/{formula-TAYYDV73.cjs → formula-PJJ6S3Z2.cjs} +9 -9
  50. package/dist/formula-PJJ6S3Z2.cjs.map +1 -0
  51. package/dist/{image-ocr-5WBAIBPQ.js → image-ocr-FLIL7MGN.js} +6 -6
  52. package/dist/{image-ocr-N6IBZJAK.js → image-ocr-WCAYXLOA.js} +8 -8
  53. package/dist/{image-ocr-ZX4W2RBS.cjs → image-ocr-ZTYAGV3W.cjs} +12 -12
  54. package/dist/image-ocr-ZTYAGV3W.cjs.map +1 -0
  55. package/dist/index.cjs +3010 -1465
  56. package/dist/index.cjs.map +1 -1
  57. package/dist/index.d.cts +11 -6
  58. package/dist/index.d.ts +11 -6
  59. package/dist/index.js +2547 -1002
  60. package/dist/index.js.map +1 -1
  61. package/dist/mcp.js +973 -932
  62. package/dist/mcp.js.map +1 -1
  63. package/dist/{model-bundle-5CBFVIXA.js → model-bundle-FSPZZ2EM.js} +5 -5
  64. package/dist/{models-L74RBKK3.js → models-CJPAQK5R.js} +5 -5
  65. package/dist/page-range-P7SDW6LR.cjs.map +1 -1
  66. package/dist/{parser-66NMJUOG.js → parser-A4TMPJAM.js} +7 -7
  67. package/dist/{parser-BK66Y5JD.js → parser-SCUTZAIJ.js} +7 -7
  68. package/dist/{parser-WM2DMVLY.cjs → parser-VCXE4I5A.cjs} +27 -27
  69. package/dist/parser-VCXE4I5A.cjs.map +1 -0
  70. package/dist/pdf-ocr-76SAUXMZ.js +13 -0
  71. package/dist/pdf-ocr-CPU55CVF.js +16 -0
  72. package/dist/pdf-ocr-MBZZ57LD.cjs +14 -0
  73. package/dist/pdf-ocr-MBZZ57LD.cjs.map +1 -0
  74. package/dist/{profile-io-JZ3FDHDK.js → profile-io-LBM263K7.js} +3 -3
  75. package/dist/{rasterize-33WOOVSM.js → rasterize-46RG4ZF6.js} +3 -3
  76. package/dist/{render-MLN4ZLVD.js → render-NGP5T24S.js} +7 -7
  77. package/dist/seal-RGUPOLXD.js +10 -0
  78. package/dist/{setup-G6AEN4J7.js → setup-AU4OCHNH.js} +3 -3
  79. package/dist/visual-NZLYIYEM.js +19 -0
  80. package/dist/{watch-OY6XKGC5.js → watch-MKPUCPXM.js} +11 -11
  81. package/package.json +2 -2
  82. package/dist/chunk-3U3PJGVO.js.map +0 -1
  83. package/dist/chunk-ANKDK5DF.cjs.map +0 -1
  84. package/dist/chunk-B7MOYHVR.cjs.map +0 -1
  85. package/dist/chunk-COUGOFT3.cjs.map +0 -1
  86. package/dist/chunk-EMQZX5QQ.js.map +0 -1
  87. package/dist/chunk-HH7T6SMB.js.map +0 -1
  88. package/dist/chunk-STLNL53H.cjs.map +0 -1
  89. package/dist/chunk-UBNJXMYX.js.map +0 -1
  90. package/dist/chunk-WAPKUYGP.cjs.map +0 -1
  91. package/dist/chunk-WRIHDGGY.cjs.map +0 -1
  92. package/dist/chunks-PEHRXW2P.js +0 -10
  93. package/dist/formula-TAYYDV73.cjs.map +0 -1
  94. package/dist/image-ocr-ZX4W2RBS.cjs.map +0 -1
  95. package/dist/parser-WM2DMVLY.cjs.map +0 -1
  96. package/dist/pdf-ocr-322MBLDK.js +0 -16
  97. package/dist/pdf-ocr-A4UBXLM2.js +0 -13
  98. package/dist/pdf-ocr-G4TBDUYL.cjs +0 -14
  99. package/dist/pdf-ocr-G4TBDUYL.cjs.map +0 -1
  100. package/dist/seal-JQWSNHRG.js +0 -10
  101. package/dist/visual-VZ7QGAUC.js +0 -19
  102. /package/dist/{-SLX6IB6Y.js.map → -AQKXLFIM.js.map} +0 -0
  103. /package/dist/{chunk-EOTAPX2M.js.map → chunk-3DUADAY2.js.map} +0 -0
  104. /package/dist/{chunk-JIQWI7S2.js.map → chunk-A7QC2ZVP.js.map} +0 -0
  105. /package/dist/{chunk-HCHA3Y2T.js.map → chunk-C7FQBSON.js.map} +0 -0
  106. /package/dist/{chunk-7VUHZFGQ.js.map → chunk-DOGPOY4B.js.map} +0 -0
  107. /package/dist/{chunk-6T6MB5ON.js.map → chunk-EDNJLUSE.js.map} +0 -0
  108. /package/dist/{chunk-LCGAO5LF.js.map → chunk-EP7KOI2V.js.map} +0 -0
  109. /package/dist/{chunk-PLXNW3J4.js.map → chunk-GDW4YP7K.js.map} +0 -0
  110. /package/dist/{chunk-J3SM7VLM.js.map → chunk-JQEFP45L.js.map} +0 -0
  111. /package/dist/{chunk-M5NRJMA4.js.map → chunk-KVWV4ULP.js.map} +0 -0
  112. /package/dist/{chunk-GMX6EKCY.js.map → chunk-NS55SM7A.js.map} +0 -0
  113. /package/dist/{chunk-XH34WJKB.js.map → chunk-QC5T6D4J.js.map} +0 -0
  114. /package/dist/{chunk-CDQJKMZ5.js.map → chunk-TNCKOL2O.js.map} +0 -0
  115. /package/dist/{chunk-RCTWZYAM.js.map → chunk-UET462HB.js.map} +0 -0
  116. /package/dist/{chunk-A2JDWBKG.js.map → chunk-VQ5W4MYO.js.map} +0 -0
  117. /package/dist/{chunk-ZWTEE63A.js.map → chunk-ZWD734EY.js.map} +0 -0
  118. /package/dist/{chunks-PEHRXW2P.js.map → chunks-SX77P5CV.js.map} +0 -0
  119. /package/dist/{formula-VSZIJZXP.js.map → formula-5S7WWXGH.js.map} +0 -0
  120. /package/dist/{formula-VYDTA27M.js.map → formula-JGFTXWYT.js.map} +0 -0
  121. /package/dist/{image-ocr-5WBAIBPQ.js.map → image-ocr-FLIL7MGN.js.map} +0 -0
  122. /package/dist/{image-ocr-N6IBZJAK.js.map → image-ocr-WCAYXLOA.js.map} +0 -0
  123. /package/dist/{model-bundle-5CBFVIXA.js.map → model-bundle-FSPZZ2EM.js.map} +0 -0
  124. /package/dist/{models-L74RBKK3.js.map → models-CJPAQK5R.js.map} +0 -0
  125. /package/dist/{parser-66NMJUOG.js.map → parser-A4TMPJAM.js.map} +0 -0
  126. /package/dist/{parser-BK66Y5JD.js.map → parser-SCUTZAIJ.js.map} +0 -0
  127. /package/dist/{pdf-ocr-322MBLDK.js.map → pdf-ocr-76SAUXMZ.js.map} +0 -0
  128. /package/dist/{pdf-ocr-A4UBXLM2.js.map → pdf-ocr-CPU55CVF.js.map} +0 -0
  129. /package/dist/{profile-io-JZ3FDHDK.js.map → profile-io-LBM263K7.js.map} +0 -0
  130. /package/dist/{rasterize-33WOOVSM.js.map → rasterize-46RG4ZF6.js.map} +0 -0
  131. /package/dist/{render-MLN4ZLVD.js.map → render-NGP5T24S.js.map} +0 -0
  132. /package/dist/{seal-JQWSNHRG.js.map → seal-RGUPOLXD.js.map} +0 -0
  133. /package/dist/{setup-G6AEN4J7.js.map → setup-AU4OCHNH.js.map} +0 -0
  134. /package/dist/{visual-VZ7QGAUC.js.map → visual-NZLYIYEM.js.map} +0 -0
  135. /package/dist/{watch-OY6XKGC5.js.map → watch-MKPUCPXM.js.map} +0 -0
@@ -7,11 +7,12 @@ import {
7
7
  decodeXmlEntities,
8
8
  escapeXmlText,
9
9
  findElementEnd,
10
+ markerRunSplices,
10
11
  paraTText,
11
12
  paraTextPureT,
12
13
  patchZipEntries,
13
14
  scanSectionXml
14
- } from "./chunk-UBNJXMYX.js";
15
+ } from "./chunk-ZWOFQRIB.js";
15
16
  import {
16
17
  CONVERT_MAP,
17
18
  FLAG_COMPRESSED,
@@ -50,12 +51,12 @@ import {
50
51
  renderDocumentToScene,
51
52
  romanNumeral,
52
53
  simulateWrap
53
- } from "./chunk-HH7T6SMB.js";
54
+ } from "./chunk-TSFS5VKD.js";
54
55
  import {
55
56
  HEADING_RATIO_H1,
56
57
  HEADING_RATIO_H2,
57
58
  HEADING_RATIO_H3
58
- } from "./chunk-HG5LXXCC.js";
59
+ } from "./chunk-7IAQ4HOK.js";
59
60
  import {
60
61
  parsePageRange
61
62
  } from "./chunk-MOL7MDBG.js";
@@ -74,7 +75,7 @@ import {
74
75
  findChildByLocalName,
75
76
  localName,
76
77
  rawTextContent
77
- } from "./chunk-3U3PJGVO.js";
78
+ } from "./chunk-ILU76UF3.js";
78
79
  import {
79
80
  MAX_COLS,
80
81
  MAX_ROWS,
@@ -83,7 +84,7 @@ import {
83
84
  convertTableToText,
84
85
  hasStructuredCellContent,
85
86
  mapPuaText
86
- } from "./chunk-XH34WJKB.js";
87
+ } from "./chunk-QC5T6D4J.js";
87
88
  import {
88
89
  KordocError,
89
90
  classifyError,
@@ -95,7 +96,7 @@ import {
95
96
  sanitizeHref,
96
97
  stripDtd,
97
98
  toArrayBuffer
98
- } from "./chunk-RCTWZYAM.js";
99
+ } from "./chunk-UET462HB.js";
99
100
 
100
101
  // src/table/visual.ts
101
102
  import { readFile as readFile2 } from "fs/promises";
@@ -1527,8 +1528,10 @@ function extractParagraphInfo(para2, styleMap, ctx) {
1527
1528
  text += "\n";
1528
1529
  break;
1529
1530
  // 강제 줄바꿈 — ref 추출기·소스맵 스캐너와 동일 모델
1531
+ // 고정폭·묶음 빈칸 — 묶음 빈칸(nbSpace)을 빠뜨리면 "2026.<nbSpace/>9." 가 "2026.9." 로 붙는다
1530
1532
  case "fwSpace":
1531
1533
  case "hwSpace":
1534
+ case "nbSpace":
1532
1535
  text += " ";
1533
1536
  break;
1534
1537
  // 테이블 자체는 walkSection에서 처리 — 글자취급(inline) 표만 경계 마커를 남겨
@@ -1704,7 +1707,11 @@ function extractRunSpans(para2, ctx, mode, requireMixed) {
1704
1707
  for (let k = 0; k < (tkids?.length ?? 0); k++) {
1705
1708
  const tk = tkids[k];
1706
1709
  if (tk.nodeType === 3 || tk.nodeType === 4) text += tk.textContent || "";
1707
- else if (tk.nodeType === 1) return null;
1710
+ else if (tk.nodeType === 1) {
1711
+ const ttag = (tk.tagName || tk.localName || "").replace(/^[^:]+:/, "");
1712
+ if (ttag === "tab" || ttag === "fwSpace" || ttag === "hwSpace" || ttag === "nbSpace") text += " ";
1713
+ else return null;
1714
+ }
1708
1715
  }
1709
1716
  } else if (rtag === "secPr" || rtag === "colPr") {
1710
1717
  } else if (rtag === "ctrl") {
@@ -2085,6 +2092,20 @@ async function extractHwpxMetadataOnly(buffer) {
2085
2092
  }
2086
2093
 
2087
2094
  // src/hwpx/parser.ts
2095
+ function assignSectionPage(block, sectionNum) {
2096
+ const pending = [block];
2097
+ while (pending.length > 0) {
2098
+ const current = pending.pop();
2099
+ current.pageNumber = sectionNum;
2100
+ for (const child of current.children ?? []) pending.push(child);
2101
+ for (const caption of current.table?.captionBlocks ?? []) pending.push(caption);
2102
+ for (const row of current.table?.cells ?? []) {
2103
+ for (const cell2 of row) {
2104
+ for (const child of cell2.blocks ?? []) pending.push(child);
2105
+ }
2106
+ }
2107
+ }
2108
+ }
2088
2109
  async function parseHwpxDocument(buffer, options) {
2089
2110
  precheckZipSize(buffer, MAX_DECOMPRESS_SIZE, MAX_ZIP_ENTRIES);
2090
2111
  let zip;
@@ -2152,7 +2173,7 @@ async function parseHwpxDocument(buffer, options) {
2152
2173
  metadata.pageCount = layoutPages ? Math.max(shared.pageState.base, 1) : sectionPaths.length;
2153
2174
  if (!layoutPages) {
2154
2175
  for (const r of sectionRanges) {
2155
- for (let b = r.start; b < r.end; b++) allBlocks[b].pageNumber = r.sectionNum;
2176
+ for (let b = r.start; b < r.end; b++) assignSectionPage(allBlocks[b], r.sectionNum);
2156
2177
  }
2157
2178
  }
2158
2179
  if (options?.pages) {
@@ -19183,6 +19204,9 @@ function resolveTheme(theme) {
19183
19204
  function escapeXml(text) {
19184
19205
  return text.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F]/g, "").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
19185
19206
  }
19207
+ function escapeTextXml(text) {
19208
+ return escapeXml(text).replace(/\u00a0/g, "<hp:nbSpace/>");
19209
+ }
19186
19210
  function headingParaPrId(level) {
19187
19211
  if (level === 1) return PARA_H1;
19188
19212
  if (level === 2) return PARA_H2;
@@ -19209,14 +19233,14 @@ function charPr(id, height, bold, italic, fontId = 0, textColor = DEFAULT_TEXT_C
19209
19233
  </hh:charPr>`;
19210
19234
  }
19211
19235
  function paraPr(id, opts = {}) {
19212
- const { align = "JUSTIFY", spaceBefore = 0, spaceAfter = 0, lineSpacing = 160, indent = 0, left = 0, right = 0, keepWord = false, keepWithNext = false, outlineLevel } = opts;
19236
+ const { align = "JUSTIFY", spaceBefore = 0, spaceAfter = 0, lineSpacing = 160, indent = 0, left = 0, right = 0, keepWord = false, keepWithNext = false, outlineLevel, autoTab = false, widowOrphan = false } = opts;
19213
19237
  const breakNonLatin = keepWord ? "BREAK_WORD" : "KEEP_WORD";
19214
19238
  const snapGrid = keepWord ? "0" : "1";
19215
19239
  const heading = outlineLevel !== void 0 ? `<hh:heading type="OUTLINE" idRef="0" level="${outlineLevel}"/>` : `<hh:heading type="NONE" idRef="0" level="0"/>`;
19216
- return ` <hh:paraPr id="${id}" tabPrIDRef="0" condense="0" fontLineHeight="0" snapToGrid="${snapGrid}" suppressLineNumbers="0" checked="0" textDir="AUTO">
19240
+ return ` <hh:paraPr id="${id}" tabPrIDRef="${autoTab ? 1 : 0}" condense="0" fontLineHeight="0" snapToGrid="${snapGrid}" suppressLineNumbers="0" checked="0" textDir="AUTO">
19217
19241
  <hh:align horizontal="${align}" vertical="BASELINE"/>
19218
19242
  ${heading}
19219
- <hh:breakSetting breakLatinWord="KEEP_WORD" breakNonLatinWord="${breakNonLatin}" widowOrphan="0" keepWithNext="${keepWithNext ? 1 : 0}" keepLines="0" pageBreakBefore="0" lineWrap="BREAK"/>
19243
+ <hh:breakSetting breakLatinWord="KEEP_WORD" breakNonLatinWord="${breakNonLatin}" widowOrphan="${widowOrphan ? 1 : 0}" keepWithNext="${keepWithNext ? 1 : 0}" keepLines="0" pageBreakBefore="0" lineWrap="BREAK"/>
19220
19244
  <hh:autoSpacing eAsianEng="0" eAsianNum="0"/>
19221
19245
  <hh:margin><hc:intent value="${indent}" unit="HWPUNIT"/><hc:left value="${left}" unit="HWPUNIT"/><hc:right value="${right}" unit="HWPUNIT"/><hc:prev value="${spaceBefore}" unit="HWPUNIT"/><hc:next value="${spaceAfter}" unit="HWPUNIT"/></hh:margin>
19222
19246
  <hh:lineSpacing type="PERCENT" value="${lineSpacing}"/>
@@ -19675,7 +19699,7 @@ function generateRuns(text, defaultCharPr = CHAR_NORMAL, mapCharId) {
19675
19699
  }
19676
19700
  }
19677
19701
  const charId = span.code || span.bold || span.italic ? spanToCharPrId(span) : defaultCharPr;
19678
- out.push(`<hp:run charPrIDRef="${mapped(charId)}"><hp:t>${escapeXml(span.text)}</hp:t></hp:run>`);
19702
+ out.push(`<hp:run charPrIDRef="${mapped(charId)}"><hp:t>${escapeTextXml(span.text)}</hp:t></hp:run>`);
19679
19703
  }
19680
19704
  closeField();
19681
19705
  return out.join("");
@@ -19902,7 +19926,7 @@ ${base2.join("\n")}
19902
19926
  const ls = gongmun.lineSpacing;
19903
19927
  const titleAlign = gongmun.centerTitle ? "CENTER" : "LEFT";
19904
19928
  const h2MarkerWidth = markerWidth(gongmun.h2Marker === "box" ? "\u25A1" : "1.", 1600);
19905
- const h2Geom = gongmun.h2Marker !== "none" ? { spaceBefore: Math.round(gongmun.bodyHeight * 2), spaceAfter: 0, indent: -h2MarkerWidth } : { spaceBefore: 600, spaceAfter: 150 };
19929
+ const h2Geom = gongmun.h2Marker !== "none" ? { spaceBefore: Math.round(gongmun.bodyHeight * 2), spaceAfter: 0, indent: -h2MarkerWidth, autoTab: true } : { spaceBefore: 600, spaceAfter: 150 };
19906
19930
  const h3Left = gongmun.h2Marker !== "none" ? h2MarkerWidth : 0;
19907
19931
  const base = [
19908
19932
  paraPr(0, { lineSpacing: ls, keepWord: true }),
@@ -19922,7 +19946,7 @@ ${base2.join("\n")}
19922
19946
  const { left, indent } = levelIndent(d, gongmun.bodyHeight, gongmun.numbering, gongmun.sizes, gongmun.bullet2, usesAsteriskThird(gongmun.preset), levelMarkerHeight(gongmun, d));
19923
19947
  const sectionGap = gongmun.numbering === "gaejosik" || gongmun.numbering === "report" ? gaejosikSpaceBefore(d, gongmun.bodyHeight) : 0;
19924
19948
  const keepNext = (gongmun.numbering === "gaejosik" || gongmun.numbering === "report") && d === 0;
19925
- base.push(paraPr(GONGMUN_LIST_BASE + d, { align: listAlign, lineSpacing: ls, left, indent, spaceBefore: sectionGap, keepWord: true, keepWithNext: keepNext }));
19949
+ base.push(paraPr(GONGMUN_LIST_BASE + d, { align: listAlign, lineSpacing: ls, left, indent, spaceBefore: sectionGap, keepWord: true, keepWithNext: keepNext, autoTab: true }));
19926
19950
  }
19927
19951
  base.push(paraPr(GONGMUN_CENTER, { align: "CENTER", lineSpacing: ls, keepWord: true }));
19928
19952
  base.push(paraPr(GONGMUN_RIGHT, { align: "RIGHT", lineSpacing: ls, keepWord: true }));
@@ -19932,7 +19956,7 @@ ${base2.join("\n")}
19932
19956
  const cham = gaejosikChamIndent(gongmun.bodyHeight, gongmun.sizes);
19933
19957
  const toc = gaejosikTocItemIndent(gongmun.bodyHeight, gongmun.sizes);
19934
19958
  base.push(
19935
- paraPr(GJ_PARA_CHAM, { align: "LEFT", lineSpacing: ls, left: cham.left, indent: cham.indent, spaceBefore: gaejosikSpaceBefore(3, gongmun.bodyHeight), keepWord: true }),
19959
+ paraPr(GJ_PARA_CHAM, { align: "LEFT", lineSpacing: ls, left: cham.left, indent: cham.indent, spaceBefore: gaejosikSpaceBefore(3, gongmun.bodyHeight), keepWord: true, autoTab: true }),
19936
19960
  paraPr(GJ_PARA_COVER, { align: "CENTER", lineSpacing: 130, keepWord: true }),
19937
19961
  paraPr(GJ_PARA_TOC_ITEM, { align: "LEFT", lineSpacing: 160, left: toc.left, indent: toc.indent, spaceBefore: 1800, keepWord: true }),
19938
19962
  // 장 헤더는 다음 문단과 같은 쪽에 — 쪽 하단 고아 헤더 방지 (실렌더 확인 이슈)
@@ -19953,7 +19977,7 @@ ${base2.join("\n")}
19953
19977
  const { left } = levelIndent(depth, gongmun.bodyHeight, gongmun.numbering, gongmun.sizes, gongmun.bullet2, usesAsteriskThird(gongmun.preset));
19954
19978
  const sectionGap = gongmun.numbering === "gaejosik" || gongmun.numbering === "report" ? gaejosikSpaceBefore(depth, gongmun.bodyHeight) : 0;
19955
19979
  const keepNext = (gongmun.numbering === "gaejosik" || gongmun.numbering === "report") && depth === 0;
19956
- base.push(paraPr(GONGMUN_LIST_VARIANT_BASE + vi, { align: listAlign, lineSpacing: ls, left, indent: -widthHu, spaceBefore: sectionGap, keepWord: true, keepWithNext: keepNext }));
19980
+ base.push(paraPr(GONGMUN_LIST_VARIANT_BASE + vi, { align: listAlign, lineSpacing: ls, left, indent: -widthHu, spaceBefore: sectionGap, keepWord: true, keepWithNext: keepNext, autoTab: true }));
19957
19981
  }
19958
19982
  assertSequentialIds(base, "paraPr", 0);
19959
19983
  return `<hh:paraProperties itemCnt="${base.length}">
@@ -20086,6 +20110,10 @@ function buildStyles(gongmun) {
20086
20110
  ${items.join("\n ")}
20087
20111
  </hh:styles>`;
20088
20112
  }
20113
+ var TAB_PROPS_GONGMUN = `<hh:tabProperties itemCnt="2">
20114
+ <hh:tabPr id="0" autoTabLeft="0" autoTabRight="0"/>
20115
+ <hh:tabPr id="1" autoTabLeft="1" autoTabRight="0"/>
20116
+ </hh:tabProperties>`;
20089
20117
  function generateHeaderXml(theme, gongmun, ratioVariants = [], extraBorderFills = [], extraCharPrXmls = [], listIndentVariants = [], extraFonts = [], v5 = null) {
20090
20118
  const bodyFace = v5?.bodyFace ?? gongmun?.fonts.body ?? (gongmun?.bodyFont === "gothic" ? "\uB9D1\uC740 \uACE0\uB515" : "\uD568\uCD08\uB86C\uBC14\uD0D5");
20091
20119
  const charPropsXml = buildCharProperties(theme, gongmun, ratioVariants, extraCharPrXmls, !!v5);
@@ -20097,7 +20125,7 @@ function generateHeaderXml(theme, gongmun, ratioVariants = [], extraBorderFills
20097
20125
  ${buildFontFaces(gongmun, bodyFace, extraFonts, !!v5)}
20098
20126
  ${buildBorderFills(gongmun, extraBorderFills, !!v5)}
20099
20127
  ${charPropsXml}
20100
- <hh:tabProperties itemCnt="0"/>
20128
+ ${v5 || gongmun ? TAB_PROPS_GONGMUN : `<hh:tabProperties itemCnt="0"/>`}
20101
20129
  ${buildNumberings()}
20102
20130
  <hh:bullets itemCnt="0"/>
20103
20131
  ${paraPropsXml}
@@ -20493,7 +20521,7 @@ function buildGaejosikCover(title, gongmun, bodyWidth = GAEJOSIK_BASE_WIDTH) {
20493
20521
  const sz = gaejosikSizes(gongmun.bodyHeight, gongmun.sizes);
20494
20522
  const innerW = g.totalW - 282;
20495
20523
  const titleCharPr = simulateWrap(title, innerW, innerW, sz.coverTitle, 100, "keep").lines > 2 ? GJ_CHAR_COVER_SUB : GJ_CHAR_COVER_TITLE;
20496
- const titlePara = `<hp:p paraPrIDRef="${GJ_PARA_COVER}" styleIDRef="0"><hp:run charPrIDRef="${titleCharPr}"><hp:t>${escapeXml(title)}</hp:t></hp:run></hp:p>`;
20524
+ const titlePara = `<hp:p paraPrIDRef="${GJ_PARA_COVER}" styleIDRef="0"><hp:run charPrIDRef="${titleCharPr}"><hp:t>${escapeTextXml(title)}</hp:t></hp:run></hp:p>`;
20497
20525
  const barEmpty = emptyPara(GJ_PARA_BAR, false, GJ_CHAR_BAR);
20498
20526
  const topRow = cell({ bf: GJ_BF_BAR_DARK, col: 0, colSpan: 2, row: 0, w: g.topDarkW, h: g.barH, paras: barEmpty }) + cell({ bf: GJ_BF_BAR_LIGHT, col: 2, row: 0, w: g.topLightW, h: g.barH, paras: barEmpty });
20499
20527
  const titleRow = cell({ bf: 1, col: 0, colSpan: 3, row: 1, w: g.totalW, h: g.titleH, paras: titlePara, name: "__kordoc_h1" });
@@ -20502,7 +20530,7 @@ function buildGaejosikCover(title, gongmun, bodyWidth = GAEJOSIK_BASE_WIDTH) {
20502
20530
  const host2 = `<hp:p paraPrIDRef="${PARA_NORMAL}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_NORMAL}">${tbl2}</hp:run></hp:p>`;
20503
20531
  const date = gongmun.cover?.date ?? formatGaejosikDate(/* @__PURE__ */ new Date());
20504
20532
  const org = gongmun.cover?.org ?? "";
20505
- const sub = (t) => `<hp:p paraPrIDRef="${GJ_PARA_COVER}" styleIDRef="0"><hp:run charPrIDRef="${GJ_CHAR_COVER_SUB}"><hp:t>${escapeXml(t)}</hp:t></hp:run></hp:p>`;
20533
+ const sub = (t) => `<hp:p paraPrIDRef="${GJ_PARA_COVER}" styleIDRef="0"><hp:run charPrIDRef="${GJ_CHAR_COVER_SUB}"><hp:t>${escapeTextXml(t)}</hp:t></hp:run></hp:p>`;
20506
20534
  const subEmpty = emptyPara(GJ_PARA_COVER, false, GJ_CHAR_COVER_SUB);
20507
20535
  return [
20508
20536
  ...Array(5).fill(emptyPara()),
@@ -20527,7 +20555,7 @@ function buildGaejosikToc(chapters, gongmun, bodyWidth = GAEJOSIK_BASE_WIDTH) {
20527
20555
  const boxW = Math.round(TOC_GEOM.boxW * bodyWidth / GAEJOSIK_BASE_WIDTH);
20528
20556
  const label = buildTocBanner(gongmun, bodyWidth);
20529
20557
  const items = chapters.map(
20530
- (title, i) => `<hp:p paraPrIDRef="${GJ_PARA_TOC_ITEM}" styleIDRef="0"><hp:run charPrIDRef="${GJ_CHAR_TOC_ROMAN}"><hp:t>${chapterRoman(i + 1)}</hp:t></hp:run><hp:run charPrIDRef="${GJ_CHAR_TOC_ITEM}"><hp:t>. ${escapeXml(title)}</hp:t></hp:run></hp:p>`
20558
+ (title, i) => `<hp:p paraPrIDRef="${GJ_PARA_TOC_ITEM}" styleIDRef="0"><hp:run charPrIDRef="${GJ_CHAR_TOC_ROMAN}"><hp:t>${chapterRoman(i + 1)}</hp:t></hp:run><hp:run charPrIDRef="${GJ_CHAR_TOC_ITEM}"><hp:t>. ${escapeTextXml(title)}</hp:t></hp:run></hp:p>`
20531
20559
  ).join("");
20532
20560
  const box = table(
20533
20561
  [cell({ bf: GJ_BF_TOC_BOX, col: 0, w: boxW, h: TOC_GEOM.boxH, paras: items, name: "__kordoc_toc" })],
@@ -20544,7 +20572,7 @@ function buildGaejosikBodyTitle(title, gongmun, bodyWidth = GAEJOSIK_BASE_WIDTH)
20544
20572
  const g = coverGeom(gongmun.bodyHeight, gongmun.sizes, bodyWidth);
20545
20573
  const bt = bodyTitleGeom(gongmun.bodyHeight, gongmun.sizes);
20546
20574
  const barEmpty = emptyPara(GJ_PARA_BAR, false, GJ_CHAR_BAR);
20547
- const titlePara = `<hp:p paraPrIDRef="${GONGMUN_CENTER}" styleIDRef="0"><hp:run charPrIDRef="${GJ_CHAR_BODY_TITLE}"><hp:t>${escapeXml(title)}</hp:t></hp:run></hp:p>`;
20575
+ const titlePara = `<hp:p paraPrIDRef="${GONGMUN_CENTER}" styleIDRef="0"><hp:run charPrIDRef="${GJ_CHAR_BODY_TITLE}"><hp:t>${escapeTextXml(title)}</hp:t></hp:run></hp:p>`;
20548
20576
  const topRow = cell({ bf: GJ_BF_BAR_DARK, col: 0, colSpan: 2, row: 0, w: g.topDarkW, h: bt.barH, paras: barEmpty }) + cell({ bf: GJ_BF_BAR_LIGHT, col: 2, row: 0, w: g.topLightW, h: bt.barH, paras: barEmpty });
20549
20577
  const titleRow = cell({ bf: 1, col: 0, colSpan: 3, row: 1, w: g.totalW, h: bt.titleH, paras: titlePara, name: "__kordoc_skip" });
20550
20578
  const botRow = cell({ bf: GJ_BF_BAR_DARK, col: 0, row: 2, w: g.botDarkW, h: bt.barH, paras: barEmpty }) + cell({ bf: GJ_BF_BAR_LIGHT, col: 1, colSpan: 2, row: 2, w: g.botLightW, h: bt.barH, paras: barEmpty });
@@ -20554,7 +20582,7 @@ function buildGaejosikBodyTitle(title, gongmun, bodyWidth = GAEJOSIK_BASE_WIDTH)
20554
20582
  function buildGaejosikChapter(n, title, gongmun, bodyWidth = GAEJOSIK_BASE_WIDTH, srcLevel = 2) {
20555
20583
  const g = gongmun ? chapterGeom(gongmun.bodyHeight, gongmun.sizes, bodyWidth) : chapterGeom(1500, {}, bodyWidth);
20556
20584
  const numPara = `<hp:p paraPrIDRef="${GONGMUN_CENTER}" styleIDRef="0"><hp:run charPrIDRef="${GJ_CHAR_CHAPTER_NUM}"><hp:t>${chapterRoman(n)}</hp:t></hp:run></hp:p>`;
20557
- const titlePara = `<hp:p paraPrIDRef="${PARA_NORMAL}" styleIDRef="0"><hp:run charPrIDRef="${GJ_CHAR_CHAPTER_TITLE}"><hp:t> ${escapeXml(title)}</hp:t></hp:run></hp:p>`;
20585
+ const titlePara = `<hp:p paraPrIDRef="${PARA_NORMAL}" styleIDRef="0"><hp:run charPrIDRef="${GJ_CHAR_CHAPTER_TITLE}"><hp:t> ${escapeTextXml(title)}</hp:t></hp:run></hp:p>`;
20558
20586
  const row = cell({ bf: GJ_BF_CHAPTER_NUM, col: 0, w: g.numW, h: g.rowH, paras: numPara }) + cell({ bf: GJ_BF_CHAPTER_GAP, col: 1, w: g.gapW, h: g.rowH }) + cell({ bf: GJ_BF_CHAPTER_TITLE, col: 2, w: g.titleW, h: g.rowH, paras: titlePara, name: `__kordoc_h${Math.min(Math.max(srcLevel, 1), 6)}` });
20559
20587
  const tbl2 = table([row], g.numW + g.gapW + g.titleW, g.rowH, 3, 1, bodyWidth);
20560
20588
  return `<hp:p paraPrIDRef="${GJ_PARA_CHAPTER}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_NORMAL}">${tbl2}</hp:run></hp:p>`;
@@ -21521,7 +21549,7 @@ function cellContentWidth(text, charHeight) {
21521
21549
  function cellMinWordWidth(text, charHeight) {
21522
21550
  let max = 0;
21523
21551
  for (const seg of text.replace(/!\[[^\]]*\]\([^)\s]+\)/g, "").replace(/\*\*|__|`/g, "").split(/<br\s*\/?>/i)) {
21524
- for (const word of seg.trim().split(/\s+/)) {
21552
+ for (const word of seg.trim().split(/[ \t]+/)) {
21525
21553
  const w = measureTextWidth(word, charHeight, 100, { faceClass: curFace });
21526
21554
  if (w > max) max = w;
21527
21555
  }
@@ -21539,7 +21567,10 @@ function colRoles(headers) {
21539
21567
  if (roles.length >= 3 && roles.includes("content") && roles[last] === null) roles[last] = "remark";
21540
21568
  return roles;
21541
21569
  }
21542
- function computeColWidths(colMax, totalWidth, colMinWord = [], roles = []) {
21570
+ function colSlack(faceClass) {
21571
+ return faceClass.startsWith("font:") ? 1.03 : 1.12;
21572
+ }
21573
+ function computeColWidths(colMax, totalWidth, colMinWord = [], roles = [], slack = 1.12) {
21543
21574
  const colCnt = colMax.length;
21544
21575
  const minW = Math.min(Math.max(2e3, Math.round(totalWidth * 0.06)), Math.floor(totalWidth / colCnt));
21545
21576
  const cap = Math.round(totalWidth * 0.8);
@@ -21553,7 +21584,7 @@ function computeColWidths(colMax, totalWidth, colMinWord = [], roles = []) {
21553
21584
  let sumFloorFree = floor.reduce((a, b) => a + b, 0);
21554
21585
  for (const i of [...raw.keys()].sort((a, b) => raw[a] - raw[b])) {
21555
21586
  if (free.size <= 1) break;
21556
- const fixed = roles[i] === "remark" ? Math.min(Math.round(raw[i] * 1.12), capOf[i]) : Math.round(raw[i] * 1.12);
21587
+ const fixed = roles[i] === "remark" ? Math.min(Math.round(raw[i] * slack), capOf[i]) : Math.round(raw[i] * slack);
21557
21588
  if (budget - fixed < sumFloorFree - floor[i]) break;
21558
21589
  widths[i] = fixed;
21559
21590
  free.delete(i);
@@ -21626,7 +21657,7 @@ function requiredTableWidth(rows, charHeight, faceClass = "hcr") {
21626
21657
  if (w > colMax[c]) colMax[c] = w;
21627
21658
  });
21628
21659
  curFace = prev;
21629
- return colMax.reduce((a, w) => a + Math.round((w + CELL_PAD) * 1.12), 0);
21660
+ return colMax.reduce((a, w) => a + Math.round((w + CELL_PAD) * colSlack(faceClass)), 0);
21630
21661
  }
21631
21662
  function generateTable(rows, theme, style = null, remap = null, seq = 0, images = null) {
21632
21663
  curFace = style?.faceClass ?? "hcr";
@@ -21648,7 +21679,7 @@ function generateTable(rows, theme, style = null, remap = null, seq = 0, images
21648
21679
  if (mw > colMinWord[c]) colMinWord[c] = mw;
21649
21680
  }));
21650
21681
  const roles = style ? colRoles(rows[0] ?? []) : [];
21651
- const colWidths = profileColWidths(prof, colCnt) ?? computeColWidths(colMax, totalW, colMinWord, roles);
21682
+ const colWidths = profileColWidths(prof, colCnt) ?? computeColWidths(colMax, totalW, colMinWord, roles, colSlack(curFace));
21652
21683
  const colCentered = colWidths.map((w, c) => roles[c] !== "content" && colMaxBody[c] + CELL_PAD <= w);
21653
21684
  const labelCol0 = !!reg && colCnt === 2 && colCentered[0] && rows.every((r) => (r[0] ?? "").replace(/\*\*|__|`/g, "").length <= 12);
21654
21685
  const tblId = nextTableId();
@@ -21748,6 +21779,7 @@ function generateHtmlTableXml(rawHtml, theme, totalWidth = 44e3, style = null, r
21748
21779
  const { placed, rowCnt, colCnt } = layoutHtmlRows(rows);
21749
21780
  if (rowCnt === 0 || colCnt === 0) return null;
21750
21781
  const measureH = style?.charHeight ?? 1e3;
21782
+ curFace = style?.faceClass ?? "hcr";
21751
21783
  const first = placed.find((p) => p.r === 0 && p.c === 0) ?? placed[0];
21752
21784
  const row0 = Array.from({ length: colCnt }, () => "");
21753
21785
  for (const cell2 of placed) {
@@ -21760,7 +21792,7 @@ function generateHtmlTableXml(rawHtml, theme, totalWidth = 44e3, style = null, r
21760
21792
  const cellParsed = placed.map((cell2) => htmlCellInnerToLines(cell2.inner));
21761
21793
  const cellLines = cellParsed.map((p) => p.lines);
21762
21794
  placed.forEach((cell2, i) => {
21763
- const w = Math.max(...cellLines[i].map((l) => measureTextWidth(unescapeHtml(l).trim(), measureH, 100)), 0) / cell2.colSpan;
21795
+ const w = Math.max(...cellLines[i].map((l) => measureTextWidth(unescapeHtml(l).trim(), measureH, 100, { faceClass: curFace })), 0) / cell2.colSpan;
21764
21796
  const mw = cell2.colSpan === 1 ? Math.max(...cellLines[i].map((l) => cellMinWordWidth(unescapeHtml(l), measureH)), 0) : 0;
21765
21797
  for (let dc = 0; dc < cell2.colSpan; dc++) {
21766
21798
  const c = cell2.c + dc;
@@ -21772,7 +21804,7 @@ function generateHtmlTableXml(rawHtml, theme, totalWidth = 44e3, style = null, r
21772
21804
  const headers = Array.from({ length: colCnt }, () => "");
21773
21805
  for (const [i, cell2] of placed.entries()) if (cell2.r === 0 && cell2.c < colCnt) headers[cell2.c] = unescapeHtml(cellLines[i].join(" "));
21774
21806
  const roles = style ? colRoles(headers) : [];
21775
- const colWidths = profileColWidths(prof, colCnt) ?? computeColWidths(colMax, totalWidth, colMinWord, roles);
21807
+ const colWidths = profileColWidths(prof, colCnt) ?? computeColWidths(colMax, totalWidth, colMinWord, roles, colSlack(curFace));
21776
21808
  const colCentered = colWidths.map((w, c) => roles[c] !== "content" && colMaxBody[c] + CELL_PAD <= w);
21777
21809
  const cellH = style ? Math.round(measureH * 1.6) + 282 : 1500;
21778
21810
  const tblW = colWidths.reduce((a, b) => a + b, 0);
@@ -21801,7 +21833,7 @@ function generateHtmlTableXml(rawHtml, theme, totalWidth = 44e3, style = null, r
21801
21833
  const segLines = segTexts.map((t) => htmlCellInnerToLines(t).lines);
21802
21834
  const usable = Math.max(spanW(cell2) - CELL_PAD, 1e3);
21803
21835
  let wrapLines = 0;
21804
- for (const line of lines) wrapLines += Math.max(1, Math.ceil(measureTextWidth(unescapeHtml(line).trim(), measureH, 100) / usable));
21836
+ for (const line of lines) wrapLines += Math.max(1, Math.ceil(measureTextWidth(unescapeHtml(line).trim(), measureH, 100, { faceClass: curFace }) / usable));
21805
21837
  const lineH = style ? Math.round(measureH * 1.6) : 800;
21806
21838
  const contentH = Math.max(cellH * rowSpan, Math.max(wrapLines, 1) * lineH + nestedH);
21807
21839
  const cellHeight = Math.max(prof?.cellH.get(`${cell2.r},${cell2.c}`) ?? 0, contentH);
@@ -21830,7 +21862,7 @@ function generateHtmlTableXml(rawHtml, theme, totalWidth = 44e3, style = null, r
21830
21862
  }
21831
21863
  }
21832
21864
  if (!images || text.trim() || picUrls.length === 0) {
21833
- paras.push(`<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0"><hp:run charPrIDRef="${charPrId}"><hp:t>${escapeXml(text)}</hp:t></hp:run></hp:p>`);
21865
+ paras.push(`<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0"><hp:run charPrIDRef="${charPrId}"><hp:t>${escapeTextXml(text)}</hp:t></hp:run></hp:p>`);
21834
21866
  }
21835
21867
  };
21836
21868
  segLines.forEach((seg, si) => {
@@ -21889,7 +21921,7 @@ function tc(opts) {
21889
21921
  return `<hp:tc name="${opts.name ?? ""}" header="0" hasMargin="0" protect="0" editable="1" dirty="0" borderFillIDRef="${opts.bf}"><hp:subList id="" textDirection="HORIZONTAL" lineWrap="BREAK" vertAlign="${opts.vAlign ?? "CENTER"}" linkListIDRef="0" linkListNextIDRef="0" textWidth="0" textHeight="0" hasTextRef="0" hasNumRef="0">${opts.paras}</hp:subList><hp:cellAddr colAddr="${opts.col}" rowAddr="${opts.row}"/><hp:cellSpan colSpan="${opts.colSpan ?? 1}" rowSpan="${opts.rowSpan ?? 1}"/><hp:cellSz width="${opts.w}" height="${opts.h}"/><hp:cellMargin left="141" right="141" top="141" bottom="141"/></hp:tc>`;
21890
21922
  }
21891
21923
  function para(text, paraPrId, charPrId) {
21892
- return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0"><hp:run charPrIDRef="${charPrId}"><hp:t>${escapeXml(text)}</hp:t></hp:run></hp:p>`;
21924
+ return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0"><hp:run charPrIDRef="${charPrId}"><hp:t>${escapeTextXml(text)}</hp:t></hp:run></hp:p>`;
21893
21925
  }
21894
21926
  var APPROVAL_COL_W = 7085;
21895
21927
  var APPROVAL_LABEL_H = 1300;
@@ -22465,6 +22497,16 @@ function buildPreamble(blocks, ctx) {
22465
22497
  ctx.paraXmls.push(...preamble);
22466
22498
  }
22467
22499
  }
22500
+ function markedParagraph(marker, content, paraPrId, charPrId, halfEm, mapCharId, styleId = 0) {
22501
+ const cid2 = mapCharId ? mapCharId(charPrId) : charPrId;
22502
+ const run = `<hp:run charPrIDRef="${cid2}"><hp:t>${escapeTextXml(marker)}<hp:tab width="${Math.round(halfEm)}" leader="0" type="1"/></hp:t></hp:run>`;
22503
+ return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="${styleId}">${run}${generateRuns(content, charPrId, mapCharId)}</hp:p>`;
22504
+ }
22505
+ function refParagraph(text, ctx) {
22506
+ const m = /^(※|\*(?=\s))\s*/.exec(text);
22507
+ const [mk, rest] = m ? [m[1], text.slice(m[0].length)] : ["\u203B", text];
22508
+ return markedParagraph(mk, rest, GJ_PARA_CHAM, GJ_CHAR_CHAM, ctx.gongmun.bodyHeight / 2, ctx.chamMap);
22509
+ }
22468
22510
  function renderHeading(block, blockIdx, ctx) {
22469
22511
  const { gongmun, dfIds, tableStyle, bfReg, measured, richAssets, gjBodyW } = ctx;
22470
22512
  if (gongmun && blockIdx === ctx.coverH1Idx) return "";
@@ -22491,24 +22533,27 @@ function renderHeading(block, blockIdx, ctx) {
22491
22533
  ctx.chapterNo = no >= 0 ? no + 1 : ctx.chapterNo + 1;
22492
22534
  return buildGaejosikChapter(ctx.chapterNo, stripChapterNumber(block.text || ""), gongmun, gjBodyW, lvl);
22493
22535
  } else if (lvl === 3) {
22494
- return generateParagraph(
22495
- `\u25A1 ${block.text || ""}`,
22536
+ return markedParagraph(
22537
+ "\u25A1",
22538
+ block.text || "",
22496
22539
  GONGMUN_LIST_BASE,
22497
22540
  GJ_CHAR_DAE,
22541
+ gongmun.bodyHeight / 2,
22498
22542
  (id) => id === CHAR_BOLD ? GJ_CHAR_DAE_BOLD : id
22499
22543
  );
22500
22544
  }
22501
- return generateParagraph(`${gongmun.bullet2} ${block.text || ""}`, GONGMUN_LIST_BASE + 1, CHAR_NORMAL);
22545
+ return markedParagraph(gongmun.bullet2, block.text || "", GONGMUN_LIST_BASE + 1, CHAR_NORMAL, gongmun.bodyHeight / 2);
22502
22546
  }
22503
22547
  const pId = headingParaPrId(block.level || 1);
22504
22548
  const cId = headingCharPrId(block.level || 1);
22505
22549
  const styleId = gongmun ? Math.min(block.level || 1, 4) : 0;
22506
- let hText = block.text || "";
22507
22550
  if (gongmun && (block.level || 1) === 2 && gongmun.h2Marker !== "none") {
22508
- const title = stripChapterNumber(hText);
22509
- hText = gongmun.h2Marker === "box" ? `\u25A1 ${title}` : `${++ctx.h2Seq}. ${title}`;
22551
+ const title = stripChapterNumber(block.text || "");
22552
+ const mk = gongmun.h2Marker === "box" ? "\u25A1" : `${++ctx.h2Seq}.`;
22553
+ if (mk.length > 2) return generateParagraph(`${mk} ${title}`, pId, cId, void 0, styleId);
22554
+ return markedParagraph(mk, title, pId, cId, gongmun.bodyHeight / 2, void 0, styleId);
22510
22555
  }
22511
- return generateParagraph(hText, pId, cId, void 0, styleId);
22556
+ return generateParagraph(block.text || "", pId, cId, void 0, styleId);
22512
22557
  }
22513
22558
  function renderParagraph(block, blockIdx, ctx) {
22514
22559
  const { gongmun, measured, fit, vBase } = ctx;
@@ -22526,7 +22571,7 @@ function renderParagraph(block, blockIdx, ctx) {
22526
22571
  }
22527
22572
  const pTrim = (block.text || "").trimStart();
22528
22573
  if (measured && (pTrim.startsWith("\u203B") || /^\*\s/.test(pTrim))) {
22529
- return generateParagraph((block.text || "").trim(), GJ_PARA_CHAM, GJ_CHAR_CHAM, ctx.chamMap);
22574
+ return refParagraph((block.text || "").trim(), ctx);
22530
22575
  }
22531
22576
  const ctr = gongmun && /^<center>([\s\S]*)<\/center>$/i.exec((block.text || "").trim());
22532
22577
  const rgt = gongmun && /^<right>([\s\S]*)<\/right>$/i.exec((block.text || "").trim());
@@ -22565,7 +22610,7 @@ function renderEquation(block, blockIdx, ctx) {
22565
22610
  function renderBlockquote(block, ctx) {
22566
22611
  if (ctx.measured) {
22567
22612
  const t = (block.text || "").replace(/\n+/g, " ").trim();
22568
- return t ? generateParagraph(t.startsWith("\u203B") ? t : `\u203B ${t}`, GJ_PARA_CHAM, GJ_CHAR_CHAM, ctx.chamMap) : "";
22613
+ return t ? refParagraph(t, ctx) : "";
22569
22614
  }
22570
22615
  const quoteChar = ctx.theme.hasQuoteOption ? CHAR_QUOTE : CHAR_NORMAL;
22571
22616
  return (block.text || "").split("\n").map((line) => generateParagraph(line, PARA_QUOTE, quoteChar)).join("\n ");
@@ -22578,12 +22623,11 @@ function renderListItem(block, blockIdx, ctx) {
22578
22623
  const marker2 = info?.marker ?? "";
22579
22624
  const content = block.text || "";
22580
22625
  if (measured && content.trimStart().startsWith("\u203B")) {
22581
- return generateParagraph(content.trim(), GJ_PARA_CHAM, GJ_CHAR_CHAM, ctx.chamMap);
22626
+ return refParagraph(content.trim(), ctx);
22582
22627
  }
22583
22628
  if (measured && block.marker === "*") {
22584
- return generateParagraph(`* ${content.trim()}`, GJ_PARA_CHAM, GJ_CHAR_CHAM, ctx.chamMap);
22629
+ return refParagraph(`* ${content.trim()}`, ctx);
22585
22630
  }
22586
- const text = marker2 ? `${marker2} ${content}` : content;
22587
22631
  const listParaPr = marker2 ? info?.indentVariant !== void 0 ? GONGMUN_LIST_VARIANT_BASE + info.indentVariant : GONGMUN_LIST_BASE + depth : GONGMUN_LIST_PLAIN_BASE + depth;
22588
22632
  let listCharPr = gongmun.numbering === "report" && depth === 0 ? CHAR_BOLD : CHAR_NORMAL;
22589
22633
  let mapId = fit ? variantMapper(fit, blockIdx, vBase) : void 0;
@@ -22603,7 +22647,7 @@ function renderListItem(block, blockIdx, ctx) {
22603
22647
  listCharPr = lv.normal;
22604
22648
  mapId = (id) => id === CHAR_BOLD ? lv.bold : id === CHAR_NORMAL ? lv.normal : id;
22605
22649
  }
22606
- return generateParagraph(text, listParaPr, listCharPr, mapId);
22650
+ return marker2 ? markedParagraph(marker2, content, listParaPr, listCharPr, gongmun.bodyHeight / 2, mapId) : generateParagraph(content, listParaPr, listCharPr, mapId);
22607
22651
  }
22608
22652
  const indent = block.indent || 0;
22609
22653
  let marker;
@@ -22860,7 +22904,7 @@ var StyleRegistry = class {
22860
22904
  return id;
22861
22905
  }
22862
22906
  para(spec) {
22863
- const key = `${spec.align ?? "JUSTIFY"}|${spec.left ?? 0}|${spec.right ?? 0}|${spec.indent ?? 0}|${spec.before ?? 0}|${spec.after ?? 0}|${spec.lineSp ?? 160}|${spec.keepWithNext ? 1 : 0}|${spec.keepWord === false ? 0 : 1}`;
22907
+ const key = `${spec.align ?? "JUSTIFY"}|${spec.left ?? 0}|${spec.right ?? 0}|${spec.indent ?? 0}|${spec.before ?? 0}|${spec.after ?? 0}|${spec.lineSp ?? 160}|${spec.keepWithNext ? 1 : 0}|${spec.keepWord === false ? 0 : 1}|${spec.autoTab ? 1 : 0}|${spec.widowOrphan ? 1 : 0}`;
22864
22908
  const hit = this.paras.get(key);
22865
22909
  if (hit !== void 0) return hit;
22866
22910
  const id = this.paraBase + this.paraXmls.length;
@@ -22873,7 +22917,9 @@ var StyleRegistry = class {
22873
22917
  spaceAfter: spec.after ?? 0,
22874
22918
  lineSpacing: spec.lineSp ?? 160,
22875
22919
  keepWithNext: !!spec.keepWithNext,
22876
- keepWord: spec.keepWord !== false
22920
+ keepWord: spec.keepWord !== false,
22921
+ autoTab: !!spec.autoTab,
22922
+ widowOrphan: !!spec.widowOrphan
22877
22923
  }));
22878
22924
  this.paras.set(key, id);
22879
22925
  return id;
@@ -23027,11 +23073,6 @@ function applySchemeOverrides(s, g) {
23027
23073
  function taHu(pt) {
23028
23074
  return Math.round(pt * 50);
23029
23075
  }
23030
- function levelGeometry(style, marker) {
23031
- const left = style.leadTa * taHu(style.pt);
23032
- const indent = marker ? -markerWidth(marker, style.pt * 100) : 0;
23033
- return { left, indent };
23034
- }
23035
23076
  function pickScheme(g, bodyHasBoxMarkers) {
23036
23077
  if (g.preset === "ministry") {
23037
23078
  return applySchemeOverrides(ministryScheme(g.bodyPtExplicit ? g.bodyHeight / 100 : 15, g.lineSpacingExplicit ? g.lineSpacing : 145), g);
@@ -23256,9 +23297,12 @@ function buildOutline(blocks, opts) {
23256
23297
  // src/hwpx/fit-line.ts
23257
23298
  var RATIOS = [100, 97, 95, 92, 90, 87, 85];
23258
23299
  var SPACINGS = [0, -3, -5];
23300
+ function safety(faceClass, approx) {
23301
+ return faceClass.startsWith("font:") ? 0.98 : approx;
23302
+ }
23259
23303
  function fitOneLine(text, font, pt, availHu, minPt = Math.max(pt - 3, 10), minRatio = 85) {
23260
23304
  const faceClass = faceClassForGen(font);
23261
- const avail = availHu * 0.98;
23305
+ const avail = availHu * safety(faceClass, 0.98);
23262
23306
  const fits = (p, r, s) => measureTextWidth(text, p * 100, r, { spacingPct: s, faceClass }) <= avail;
23263
23307
  if (fits(pt, 100, 0)) return { pt, ratio: 100, spacing: 0, overflow: false };
23264
23308
  const ratios = RATIOS.filter((r) => r >= minRatio);
@@ -23269,27 +23313,139 @@ function fitOneLine(text, font, pt, availHu, minPt = Math.max(pt - 3, 10), minRa
23269
23313
  }
23270
23314
  return { pt: minPt, ratio: ratios[ratios.length - 1], spacing: SPACINGS[SPACINGS.length - 1], overflow: true };
23271
23315
  }
23272
- function fitOrphanLine(text, font, pt, firstW, contW, orphanRatio = 0.2) {
23316
+ var SQUEEZE = (() => {
23317
+ const out = [];
23318
+ for (let sp = -1; sp >= -12; sp--) out.push([100, sp]);
23319
+ for (const r of [97, 95, 92, 90, 88]) for (let sp = 0; sp >= -12; sp--) out.push([r, sp]);
23320
+ return out;
23321
+ })();
23322
+ var LOOSE_LIMIT = 1;
23323
+ var PULL_TAIL = 0.5;
23324
+ var PULL_MAX = 0.15;
23325
+ var squeezeOf = (r, sp) => 1 - r / 100 * (1 + sp / 100);
23326
+ var ORPHAN_RATIO = 0.22;
23327
+ var ORPHAN_COST = 1.5;
23328
+ var COMPRESS_COST = 10;
23329
+ function worstLooseness(text, starts, firstW, contW, h, ratio, spacing, faceClass) {
23330
+ const spaceW = 0.5 * h * (ratio / 100) * (1 + spacing / 100);
23331
+ let worst = 0;
23332
+ for (let i = 0; i + 1 < starts.length; i++) {
23333
+ const seg = text.slice(starts[i], starts[i + 1]).replace(/ +$/, "");
23334
+ const slack = (i === 0 ? firstW : contW) - measureTextWidth(seg, h, ratio, { faceClass, spacingPct: spacing });
23335
+ const spaces = (seg.match(/ /g) ?? []).length;
23336
+ worst = Math.max(worst, slack / (Math.max(spaces, 1) * spaceW));
23337
+ }
23338
+ return worst;
23339
+ }
23340
+ function fitParagraph(text, font, pt, firstW, contW, minRatio = 88, orphanRatio = ORPHAN_RATIO) {
23273
23341
  const faceClass = faceClassForGen(font);
23274
23342
  const h = pt * 100;
23275
- const SAFE = 0.9;
23276
- const width = (r, sp) => measureTextWidth(text, h, r, { faceClass, spacingPct: sp });
23277
- const est = width(100, 0);
23278
- if (est <= firstW * SAFE) return null;
23279
- const combos = [];
23280
- for (let sp = -1; sp >= -12; sp--) combos.push([100, sp]);
23281
- for (const r of [97, 95, 92, 90, 88]) for (let sp = 0; sp >= -12; sp--) combos.push([r, sp]);
23282
- if (est <= firstW * 1.22) {
23283
- for (const [r, sp] of combos) if (width(r, sp) <= firstW * SAFE) return { ratio: r, spacing: sp };
23284
- return null;
23343
+ const k = safety(faceClass, 0.95);
23344
+ const f = firstW * k, c = contW * k;
23345
+ const ladder = [[100, 0], ...SQUEEZE.filter(([r]) => r >= minRatio)];
23346
+ const base = simulateWrap(text, f, c, h, 100, "keep", { faceClass });
23347
+ if (base.lines < 2) return null;
23348
+ if (base.lastLineWidth <= c * PULL_TAIL) {
23349
+ let pull = null;
23350
+ for (const [r, sp] of ladder) {
23351
+ const amt = squeezeOf(r, sp);
23352
+ if (amt > PULL_MAX + 1e-9 || pull && amt >= pull.amt - 1e-9) continue;
23353
+ const w = simulateWrap(text, f, c, h, r, "keep", { faceClass, spacingPct: sp });
23354
+ if (w.lines < base.lines && worstLooseness(text, w.starts, f, c, h, r, sp, faceClass) <= LOOSE_LIMIT) pull = { r, sp, amt };
23355
+ }
23356
+ if (pull) return { ratio: pull.r, spacing: pull.sp };
23357
+ }
23358
+ let baseLines = 0;
23359
+ let best = null;
23360
+ for (const [r, sp] of ladder) {
23361
+ const w = simulateWrap(text, f, c, h, r, "keep", { faceClass, spacingPct: sp });
23362
+ if (!best) {
23363
+ if (w.lines < 2) return null;
23364
+ baseLines = w.lines;
23365
+ }
23366
+ if (w.lines > baseLines) continue;
23367
+ const orphan = w.lines > 1 && w.lastLineWidth <= contW * orphanRatio;
23368
+ const loose = worstLooseness(text, w.starts, f, c, h, r, sp, faceClass);
23369
+ const cost = Math.max(0, loose - LOOSE_LIMIT) + (orphan ? ORPHAN_COST : 0) + squeezeOf(r, sp) * COMPRESS_COST;
23370
+ if (!best || cost < best.cost - 1e-9) best = { r, sp, cost };
23371
+ }
23372
+ return best && (best.r !== 100 || best.sp !== 0) ? { ratio: best.r, spacing: best.sp } : null;
23373
+ }
23374
+ var LIST_BREAK = /* @__PURE__ */ new Set([..."\xB7,\u3001/"]);
23375
+ function fitCharBreaks(text, font, pt, firstW, contW, minRatio = 88) {
23376
+ const faceClass = faceClassForGen(font);
23377
+ const h = pt * 100;
23378
+ const k = safety(faceClass, 0.95);
23379
+ if (!text.split(/ +/).some((w) => measureTextWidth(w, h, 100, { faceClass }) > contW * k)) return null;
23380
+ let best = null;
23381
+ for (const [r, sp] of [[100, 0], ...SQUEEZE.filter(([r2]) => r2 >= minRatio)]) {
23382
+ const amt = squeezeOf(r, sp);
23383
+ if (amt > PULL_MAX + 1e-9 || best && amt >= best.amt - 1e-9) continue;
23384
+ const wrapAt = (s) => simulateWrap(text, firstW * s, contW * s, h, r, "charAll", { faceClass, spacingPct: sp }).starts;
23385
+ const starts = wrapAt(1);
23386
+ if (wrapAt(0.99).join() !== starts.join() || wrapAt(1.01).join() !== starts.join()) continue;
23387
+ if (!starts.slice(1).every((s) => text[s - 1] === " " || LIST_BREAK.has(text[s - 1]))) continue;
23388
+ if (worstLooseness(text, starts, firstW, contW, h, r, sp, faceClass) > LOOSE_LIMIT) continue;
23389
+ best = { r, sp, amt };
23390
+ }
23391
+ return best ? { ratio: best.r, spacing: best.sp } : null;
23392
+ }
23393
+
23394
+ // src/hwpx/gen-marker.ts
23395
+ function markerLayout(font, pt, leadTa, marker) {
23396
+ const left = leadTa * taHu(pt);
23397
+ if (!marker) return { left, hang: 0, markerW: 0 };
23398
+ const markerW = Math.round(measureTextWidth(marker, pt * 100, 100, { faceClass: faceClassForGen(font) }));
23399
+ return { left, hang: markerW + taHu(pt), markerW };
23400
+ }
23401
+ function markerRunXml(marker, charPr2, lay) {
23402
+ return `<hp:run charPrIDRef="${charPr2}"><hp:t>${escapeTextXml(marker)}<hp:tab width="${lay.hang - lay.markerW}" leader="0" type="1"/></hp:t></hp:run>`;
23403
+ }
23404
+
23405
+ // src/hwpx/gongmun-typo.ts
23406
+ var NBSP = "\xA0";
23407
+ var OPENER_BEFORE = /[\s(\[{>「『〈《【〔‘“·/:,~—–-]/u;
23408
+ function bindSpaces(s) {
23409
+ return s.replace(/(\d{4}|['’]\d{2})\. (\d{1,2})\. (\d{1,2})\.(?!\d)/g, `$1.${NBSP}$2.${NBSP}$3.`).replace(/(\d{4}|['’]\d{2})\. (\d{1,2})\.(?!\d)/g, `$1.${NBSP}$2.`).replace(/(?<![\d.])(\d{1,2})\. (\d{1,2})\.(?!\d)/g, `$1.${NBSP}$2.`).replace(/(\d{1,2}:\d{2}) ([~∼-]) (\d{1,2}:\d{2})/g, `$1${NBSP}$2${NBSP}$3`).replace(/(\d(?:조|억|만|천)?) 원/g, `$1${NBSP}\uC6D0`);
23410
+ }
23411
+ function neighbor(s, i, dir) {
23412
+ for (let k = i + dir; k >= 0 && k < s.length; k += dir) if (!/[*_~]/.test(s[k])) return s[k];
23413
+ return "";
23414
+ }
23415
+ function curlQuotes(s, before = "") {
23416
+ let out = "";
23417
+ for (let i = 0; i < s.length; i++) {
23418
+ const c = s[i];
23419
+ if (c !== "'" && c !== '"') {
23420
+ out += c;
23421
+ continue;
23422
+ }
23423
+ const prev = neighbor(s, i, -1) || before;
23424
+ const opening = prev === "" || OPENER_BEFORE.test(prev);
23425
+ if (c === "'") {
23426
+ if (opening && /^\d{2}(?![\d'])/.test(s.slice(i + 1))) {
23427
+ out += "\u2019";
23428
+ continue;
23429
+ }
23430
+ out += opening ? "\u2018" : "\u2019";
23431
+ } else {
23432
+ out += opening ? "\u201C" : "\u201D";
23433
+ }
23285
23434
  }
23286
- const f = firstW * 0.95, c = contW * 0.95;
23287
- const base = simulateWrap(text, f, c, h, 100, "charAll", { faceClass });
23288
- if (base.lines < 2 || base.lastLineWidth > c * orphanRatio) return null;
23289
- for (const [r, sp] of combos) {
23290
- if (simulateWrap(text, f, c, h, r, "charAll", { faceClass, spacingPct: sp }).lines < base.lines) return { ratio: r, spacing: sp };
23435
+ return out;
23436
+ }
23437
+ function polishGongmunText(text) {
23438
+ if (!text) return text;
23439
+ let out = "";
23440
+ for (const [i, seg] of text.split(/(`[^`]*`|\]\([^)]*\))/).entries()) {
23441
+ out += i % 2 === 1 ? seg : curlQuotes(bindSpaces(seg), out.replace(/[*_~]+$/, "").slice(-1));
23291
23442
  }
23292
- return null;
23443
+ return out;
23444
+ }
23445
+ function polishGongmunBlock(b) {
23446
+ if (b.type === "table") return b.rows ? { ...b, rows: b.rows.map((r) => r.map(polishGongmunText)) } : b;
23447
+ if (b.type === "paragraph" || b.type === "heading" || b.type === "list_item" || b.type === "blockquote") return b.text ? { ...b, text: polishGongmunText(b.text) } : b;
23448
+ return b;
23293
23449
  }
23294
23450
 
23295
23451
  // src/hwpx/gen-frame-seoul.ts
@@ -23506,13 +23662,13 @@ function buildSummaryBox(text, ctx) {
23506
23662
  const { reg, bf, frame } = ctx;
23507
23663
  const w = ctx.W - 566;
23508
23664
  const avail = w - 280 - SUMMARY_PAD * 2;
23509
- const p = reg.para({ align: "JUSTIFY", lineSp: 160, left: SUMMARY_PAD, right: SUMMARY_PAD, keepWord: false });
23665
+ const p = reg.para({ align: "JUSTIFY", lineSp: 160, left: SUMMARY_PAD, right: SUMMARY_PAD });
23510
23666
  const bodies = text.split("\n").map((l) => l.trim().replace(/^[□■○ㅇ◦●\-–ㆍ·•]\s*/u, "")).filter(Boolean);
23511
23667
  let lines = 0;
23512
23668
  const paras = bodies.map((b) => {
23513
- const f = fitOrphanLine(b, frame.summaryFont, frame.summaryPt, avail, avail);
23669
+ const f = fitParagraph(b, frame.summaryFont, frame.summaryPt, avail, avail);
23514
23670
  const c = reg.char({ font: frame.summaryFont, pt: frame.summaryPt, bold: true, ratio: f?.ratio ?? 100, spacing: f?.spacing ?? 0 });
23515
- lines += simulateWrap(b, avail * 0.95, avail * 0.95, frame.summaryPt * 100, f?.ratio ?? 100, "charAll", { faceClass: "gothic", spacingPct: f?.spacing ?? 0 }).lines;
23671
+ lines += simulateWrap(b, avail * 0.995, avail * 0.995, frame.summaryPt * 100, f?.ratio ?? 100, "keep", { faceClass: faceClassForGen(frame.summaryFont), spacingPct: f?.spacing ?? 0 }).lines;
23516
23672
  return para(b, p, c);
23517
23673
  });
23518
23674
  const h = lines * Math.round(frame.summaryPt * 100 * 1.6) + 280 + 600;
@@ -23605,11 +23761,11 @@ function ministryRuns(marker, text, ctx, base, keywordColor, emphasisColor) {
23605
23761
  const { reg } = ctx;
23606
23762
  const baseId = reg.char(base);
23607
23763
  const mapper = inlineMapper(reg, base, emphasisColor);
23608
- let out = marker ? `<hp:run charPrIDRef="${baseId}"><hp:t>${escapeXml(marker + " ")}</hp:t></hp:run>` : "";
23764
+ let out = marker ? `<hp:run charPrIDRef="${baseId}"><hp:t>${escapeTextXml(marker + " ")}</hp:t></hp:run>` : "";
23609
23765
  const m = KEYWORD_RE.exec(text);
23610
23766
  if (m) {
23611
23767
  const kw = reg.char({ ...base, bold: true, color: keywordColor ?? base.color });
23612
- out += `<hp:run charPrIDRef="${kw}"><hp:t>${escapeXml(m[1] + " ")}</hp:t></hp:run>`;
23768
+ out += `<hp:run charPrIDRef="${kw}"><hp:t>${escapeTextXml(m[1] + " ")}</hp:t></hp:run>`;
23613
23769
  text = text.slice(m[0].length);
23614
23770
  }
23615
23771
  return out + generateRuns(text, baseId, mapper);
@@ -23666,8 +23822,8 @@ function buildMinistryToc(chapters, ctx) {
23666
23822
  const cCh = reg.char({ font: MINISTRY.headFont, pt: t.chapterPt });
23667
23823
  const cSub = reg.char({ font: MINISTRY.headFont, pt: t.subPt });
23668
23824
  const pLabel = reg.para({ align: "LEFT", lineSp: 130, left: pad, before: 1200, after: 2400 });
23669
- const pCh = reg.para({ align: "LEFT", lineSp: 130, left: pad, before: 2e3, keepWord: false });
23670
- const pSub = reg.para({ align: "LEFT", lineSp: 130, left: pad + 1400, before: 1200, keepWord: false });
23825
+ const pCh = reg.para({ align: "LEFT", lineSp: 130, left: pad, before: 2e3 });
23826
+ const pSub = reg.para({ align: "LEFT", lineSp: 130, left: pad + 1400, before: 1200 });
23671
23827
  const paras = [para("\uBAA9 \uCC28", pLabel, cLabel)];
23672
23828
  let h = 1200 + Math.round(t.labelPt * 130) + 2400;
23673
23829
  let roman = 0;
@@ -23747,10 +23903,10 @@ function buildMinistryItemBand(n, text, ctx, before) {
23747
23903
  const w = ctx.W;
23748
23904
  const band = bf.get({ t: s.line, b: s.line, l: NONE, r: NONE, fill: s.fill });
23749
23905
  const base = { font: MINISTRY.bandFont, pt: s.pt, bold: false };
23750
- const f = fitOrphanLine(plain(text), MINISTRY.bandFont, s.pt, w - 1800, w - 1800);
23751
- const styled = f ? { ...base, ratio: f.ratio, spacing: f.spacing } : base;
23906
+ const f = fitOneLine(plain(text), MINISTRY.bandFont, s.pt, w - 1800, s.pt);
23907
+ const styled = f.overflow || f.ratio === 100 && f.spacing === 0 ? base : { ...base, ratio: f.ratio, spacing: f.spacing };
23752
23908
  const runs = ministryRuns(circledNumber(n - 1), text, ctx, styled, MINISTRY.blue, MINISTRY.blue);
23753
- const p = reg.para({ align: "LEFT", lineSp: 130, left: 300, keepWord: false });
23909
+ const p = reg.para({ align: "LEFT", lineSp: 130, left: 300 });
23754
23910
  const cell2 = tc({ bf: band, row: 0, col: 0, w, h: s.h, paras: `<hp:p paraPrIDRef="${p}" styleIDRef="0">${runs}</hp:p>`, name: "__kordoc_h5" });
23755
23911
  return host(ftbl([cell2], w, s.h, 1, { bottomGap: 700 }), reg.para({ align: "LEFT", lineSp: 100, before, keepWithNext: true }), reg.char(base));
23756
23912
  }
@@ -23759,20 +23915,21 @@ function buildMinistrySummaryBox(text, ctx) {
23759
23915
  const s = MINISTRY.summary;
23760
23916
  const w = ctx.W - 600;
23761
23917
  const avail = w - 280 - 600;
23762
- const pItem = reg.para({ align: "LEFT", lineSp: 140, left: 300, right: 300, indent: -Math.round(s.pt * 100 * 0.9), keepWord: false });
23763
- const pRef = reg.para({ align: "LEFT", lineSp: 130, left: 300 + Math.round(s.pt * 100 * 0.9), right: 300, keepWord: false });
23918
+ const lay = markerLayout(MINISTRY.bodyFont, s.pt, 0, "\u25AA");
23919
+ const pItem = reg.para({ align: "LEFT", lineSp: 140, left: 300, right: 300, indent: -lay.hang, autoTab: true });
23920
+ const pRef = reg.para({ align: "LEFT", lineSp: 130, left: 300 + lay.hang, right: 300 });
23764
23921
  const baseItem = { font: MINISTRY.bodyFont, pt: s.pt, bold: false };
23765
23922
  const cRef = reg.char({ font: MINISTRY.refFont, pt: s.refPt });
23766
23923
  let h = 0;
23767
23924
  const paras = text.split("\n").map((raw) => raw.trim()).filter(Boolean).map((line) => {
23768
23925
  const isRef = /^(\*|※)/.test(line);
23769
23926
  if (isRef) {
23770
- h += Math.round(s.refPt * 100 * 1.3) * simulateWrap(line, avail, avail, s.refPt * 100, 100, "charAll", { faceClass: "gothic" }).lines;
23927
+ h += Math.round(s.refPt * 100 * 1.3) * simulateWrap(line, avail - lay.hang, avail - lay.hang, s.refPt * 100, 100, "keep", { faceClass: faceClassForGen(MINISTRY.refFont) }).lines;
23771
23928
  return `<hp:p paraPrIDRef="${pRef}" styleIDRef="0">${generateRuns(line, cRef, inlineMapper(reg, { font: MINISTRY.refFont, pt: s.refPt, bold: false }))}</hp:p>`;
23772
23929
  }
23773
23930
  const body = line.replace(/^[▪■□○ㅇ●\-–ㆍ·•]\s*/u, "");
23774
- h += Math.round(s.pt * 100 * 1.4) * simulateWrap(plain(body), avail, avail, s.pt * 100, 100, "charAll").lines;
23775
- return `<hp:p paraPrIDRef="${pItem}" styleIDRef="0">${ministryRuns("\u25AA", body, ctx, baseItem, MINISTRY.blue)}</hp:p>`;
23931
+ h += Math.round(s.pt * 100 * 1.4) * simulateWrap(plain(body), avail - lay.hang, avail - lay.hang, s.pt * 100, 100, "keep", { faceClass: faceClassForGen(MINISTRY.bodyFont) }).lines;
23932
+ return `<hp:p paraPrIDRef="${pItem}" styleIDRef="0">${markerRunXml("\u25AA", reg.char(baseItem), lay)}${ministryRuns("", body, ctx, baseItem, MINISTRY.blue)}</hp:p>`;
23776
23933
  });
23777
23934
  h += 280 + 600;
23778
23935
  const box = bf.get({ t: "thin", b: "thin", l: "thin", r: "thin", fill: s.fill });
@@ -23824,7 +23981,8 @@ function buildGongmunSectionV5(blocks, gongmun, deps, theme) {
23824
23981
  const pre = buildOutline(blocks, isMinistry ? { gaejosik: true, consumeTitle: true, summaryFromQuote: true, quoteBox: true, headingFrames: true, keepMarkers: true } : { gaejosik: true, consumeTitle: true, summaryFromQuote: isReport });
23825
23982
  const scheme = pickScheme(g, pre.hasBoxMarkers);
23826
23983
  const gaejosik = scheme.kind === "gaejosik";
23827
- const outline = gaejosik ? pre : buildOutline(blocks, { gaejosik: false, consumeTitle: true, summaryFromQuote: false });
23984
+ const raw = gaejosik ? pre : buildOutline(blocks, { gaejosik: false, consumeTitle: true, summaryFromQuote: false });
23985
+ const outline = { ...raw, title: raw.title && polishGongmunText(raw.title), nodes: raw.nodes.map(polishNode) };
23828
23986
  const frame = { reg, bf: bfReg, frame: scheme.frame, W };
23829
23987
  const lineHu = (st) => Math.round(st.pt * 100 * ((st.lineSp ?? scheme.lineSp) / 100));
23830
23988
  const paras = [];
@@ -23848,15 +24006,16 @@ function buildGongmunSectionV5(blocks, gongmun, deps, theme) {
23848
24006
  let frontKind = "start";
23849
24007
  const pushSummary = (t) => {
23850
24008
  frontKind = "summary";
23851
- const box = buildSummaryBox(t, frame);
24009
+ const box = buildSummaryBox(polishGongmunText(t), frame);
23852
24010
  if (box.lines > 3) warnings.push(`\uC694\uC57D\uBC15\uC2A4\uAC00 ${box.lines}\uC904\uC785\uB2C8\uB2E4 \u2014 \uBCF4\uACE0 \uBAA9\uC801\uC744 \uD55C \uBB38\uC7A5(\uC27C\uD45C \uD5C8\uC6A9) 3\uC904 \uC774\uB0B4 "\u2026\uD558\uACE0\uC790 \uD568"\uC73C\uB85C \uC904\uC774\uC138\uC694`);
23853
24011
  paras.push(box.xml);
23854
24012
  };
23855
- const docTitle = g.docHead?.title ?? outline.title ?? "";
24013
+ const docTitle = polishGongmunText(g.docHead?.title ?? outline.title ?? "");
24014
+ const reportInfo = g.reportInfo && polishGongmunText(g.reportInfo);
23856
24015
  if (preset === "official") {
23857
24016
  if (g.docHead) paras.push(buildDocHeadTable({ ...g.docHead, title: docTitle }, frame));
23858
24017
  else if (outline.title) paras.push(generateParagraph(outline.title, reg.para({ align: "CENTER", lineSp: scheme.lineSp, after: lineHu(scheme.body) }), reg.char({ font: scheme.body.font, pt: scheme.body.pt + 2, bold: true }), void 0, 1));
23859
- if (g.reportInfo) paras.push(generateParagraph(g.reportInfo, reg.para({ align: "RIGHT", lineSp: scheme.lineSp }), reg.char({ font: scheme.body.font, pt: 12 })));
24018
+ if (reportInfo) paras.push(generateParagraph(reportInfo, reg.para({ align: "RIGHT", lineSp: scheme.lineSp }), reg.char({ font: scheme.body.font, pt: 12 })));
23860
24019
  if (g.approval) paras.push(buildApprovalSeoul(g.approval, null, frame));
23861
24020
  } else if (isMinistry) {
23862
24021
  if (g.cover) {
@@ -23895,7 +24054,7 @@ function buildGongmunSectionV5(blocks, gongmun, deps, theme) {
23895
24054
  paras.push(buildApprovalSeoul(g.approval, null, frame));
23896
24055
  }
23897
24056
  if (docTitle) {
23898
- const t = buildReportTitleTable(docTitle, g.reportInfo, frame);
24057
+ const t = buildReportTitleTable(docTitle, reportInfo, frame);
23899
24058
  if (t.overflow) warnings.push(`\uC81C\uBAA9\uC774 \uAE38\uC5B4 \uD55C \uC904\uC5D0 \uB2F4\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4(20pt\xB7\uC7A5\uD3C9 85%\uAE4C\uC9C0 \uCD95\uC18C) \u2014 \uC81C\uBAA9\uC744 \uC904\uC774\uC138\uC694: "${docTitle.slice(0, 30)}\u2026"`);
23900
24059
  if (pendingPageBreak) {
23901
24060
  paras.push(t.xml.replace(/^<hp:p /, `<hp:p pageBreak="1" `).replace(/<hp:run charPrIDRef="(\d+)">/, `<hp:run charPrIDRef="$1">${newPageNumCtrl(1)}`));
@@ -23903,7 +24062,7 @@ function buildGongmunSectionV5(blocks, gongmun, deps, theme) {
23903
24062
  } else paras.push(t.xml);
23904
24063
  frontKind = "title";
23905
24064
  }
23906
- if (!docTitle && g.reportInfo) paras.push(generateParagraph(g.reportInfo, reg.para({ align: "RIGHT", lineSp: scheme.lineSp }), reg.char({ font: scheme.body.font, pt: 12 })));
24065
+ if (!docTitle && reportInfo) paras.push(generateParagraph(reportInfo, reg.para({ align: "RIGHT", lineSp: scheme.lineSp }), reg.char({ font: scheme.body.font, pt: 12 })));
23907
24066
  if (g.summary) pushSummary(g.summary);
23908
24067
  else if (!outline.nodes.some((n) => n.kind === "summary")) warnings.push('\uBCF4\uACE0\uC11C \uC694\uC57D\uBC15\uC2A4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 \uC81C\uBAA9 \uC9C1\uD6C4 \uC778\uC6A9\uBB38(>)\uC5D0 \uBCF4\uACE0 \uBAA9\uC801\uC744 \uD55C \uBB38\uC7A5(\uC27C\uD45C \uD5C8\uC6A9) 3\uC904 \uC774\uB0B4 "\u2026\uD558\uACE0\uC790 \uD568"\uC73C\uB85C \uB123\uAC70\uB098 summary \uC635\uC158\uC744 \uC9C0\uC815\uD558\uC138\uC694');
23909
24068
  } else {
@@ -23942,51 +24101,55 @@ function buildGongmunSectionV5(blocks, gongmun, deps, theme) {
23942
24101
  marker = numberer.next(depth, sup);
23943
24102
  itemSeq++;
23944
24103
  }
23945
- const text = marker ? `${marker} ${node.text}` : node.text;
23946
- const geom = levelGeometry(st, marker);
23947
- const availFirst = W - geom.left;
23948
- const availCont = W - geom.left + geom.indent;
23949
- let pt = st.pt, ratio = 100, spacing = 0;
24104
+ const mk = isMinistry && node.marker ? node.marker : marker;
24105
+ const lay = markerLayout(st.font, st.pt, st.leadTa, mk);
24106
+ const textW2 = W - lay.left - lay.hang;
24107
+ let ratio = 100, spacing = 0, charBreaks = false;
23950
24108
  if (st.oneLine) {
23951
- const fit = fitOneLine(plain2(text), st.font, st.pt, availFirst, st.pt, 90);
24109
+ const fit = fitOneLine(plain2(node.text), st.font, st.pt, textW2, st.pt, 90);
23952
24110
  if (fit.overflow) warnings.push(`\u25A1 \uD56D\uBAA9\uC774 \uD55C \uC904\uC5D0 \uB2F4\uAE30\uC9C0 \uC54A\uC544 \uB450 \uC904\uB85C \uAEBE\uC785\uB2C8\uB2E4 \u2014 \uBB38\uC7A5\uC744 \uC904\uC774\uC138\uC694(\uC7A5\uD3C9 90%\xB7\uC790\uAC04 -5 \uB85C\uB3C4 \uCD08\uACFC): "${node.text.slice(0, 30)}\u2026"`);
23953
24111
  else {
23954
24112
  ratio = fit.ratio;
23955
24113
  spacing = fit.spacing;
23956
24114
  }
23957
- } else if (g.autoFitMinRatio !== null) {
23958
- const f = fitOrphanLine(plain2(text), st.font, st.pt, availFirst, availCont);
24115
+ } else {
24116
+ const t = plain2(node.text);
24117
+ const cb = fitCharBreaks(t, st.font, st.pt, textW2, textW2, g.autoFitMinRatio ?? 101);
24118
+ const f = cb ?? (g.autoFitMinRatio !== null ? fitParagraph(t, st.font, st.pt, textW2, textW2, g.autoFitMinRatio) : null);
23959
24119
  if (f) {
23960
24120
  ratio = f.ratio;
23961
24121
  spacing = f.spacing;
23962
24122
  }
24123
+ charBreaks = !!cb;
23963
24124
  }
23964
- const base = { font: st.font, pt, bold: st.bold, ratio, spacing };
23965
- const geom2 = pt !== st.pt ? levelGeometry({ ...st, pt }, marker) : geom;
24125
+ const base = { font: st.font, pt: st.pt, bold: st.bold, ratio, spacing };
23966
24126
  const consecutiveBox = prevKind === "item" && prevItemDepth === 0 && depth === 0;
23967
24127
  const afterBand = depth === 0 && (prevKind === "chapter" && chapterStyle === "band" || prevKind === "title" && !!st.blankBefore);
23968
24128
  const before = afterBand ? BOX_GAP_AFTER_BAND : st.blankBefore && !consecutiveBox && prevKind !== "chapter" && prevKind !== "start" && prevKind !== "summary" ? BOX_BLANK_HU : 0;
23969
24129
  const keepNext = !!st.keepWithNext && !!nextNode && (nextNode.kind === "item" && nextNode.depth > depth || nextNode.kind === "ref");
24130
+ const paraSpec = { align: "JUSTIFY", left: lay.left, indent: -lay.hang, before, lineSp: st.lineSp ?? scheme.lineSp, keepWithNext: keepNext, keepWord: !charBreaks, autoTab: lay.hang > 0, widowOrphan: true };
24131
+ const markerRun = mk ? markerRunXml(mk, reg.char({ font: st.font, pt: st.pt, bold: st.bold }), lay) : "";
23970
24132
  if (isMinistry) {
23971
- const mk = node.marker ?? marker;
23972
- const g2 = node.marker ? levelGeometry(st, mk) : geom2;
23973
- const paraId2 = reg.para({ align: "JUSTIFY", left: g2.left, indent: g2.indent, before, after: 600, lineSp: st.lineSp ?? scheme.lineSp, keepWithNext: keepNext, keepWord: false });
23974
- const runs = ministryRuns(mk, node.text, frame, base, depth === 0 ? MINISTRY.blue : null);
24133
+ const paraId2 = reg.para({ ...paraSpec, after: 600 });
24134
+ const runs = markerRun + ministryRuns("", node.text, frame, base, depth === 0 ? MINISTRY.blue : null);
23975
24135
  return `<hp:p paraPrIDRef="${paraId2}" styleIDRef="${styleId}">${runs}</hp:p>`;
23976
24136
  }
23977
- const paraId = reg.para({ align: "JUSTIFY", left: geom2.left, indent: geom2.indent, before, lineSp: st.lineSp ?? scheme.lineSp, keepWithNext: keepNext, keepWord: false });
23978
- return generateParagraph(text, paraId, reg.char(base), inlineMapper(reg, base), styleId);
24137
+ const paraId = reg.para(paraSpec);
24138
+ return `<hp:p paraPrIDRef="${paraId}" styleIDRef="${styleId}">${markerRun}${generateRuns(node.text, reg.char(base), inlineMapper(reg, base))}</hp:p>`;
23979
24139
  };
23980
24140
  const renderRef = (node) => {
23981
24141
  const st = scheme.ref;
23982
24142
  const marker = isMinistry ? "*" : "\u203B";
24143
+ const lay = markerLayout(st.font, st.pt, 0, marker);
23983
24144
  const left = isMinistry ? st.leadTa * taHu(st.pt) : leadLeft(node.depth, st.pt);
23984
- const geom = levelGeometry({ ...st, leadTa: 0 }, marker);
23985
- const base = { font: st.font, pt: st.pt, bold: st.bold };
23986
- const f = fitOrphanLine(plain2(`${marker} ${node.text}`), st.font, st.pt, W - left, W - left + geom.indent);
23987
- const baseF = f ? { ...base, ratio: f.ratio, spacing: f.spacing } : base;
23988
- const paraId = reg.para({ align: "JUSTIFY", left, indent: geom.indent, after: isMinistry ? 400 : 0, lineSp: isMinistry ? 130 : st.lineSp ?? scheme.lineSp, keepWord: false });
23989
- return generateParagraph(`${marker} ${node.text}`, paraId, reg.char(baseF), inlineMapper(reg, baseF));
24145
+ const textW2 = W - left - lay.hang;
24146
+ const t = plain2(node.text);
24147
+ const cb = fitCharBreaks(t, st.font, st.pt, textW2, textW2, g.autoFitMinRatio ?? 101);
24148
+ const f = cb ?? (g.autoFitMinRatio !== null ? fitParagraph(t, st.font, st.pt, textW2, textW2, g.autoFitMinRatio) : null);
24149
+ const base = { font: st.font, pt: st.pt, bold: st.bold, ratio: f?.ratio ?? 100, spacing: f?.spacing ?? 0 };
24150
+ const paraId = reg.para({ align: "JUSTIFY", left, indent: -lay.hang, after: isMinistry ? 400 : 0, lineSp: isMinistry ? 130 : st.lineSp ?? scheme.lineSp, keepWord: !cb, autoTab: true, widowOrphan: true });
24151
+ const markerRun = markerRunXml(marker, reg.char({ font: st.font, pt: st.pt, bold: st.bold }), lay);
24152
+ return `<hp:p paraPrIDRef="${paraId}" styleIDRef="0">${markerRun}${generateRuns(node.text, reg.char(base), inlineMapper(reg, base))}</hp:p>`;
23990
24153
  };
23991
24154
  const renderPara = (node) => {
23992
24155
  const st = scheme.body;
@@ -24000,16 +24163,19 @@ function buildGongmunSectionV5(blocks, gongmun, deps, theme) {
24000
24163
  if (pics.every(Boolean)) return `<hp:p paraPrIDRef="${reg.para({ align: "CENTER", lineSp: scheme.lineSp })}" styleIDRef="0"><hp:run charPrIDRef="${reg.char({ font: st.font, pt: st.pt })}">${pics.join("")}</hp:run></hp:p>`;
24001
24164
  }
24002
24165
  }
24003
- let ratio = 100, spacing = 0;
24004
- if (!node.align && g.autoFitMinRatio !== null) {
24005
- const f = fitOrphanLine(plain2(node.text), st.font, st.pt, W, W);
24166
+ let ratio = 100, spacing = 0, charBreaks = false;
24167
+ if (!node.align) {
24168
+ const t = plain2(node.text);
24169
+ const cb = fitCharBreaks(t, st.font, st.pt, W, W, g.autoFitMinRatio ?? 101);
24170
+ const f = cb ?? (g.autoFitMinRatio !== null ? fitParagraph(t, st.font, st.pt, W, W, g.autoFitMinRatio) : null);
24006
24171
  if (f) {
24007
24172
  ratio = f.ratio;
24008
24173
  spacing = f.spacing;
24009
24174
  }
24175
+ charBreaks = !!cb;
24010
24176
  }
24011
24177
  const base = { font: st.font, pt: st.pt, bold: st.bold, ratio, spacing };
24012
- const paraId = reg.para({ align: node.align ?? "JUSTIFY", lineSp: scheme.lineSp, keepWord: false });
24178
+ const paraId = reg.para({ align: node.align ?? "JUSTIFY", lineSp: scheme.lineSp, keepWord: !charBreaks, widowOrphan: true });
24013
24179
  return generateParagraph(node.text, paraId, reg.char(base), inlineMapper(reg, base));
24014
24180
  };
24015
24181
  const renderChapter = (node) => {
@@ -24037,7 +24203,7 @@ function buildGongmunSectionV5(blocks, gongmun, deps, theme) {
24037
24203
  const fit = fitOneLine(plain2(text), st.font, st.pt, W, st.pt - 2);
24038
24204
  const base = { font: st.font, pt: fit.pt, bold: st.bold, ratio: fit.ratio, spacing: fit.spacing };
24039
24205
  const before = prevKind === "start" || prevKind === "title" || prevKind === "summary" ? 0 : lineHu(scheme.body);
24040
- const paraId = reg.para({ align: "LEFT", before, after: Math.round(lineHu(scheme.body) * 0.3), lineSp: st.lineSp ?? scheme.lineSp, keepWithNext: true, keepWord: false });
24206
+ const paraId = reg.para({ align: "LEFT", before, after: Math.round(lineHu(scheme.body) * 0.3), lineSp: st.lineSp ?? scheme.lineSp, keepWithNext: true });
24041
24207
  return generateParagraph(text, paraId, reg.char(base), inlineMapper(reg, base), 2);
24042
24208
  };
24043
24209
  const renderAttach = (node, first) => {
@@ -24045,7 +24211,7 @@ function buildGongmunSectionV5(blocks, gongmun, deps, theme) {
24045
24211
  let text = node.text;
24046
24212
  if (/^\s*붙\s*임/.test(text)) text = text.replace(/^\s*붙\s*임\s*[::]?\s*/, "\uBD99\uC784 ");
24047
24213
  else text = text.replace(/\s+$/, "");
24048
- const paraId = reg.para({ align: "LEFT", before: first ? lineHu(scheme.body) : 0, lineSp: st.lineSp ?? scheme.lineSp, keepWord: false });
24214
+ const paraId = reg.para({ align: "LEFT", before: first ? lineHu(scheme.body) : 0, lineSp: st.lineSp ?? scheme.lineSp });
24049
24215
  const base = { font: st.font, pt: st.pt, bold: st.bold };
24050
24216
  return generateParagraph(text, paraId, reg.char(base), inlineMapper(reg, base));
24051
24217
  };
@@ -24215,6 +24381,13 @@ function buildGongmunSectionV5(blocks, gongmun, deps, theme) {
24215
24381
  scheme
24216
24382
  };
24217
24383
  }
24384
+ function polishNode(n) {
24385
+ if (n.kind === "block") {
24386
+ const b = n.block;
24387
+ return b.type === "table" && b.rows ? { ...n, block: { ...b, rows: b.rows.map((r) => r.map(polishGongmunText)) } } : n;
24388
+ }
24389
+ return { ...n, text: polishGongmunText(n.text) };
24390
+ }
24218
24391
  function legalDepthOf(marker) {
24219
24392
  if (/^\d{1,2}\.$/.test(marker)) return 0;
24220
24393
  if (/^[가-힣]\.$/.test(marker)) return 1;
@@ -24271,7 +24444,7 @@ async function markdownToHwpx(markdown, options) {
24271
24444
  }
24272
24445
  const measured = !!gongmun && usesReportFonts(gongmun.preset);
24273
24446
  const richAssets = !!gongmun && needsGaejosikAssets(gongmun);
24274
- const blocks = parseMarkdownToBlocks(md);
24447
+ const blocks = gongmun ? parseMarkdownToBlocks(md).map(polishGongmunBlock) : parseMarkdownToBlocks(md);
24275
24448
  const gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null;
24276
24449
  const fit = gongmun && gongmunList ? computeGongmunFitPlan(blocks, gongmun, gongmunList) : null;
24277
24450
  const staticBfEnd = staticBorderFillNext(gongmun);
@@ -26353,7 +26526,8 @@ function patchParagraphUnit(block, orig, edited, ctx, skip) {
26353
26526
  if (sanitizeText(newPlain) !== newPlain) {
26354
26527
  return skip("\uACF5\uBC31 \uC815\uADDC\uD654 \uBD88\uC548\uC815 \uD14D\uC2A4\uD2B8 \u2014 \uD328\uCE58 \uC2DC \uC6D0\uBB38 \uBCF4\uC874 \uBD88\uAC00\uB85C \uBBF8\uC9C0\uC6D0");
26355
26528
  }
26356
- const splices = buildParagraphSplices(mapping.para, newPlain, ctx.scans[mapping.para.sectionIndex]?.xml);
26529
+ const xml = ctx.scans[mapping.para.sectionIndex]?.xml;
26530
+ const splices = (xml ? markerRunSplices(mapping.para, xml, newPlain) : null) ?? buildParagraphSplices(mapping.para, newPlain, xml);
26357
26531
  if (splices === null) return skip("\uBB38\uB2E8\uC5D0 \uD14D\uC2A4\uD2B8 \uB178\uB4DC\uB97C \uB9CC\uB4E4 \uC218 \uC5C6\uC74C");
26358
26532
  ctx.sectionSplices[mapping.para.sectionIndex].push(...splices);
26359
26533
  return 1;
@@ -28041,6 +28215,9 @@ async function dispatch(format, buffer, opts) {
28041
28215
  const zipFormat = await detectZipFormat(buffer);
28042
28216
  if (zipFormat === "xlsx") return parseXlsx(buffer, opts);
28043
28217
  if (zipFormat === "docx") return parseDocx(buffer, opts);
28218
+ if (zipFormat === "pptx") {
28219
+ return { success: false, fileType: "pptx", error: "PPTX \uD30C\uC77C\uC740 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD30C\uC77C \uD615\uC2DD\uC785\uB2C8\uB2E4.", code: "UNSUPPORTED_FORMAT" };
28220
+ }
28044
28221
  return parseHwpx(buffer, opts);
28045
28222
  }
28046
28223
  case "hwp": {
@@ -28062,7 +28239,7 @@ async function dispatch(format, buffer, opts) {
28062
28239
  }
28063
28240
  async function parseImage(buffer, options) {
28064
28241
  try {
28065
- const { parseImageDocument } = await import("./image-ocr-N6IBZJAK.js");
28242
+ const { parseImageDocument } = await import("./image-ocr-WCAYXLOA.js");
28066
28243
  const { blocks, warnings } = await parseImageDocument(buffer, options);
28067
28244
  return {
28068
28245
  success: true,
@@ -28121,7 +28298,7 @@ async function parseHwp(buffer, options) {
28121
28298
  async function parsePdf(buffer, options) {
28122
28299
  let parsePdfDocument;
28123
28300
  try {
28124
- const mod = await import("./parser-BK66Y5JD.js");
28301
+ const mod = await import("./parser-SCUTZAIJ.js");
28125
28302
  parsePdfDocument = mod.parsePdfDocument;
28126
28303
  } catch {
28127
28304
  return {
@@ -28331,4 +28508,4 @@ export {
28331
28508
  parseHwpml,
28332
28509
  fillForm
28333
28510
  };
28334
- //# sourceMappingURL=chunk-EMQZX5QQ.js.map
28511
+ //# sourceMappingURL=chunk-EISO3POT.js.map