kordoc 3.18.0 → 4.0.0

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 (78) hide show
  1. package/README.md +768 -752
  2. package/dist/{-OUCPI6B3.js → -URVKBXYK.js} +12 -8
  3. package/dist/{chunk-MEPHGCPQ.js → chunk-5CJGKKMZ.js} +1 -1
  4. package/dist/chunk-5CJGKKMZ.js.map +1 -0
  5. package/dist/{chunk-YWIYGXLI.js → chunk-7ETIIYGI.js} +2 -2
  6. package/dist/chunk-7ETIIYGI.js.map +1 -0
  7. package/dist/chunk-DCZVOIEO.cjs.map +1 -1
  8. package/dist/{chunk-4YEZTZAR.js → chunk-DVUNWK6W.js} +8 -2
  9. package/dist/chunk-DVUNWK6W.js.map +1 -0
  10. package/dist/{chunk-5HDBLRVP.cjs → chunk-EBSCV3JC.cjs} +2 -2
  11. package/dist/chunk-EBSCV3JC.cjs.map +1 -0
  12. package/dist/chunk-GS7T56RP.cjs.map +1 -1
  13. package/dist/{chunk-GIXXV52X.js → chunk-IA5UZZKV.js} +2 -2
  14. package/dist/chunk-IA5UZZKV.js.map +1 -0
  15. package/dist/{chunk-ZTUQYITH.js → chunk-JUJEKFUF.js} +6 -4
  16. package/dist/chunk-JUJEKFUF.js.map +1 -0
  17. package/dist/chunk-MOL7MDBG.js +0 -0
  18. package/dist/{chunk-PWHM3KAA.js → chunk-PGWAF755.js} +1613 -673
  19. package/dist/chunk-PGWAF755.js.map +1 -0
  20. package/dist/{chunk-VP34RO24.js → chunk-THZVBYHE.js} +3 -3
  21. package/dist/chunk-THZVBYHE.js.map +1 -0
  22. package/dist/{chunk-6Y4KKPC3.js → chunk-ZKG6SBHV.js} +2 -2
  23. package/dist/chunk-ZKG6SBHV.js.map +1 -0
  24. package/dist/cli.js +42 -18
  25. package/dist/cli.js.map +1 -1
  26. package/dist/{detect-RI2MQ33K.js → detect-PJZMUL2Z.js} +2 -2
  27. package/dist/formula-5NKVS2LR.cjs.map +1 -1
  28. package/dist/formula-JCNF43NE.js +0 -0
  29. package/dist/index.cjs +1999 -1052
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.cts +82 -9
  32. package/dist/index.d.ts +82 -9
  33. package/dist/index.js +1772 -825
  34. package/dist/index.js.map +1 -1
  35. package/dist/mcp.js +57 -29
  36. package/dist/mcp.js.map +1 -1
  37. package/dist/page-range-737B4EZW.js +0 -0
  38. package/dist/page-range-P7SDW6LR.cjs.map +1 -1
  39. package/dist/{parser-S34YR2SH.cjs → parser-6TV6JKHF.cjs} +15 -15
  40. package/dist/parser-6TV6JKHF.cjs.map +1 -0
  41. package/dist/{parser-NZAE7PBE.js → parser-LHUO6UUA.js} +4 -4
  42. package/dist/parser-LHUO6UUA.js.map +1 -0
  43. package/dist/{parser-5D6BQYTX.js → parser-NXHY37WH.js} +3 -3
  44. package/dist/parser-NXHY37WH.js.map +1 -0
  45. package/dist/{provider-G4C2V2PD.cjs → provider-5K7O3Z2O.cjs} +1 -1
  46. package/dist/provider-5K7O3Z2O.cjs.map +1 -0
  47. package/dist/{provider-AKROB7WQ.js → provider-7H4CPZYS.js} +1 -1
  48. package/dist/provider-7H4CPZYS.js.map +1 -0
  49. package/dist/{provider-4ZJKV3DC.js → provider-H4WWSPOV.js} +1 -1
  50. package/dist/provider-H4WWSPOV.js.map +1 -0
  51. package/dist/render-T5O6QHBJ.js +10 -0
  52. package/dist/seal-7KNR5WFH.js +10 -0
  53. package/dist/setup-57FB3LSP.js +0 -0
  54. package/dist/{watch-2EFXBRYK.js → watch-PNXTAWDR.js} +8 -8
  55. package/dist/watch-PNXTAWDR.js.map +1 -0
  56. package/package.json +1 -1
  57. package/dist/chunk-4YEZTZAR.js.map +0 -1
  58. package/dist/chunk-5HDBLRVP.cjs.map +0 -1
  59. package/dist/chunk-6Y4KKPC3.js.map +0 -1
  60. package/dist/chunk-GIXXV52X.js.map +0 -1
  61. package/dist/chunk-MEPHGCPQ.js.map +0 -1
  62. package/dist/chunk-PWHM3KAA.js.map +0 -1
  63. package/dist/chunk-VP34RO24.js.map +0 -1
  64. package/dist/chunk-YWIYGXLI.js.map +0 -1
  65. package/dist/chunk-ZTUQYITH.js.map +0 -1
  66. package/dist/parser-5D6BQYTX.js.map +0 -1
  67. package/dist/parser-NZAE7PBE.js.map +0 -1
  68. package/dist/parser-S34YR2SH.cjs.map +0 -1
  69. package/dist/provider-4ZJKV3DC.js.map +0 -1
  70. package/dist/provider-AKROB7WQ.js.map +0 -1
  71. package/dist/provider-G4C2V2PD.cjs.map +0 -1
  72. package/dist/render-HRAW7ASR.js +0 -10
  73. package/dist/seal-CK64CXWO.js +0 -10
  74. package/dist/watch-2EFXBRYK.js.map +0 -1
  75. /package/dist/{-OUCPI6B3.js.map → -URVKBXYK.js.map} +0 -0
  76. /package/dist/{detect-RI2MQ33K.js.map → detect-PJZMUL2Z.js.map} +0 -0
  77. /package/dist/{render-HRAW7ASR.js.map → render-T5O6QHBJ.js.map} +0 -0
  78. /package/dist/{seal-CK64CXWO.js.map → seal-7KNR5WFH.js.map} +0 -0
@@ -11,13 +11,13 @@ import {
11
11
  dedupeRunningHeaders,
12
12
  flattenLayoutTables,
13
13
  mapPuaText
14
- } from "./chunk-YWIYGXLI.js";
14
+ } from "./chunk-7ETIIYGI.js";
15
15
  import {
16
16
  detectFormat,
17
17
  detectOle2Format,
18
18
  detectZipFormat,
19
19
  parseLenientCfb
20
- } from "./chunk-MEPHGCPQ.js";
20
+ } from "./chunk-5CJGKKMZ.js";
21
21
  import {
22
22
  parsePageRange
23
23
  } from "./chunk-MOL7MDBG.js";
@@ -32,12 +32,14 @@ import {
32
32
  paraTextPureT,
33
33
  patchZipEntries,
34
34
  scanSectionXml
35
- } from "./chunk-VP34RO24.js";
35
+ } from "./chunk-THZVBYHE.js";
36
36
  import {
37
37
  SPACE_EM_FIXED,
38
38
  charWidthEm1000,
39
- fitRatioForFewerLines
40
- } from "./chunk-ZTUQYITH.js";
39
+ fitRatioForFewerLines,
40
+ measureTextWidth,
41
+ simulateWrap
42
+ } from "./chunk-JUJEKFUF.js";
41
43
  import {
42
44
  MAX_DECOMPRESS_SIZE,
43
45
  MAX_XML_DEPTH,
@@ -48,7 +50,7 @@ import {
48
50
  createXmlParser,
49
51
  extractTextFromNode,
50
52
  findChildByLocalName
51
- } from "./chunk-4YEZTZAR.js";
53
+ } from "./chunk-DVUNWK6W.js";
52
54
  import {
53
55
  KordocError,
54
56
  classifyError,
@@ -59,7 +61,7 @@ import {
59
61
  sanitizeHref,
60
62
  stripDtd,
61
63
  toArrayBuffer
62
- } from "./chunk-6Y4KKPC3.js";
64
+ } from "./chunk-ZKG6SBHV.js";
63
65
 
64
66
  // src/index.ts
65
67
  import { readFile } from "fs/promises";
@@ -153,8 +155,8 @@ function comResultToParseResult(pages, pageCount, warnings) {
153
155
  const text = (pages[i] ?? "").trim();
154
156
  if (!text) continue;
155
157
  const paragraphs = text.split(/\n/);
156
- for (const para of paragraphs) {
157
- const trimmed = para.trim();
158
+ for (const para2 of paragraphs) {
159
+ const trimmed = para2.trim();
158
160
  if (!trimmed) continue;
159
161
  blocks.push({ type: "paragraph", text: trimmed, pageNumber: i + 1 });
160
162
  lines.push(trimmed);
@@ -835,7 +837,7 @@ var HANGUL_SYLLABLE_SEQ = "\uAC00\uB098\uB2E4\uB77C\uB9C8\uBC14\uC0AC\uC544\uC79
835
837
  var HANGUL_JAMO_SEQ = "\u3131\u3134\u3137\u3139\u3141\u3142\u3145\u3147\u3148\u314A\u314B\u314C\u314D\u314E";
836
838
  function toRoman(n) {
837
839
  if (n <= 0 || n >= 4e3) return String(n);
838
- const table = [
840
+ const table2 = [
839
841
  [1e3, "M"],
840
842
  [900, "CM"],
841
843
  [500, "D"],
@@ -851,7 +853,7 @@ function toRoman(n) {
851
853
  [1, "I"]
852
854
  ];
853
855
  let out = "";
854
- for (const [v, s] of table) {
856
+ for (const [v, s] of table2) {
855
857
  while (n >= v) {
856
858
  out += s;
857
859
  n -= v;
@@ -893,10 +895,17 @@ function formatHeadNumber(n, numFormat) {
893
895
  function resolveParaHeading(paraEl, ctx) {
894
896
  const sm = ctx.styleMap;
895
897
  if (!sm) return null;
898
+ const styleId = paraEl.getAttribute("styleIDRef");
899
+ let styleHeading;
900
+ if (styleId && styleId !== "0") {
901
+ const st = sm.styles.get(styleId);
902
+ const m = st && /^개요\s*([1-6])$/.exec(st.name);
903
+ if (m) styleHeading = Math.min(parseInt(m[1], 10), 6);
904
+ }
896
905
  const prId = paraEl.getAttribute("paraPrIDRef");
897
- if (!prId) return null;
906
+ if (!prId) return styleHeading ? { headingLevel: styleHeading } : null;
898
907
  const ref = sm.paraHeadings.get(prId);
899
- if (!ref) return null;
908
+ if (!ref) return styleHeading ? { headingLevel: styleHeading } : null;
900
909
  if (ref.type === "BULLET") {
901
910
  const char = sm.bullets.get(ref.idRef);
902
911
  return char ? { prefix: char } : null;
@@ -926,24 +935,24 @@ function resolveParaHeading(paraEl, ctx) {
926
935
 
927
936
  // src/hwpx/table-build.ts
928
937
  function buildTableWithCellMeta(state) {
929
- const table = buildTable(state.rows);
930
- if (state.caption) table.caption = state.caption;
938
+ const table2 = buildTable(state.rows);
939
+ if (state.caption) table2.caption = state.caption;
931
940
  const anchors = [];
932
941
  {
933
942
  const covered = /* @__PURE__ */ new Set();
934
- for (let r = 0; r < table.rows; r++) {
935
- for (let c = 0; c < table.cols; c++) {
943
+ for (let r = 0; r < table2.rows; r++) {
944
+ for (let c = 0; c < table2.cols; c++) {
936
945
  if (covered.has(`${r},${c}`)) continue;
937
- const cell = table.cells[r]?.[c];
938
- if (!cell) continue;
939
- for (let dr = 0; dr < cell.rowSpan; dr++) {
940
- for (let dc = 0; dc < cell.colSpan; dc++) {
946
+ const cell2 = table2.cells[r]?.[c];
947
+ if (!cell2) continue;
948
+ for (let dr = 0; dr < cell2.rowSpan; dr++) {
949
+ for (let dc = 0; dc < cell2.colSpan; dc++) {
941
950
  if (dr === 0 && dc === 0) continue;
942
- if (r + dr < table.rows && c + dc < table.cols) covered.add(`${r + dr},${c + dc}`);
951
+ if (r + dr < table2.rows && c + dc < table2.cols) covered.add(`${r + dr},${c + dc}`);
943
952
  }
944
953
  }
945
- anchors.push(cell);
946
- c += cell.colSpan - 1;
954
+ anchors.push(cell2);
955
+ c += cell2.colSpan - 1;
947
956
  }
948
957
  }
949
958
  }
@@ -959,11 +968,11 @@ function buildTableWithCellMeta(state) {
959
968
  let target;
960
969
  const trimmed = src.text.trim();
961
970
  if (src.rowAddr !== void 0 && src.colAddr !== void 0) {
962
- const cand = table.cells[src.rowAddr]?.[src.colAddr];
971
+ const cand = table2.cells[src.rowAddr]?.[src.colAddr];
963
972
  if (cand && cand.text === trimmed && !claimed.has(cand)) target = cand;
964
973
  }
965
974
  if (!target) {
966
- outer: for (const irRow of table.cells) {
975
+ outer: for (const irRow of table2.cells) {
967
976
  for (const cand of irRow) {
968
977
  if (!claimed.has(cand) && cand.text === trimmed && cand.colSpan === src.colSpan && cand.rowSpan === src.rowSpan) {
969
978
  target = cand;
@@ -982,7 +991,7 @@ function buildTableWithCellMeta(state) {
982
991
  if (src.isHeader) target.isHeader = true;
983
992
  }
984
993
  }
985
- return table;
994
+ return table2;
986
995
  }
987
996
  function completeTable(newTable, tableStack, blocks, ctx) {
988
997
  const parentTable = tableStack.length > 0 ? tableStack.pop() : null;
@@ -993,12 +1002,12 @@ function completeTable(newTable, tableStack, blocks, ctx) {
993
1002
  const ir = buildTableWithCellMeta(newTable);
994
1003
  const block = { type: "table", table: ir, pageNumber: ctx.sectionNum };
995
1004
  if (parentTable?.cell) {
996
- const cell = parentTable.cell;
997
- (cell.blocks ??= []).push(block);
998
- cell.hasStructure = true;
1005
+ const cell2 = parentTable.cell;
1006
+ (cell2.blocks ??= []).push(block);
1007
+ cell2.hasStructure = true;
999
1008
  let flat = convertTableToText(newTable.rows);
1000
1009
  if (newTable.caption) flat = newTable.caption + (flat ? "\n" + flat : "");
1001
- if (flat) cell.text += (cell.text ? "\n" : "") + flat;
1010
+ if (flat) cell2.text += (cell2.text ? "\n" : "") + flat;
1002
1011
  } else {
1003
1012
  blocks.push(block);
1004
1013
  }
@@ -1114,10 +1123,10 @@ function walkSection(node, blocks, tableCtx, tableStack, ctx, depth = 0) {
1114
1123
  }
1115
1124
  if (text) {
1116
1125
  if (tableCtx?.cell) {
1117
- const cell = tableCtx.cell;
1126
+ const cell2 = tableCtx.cell;
1118
1127
  if (footnote) text += ` (\uC8FC: ${footnote})`;
1119
- cell.text += (cell.text ? "\n" : "") + text;
1120
- (cell.blocks ??= []).push({ type: "paragraph", text, pageNumber: ctx.sectionNum });
1128
+ cell2.text += (cell2.text ? "\n" : "") + text;
1129
+ (cell2.blocks ??= []).push({ type: "paragraph", text, pageNumber: ctx.sectionNum });
1121
1130
  } else if (!tableCtx) {
1122
1131
  const block = { type: headingLevel ? "heading" : "paragraph", text, pageNumber: ctx.sectionNum };
1123
1132
  if (headingLevel) block.level = headingLevel;
@@ -1190,18 +1199,18 @@ function userShapeComment(el) {
1190
1199
  if (/^(?:모서리가 둥근 |둥근 )?[^\n]{1,20}입니다\.?$/.test(text)) return void 0;
1191
1200
  return text;
1192
1201
  }
1193
- function mergeBlocksIntoCell(cell, sink) {
1202
+ function mergeBlocksIntoCell(cell2, sink) {
1194
1203
  for (const b of sink) {
1195
1204
  if ((b.type === "paragraph" || b.type === "heading") && b.text) {
1196
- cell.text += (cell.text ? "\n" : "") + b.text;
1197
- (cell.blocks ??= []).push(b);
1205
+ cell2.text += (cell2.text ? "\n" : "") + b.text;
1206
+ (cell2.blocks ??= []).push(b);
1198
1207
  } else if (b.type === "image" || b.type === "table") {
1199
1208
  if (b.type === "image" && b.text) {
1200
- cell.text += (cell.text ? "\n" : "") + `![image](${b.text})`;
1209
+ cell2.text += (cell2.text ? "\n" : "") + `![image](${b.text})`;
1201
1210
  }
1202
1211
  ;
1203
- (cell.blocks ??= []).push(b);
1204
- cell.hasStructure = true;
1212
+ (cell2.blocks ??= []).push(b);
1213
+ cell2.hasStructure = true;
1205
1214
  }
1206
1215
  }
1207
1216
  }
@@ -1330,7 +1339,7 @@ function extractHyperlinkHref(fieldBegin) {
1330
1339
  function isInDeletedRange(ctx) {
1331
1340
  return (ctx?.shared.track.deleteDepth ?? 0) > 0;
1332
1341
  }
1333
- function extractParagraphInfo(para, styleMap, ctx) {
1342
+ function extractParagraphInfo(para2, styleMap, ctx) {
1334
1343
  let text = "";
1335
1344
  let href;
1336
1345
  let footnote;
@@ -1540,7 +1549,7 @@ function extractParagraphInfo(para, styleMap, ctx) {
1540
1549
  }
1541
1550
  }
1542
1551
  };
1543
- walk(para);
1552
+ walk(para2);
1544
1553
  const leaderIdx = text.indexOf("");
1545
1554
  if (leaderIdx >= 0) text = text.substring(0, leaderIdx);
1546
1555
  let cleanText = text.replace(/[ \t]+/g, " ").trim();
@@ -1605,8 +1614,8 @@ function collectImageBlocks(blocks, out, ownerCell, depth = 0) {
1605
1614
  out.push({ block, ownerCell });
1606
1615
  } else if (block.type === "table" && block.table) {
1607
1616
  for (const row of block.table.cells) {
1608
- for (const cell of row) {
1609
- if (cell.blocks?.length) collectImageBlocks(cell.blocks, out, cell, depth + 1);
1617
+ for (const cell2 of row) {
1618
+ if (cell2.blocks?.length) collectImageBlocks(cell2.blocks, out, cell2, depth + 1);
1610
1619
  }
1611
1620
  }
1612
1621
  }
@@ -2267,8 +2276,8 @@ var GANADA = "\uAC00\uB098\uB2E4\uB77C\uB9C8\uBC14\uC0AC\uC544\uC790\uCC28\uCE74
2267
2276
  var CIRCLED_GANADA = "\u326E\u326F\u3270\u3271\u3272\u3273\u3274\u3275\u3276\u3277\u3278\u3279\u327A\u327B";
2268
2277
  var JAMO = "\u3131\u3134\u3137\u3139\u3141\u3142\u3145\u3147\u3148\u314A\u314B\u314C\u314D\u314E";
2269
2278
  var CIRCLED_JAMO = "\u3260\u3261\u3262\u3263\u3264\u3265\u3266\u3267\u3268\u3269\u326A\u326B\u326C\u326D";
2270
- function fromTable(n, table) {
2271
- return n >= 1 && n <= table.length ? table[n - 1] : String(n);
2279
+ function fromTable(n, table2) {
2280
+ return n >= 1 && n <= table2.length ? table2[n - 1] : String(n);
2272
2281
  }
2273
2282
  function formatRoman(n, upper) {
2274
2283
  if (n <= 0 || n > 3999) return String(n);
@@ -2391,8 +2400,8 @@ function collectImageBlocks2(blocks, out) {
2391
2400
  if (b.type === "image") out.push(b);
2392
2401
  if (b.table) {
2393
2402
  for (const row of b.table.cells) {
2394
- for (const cell of row) {
2395
- if (cell.blocks) collectImageBlocks2(cell.blocks, out);
2403
+ for (const cell2 of row) {
2404
+ if (cell2.blocks) collectImageBlocks2(cell2.blocks, out);
2396
2405
  }
2397
2406
  }
2398
2407
  }
@@ -2403,9 +2412,9 @@ function forEachTableCell(blocks, fn) {
2403
2412
  for (const b of blocks) {
2404
2413
  if (b.table) {
2405
2414
  for (const row of b.table.cells) {
2406
- for (const cell of row) {
2407
- fn(cell);
2408
- if (cell.blocks) forEachTableCell(cell.blocks, fn);
2415
+ for (const cell2 of row) {
2416
+ fn(cell2);
2417
+ if (cell2.blocks) forEachTableCell(cell2.blocks, fn);
2409
2418
  }
2410
2419
  }
2411
2420
  }
@@ -2414,9 +2423,9 @@ function forEachTableCell(blocks, fn) {
2414
2423
  }
2415
2424
  var CELL_IMAGE_SENTINEL_RE = /!\[image\]\(hwp5bin:(\d+)\)/g;
2416
2425
  function resolveCellImageSentinels(blocks, renamed) {
2417
- forEachTableCell(blocks, (cell) => {
2418
- if (!cell.text.includes("hwp5bin:")) return;
2419
- cell.text = cell.text.replace(CELL_IMAGE_SENTINEL_RE, (_m, idStr) => {
2426
+ forEachTableCell(blocks, (cell2) => {
2427
+ if (!cell2.text.includes("hwp5bin:")) return;
2428
+ cell2.text = cell2.text.replace(CELL_IMAGE_SENTINEL_RE, (_m, idStr) => {
2420
2429
  const filename = renamed.get(Number(idStr));
2421
2430
  return filename ? `![image](${filename})` : "[\uC774\uBBF8\uC9C0]";
2422
2431
  });
@@ -2507,15 +2516,15 @@ function extractHwp5ImagesLenient(lcfb, blocks, warnings) {
2507
2516
  // src/image/transcode.ts
2508
2517
  import { deflateSync } from "zlib";
2509
2518
  var CRC_TABLE = (() => {
2510
- const table = new Uint32Array(256);
2519
+ const table2 = new Uint32Array(256);
2511
2520
  for (let n = 0; n < 256; n++) {
2512
2521
  let c = n;
2513
2522
  for (let k = 0; k < 8; k++) {
2514
2523
  c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
2515
2524
  }
2516
- table[n] = c >>> 0;
2525
+ table2[n] = c >>> 0;
2517
2526
  }
2518
- return table;
2527
+ return table2;
2519
2528
  })();
2520
2529
  function crc32(bytes) {
2521
2530
  let c = 4294967295;
@@ -2526,7 +2535,7 @@ function crc32(bytes) {
2526
2535
  }
2527
2536
  var BI_RGB = 0;
2528
2537
  var MAX_DIM = 32767;
2529
- var MAX_PIXELS = 64e6;
2538
+ var MAX_PIXELS = 36e6;
2530
2539
  function bmpToPng(bmp) {
2531
2540
  if (bmp.length < 54) return null;
2532
2541
  if (bmp[0] !== 66 || bmp[1] !== 77) return null;
@@ -2614,7 +2623,6 @@ function encodePng(width, height, rgba) {
2614
2623
  out.set(iendChunk, o);
2615
2624
  return out;
2616
2625
  }
2617
- var MAX_INLINE_MD_BYTES = 4 * 1024 * 1024;
2618
2626
  function escapeRegExp(s) {
2619
2627
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2620
2628
  }
@@ -2633,8 +2641,11 @@ function inlineImagesIntoMarkdown(markdown, images, opts) {
2633
2641
  }
2634
2642
  const base64 = Buffer.from(bytes).toString("base64");
2635
2643
  const dataUri = `data:${mime};base64,${base64}`;
2636
- const re = new RegExp(`!\\[image\\]\\((?:images/)?${escapeRegExp(img.filename)}\\)`, "g");
2637
- out = out.replace(re, () => `![image](${dataUri})`);
2644
+ const name = escapeRegExp(img.filename);
2645
+ const mdRe = new RegExp(`!\\[image\\]\\((?:images/)?${name}\\)`, "g");
2646
+ out = out.replace(mdRe, () => `![image](${dataUri})`);
2647
+ const imgTagRe = new RegExp(`(<img\\b[^>]*\\bsrc=")(?:images/)?${name}(")`, "g");
2648
+ out = out.replace(imgTagRe, (_m, pre, post) => `${pre}${dataUri}${post}`);
2638
2649
  }
2639
2650
  return out;
2640
2651
  }
@@ -4056,8 +4067,8 @@ function parseParagraph(records, start, end, ctx) {
4056
4067
  function applyCtrlEffect(ctrl, records, ctx) {
4057
4068
  switch (ctrl.id) {
4058
4069
  case CTRL_TBL: {
4059
- const table = parseTableControl(ctrl, records, ctx);
4060
- if (table) ctrl.afterBlocks = [{ type: "table", table, pageNumber: ctx.sectionNum }];
4070
+ const table2 = parseTableControl(ctrl, records, ctx);
4071
+ if (table2) ctrl.afterBlocks = [{ type: "table", table: table2, pageNumber: ctx.sectionNum }];
4061
4072
  return;
4062
4073
  }
4063
4074
  case CTRL_GSO: {
@@ -4276,14 +4287,14 @@ function parseTableControl(ctrl, records, ctx) {
4276
4287
  if (c.isHeader) ir.isHeader = true;
4277
4288
  return ir;
4278
4289
  }));
4279
- const table2 = { rows, cols, cells: irCells, hasHeader: rows > 1 };
4280
- if (caption) table2.caption = caption;
4281
- return table2;
4290
+ const table3 = { rows, cols, cells: irCells, hasHeader: rows > 1 };
4291
+ if (caption) table3.caption = caption;
4292
+ return table3;
4282
4293
  }
4283
4294
  const cellRows = arrangeCells(rows, cols, cells);
4284
- const table = buildTable(cellRows);
4285
- if (caption && table.rows > 0) table.caption = caption;
4286
- return table.rows > 0 ? table : null;
4295
+ const table2 = buildTable(cellRows);
4296
+ if (caption && table2.rows > 0) table2.caption = caption;
4297
+ return table2.rows > 0 ? table2 : null;
4287
4298
  }
4288
4299
  function parseCell(records, lhIdx, end, ctx) {
4289
4300
  const rec = records[lhIdx];
@@ -4321,22 +4332,22 @@ function parseCell(records, lhIdx, end, ctx) {
4321
4332
  parts.push(t);
4322
4333
  }
4323
4334
  }
4324
- const cell = { text: parts.join("\n"), colSpan, rowSpan, colAddr, rowAddr };
4325
- if (hasStructure && blocks.length > 0) cell.blocks = blocks;
4326
- if (isHeader) cell.isHeader = true;
4327
- return cell;
4335
+ const cell2 = { text: parts.join("\n"), colSpan, rowSpan, colAddr, rowAddr };
4336
+ if (hasStructure && blocks.length > 0) cell2.blocks = blocks;
4337
+ if (isHeader) cell2.isHeader = true;
4338
+ return cell2;
4328
4339
  }
4329
4340
  function arrangeCells(rows, cols, cells) {
4330
4341
  const grid = Array.from({ length: rows }, () => Array(cols).fill(null));
4331
4342
  const hasAddr = cells.some((c) => c.colAddr !== void 0 && c.rowAddr !== void 0);
4332
4343
  if (hasAddr) {
4333
- for (const cell of cells) {
4334
- const r = cell.rowAddr ?? 0;
4335
- const c = cell.colAddr ?? 0;
4344
+ for (const cell2 of cells) {
4345
+ const r = cell2.rowAddr ?? 0;
4346
+ const c = cell2.colAddr ?? 0;
4336
4347
  if (r >= rows || c >= cols) continue;
4337
- grid[r][c] = cell;
4338
- for (let dr = 0; dr < cell.rowSpan; dr++) {
4339
- for (let dc = 0; dc < cell.colSpan; dc++) {
4348
+ grid[r][c] = cell2;
4349
+ for (let dr = 0; dr < cell2.rowSpan; dr++) {
4350
+ for (let dc = 0; dc < cell2.colSpan; dc++) {
4340
4351
  if (dr === 0 && dc === 0) continue;
4341
4352
  if (r + dr < rows && c + dc < cols)
4342
4353
  grid[r + dr][c + dc] = { text: "", colSpan: 1, rowSpan: 1 };
@@ -4348,10 +4359,10 @@ function arrangeCells(rows, cols, cells) {
4348
4359
  for (let r = 0; r < rows && cellIdx < cells.length; r++) {
4349
4360
  for (let c = 0; c < cols && cellIdx < cells.length; c++) {
4350
4361
  if (grid[r][c] !== null) continue;
4351
- const cell = cells[cellIdx++];
4352
- grid[r][c] = cell;
4353
- for (let dr = 0; dr < cell.rowSpan; dr++) {
4354
- for (let dc = 0; dc < cell.colSpan; dc++) {
4362
+ const cell2 = cells[cellIdx++];
4363
+ grid[r][c] = cell2;
4364
+ for (let dr = 0; dr < cell2.rowSpan; dr++) {
4365
+ for (let dc = 0; dc < cell2.colSpan; dc++) {
4355
4366
  if (dr === 0 && dc === 0) continue;
4356
4367
  if (r + dr < rows && c + dc < cols)
4357
4368
  grid[r + dr][c + dc] = { text: "", colSpan: 1, rowSpan: 1 };
@@ -16867,7 +16878,7 @@ function sheetToBlocks(sheetName, grid, merges, maxRow, maxCol, sheetIndex) {
16867
16878
  let lastRow = -1;
16868
16879
  for (let r = 0; r <= maxRow; r++) {
16869
16880
  const row = grid[r];
16870
- if (row && row.some((cell) => cell !== "")) {
16881
+ if (row && row.some((cell2) => cell2 !== "")) {
16871
16882
  if (firstRow === -1) firstRow = r;
16872
16883
  lastRow = r;
16873
16884
  }
@@ -16890,9 +16901,9 @@ function sheetToBlocks(sheetName, grid, merges, maxRow, maxCol, sheetIndex) {
16890
16901
  cellRows.push(row);
16891
16902
  }
16892
16903
  if (cellRows.length > 0) {
16893
- const table = buildTable(cellRows);
16894
- if (table.rows > 0) {
16895
- blocks.push({ type: "table", table, pageNumber: sheetIndex + 1 });
16904
+ const table2 = buildTable(cellRows);
16905
+ if (table2.rows > 0) {
16906
+ blocks.push({ type: "table", table: table2, pageNumber: sheetIndex + 1 });
16896
16907
  }
16897
16908
  }
16898
16909
  return blocks;
@@ -17510,9 +17521,9 @@ function sheetToBlocks2(sheetName, sheet, sheetIndex) {
17510
17521
  cellRows.push(row);
17511
17522
  }
17512
17523
  if (cellRows.length > 0) {
17513
- const table = buildTable(cellRows);
17514
- if (table.rows > 0) {
17515
- blocks.push({ type: "table", table, pageNumber: sheetIndex + 1 });
17524
+ const table2 = buildTable(cellRows);
17525
+ if (table2.rows > 0) {
17526
+ blocks.push({ type: "table", table: table2, pageNumber: sheetIndex + 1 });
17516
17527
  }
17517
17528
  }
17518
17529
  return blocks;
@@ -18258,8 +18269,8 @@ function collectTextboxParagraphs(node, inTxbx = false, out = [], depth = 0) {
18258
18269
  }
18259
18270
  return out;
18260
18271
  }
18261
- function parseTable(tbl, styles, numbering, footnotes, rels) {
18262
- const trElements = getChildElements(tbl, "tr");
18272
+ function parseTable(tbl2, styles, numbering, footnotes, rels) {
18273
+ const trElements = getChildElements(tbl2, "tr");
18263
18274
  if (trElements.length === 0) return null;
18264
18275
  const rawRows = [];
18265
18276
  for (const tr of trElements) {
@@ -18272,10 +18283,10 @@ function parseTable(tbl, styles, numbering, footnotes, rels) {
18272
18283
  col = Math.max(0, parseInt(getAttr(gridBeforeEls[0], "val") ?? "0", 10) || 0);
18273
18284
  }
18274
18285
  }
18275
- for (const tc of getChildElements(tr, "tc")) {
18286
+ for (const tc2 of getChildElements(tr, "tc")) {
18276
18287
  let colSpan = 1;
18277
18288
  let vMerge = null;
18278
- const tcPrEls = getChildElements(tc, "tcPr");
18289
+ const tcPrEls = getChildElements(tc2, "tcPr");
18279
18290
  if (tcPrEls.length > 0) {
18280
18291
  const gridSpanEls = getChildElements(tcPrEls[0], "gridSpan");
18281
18292
  if (gridSpanEls.length > 0) {
@@ -18286,48 +18297,48 @@ function parseTable(tbl, styles, numbering, footnotes, rels) {
18286
18297
  vMerge = getAttr(vMergeEls[0], "val") === "restart" ? "restart" : "continue";
18287
18298
  }
18288
18299
  }
18289
- const text = collectCellText(tc, styles, numbering, footnotes, rels, 0).join("\n");
18300
+ const text = collectCellText(tc2, styles, numbering, footnotes, rels, 0).join("\n");
18290
18301
  row.push({ col, colSpan, vMerge, text });
18291
18302
  col += colSpan;
18292
18303
  }
18293
18304
  rawRows.push(row);
18294
18305
  }
18295
18306
  for (let r = 0; r < rawRows.length; r++) {
18296
- for (const cell of rawRows[r]) {
18297
- if (cell.vMerge !== "continue" || !cell.text) continue;
18307
+ for (const cell2 of rawRows[r]) {
18308
+ if (cell2.vMerge !== "continue" || !cell2.text) continue;
18298
18309
  let start;
18299
18310
  for (let pr = r - 1; pr >= 0 && !start; pr--) {
18300
- start = rawRows[pr].find((pc) => pc.col === cell.col && pc.vMerge !== "continue");
18311
+ start = rawRows[pr].find((pc) => pc.col === cell2.col && pc.vMerge !== "continue");
18301
18312
  }
18302
18313
  if (start) {
18303
18314
  start.text = start.text ? `${start.text}
18304
- ${cell.text}` : cell.text;
18305
- cell.text = "";
18315
+ ${cell2.text}` : cell2.text;
18316
+ cell2.text = "";
18306
18317
  } else {
18307
- cell.vMerge = null;
18318
+ cell2.vMerge = null;
18308
18319
  }
18309
18320
  }
18310
18321
  }
18311
18322
  const cellRows = rawRows.map(
18312
- (row, r) => row.filter((cell) => cell.vMerge !== "continue").map((cell) => {
18323
+ (row, r) => row.filter((cell2) => cell2.vMerge !== "continue").map((cell2) => {
18313
18324
  let rowSpan = 1;
18314
- if (cell.vMerge === "restart") {
18325
+ if (cell2.vMerge === "restart") {
18315
18326
  for (let nr = r + 1; nr < rawRows.length; nr++) {
18316
- if (!rawRows[nr].some((nc) => nc.col === cell.col && nc.vMerge === "continue")) break;
18327
+ if (!rawRows[nr].some((nc) => nc.col === cell2.col && nc.vMerge === "continue")) break;
18317
18328
  rowSpan++;
18318
18329
  }
18319
18330
  }
18320
- return { text: cell.text, colSpan: cell.colSpan, rowSpan, colAddr: cell.col, rowAddr: r };
18331
+ return { text: cell2.text, colSpan: cell2.colSpan, rowSpan, colAddr: cell2.col, rowAddr: r };
18321
18332
  })
18322
18333
  );
18323
- const table = buildTable(cellRows);
18324
- if (table.rows === 0 || table.cols === 0) return null;
18325
- return { type: "table", table };
18334
+ const table2 = buildTable(cellRows);
18335
+ if (table2.rows === 0 || table2.cols === 0) return null;
18336
+ return { type: "table", table: table2 };
18326
18337
  }
18327
- function collectCellText(tc, styles, numbering, footnotes, rels, depth) {
18338
+ function collectCellText(tc2, styles, numbering, footnotes, rels, depth) {
18328
18339
  const parts = [];
18329
18340
  if (depth > 20) return parts;
18330
- for (const el of effectiveChildElements(tc)) {
18341
+ for (const el of effectiveChildElements(tc2)) {
18331
18342
  if (matchesLocal(el, "p")) {
18332
18343
  const block = parseParagraph2(el, styles, numbering, footnotes, rels);
18333
18344
  if (block?.text) parts.push(block.text);
@@ -18688,13 +18699,13 @@ function parseTable2(el, blocks, paraShapeMap, sectionNum, warnings) {
18688
18699
  }
18689
18700
  if (cells.length === 0) return;
18690
18701
  const grid = Array.from({ length: rowCount }, () => Array(colCount).fill(null));
18691
- for (const cell of cells) {
18692
- const r = cell.rowAddr ?? 0;
18693
- const c = cell.colAddr ?? 0;
18702
+ for (const cell2 of cells) {
18703
+ const r = cell2.rowAddr ?? 0;
18704
+ const c = cell2.colAddr ?? 0;
18694
18705
  if (isNaN(r) || isNaN(c) || r >= rowCount || c >= colCount) continue;
18695
- grid[r][c] = cell;
18696
- for (let dr = 0; dr < cell.rowSpan; dr++) {
18697
- for (let dc = 0; dc < cell.colSpan; dc++) {
18706
+ grid[r][c] = cell2;
18707
+ for (let dr = 0; dr < cell2.rowSpan; dr++) {
18708
+ for (let dc = 0; dc < cell2.colSpan; dc++) {
18698
18709
  if (dr === 0 && dc === 0) continue;
18699
18710
  if (r + dr < rowCount && c + dc < colCount) {
18700
18711
  grid[r + dr][c + dc] = { text: "", colSpan: 1, rowSpan: 1 };
@@ -18703,14 +18714,14 @@ function parseTable2(el, blocks, paraShapeMap, sectionNum, warnings) {
18703
18714
  }
18704
18715
  }
18705
18716
  const cellRows = grid.map(
18706
- (row) => row.map((cell) => cell ?? { text: "", colSpan: 1, rowSpan: 1 })
18717
+ (row) => row.map((cell2) => cell2 ?? { text: "", colSpan: 1, rowSpan: 1 })
18707
18718
  );
18708
- const table = buildTable(cellRows);
18719
+ const table2 = buildTable(cellRows);
18709
18720
  const caption = extractShapeCaption(el);
18710
18721
  if (caption.text && caption.before) {
18711
18722
  blocks.push({ type: "paragraph", text: caption.text, pageNumber: sectionNum });
18712
18723
  }
18713
- blocks.push({ type: "table", table, pageNumber: sectionNum });
18724
+ blocks.push({ type: "table", table: table2, pageNumber: sectionNum });
18714
18725
  if (caption.text && !caption.before) {
18715
18726
  blocks.push({ type: "paragraph", text: caption.text, pageNumber: sectionNum });
18716
18727
  }
@@ -19210,13 +19221,13 @@ function extractFormFields(blocks) {
19210
19221
  const confidence = totalTables > 0 ? formTables / totalTables : fields.length > 0 ? 0.3 : 0;
19211
19222
  return { fields, confidence: Math.min(confidence, 1) };
19212
19223
  }
19213
- function extractFromTable(table) {
19224
+ function extractFromTable(table2) {
19214
19225
  const fields = [];
19215
- if (table.cols >= 2) {
19216
- for (let r = 0; r < table.rows; r++) {
19217
- for (let c = 0; c < table.cols - 1; c++) {
19218
- const labelCell = table.cells[r]?.[c];
19219
- const valueCell = table.cells[r]?.[c + 1];
19226
+ if (table2.cols >= 2) {
19227
+ for (let r = 0; r < table2.rows; r++) {
19228
+ for (let c = 0; c < table2.cols - 1; c++) {
19229
+ const labelCell = table2.cells[r]?.[c];
19230
+ const valueCell = table2.cells[r]?.[c + 1];
19220
19231
  if (!labelCell || !valueCell) continue;
19221
19232
  if (isLabelCell(labelCell.text)) {
19222
19233
  fields.push({
@@ -19229,17 +19240,17 @@ function extractFromTable(table) {
19229
19240
  }
19230
19241
  }
19231
19242
  }
19232
- if (fields.length === 0 && table.rows >= 2 && table.cols >= 2) {
19233
- const headerRow = table.cells[0];
19234
- const allLabels = headerRow.every((cell) => {
19235
- const t = cell.text.trim();
19243
+ if (fields.length === 0 && table2.rows >= 2 && table2.cols >= 2) {
19244
+ const headerRow = table2.cells[0];
19245
+ const allLabels = headerRow.every((cell2) => {
19246
+ const t = cell2.text.trim();
19236
19247
  return t.length > 0 && t.length <= 20;
19237
19248
  });
19238
19249
  if (allLabels) {
19239
- for (let r = 1; r < table.rows; r++) {
19240
- for (let c = 0; c < table.cols; c++) {
19250
+ for (let r = 1; r < table2.rows; r++) {
19251
+ for (let c = 0; c < table2.cols; c++) {
19241
19252
  const label = headerRow[c]?.text.trim() ?? "";
19242
- const value = table.cells[r]?.[c]?.text.trim() ?? "";
19253
+ const value = table2.cells[r]?.[c]?.text.trim() ?? "";
19243
19254
  if (label && value) {
19244
19255
  fields.push({ label, value, row: r, col: c });
19245
19256
  }
@@ -19276,9 +19287,9 @@ function inferFieldType(label, value) {
19276
19287
  if (/^[\d,.\s]+(?:원|명|건|개|회|부|매|%)$/.test(v) && /\d/.test(v)) return "amount";
19277
19288
  if (/^\d{1,3}(?:,\d{3})+$/.test(v)) return "amount";
19278
19289
  }
19279
- const norm = label.replace(/\s/g, "");
19290
+ const norm2 = label.replace(/\s/g, "");
19280
19291
  for (const [re, type] of LABEL_TYPE_RULES) {
19281
- if (re.test(norm)) return type;
19292
+ if (re.test(norm2)) return type;
19282
19293
  }
19283
19294
  return "text";
19284
19295
  }
@@ -19329,15 +19340,15 @@ function fillFormFields(blocks, values, blockedLabels) {
19329
19340
  const cursor = new ValueCursor(normalizedValues);
19330
19341
  const allTables = collectIRTables(cloned, 0);
19331
19342
  const patternFilledCells = /* @__PURE__ */ new Set();
19332
- for (const table of allTables) {
19333
- for (let r = 0; r < table.rows; r++) {
19334
- for (let c = 0; c < table.cols; c++) {
19335
- const cell = table.cells[r]?.[c];
19336
- if (!cell) continue;
19337
- const result = fillInCellPatterns(cell.text, cursor, matchedLabels, blockedLabels);
19343
+ for (const table2 of allTables) {
19344
+ for (let r = 0; r < table2.rows; r++) {
19345
+ for (let c = 0; c < table2.cols; c++) {
19346
+ const cell2 = table2.cells[r]?.[c];
19347
+ if (!cell2) continue;
19348
+ const result = fillInCellPatterns(cell2.text, cursor, matchedLabels, blockedLabels);
19338
19349
  if (result) {
19339
- cell.text = result.text;
19340
- patternFilledCells.add(cell);
19350
+ cell2.text = result.text;
19351
+ patternFilledCells.add(cell2);
19341
19352
  for (const m of result.matches) {
19342
19353
  filled.push({ label: m.label, value: m.value, row: r, col: c, key: m.key });
19343
19354
  }
@@ -19345,8 +19356,8 @@ function fillFormFields(blocks, values, blockedLabels) {
19345
19356
  }
19346
19357
  }
19347
19358
  }
19348
- for (const table of allTables) {
19349
- fillTable(table, cursor, filled, matchedLabels, patternFilledCells, blockedLabels);
19359
+ for (const table2 of allTables) {
19360
+ fillTable(table2, cursor, filled, matchedLabels, patternFilledCells, blockedLabels);
19350
19361
  }
19351
19362
  for (const block of cloned) {
19352
19363
  if (block.type !== "paragraph" || !block.text) continue;
@@ -19363,44 +19374,44 @@ function collectIRTables(blocks, depth) {
19363
19374
  if (block.type !== "table" || !block.table) continue;
19364
19375
  out.push(block.table);
19365
19376
  for (const row of block.table.cells) {
19366
- for (const cell of row) {
19367
- if (cell?.blocks?.length) out.push(...collectIRTables(cell.blocks, depth + 1));
19377
+ for (const cell2 of row) {
19378
+ if (cell2?.blocks?.length) out.push(...collectIRTables(cell2.blocks, depth + 1));
19368
19379
  }
19369
19380
  }
19370
19381
  }
19371
19382
  return out;
19372
19383
  }
19373
- function coveredPositions(table) {
19384
+ function coveredPositions(table2) {
19374
19385
  const covered = /* @__PURE__ */ new Set();
19375
- for (let r = 0; r < table.rows; r++) {
19376
- for (let c = 0; c < table.cols; c++) {
19386
+ for (let r = 0; r < table2.rows; r++) {
19387
+ for (let c = 0; c < table2.cols; c++) {
19377
19388
  if (covered.has(`${r},${c}`)) continue;
19378
- const cell = table.cells[r]?.[c];
19379
- if (!cell) continue;
19380
- for (let dr = 0; dr < cell.rowSpan; dr++) {
19381
- for (let dc = 0; dc < cell.colSpan; dc++) {
19389
+ const cell2 = table2.cells[r]?.[c];
19390
+ if (!cell2) continue;
19391
+ for (let dr = 0; dr < cell2.rowSpan; dr++) {
19392
+ for (let dc = 0; dc < cell2.colSpan; dc++) {
19382
19393
  if (dr === 0 && dc === 0) continue;
19383
- if (r + dr < table.rows && c + dc < table.cols) covered.add(`${r + dr},${c + dc}`);
19394
+ if (r + dr < table2.rows && c + dc < table2.cols) covered.add(`${r + dr},${c + dc}`);
19384
19395
  }
19385
19396
  }
19386
- c += cell.colSpan - 1;
19397
+ c += cell2.colSpan - 1;
19387
19398
  }
19388
19399
  }
19389
19400
  return covered;
19390
19401
  }
19391
- function fillTable(table, values, filled, matchedLabels, patternFilledCells, blockedLabels) {
19392
- if (table.cols < 2) return;
19393
- const covered = coveredPositions(table);
19394
- for (let r = 0; r < table.rows; r++) {
19395
- for (let c = 0; c < table.cols; c++) {
19402
+ function fillTable(table2, values, filled, matchedLabels, patternFilledCells, blockedLabels) {
19403
+ if (table2.cols < 2) return;
19404
+ const covered = coveredPositions(table2);
19405
+ for (let r = 0; r < table2.rows; r++) {
19406
+ for (let c = 0; c < table2.cols; c++) {
19396
19407
  if (covered.has(`${r},${c}`)) continue;
19397
- const labelCell = table.cells[r][c];
19408
+ const labelCell = table2.cells[r][c];
19398
19409
  if (!labelCell) continue;
19399
19410
  if (!isLabelCell(labelCell.text)) continue;
19400
19411
  let vc = c + labelCell.colSpan;
19401
- while (vc < table.cols && covered.has(`${r},${vc}`)) vc++;
19402
- if (vc >= table.cols) continue;
19403
- const valueCell = table.cells[r][vc];
19412
+ while (vc < table2.cols && covered.has(`${r},${vc}`)) vc++;
19413
+ if (vc >= table2.cols) continue;
19414
+ const valueCell = table2.cells[r][vc];
19404
19415
  if (!valueCell) continue;
19405
19416
  if (isKeywordLabel(valueCell.text)) continue;
19406
19417
  const normalizedCellLabel = normalizeLabel(labelCell.text);
@@ -19425,18 +19436,18 @@ function fillTable(table, values, filled, matchedLabels, patternFilledCells, blo
19425
19436
  });
19426
19437
  }
19427
19438
  }
19428
- if (table.rows >= 2 && table.cols >= 2) {
19429
- const headerRow = table.cells[0];
19430
- const allLabels = headerRow.every((cell) => {
19431
- const t = cell.text.trim();
19439
+ if (table2.rows >= 2 && table2.cols >= 2) {
19440
+ const headerRow = table2.cells[0];
19441
+ const allLabels = headerRow.every((cell2) => {
19442
+ const t = cell2.text.trim();
19432
19443
  return t.length > 0 && t.length <= 20 && isLabelCell(t);
19433
19444
  });
19434
19445
  if (!allLabels) return;
19435
- for (let r = 1; r < table.rows; r++) {
19436
- for (let c = 0; c < table.cols; c++) {
19446
+ for (let r = 1; r < table2.rows; r++) {
19447
+ for (let c = 0; c < table2.cols; c++) {
19437
19448
  if (covered.has(`${r},${c}`)) continue;
19438
19449
  const headerCell = headerRow[c];
19439
- const valueCell = table.cells[r]?.[c];
19450
+ const valueCell = table2.cells[r]?.[c];
19440
19451
  if (!headerCell || !valueCell) continue;
19441
19452
  const headerLabel = normalizeLabel(headerCell.text);
19442
19453
  if (blockedLabels?.has(headerLabel)) continue;
@@ -19507,28 +19518,28 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19507
19518
  return l;
19508
19519
  };
19509
19520
  const matchText = (p) => paraTText(p, xml) ?? p.text;
19510
- const cellLabelText = (cell) => cell.paragraphs.filter((p) => !p.inTextbox).map((p) => matchText(p)).join("");
19521
+ const cellLabelText = (cell2) => cell2.paragraphs.filter((p) => !p.inTextbox).map((p) => matchText(p)).join("");
19511
19522
  const allTables = [];
19512
19523
  const collectTables = (tables, depth) => {
19513
19524
  if (depth > 16) return;
19514
19525
  for (const t of tables) {
19515
19526
  allTables.push(t);
19516
19527
  for (const row of t.rows) {
19517
- for (const cell of row) collectTables(cell.tables, depth + 1);
19528
+ for (const cell2 of row) collectTables(cell2.tables, depth + 1);
19518
19529
  }
19519
19530
  }
19520
19531
  };
19521
19532
  collectTables(scan.tables, 0);
19522
19533
  collectTables(scan.orphanTables, 0);
19523
19534
  const patternApplied = /* @__PURE__ */ new Set();
19524
- for (const table of allTables) {
19525
- for (const row of table.rows) {
19526
- for (const cell of row) {
19527
- for (const para of cell.paragraphs) {
19528
- const text = matchText(para);
19535
+ for (const table2 of allTables) {
19536
+ for (const row of table2.rows) {
19537
+ for (const cell2 of row) {
19538
+ for (const para2 of cell2.paragraphs) {
19539
+ const text = matchText(para2);
19529
19540
  const result = fillInCellPatterns(text, cursor, matchedLabels, blockedLabels);
19530
19541
  if (!result) continue;
19531
- const l = led(para);
19542
+ const l = led(para2);
19532
19543
  if (l.fullText !== void 0) continue;
19533
19544
  const newT = result.text;
19534
19545
  let s = 0;
@@ -19540,7 +19551,7 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19540
19551
  en--;
19541
19552
  }
19542
19553
  l.ranges.push({ start: s, end: eo, replacement: newT.slice(s, en) });
19543
- patternApplied.add(cell);
19554
+ patternApplied.add(cell2);
19544
19555
  for (const m of result.matches) {
19545
19556
  l.filledIdx.push(filled.length);
19546
19557
  l.matchKeys.push(m.key);
@@ -19550,9 +19561,9 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19550
19561
  }
19551
19562
  }
19552
19563
  }
19553
- for (const table of allTables) {
19554
- for (let rowIdx = 0; rowIdx < table.rows.length; rowIdx++) {
19555
- const cells = table.rows[rowIdx];
19564
+ for (const table2 of allTables) {
19565
+ for (let rowIdx = 0; rowIdx < table2.rows.length; rowIdx++) {
19566
+ const cells = table2.rows[rowIdx];
19556
19567
  for (let colIdx = 0; colIdx < cells.length - 1; colIdx++) {
19557
19568
  const labelText = cellLabelText(cells[colIdx]);
19558
19569
  if (!isLabelCell(labelText)) continue;
@@ -19607,15 +19618,15 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19607
19618
  }
19608
19619
  }
19609
19620
  }
19610
- if (table.rows.length >= 2) {
19611
- const headerCells = table.rows[0];
19612
- const allLabels = headerCells.length > 0 && headerCells.every((cell) => {
19613
- const t = cellLabelText(cell).trim();
19621
+ if (table2.rows.length >= 2) {
19622
+ const headerCells = table2.rows[0];
19623
+ const allLabels = headerCells.length > 0 && headerCells.every((cell2) => {
19624
+ const t = cellLabelText(cell2).trim();
19614
19625
  return t.length > 0 && t.length <= 20 && isLabelCell(t);
19615
19626
  });
19616
19627
  if (allLabels) {
19617
- for (let rowIdx = 1; rowIdx < table.rows.length; rowIdx++) {
19618
- const dataCells = table.rows[rowIdx];
19628
+ for (let rowIdx = 1; rowIdx < table2.rows.length; rowIdx++) {
19629
+ const dataCells = table2.rows[rowIdx];
19619
19630
  for (let colIdx = 0; colIdx < Math.min(headerCells.length, dataCells.length); colIdx++) {
19620
19631
  const headerLabel = normalizeLabel(cellLabelText(headerCells[colIdx]));
19621
19632
  if (blockedLabels?.has(headerLabel)) continue;
@@ -19649,10 +19660,10 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19649
19660
  }
19650
19661
  }
19651
19662
  }
19652
- for (const para of [...scan.bodyParagraphs, ...scan.excludedParagraphs]) {
19653
- const existing = ledger.get(para);
19663
+ for (const para2 of [...scan.bodyParagraphs, ...scan.excludedParagraphs]) {
19664
+ const existing = ledger.get(para2);
19654
19665
  if (existing?.fullText !== void 0) continue;
19655
- const text = matchText(para);
19666
+ const text = matchText(para2);
19656
19667
  for (const seg of scanInlineSegments(text)) {
19657
19668
  const nlabel = normalizeLabel(seg.label);
19658
19669
  if (blockedLabels?.has(nlabel)) continue;
@@ -19661,7 +19672,7 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19661
19672
  const newValue = cursor.consume(matchKey);
19662
19673
  if (newValue === void 0) continue;
19663
19674
  const replacement = seg.valueStart === seg.valueEnd ? padInsertion(text, seg.valueStart, newValue) : newValue;
19664
- const l = led(para);
19675
+ const l = led(para2);
19665
19676
  l.ranges.push({ start: seg.valueStart, end: seg.valueEnd, replacement });
19666
19677
  matchedLabels.add(matchKey);
19667
19678
  l.filledIdx.push(filled.length);
@@ -19670,10 +19681,10 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19670
19681
  }
19671
19682
  }
19672
19683
  const splices = [];
19673
- for (const [para, l] of ledger) {
19684
+ for (const [para2, l] of ledger) {
19674
19685
  let paraSplices = null;
19675
19686
  if (l.fullText !== void 0) {
19676
- paraSplices = buildParagraphSplices(para, l.fullText, xml);
19687
+ paraSplices = buildParagraphSplices(para2, l.fullText, xml);
19677
19688
  } else if (l.ranges.length > 0) {
19678
19689
  const sorted = [...l.ranges].sort((a, b) => a.start - b.start || a.end - b.end);
19679
19690
  const merged = [];
@@ -19682,11 +19693,11 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19682
19693
  if (prev && r.start < prev.end) continue;
19683
19694
  merged.push(r);
19684
19695
  }
19685
- if (paraTText(para, xml) !== null) {
19696
+ if (paraTText(para2, xml) !== null) {
19686
19697
  const precise = [];
19687
19698
  let ok = true;
19688
19699
  for (const r of merged) {
19689
- const sp = buildRangeSplices(para, xml, r.start, r.end, r.replacement);
19700
+ const sp = buildRangeSplices(para2, xml, r.start, r.end, r.replacement);
19690
19701
  if (!sp) {
19691
19702
  ok = false;
19692
19703
  break;
@@ -19694,13 +19705,13 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19694
19705
  precise.push(...sp);
19695
19706
  }
19696
19707
  paraSplices = ok ? precise : null;
19697
- } else if (paraTextPureT(para, xml)) {
19698
- let text = para.text;
19708
+ } else if (paraTextPureT(para2, xml)) {
19709
+ let text = para2.text;
19699
19710
  for (let k = merged.length - 1; k >= 0; k--) {
19700
19711
  const r = merged[k];
19701
19712
  text = text.slice(0, r.start) + r.replacement + text.slice(r.end);
19702
19713
  }
19703
- paraSplices = buildParagraphSplices(para, text, xml);
19714
+ paraSplices = buildParagraphSplices(para2, text, xml);
19704
19715
  } else {
19705
19716
  paraSplices = null;
19706
19717
  }
@@ -19734,14 +19745,126 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19734
19745
  // src/hwpx/generator.ts
19735
19746
  import JSZip6 from "jszip";
19736
19747
 
19748
+ // src/hwpx/gaejosik.ts
19749
+ var GAEJOSIK_BULLETS = ["\u25A1", "\u25CB", "\u2015", "\u318D"];
19750
+ function gaejosikMarker(depth) {
19751
+ return GAEJOSIK_BULLETS[Math.min(depth, GAEJOSIK_BULLETS.length - 1)];
19752
+ }
19753
+ function gaejosikSizes(bodyHeight, ov = {}) {
19754
+ const s = bodyHeight / 1500;
19755
+ const r = (v, pt) => pt ? Math.round(pt * 100) : Math.round(v * s);
19756
+ return {
19757
+ /** □ 대항목 — HY헤드라인M 16pt */
19758
+ dae: r(1600, ov.dae),
19759
+ /** ※ 참고 — 한양중고딕 13pt */
19760
+ cham: r(1300, ov.cham),
19761
+ /** 장 헤더(로마숫자·제목) 17pt */
19762
+ chapter: r(1700, ov.chapter),
19763
+ /** 표지 제목 30pt */
19764
+ coverTitle: r(3e3, ov.coverTitle),
19765
+ /** 표지 날짜·기관명 25pt */
19766
+ coverSub: r(2500, ov.coverSub),
19767
+ /** 목차 라벨 "목 차" 28pt */
19768
+ tocLabel: r(2800, ov.tocLabel),
19769
+ /** 목차 로마숫자 21pt(한양신명조) */
19770
+ tocRoman: r(2100, ov.tocRoman),
19771
+ /** 목차 항목 18pt */
19772
+ tocItem: r(1800, ov.tocItem),
19773
+ /** 표 셀 — 맑은 고딕 12pt (실측: 정부 양식 표) */
19774
+ table: r(1200, ov.table),
19775
+ /** 표지 장식 바 셀 빈 문단 — 6pt (실측: 바 높이 818 안에 줄높이 수납) */
19776
+ bar: r(600),
19777
+ /** 본문 첫 페이지 제목 박스 — HY헤드라인M 22pt (실측: GT3 표④) */
19778
+ bodyTitle: r(2200, ov.bodyTitle)
19779
+ };
19780
+ }
19781
+ function gaejosikSpaceBefore(depth, bodyHeight) {
19782
+ const s = bodyHeight / 1500;
19783
+ const ui = [3e3, 2e3, 1200, 600][Math.min(depth, 3)];
19784
+ return Math.round(ui * s);
19785
+ }
19786
+ function gaejosikLevelIndent(depth, bodyHeight, sizes = {}) {
19787
+ const lefts = [0, 1, 1.5, 2];
19788
+ const left = depth <= 3 ? Math.round(lefts[depth] * bodyHeight) : Math.round((2 + (depth - 3) * 0.5) * bodyHeight);
19789
+ const h = depth === 0 ? gaejosikSizes(bodyHeight, sizes).dae : bodyHeight;
19790
+ return { left, indent: -markerWidth(gaejosikMarker(depth), h) };
19791
+ }
19792
+ function gaejosikChamIndent(bodyHeight, sizes = {}) {
19793
+ const cham = gaejosikSizes(bodyHeight, sizes).cham;
19794
+ return { left: Math.round(2.5 * cham), indent: -markerWidth("\u203B", cham) };
19795
+ }
19796
+ function gaejosikTocItemIndent(bodyHeight, sizes = {}) {
19797
+ const sz = gaejosikSizes(bodyHeight, sizes);
19798
+ const hang = markerWidth("\u2167.", sz.tocRoman);
19799
+ return { left: 2e3 + hang, indent: -hang };
19800
+ }
19801
+ function formatGaejosikDate(d) {
19802
+ return `${d.getFullYear()}. ${d.getMonth() + 1}. ${d.getDate()}.`;
19803
+ }
19804
+ function stripChapterNumber(title) {
19805
+ return title.replace(/^\s*(?:\d+|[ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩ]+)\s*[.)]\s*/u, "").trim();
19806
+ }
19807
+ var GAEJOSIK_COLORS = {
19808
+ /** 장헤더 로마숫자 셀·표지 진한 바 음영 */
19809
+ primary: "#193AAA",
19810
+ /** 장헤더 셀 테두리 */
19811
+ border: "#006699",
19812
+ /** 표지 연한 바 */
19813
+ accent: "#A0B4E6",
19814
+ /** 장헤더 제목 셀 음영 */
19815
+ titleFill: "#F2F2F2",
19816
+ /** 장헤더 제목 셀 상하선 */
19817
+ titleLine: "#A6A6A6",
19818
+ /** 목차 박스 테두리 */
19819
+ tocBorder: "#514BAC",
19820
+ /** 목차 배너 라벤더 스트라이프 (실측: GT3 표②) */
19821
+ tocStripe: "#E0E5FA"
19822
+ };
19823
+ var CHAPTER_GEOM = { numW: 3327, gapW: 848, titleW: 43513, rowH: 2832 };
19824
+ var COVER_GEOM = {
19825
+ totalW: 48180,
19826
+ topDarkW: 38219,
19827
+ topLightW: 9961,
19828
+ barH: 818,
19829
+ titleH: 11060,
19830
+ botDarkW: 10466,
19831
+ botLightW: 37714,
19832
+ botBarH: 812
19833
+ };
19834
+ var TOC_GEOM = { boxW: 46492, boxH: 57840 };
19835
+ function chapterGeom(bodyHeight, ov = {}) {
19836
+ const s = gaejosikSizes(bodyHeight, ov).chapter / 1700;
19837
+ return { ...CHAPTER_GEOM, rowH: Math.round(CHAPTER_GEOM.rowH * s) };
19838
+ }
19839
+ function coverGeom(bodyHeight, ov = {}) {
19840
+ const s = gaejosikSizes(bodyHeight, ov).coverTitle / 3e3;
19841
+ return { ...COVER_GEOM, titleH: Math.round(COVER_GEOM.titleH * s) };
19842
+ }
19843
+ var TOC_BANNER_GEOM = {
19844
+ colWs: [565, 565, 1414, 13191, 1414, 565, 565],
19845
+ h: 3931
19846
+ };
19847
+ function tocBannerGeom(bodyHeight, ov = {}) {
19848
+ const s = gaejosikSizes(bodyHeight, ov).tocLabel / 2800;
19849
+ return { colWs: TOC_BANNER_GEOM.colWs, h: Math.round(TOC_BANNER_GEOM.h * s) };
19850
+ }
19851
+ var BODY_TITLE_GEOM = { barH: 600, titleH: 3566 };
19852
+ function bodyTitleGeom(bodyHeight, ov = {}) {
19853
+ const s = gaejosikSizes(bodyHeight, ov).bodyTitle / 2200;
19854
+ return { barH: BODY_TITLE_GEOM.barH, titleH: Math.round(BODY_TITLE_GEOM.titleH * s) };
19855
+ }
19856
+
19737
19857
  // src/hwpx/gongmun.ts
19738
19858
  var OFFICIAL_MARGINS = { top: 20, bottom: 10, left: 20, right: 20 };
19859
+ var GAEJOSIK_MARGINS = { top: 15, bottom: 15, left: 20, right: 20 };
19860
+ var GAEJOSIK_HEADER_FOOTER = 4251;
19739
19861
  var PRESET_DEFAULTS = {
19740
19862
  official: { bodyPt: 15, lineSpacing: 160, numbering: "standard" },
19741
19863
  report: { bodyPt: 15, lineSpacing: 160, numbering: "report" },
19742
19864
  plan: { bodyPt: 15, lineSpacing: 160, numbering: "standard" },
19743
19865
  notice: { bodyPt: 15, lineSpacing: 160, numbering: "standard" },
19744
- minutes: { bodyPt: 14, lineSpacing: 130, numbering: "standard" }
19866
+ minutes: { bodyPt: 14, lineSpacing: 130, numbering: "standard" },
19867
+ gaejosik: { bodyPt: 15, lineSpacing: 160, numbering: "gaejosik" }
19745
19868
  };
19746
19869
  var PRESET_ALIAS = {
19747
19870
  official: "official",
@@ -19759,7 +19882,12 @@ var PRESET_ALIAS = {
19759
19882
  \uC54C\uB9BC: "notice",
19760
19883
  \uC548\uB0B4: "notice",
19761
19884
  minutes: "minutes",
19762
- \uD68C\uC758\uB85D: "minutes"
19885
+ \uD68C\uC758\uB85D: "minutes",
19886
+ gaejosik: "gaejosik",
19887
+ \uAC1C\uC870\uC2DD: "gaejosik",
19888
+ \uAC1C\uC870\uC2DD\uBCF4\uACE0\uC11C: "gaejosik",
19889
+ \uC815\uBD80\uBCF4\uACE0\uC11C: "gaejosik",
19890
+ \uC815\uBD80\uD45C\uC900\uAC1C\uC870\uC2DD\uBCF4\uACE0\uC11C: "gaejosik"
19763
19891
  };
19764
19892
  function normalizeGongmunPreset(preset) {
19765
19893
  if (!preset) return "official";
@@ -19770,15 +19898,30 @@ function resolveGongmun(opts) {
19770
19898
  const d = PRESET_DEFAULTS[preset];
19771
19899
  const bodyPt = opts.bodyPt ?? d.bodyPt;
19772
19900
  const autoFitMinRatio = opts.autoFit === false ? null : typeof opts.autoFit === "object" ? Math.min(Math.max(opts.autoFit.minRatio ?? 90, 50), 99) : 90;
19901
+ const coverOn = opts.cover !== void 0 ? opts.cover !== false : preset === "gaejosik";
19902
+ const coverOpts = typeof opts.cover === "object" ? opts.cover : {};
19903
+ const gaejosik = preset === "gaejosik";
19773
19904
  return {
19774
19905
  preset,
19775
19906
  bodyFont: opts.bodyFont ?? "myeongjo",
19776
19907
  bodyHeight: Math.round(bodyPt * 100),
19777
19908
  lineSpacing: opts.lineSpacing ?? d.lineSpacing,
19778
19909
  numbering: opts.numbering ?? d.numbering,
19779
- margins: opts.margins ?? OFFICIAL_MARGINS,
19910
+ margins: opts.margins ?? (gaejosik ? GAEJOSIK_MARGINS : OFFICIAL_MARGINS),
19780
19911
  centerTitle: opts.centerTitle ?? true,
19781
- autoFitMinRatio
19912
+ autoFitMinRatio,
19913
+ cover: coverOn ? { date: coverOpts.date ?? null, org: coverOpts.org ?? "" } : null,
19914
+ toc: opts.toc ?? gaejosik,
19915
+ fonts: opts.fonts ?? {},
19916
+ sizes: opts.sizes ?? {},
19917
+ // 쪽번호 — 보고서 계열 관행(실측: 2_보고서 양식·추진계획·공고문 전부 하단 중앙)
19918
+ pageNumbers: opts.pageNumbers ?? (gaejosik || preset === "report" || preset === "plan"),
19919
+ headerFooter: gaejosik ? GAEJOSIK_HEADER_FOOTER : 0,
19920
+ // "끝." — 기안문 규정(본문 끝 2타+"끝."). 그 외는 opt-in
19921
+ endMark: opts.endMark ?? preset === "official",
19922
+ approval: opts.approval && opts.approval.length > 0 ? opts.approval : null,
19923
+ // 본문 제목박스 — 실측(GT3·GT12): 목차 뒤 본문 시작에 제목 반복. 표지 켜진 개조식 기본
19924
+ bodyTitleBox: opts.bodyTitleBox ?? (gaejosik && coverOn)
19782
19925
  };
19783
19926
  }
19784
19927
  var HANGUL_INITIALS = [0, 2, 3, 5, 6, 7, 9, 11, 12, 14, 15, 16, 17, 18];
@@ -19826,7 +19969,8 @@ function markerWidth(marker, bodyHeight) {
19826
19969
  for (const c of marker) em += charWidthEm1000(c.codePointAt(0));
19827
19970
  return Math.round(em / 1e3 * bodyHeight);
19828
19971
  }
19829
- function levelIndent(depth, bodyHeight, numbering) {
19972
+ function levelIndent(depth, bodyHeight, numbering, sizes = {}) {
19973
+ if (numbering === "gaejosik") return gaejosikLevelIndent(depth, bodyHeight, sizes);
19830
19974
  const marker = numbering === "report" ? reportMarker(depth) : standardMarker(depth, 0);
19831
19975
  return { left: Math.round(depth * bodyHeight), indent: -markerWidth(marker, bodyHeight) };
19832
19976
  }
@@ -19854,6 +19998,7 @@ var GongmunNumberer = class {
19854
19998
  const n = this.counts[depth] ?? 0;
19855
19999
  this.counts[depth] = n + 1;
19856
20000
  if (suppress) return "";
20001
+ if (this.numbering === "gaejosik") return gaejosikMarker(depth);
19857
20002
  return this.numbering === "report" ? reportMarker(depth) : standardMarker(depth, n);
19858
20003
  }
19859
20004
  reset() {
@@ -19921,27 +20066,28 @@ function headingCharPrId(level) {
19921
20066
  if (level === 3) return CHAR_H3;
19922
20067
  return CHAR_H4;
19923
20068
  }
19924
- function charPr(id, height, bold, italic, fontId = 0, textColor = DEFAULT_TEXT_COLOR, ratioPct = 100) {
20069
+ function charPr(id, height, bold, italic, fontId = 0, textColor = DEFAULT_TEXT_COLOR, ratioPct = 100, keepFontOnBold = false) {
19925
20070
  const boldAttr = bold ? ` bold="1"` : "";
19926
20071
  const italicAttr = italic ? ` italic="1"` : "";
19927
- const effFont = bold ? 2 : fontId;
20072
+ const effFont = bold && !keepFontOnBold ? 2 : fontId;
20073
+ const boldEl = bold ? `<hh:bold/>` : "";
19928
20074
  return ` <hh:charPr id="${id}" height="${height}" textColor="${textColor}" shadeColor="none" useFontSpace="0" useKerning="0" symMark="NONE" borderFillIDRef="1"${boldAttr}${italicAttr}>
19929
20075
  <hh:fontRef hangul="${effFont}" latin="${effFont}" hanja="${effFont}" japanese="${effFont}" other="${effFont}" symbol="${effFont}" user="${effFont}"/>
19930
20076
  <hh:ratio hangul="${ratioPct}" latin="${ratioPct}" hanja="${ratioPct}" japanese="100" other="100" symbol="100" user="100"/>
19931
20077
  <hh:spacing hangul="0" latin="0" hanja="0" japanese="0" other="0" symbol="0" user="0"/>
19932
20078
  <hh:relSz hangul="100" latin="100" hanja="100" japanese="100" other="100" symbol="100" user="100"/>
19933
- <hh:offset hangul="0" latin="0" hanja="0" japanese="0" other="0" symbol="0" user="0"/>
20079
+ <hh:offset hangul="0" latin="0" hanja="0" japanese="0" other="0" symbol="0" user="0"/>${boldEl}
19934
20080
  </hh:charPr>`;
19935
20081
  }
19936
20082
  function paraPr(id, opts = {}) {
19937
- const { align = "JUSTIFY", spaceBefore = 0, spaceAfter = 0, lineSpacing = 160, indent = 0, left = 0, keepWord = false, outlineLevel } = opts;
19938
- const breakNonLatin = keepWord ? "KEEP_WORD" : "BREAK_WORD";
20083
+ const { align = "JUSTIFY", spaceBefore = 0, spaceAfter = 0, lineSpacing = 160, indent = 0, left = 0, keepWord = false, keepWithNext = false, outlineLevel } = opts;
20084
+ const breakNonLatin = keepWord ? "BREAK_WORD" : "KEEP_WORD";
19939
20085
  const snapGrid = keepWord ? "0" : "1";
19940
20086
  const heading = outlineLevel !== void 0 ? `<hh:heading type="OUTLINE" idRef="0" level="${outlineLevel}"/>` : `<hh:heading type="NONE" idRef="0" level="0"/>`;
19941
20087
  return ` <hh:paraPr id="${id}" tabPrIDRef="0" condense="0" fontLineHeight="0" snapToGrid="${snapGrid}" suppressLineNumbers="0" checked="0" textDir="AUTO">
19942
20088
  <hh:align horizontal="${align}" vertical="BASELINE"/>
19943
20089
  ${heading}
19944
- <hh:breakSetting breakLatinWord="KEEP_WORD" breakNonLatinWord="${breakNonLatin}" widowOrphan="0" keepWithNext="0" keepLines="0" pageBreakBefore="0" lineWrap="BREAK"/>
20090
+ <hh:breakSetting breakLatinWord="KEEP_WORD" breakNonLatinWord="${breakNonLatin}" widowOrphan="0" keepWithNext="${keepWithNext ? 1 : 0}" keepLines="0" pageBreakBefore="0" lineWrap="BREAK"/>
19945
20091
  <hh:autoSpacing eAsianEng="0" eAsianNum="0"/>
19946
20092
  <hh:margin><hc:intent value="${indent}" unit="HWPUNIT"/><hc:left value="${left}" unit="HWPUNIT"/><hc:right value="0" unit="HWPUNIT"/><hc:prev value="${spaceBefore}" unit="HWPUNIT"/><hc:next value="${spaceAfter}" unit="HWPUNIT"/></hh:margin>
19947
20093
  <hh:lineSpacing type="PERCENT" value="${lineSpacing}"/>
@@ -19951,7 +20097,72 @@ function paraPr(id, opts = {}) {
19951
20097
  var GONGMUN_LIST_BASE = 8;
19952
20098
  var GONGMUN_LIST_LEVELS = 8;
19953
20099
  var GONGMUN_CENTER = GONGMUN_LIST_BASE + GONGMUN_LIST_LEVELS;
20100
+ var GONGMUN_RIGHT = GONGMUN_CENTER + 1;
20101
+ var GONGMUN_TBL_CENTER = GONGMUN_RIGHT + 1;
20102
+ var GONGMUN_TBL_LEFT = GONGMUN_TBL_CENTER + 1;
20103
+ var GJ_CHAR_DAE = 11;
20104
+ var GJ_CHAR_DAE_BOLD = 12;
20105
+ var GJ_CHAR_CHAM = 13;
20106
+ var GJ_CHAR_CHAM_BOLD = 14;
20107
+ var GJ_CHAR_CHAPTER_NUM = 15;
20108
+ var GJ_CHAR_CHAPTER_TITLE = 16;
20109
+ var GJ_CHAR_COVER_TITLE = 17;
20110
+ var GJ_CHAR_COVER_SUB = 18;
20111
+ var GJ_CHAR_TOC_LABEL = 19;
20112
+ var GJ_CHAR_TOC_ROMAN = 20;
20113
+ var GJ_CHAR_TOC_ITEM = 21;
20114
+ var GJ_CHAR_TABLE = 22;
20115
+ var GJ_CHAR_TABLE_BOLD = 23;
20116
+ var GJ_CHAR_BAR = 24;
20117
+ var GJ_CHAR_BODY_TITLE = 25;
20118
+ var GJ_CHAR_COUNT = 15;
20119
+ var GJ_PARA_CHAM = 20;
20120
+ var GJ_PARA_COVER = 21;
20121
+ var GJ_PARA_TOC_ITEM = 22;
20122
+ var GJ_PARA_CHAPTER = 23;
20123
+ var GJ_PARA_BAR = 24;
20124
+ var GJ_BF_CHAPTER_NUM = 3;
20125
+ var GJ_BF_CHAPTER_GAP = 4;
20126
+ var GJ_BF_CHAPTER_TITLE = 5;
20127
+ var GJ_BF_BAR_DARK = 6;
20128
+ var GJ_BF_BAR_LIGHT = 7;
20129
+ var GJ_BF_TOC_BOX = 8;
20130
+ var GJ_BF_TOC_STRIPE = 9;
20131
+ function gongmunTableHeaderBf(gaejosik) {
20132
+ return gaejosik ? 10 : 3;
20133
+ }
20134
+ function borderFillEntry(id, b, fill) {
20135
+ const side = (name, v) => v ? ` <hh:${name} type="${v[2] ?? "SOLID"}" width="${v[0]}" color="${v[1]}"/>` : ` <hh:${name} type="NONE" width="0.1 mm" color="#000000"/>`;
20136
+ let brush = "";
20137
+ if (typeof fill === "string") {
20138
+ brush = `
20139
+ <hc:fillBrush><hc:winBrush faceColor="${fill}" hatchColor="#000000" alpha="0"/></hc:fillBrush>`;
20140
+ } else if (fill) {
20141
+ brush = `
20142
+ <hc:fillBrush><hc:gradation type="RADIAL" angle="0" centerX="0" centerY="0" step="50" colorNum="2" stepCenter="50" alpha="0"><hc:color value="${fill.gradient[0]}"/><hc:color value="${fill.gradient[1]}"/></hc:gradation></hc:fillBrush>`;
20143
+ }
20144
+ return ` <hh:borderFill id="${id}" threeD="0" shadow="0" centerLine="NONE" breakCellSeparateLine="0">
20145
+ <hh:slash type="NONE" Crooked="0" isCounter="0"/>
20146
+ <hh:backSlash type="NONE" Crooked="0" isCounter="0"/>
20147
+ ${side("leftBorder", b.l)}
20148
+ ${side("rightBorder", b.r)}
20149
+ ${side("topBorder", b.t)}
20150
+ ${side("bottomBorder", b.b)}${brush}
20151
+ </hh:borderFill>`;
20152
+ }
20153
+ function pageNumCtrl() {
20154
+ return `<hp:ctrl><hp:pageNum pos="BOTTOM_CENTER" formatType="DIGIT" sideChar="-"/></hp:ctrl>`;
20155
+ }
20156
+ function newPageNumCtrl(num2 = 1) {
20157
+ return `<hp:ctrl><hp:newNum num="${num2}" numType="PAGE"/></hp:ctrl>`;
20158
+ }
20159
+ function pageHidingCtrl(hideHeader = false) {
20160
+ return `<hp:ctrl><hp:pageHiding hideHeader="${hideHeader ? 1 : 0}" hideFooter="0" hideMasterPage="0" hideBorder="0" hideFill="0" hidePageNum="1"/></hp:ctrl>`;
20161
+ }
19954
20162
  var CHAR_VARIANT_BASE = 11;
20163
+ function charVariantBase(gaejosik) {
20164
+ return gaejosik ? CHAR_VARIANT_BASE + GJ_CHAR_COUNT : CHAR_VARIANT_BASE;
20165
+ }
19955
20166
  var GONGMUN_BODY_RATIO = 95;
19956
20167
 
19957
20168
  // src/hwpx/md-runs.ts
@@ -20165,12 +20376,12 @@ function generateRuns(text, defaultCharPr = CHAR_NORMAL, mapCharId) {
20165
20376
  return `<hp:run charPrIDRef="${charId}"><hp:t>${escapeXml(span.text)}</hp:t></hp:run>`;
20166
20377
  }).join("");
20167
20378
  }
20168
- function generateParagraph(text, paraPrId = PARA_NORMAL, charPrId = CHAR_NORMAL, mapCharId) {
20379
+ function generateParagraph(text, paraPrId = PARA_NORMAL, charPrId = CHAR_NORMAL, mapCharId, styleId = 0) {
20169
20380
  if (paraPrId === PARA_CODE) {
20170
20381
  return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_CODE}"><hp:t>${escapeXml(text)}</hp:t></hp:run></hp:p>`;
20171
20382
  }
20172
20383
  const runs = generateRuns(text, charPrId, mapCharId);
20173
- return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0">${runs}</hp:p>`;
20384
+ return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="${styleId}">${runs}</hp:p>`;
20174
20385
  }
20175
20386
 
20176
20387
  // src/hwpx/gen-header.ts
@@ -20198,6 +20409,7 @@ function generateManifest(chartParts = []) {
20198
20409
  </opf:package>`;
20199
20410
  }
20200
20411
  function buildCharProperties(theme, gongmun, ratioVariants = [], extraCharPrXmls = []) {
20412
+ const gaejosik = gongmun?.preset === "gaejosik";
20201
20413
  let body = 1e3, code = 900, h1 = 1800, h2 = 1400, h3 = 1200, h4 = 1100;
20202
20414
  if (gongmun) {
20203
20415
  body = gongmun.bodyHeight;
@@ -20207,26 +20419,62 @@ function buildCharProperties(theme, gongmun, ratioVariants = [], extraCharPrXmls
20207
20419
  h3 = body;
20208
20420
  h4 = Math.max(body - 100, 1300);
20209
20421
  }
20422
+ const bodyFont = gaejosik ? 4 : 0;
20210
20423
  const bodyRatio = gongmun ? GONGMUN_BODY_RATIO : 100;
20211
20424
  const rows = [
20212
- charPr(0, body, false, false, 0, theme.body, bodyRatio),
20213
- charPr(1, body, true, false, 0, theme.body, bodyRatio),
20214
- charPr(2, body, false, true, 0, theme.body, bodyRatio),
20215
- charPr(3, body, true, true, 0, theme.body, bodyRatio),
20425
+ charPr(0, body, false, false, bodyFont, theme.body, bodyRatio),
20426
+ charPr(1, body, true, false, bodyFont, theme.body, bodyRatio),
20427
+ charPr(2, body, false, true, bodyFont, theme.body, bodyRatio),
20428
+ charPr(3, body, true, true, bodyFont, theme.body, bodyRatio),
20216
20429
  charPr(4, code, false, false, 1),
20217
20430
  charPr(5, h1, true, false, 1, theme.h1),
20218
20431
  charPr(6, h2, true, false, 1, theme.h2),
20219
20432
  charPr(7, h3, true, false, 1, theme.h3),
20220
20433
  charPr(8, h4, true, false, 1, theme.h4),
20221
- charPr(CHAR_TABLE_HEADER, body, theme.tableHeaderBold, false, 0, theme.tableHeader),
20222
- charPr(CHAR_QUOTE, body, false, true, 0, theme.quote)
20434
+ charPr(CHAR_TABLE_HEADER, body, theme.tableHeaderBold, false, bodyFont, theme.tableHeader),
20435
+ charPr(CHAR_QUOTE, body, false, true, bodyFont, theme.quote)
20223
20436
  ];
20437
+ if (gaejosik) {
20438
+ const sz = gaejosikSizes(body, gongmun.sizes);
20439
+ rows.push(
20440
+ charPr(11, sz.dae, false, false, 3),
20441
+ // □ HY헤드라인M
20442
+ charPr(12, sz.dae, true, false, 3, "#000000", 100, true),
20443
+ // □ bold
20444
+ charPr(13, sz.cham, false, false, 5),
20445
+ // ※ 한양중고딕
20446
+ charPr(14, sz.cham, true, false, 5, "#000000", 100, true),
20447
+ // ※ bold
20448
+ charPr(15, sz.chapter, true, false, 4, "#FFFFFF", 100, true),
20449
+ // 장 로마숫자(흰)
20450
+ charPr(16, sz.chapter, false, false, 3),
20451
+ // 장 제목
20452
+ charPr(17, sz.coverTitle, false, false, 3),
20453
+ // 표지 제목
20454
+ charPr(18, sz.coverSub, false, false, 3),
20455
+ // 표지 날짜·기관명
20456
+ charPr(19, sz.tocLabel, true, false, 3, "#000000", 100, true),
20457
+ // 목 차
20458
+ charPr(20, sz.tocRoman, true, false, 6, "#000000", 100, true),
20459
+ // 목차 로마숫자(한양신명조)
20460
+ charPr(21, sz.tocItem, false, false, 3),
20461
+ // 목차 항목
20462
+ charPr(22, sz.table, false, false, 7),
20463
+ // 표 셀(맑은 고딕 12pt)
20464
+ charPr(23, sz.table, true, false, 7, "#000000", 100, true),
20465
+ // 표 셀 bold
20466
+ charPr(24, sz.bar, false, false, 4),
20467
+ // 표지 바 셀 빈 문단(6pt)
20468
+ charPr(25, sz.bodyTitle, false, false, 3)
20469
+ // 본문 제목박스(HY헤드라인M 22pt, 실측 GT3 표④)
20470
+ );
20471
+ }
20224
20472
  for (const r of ratioVariants) {
20225
20473
  rows.push(
20226
- charPr(rows.length, body, false, false, 0, theme.body, r),
20227
- charPr(rows.length + 1, body, true, false, 0, theme.body, r),
20228
- charPr(rows.length + 2, body, false, true, 0, theme.body, r),
20229
- charPr(rows.length + 3, body, true, true, 0, theme.body, r)
20474
+ charPr(rows.length, body, false, false, bodyFont, theme.body, r),
20475
+ charPr(rows.length + 1, body, true, false, bodyFont, theme.body, r),
20476
+ charPr(rows.length + 2, body, false, true, bodyFont, theme.body, r),
20477
+ charPr(rows.length + 3, body, true, true, bodyFont, theme.body, r)
20230
20478
  );
20231
20479
  }
20232
20480
  rows.push(...extraCharPrXmls);
@@ -20237,14 +20485,14 @@ ${rows.join("\n")}
20237
20485
  function buildParaProperties(gongmun) {
20238
20486
  if (!gongmun) {
20239
20487
  const base2 = [
20240
- paraPr(0),
20241
- paraPr(1, { align: "LEFT", spaceBefore: 800, spaceAfter: 200, lineSpacing: 180, outlineLevel: 0 }),
20242
- paraPr(2, { align: "LEFT", spaceBefore: 600, spaceAfter: 150, lineSpacing: 170, outlineLevel: 1 }),
20243
- paraPr(3, { align: "LEFT", spaceBefore: 400, spaceAfter: 100, lineSpacing: 160, outlineLevel: 2 }),
20244
- paraPr(4, { align: "LEFT", spaceBefore: 300, spaceAfter: 100, lineSpacing: 160, outlineLevel: 3 }),
20245
- paraPr(5, { align: "LEFT", lineSpacing: 130, indent: 400 }),
20246
- paraPr(6, { align: "LEFT", lineSpacing: 150, indent: 600 }),
20247
- paraPr(7, { align: "LEFT", lineSpacing: 160, indent: 600 })
20488
+ paraPr(0, { keepWord: true }),
20489
+ paraPr(1, { align: "LEFT", spaceBefore: 800, spaceAfter: 200, lineSpacing: 180, outlineLevel: 0, keepWord: true }),
20490
+ paraPr(2, { align: "LEFT", spaceBefore: 600, spaceAfter: 150, lineSpacing: 170, outlineLevel: 1, keepWord: true }),
20491
+ paraPr(3, { align: "LEFT", spaceBefore: 400, spaceAfter: 100, lineSpacing: 160, outlineLevel: 2, keepWord: true }),
20492
+ paraPr(4, { align: "LEFT", spaceBefore: 300, spaceAfter: 100, lineSpacing: 160, outlineLevel: 3, keepWord: true }),
20493
+ paraPr(5, { align: "LEFT", lineSpacing: 130, indent: 400, keepWord: true }),
20494
+ paraPr(6, { align: "LEFT", lineSpacing: 150, indent: 600, keepWord: true }),
20495
+ paraPr(7, { align: "LEFT", lineSpacing: 160, indent: 600, keepWord: true })
20248
20496
  ];
20249
20497
  return `<hh:paraProperties itemCnt="${base2.length}">
20250
20498
  ${base2.join("\n")}
@@ -20254,20 +20502,37 @@ ${base2.join("\n")}
20254
20502
  const titleAlign = gongmun.centerTitle ? "CENTER" : "LEFT";
20255
20503
  const base = [
20256
20504
  paraPr(0, { lineSpacing: ls, keepWord: true }),
20257
- paraPr(1, { align: titleAlign, spaceBefore: 400, spaceAfter: 400, lineSpacing: ls, keepWord: true, outlineLevel: 0 }),
20258
- paraPr(2, { align: "LEFT", spaceBefore: 600, spaceAfter: 150, lineSpacing: ls, keepWord: true, outlineLevel: 1 }),
20259
- paraPr(3, { align: "LEFT", spaceBefore: 400, spaceAfter: 100, lineSpacing: ls, keepWord: true, outlineLevel: 2 }),
20260
- paraPr(4, { align: "LEFT", spaceBefore: 300, spaceAfter: 100, lineSpacing: ls, keepWord: true, outlineLevel: 3 }),
20505
+ paraPr(1, { align: titleAlign, spaceBefore: 400, spaceAfter: 400, lineSpacing: ls, keepWord: true }),
20506
+ paraPr(2, { align: "LEFT", spaceBefore: 600, spaceAfter: 150, lineSpacing: ls, keepWord: true }),
20507
+ paraPr(3, { align: "LEFT", spaceBefore: 400, spaceAfter: 100, lineSpacing: ls, keepWord: true }),
20508
+ paraPr(4, { align: "LEFT", spaceBefore: 300, spaceAfter: 100, lineSpacing: ls, keepWord: true }),
20261
20509
  paraPr(5, { align: "LEFT", lineSpacing: 130, indent: 400, keepWord: true }),
20262
20510
  paraPr(6, { align: "LEFT", lineSpacing: ls, indent: 600, keepWord: true }),
20263
20511
  paraPr(7, { align: "LEFT", lineSpacing: ls, indent: 600, keepWord: true })
20264
20512
  ];
20265
20513
  for (let d = 0; d < GONGMUN_LIST_LEVELS; d++) {
20266
- const { left, indent } = levelIndent(d, gongmun.bodyHeight, gongmun.numbering);
20267
- const sectionGap = gongmun.numbering === "report" && d === 0 ? Math.round(gongmun.bodyHeight * 0.5) : 0;
20268
- base.push(paraPr(GONGMUN_LIST_BASE + d, { align: "JUSTIFY", lineSpacing: ls, left, indent, spaceBefore: sectionGap, keepWord: true }));
20514
+ const { left, indent } = levelIndent(d, gongmun.bodyHeight, gongmun.numbering, gongmun.sizes);
20515
+ const sectionGap = gongmun.numbering === "gaejosik" ? gaejosikSpaceBefore(d, gongmun.bodyHeight) : gongmun.numbering === "report" && d === 0 ? Math.round(gongmun.bodyHeight * 0.5) : 0;
20516
+ const keepNext = gongmun.numbering === "gaejosik" && d === 0;
20517
+ base.push(paraPr(GONGMUN_LIST_BASE + d, { align: "JUSTIFY", lineSpacing: ls, left, indent, spaceBefore: sectionGap, keepWord: true, keepWithNext: keepNext }));
20269
20518
  }
20270
20519
  base.push(paraPr(GONGMUN_CENTER, { align: "CENTER", lineSpacing: ls, keepWord: true }));
20520
+ base.push(paraPr(GONGMUN_RIGHT, { align: "RIGHT", lineSpacing: ls, keepWord: true }));
20521
+ base.push(paraPr(GONGMUN_TBL_CENTER, { align: "CENTER", lineSpacing: 130, keepWord: true }));
20522
+ base.push(paraPr(GONGMUN_TBL_LEFT, { align: "LEFT", lineSpacing: 130, keepWord: true }));
20523
+ if (gongmun.preset === "gaejosik") {
20524
+ const cham = gaejosikChamIndent(gongmun.bodyHeight, gongmun.sizes);
20525
+ const toc = gaejosikTocItemIndent(gongmun.bodyHeight, gongmun.sizes);
20526
+ base.push(
20527
+ paraPr(GJ_PARA_CHAM, { align: "JUSTIFY", lineSpacing: ls, left: cham.left, indent: cham.indent, spaceBefore: gaejosikSpaceBefore(3, gongmun.bodyHeight), keepWord: true }),
20528
+ paraPr(GJ_PARA_COVER, { align: "CENTER", lineSpacing: 130, keepWord: true }),
20529
+ paraPr(GJ_PARA_TOC_ITEM, { align: "LEFT", lineSpacing: 160, left: toc.left, indent: toc.indent, spaceBefore: 1800, keepWord: true }),
20530
+ // 장 헤더는 다음 문단과 같은 쪽에 — 쪽 하단 고아 헤더 방지 (실렌더 확인 이슈)
20531
+ paraPr(GJ_PARA_CHAPTER, { align: "LEFT", lineSpacing: ls, spaceBefore: 2400, spaceAfter: 600, keepWord: true, keepWithNext: true }),
20532
+ // 표지 장식 바 셀 빈 문단 — 저줄간격(실측 71%)으로 바 높이 818 안에 수납
20533
+ paraPr(GJ_PARA_BAR, { align: "CENTER", lineSpacing: 70, keepWord: true })
20534
+ );
20535
+ }
20271
20536
  return `<hh:paraProperties itemCnt="${base.length}">
20272
20537
  ${base.join("\n")}
20273
20538
  </hh:paraProperties>`;
@@ -20283,25 +20548,37 @@ ${heads}
20283
20548
  </hh:numbering>
20284
20549
  </hh:numberings>`;
20285
20550
  }
20286
- function generateHeaderXml(theme, gongmun, ratioVariants = [], remap = null) {
20287
- const bodyFace = gongmun?.bodyFont === "gothic" ? "\uB9D1\uC740 \uACE0\uB515" : "\uD568\uCD08\uB86C\uBC14\uD0D5";
20288
- const charPropsXml = buildCharProperties(theme, gongmun, ratioVariants, remap?.charPrXmls ?? []);
20289
- const paraPropsXml = buildParaProperties(gongmun);
20290
- return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
20291
- <hh:head xmlns:hh="${NS_HEAD}" xmlns:hp="${NS_PARA}" xmlns:hc="${NS_CORE}" version="1.4" secCnt="1">
20292
- <hh:beginNum page="1" footnote="1" endnote="1" pic="1" tbl="1" equation="1"/>
20293
- <hh:refList>
20294
- <hh:fontfaces itemCnt="7">
20551
+ function fontEntry(id, face, weight = 6) {
20552
+ return ` <hh:font id="${id}" face="${face}" type="TTF" isEmbedded="0">
20553
+ <hh:typeInfo familyType="FCAT_GOTHIC" weight="${weight}" proportion="4" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
20554
+ </hh:font>`;
20555
+ }
20556
+ function buildFontFaces(gongmun, bodyFace) {
20557
+ if (gongmun?.preset === "gaejosik") {
20558
+ const ov = gongmun.fonts;
20559
+ const faces = [
20560
+ "\uD568\uCD08\uB86C\uBC14\uD0D5",
20561
+ "\uD568\uCD08\uB86C\uB3CB\uC6C0",
20562
+ "HY\uACAC\uACE0\uB515",
20563
+ ov.heading ?? "HY\uD5E4\uB4DC\uB77C\uC778M",
20564
+ ov.body ?? "\uD734\uBA3C\uBA85\uC870",
20565
+ ov.ref ?? "\uD55C\uC591\uC911\uACE0\uB515",
20566
+ "\uD55C\uC591\uC2E0\uBA85\uC870",
20567
+ ov.table ?? "\uB9D1\uC740 \uACE0\uB515"
20568
+ ];
20569
+ const list = faces.map((f, i) => fontEntry(i, f, i === 2 || i === 3 ? 9 : 6)).join("\n");
20570
+ const langs = ["HANGUL", "LATIN", "HANJA", "JAPANESE", "OTHER", "SYMBOL", "USER"];
20571
+ return `<hh:fontfaces itemCnt="${langs.length}">
20572
+ ` + langs.map((l) => ` <hh:fontface lang="${l}" fontCnt="${faces.length}">
20573
+ ${list}
20574
+ </hh:fontface>`).join("\n") + `
20575
+ </hh:fontfaces>`;
20576
+ }
20577
+ return `<hh:fontfaces itemCnt="7">
20295
20578
  <hh:fontface lang="HANGUL" fontCnt="3">
20296
- <hh:font id="0" face="${bodyFace}" type="TTF" isEmbedded="0">
20297
- <hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="4" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
20298
- </hh:font>
20299
- <hh:font id="1" face="\uD568\uCD08\uB86C\uB3CB\uC6C0" type="TTF" isEmbedded="0">
20300
- <hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="4" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
20301
- </hh:font>
20302
- <hh:font id="2" face="HY\uACAC\uACE0\uB515" type="TTF" isEmbedded="0">
20303
- <hh:typeInfo familyType="FCAT_GOTHIC" weight="9" proportion="0" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
20304
- </hh:font>
20579
+ ${fontEntry(0, bodyFace)}
20580
+ ${fontEntry(1, "\uD568\uCD08\uB86C\uB3CB\uC6C0")}
20581
+ ${fontEntry(2, "HY\uACAC\uACE0\uB515", 9)}
20305
20582
  </hh:fontface>
20306
20583
  <hh:fontface lang="LATIN" fontCnt="3">
20307
20584
  <hh:font id="0" face="Times New Roman" type="TTF" isEmbedded="0">
@@ -20315,57 +20592,87 @@ function generateHeaderXml(theme, gongmun, ratioVariants = [], remap = null) {
20315
20592
  </hh:font>
20316
20593
  </hh:fontface>
20317
20594
  <hh:fontface lang="HANJA" fontCnt="1">
20318
- <hh:font id="0" face="\uD568\uCD08\uB86C\uBC14\uD0D5" type="TTF" isEmbedded="0">
20319
- <hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="4" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
20320
- </hh:font>
20595
+ ${fontEntry(0, "\uD568\uCD08\uB86C\uBC14\uD0D5")}
20321
20596
  </hh:fontface>
20322
20597
  <hh:fontface lang="JAPANESE" fontCnt="1">
20323
- <hh:font id="0" face="\uAD74\uB9BC" type="TTF" isEmbedded="0">
20324
- <hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="0" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
20325
- </hh:font>
20598
+ ${fontEntry(0, "\uAD74\uB9BC")}
20326
20599
  </hh:fontface>
20327
20600
  <hh:fontface lang="OTHER" fontCnt="1">
20328
- <hh:font id="0" face="\uAD74\uB9BC" type="TTF" isEmbedded="0">
20329
- <hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="0" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
20330
- </hh:font>
20601
+ ${fontEntry(0, "\uAD74\uB9BC")}
20331
20602
  </hh:fontface>
20332
20603
  <hh:fontface lang="SYMBOL" fontCnt="1">
20333
- <hh:font id="0" face="Symbol" type="TTF" isEmbedded="0">
20334
- <hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="0" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
20335
- </hh:font>
20604
+ ${fontEntry(0, "Symbol")}
20336
20605
  </hh:fontface>
20337
20606
  <hh:fontface lang="USER" fontCnt="1">
20338
- <hh:font id="0" face="\uAD74\uB9BC" type="TTF" isEmbedded="0">
20339
- <hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="0" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
20340
- </hh:font>
20607
+ ${fontEntry(0, "\uAD74\uB9BC")}
20341
20608
  </hh:fontface>
20342
- </hh:fontfaces>
20343
- <hh:borderFills itemCnt="${2 + (remap?.borderFillXmls.length ?? 0)}">
20344
- <hh:borderFill id="1" threeD="0" shadow="0" centerLine="NONE" breakCellSeparateLine="0">
20345
- <hh:slash type="NONE" Crooked="0" isCounter="0"/>
20346
- <hh:backSlash type="NONE" Crooked="0" isCounter="0"/>
20347
- <hh:leftBorder type="NONE" width="0.1 mm" color="#000000"/>
20348
- <hh:rightBorder type="NONE" width="0.1 mm" color="#000000"/>
20349
- <hh:topBorder type="NONE" width="0.1 mm" color="#000000"/>
20350
- <hh:bottomBorder type="NONE" width="0.1 mm" color="#000000"/>
20351
- </hh:borderFill>
20352
- <hh:borderFill id="2" threeD="0" shadow="0" centerLine="NONE" breakCellSeparateLine="0">
20353
- <hh:slash type="NONE" Crooked="0" isCounter="0"/>
20354
- <hh:backSlash type="NONE" Crooked="0" isCounter="0"/>
20355
- <hh:leftBorder type="SOLID" width="0.12 mm" color="#000000"/>
20356
- <hh:rightBorder type="SOLID" width="0.12 mm" color="#000000"/>
20357
- <hh:topBorder type="SOLID" width="0.12 mm" color="#000000"/>
20358
- <hh:bottomBorder type="SOLID" width="0.12 mm" color="#000000"/>
20359
- </hh:borderFill>${remap && remap.borderFillXmls.length ? "\n" + remap.borderFillXmls.join("\n") : ""}
20360
- </hh:borderFills>
20609
+ </hh:fontfaces>`;
20610
+ }
20611
+ function buildBorderFills(gongmun, extra = []) {
20612
+ const thin = ["0.12 mm", "#000000"];
20613
+ const items = [
20614
+ borderFillEntry(1, {}),
20615
+ borderFillEntry(2, { l: thin, r: thin, t: thin, b: thin })
20616
+ ];
20617
+ if (gongmun?.preset === "gaejosik") {
20618
+ const c = GAEJOSIK_COLORS;
20619
+ const edge = ["0.12 mm", c.border];
20620
+ const grayLine = ["0.1 mm", c.titleLine];
20621
+ const tocEdge = ["0.4 mm", c.tocBorder];
20622
+ items.push(
20623
+ borderFillEntry(3, { l: edge, r: edge, t: edge, b: edge }, c.primary),
20624
+ // 로마숫자
20625
+ borderFillEntry(4, { l: edge }),
20626
+ // 간격 (좌선)
20627
+ borderFillEntry(5, { t: grayLine, b: grayLine }, c.titleFill),
20628
+ // 장 제목 셀
20629
+ borderFillEntry(6, {}, c.primary),
20630
+ // 표지 진한 바
20631
+ borderFillEntry(7, {}, c.accent),
20632
+ // 표지 연한 바
20633
+ borderFillEntry(8, { l: tocEdge, r: tocEdge, t: tocEdge, b: tocEdge }),
20634
+ // 목차 박스
20635
+ borderFillEntry(9, {}, c.tocStripe)
20636
+ // 목차 배너 라벤더 스트라이프
20637
+ );
20638
+ }
20639
+ if (gongmun) {
20640
+ items.push(borderFillEntry(items.length + 1, { l: thin, r: thin, t: thin, b: thin }, "#E6E6E6"));
20641
+ }
20642
+ items.push(...extra);
20643
+ return `<hh:borderFills itemCnt="${items.length}">
20644
+ ${items.join("\n")}
20645
+ </hh:borderFills>`;
20646
+ }
20647
+ function buildStyles(gongmun) {
20648
+ const items = [
20649
+ `<hh:style id="0" type="PARA" name="\uBC14\uD0D5\uAE00" engName="Normal" paraPrIDRef="0" charPrIDRef="0" nextStyleIDRef="0" langIDRef="1042" lockForm="0"/>`
20650
+ ];
20651
+ if (gongmun) {
20652
+ for (let lvl = 1; lvl <= 4; lvl++) {
20653
+ items.push(`<hh:style id="${lvl}" type="PARA" name="\uAC1C\uC694 ${lvl}" engName="Outline ${lvl}" paraPrIDRef="${lvl}" charPrIDRef="${4 + lvl}" nextStyleIDRef="0" langIDRef="1042" lockForm="0"/>`);
20654
+ }
20655
+ }
20656
+ return `<hh:styles itemCnt="${items.length}">
20657
+ ${items.join("\n ")}
20658
+ </hh:styles>`;
20659
+ }
20660
+ function generateHeaderXml(theme, gongmun, ratioVariants = [], extraBorderFills = [], extraCharPrXmls = []) {
20661
+ const bodyFace = gongmun?.fonts.body ?? (gongmun?.bodyFont === "gothic" ? "\uB9D1\uC740 \uACE0\uB515" : "\uD568\uCD08\uB86C\uBC14\uD0D5");
20662
+ const charPropsXml = buildCharProperties(theme, gongmun, ratioVariants, extraCharPrXmls);
20663
+ const paraPropsXml = buildParaProperties(gongmun);
20664
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
20665
+ <hh:head xmlns:hh="${NS_HEAD}" xmlns:hp="${NS_PARA}" xmlns:hc="${NS_CORE}" version="1.4" secCnt="1">
20666
+ <hh:beginNum page="1" footnote="1" endnote="1" pic="1" tbl="1" equation="1"/>
20667
+ <hh:refList>
20668
+ ${buildFontFaces(gongmun, bodyFace)}
20669
+ ${buildBorderFills(gongmun, extraBorderFills)}
20361
20670
  ${charPropsXml}
20362
20671
  <hh:tabProperties itemCnt="0"/>
20363
20672
  ${buildNumberings()}
20364
20673
  <hh:bullets itemCnt="0"/>
20365
20674
  ${paraPropsXml}
20366
- <hh:styles itemCnt="1">
20367
- <hh:style id="0" type="PARA" name="\uBC14\uD0D5\uAE00" engName="Normal" paraPrIDRef="0" charPrIDRef="0" nextStyleIDRef="0" langIDRef="1042" lockForm="0"/>
20368
- </hh:styles>
20675
+ ${buildStyles(gongmun)}
20369
20676
  </hh:refList>
20370
20677
  <hh:compatibleDocument targetProgram="HWP2018"><hh:layoutCompatibility/></hh:compatibleDocument>
20371
20678
  </hh:head>`;
@@ -20601,6 +20908,7 @@ function computeGongmunFitPlan(blocks, gongmun, gongmunList) {
20601
20908
  let contW;
20602
20909
  if (block.type === "list_item" && gongmunList.has(i)) {
20603
20910
  const { marker, depth } = gongmunList.get(i);
20911
+ if (gongmun.numbering === "gaejosik" && (depth === 0 || (block.text || "").trimStart().startsWith("\u203B"))) continue;
20604
20912
  const content = plainRenderText(block.text || "");
20605
20913
  text = marker ? `${marker} ${content}` : content;
20606
20914
  const { left, indent } = levelIndent(depth, gongmun.bodyHeight, gongmun.numbering);
@@ -20609,6 +20917,7 @@ function computeGongmunFitPlan(blocks, gongmun, gongmunList) {
20609
20917
  } else if (block.type === "paragraph") {
20610
20918
  const raw = (block.text || "").trim();
20611
20919
  if (/^<center>[\s\S]*<\/center>$/i.test(raw)) continue;
20920
+ if (gongmun.numbering === "gaejosik" && raw.startsWith("\u203B")) continue;
20612
20921
  text = plainRenderText(raw);
20613
20922
  firstW = contW = pageW;
20614
20923
  } else {
@@ -20622,14 +20931,15 @@ function computeGongmunFitPlan(blocks, gongmun, gongmunList) {
20622
20931
  }
20623
20932
  return ratioByBlock.size > 0 ? { ratioByBlock, variants } : null;
20624
20933
  }
20625
- function variantMapper(fit, blockIdx) {
20934
+ function variantMapper(fit, blockIdx, base = CHAR_VARIANT_BASE) {
20626
20935
  const r = fit.ratioByBlock.get(blockIdx);
20627
20936
  if (r === void 0) return void 0;
20628
20937
  const vi = fit.variants.indexOf(r);
20629
- return (id) => id >= 0 && id <= 3 ? CHAR_VARIANT_BASE + vi * 4 + id : id;
20938
+ return (id) => id >= 0 && id <= 3 ? base + vi * 4 + id : id;
20630
20939
  }
20631
20940
  function precomputeGongmunList(blocks, gongmun) {
20632
20941
  const result = /* @__PURE__ */ new Map();
20942
+ const depthOffset = gongmun.numbering === "gaejosik" && blocks.some((b) => b.type === "heading" && b.level === 3) ? 1 : 0;
20633
20943
  let i = 0;
20634
20944
  while (i < blocks.length) {
20635
20945
  if (blocks[i].type !== "list_item") {
@@ -20655,7 +20965,7 @@ function precomputeGongmunList(blocks, gongmun) {
20655
20965
  }
20656
20966
  break;
20657
20967
  }
20658
- const depths = run.map((bi) => Math.min(Math.max(blocks[bi].indent || 0, 0), GONGMUN_LIST_LEVELS - 1));
20968
+ const depths = run.map((bi) => Math.min(Math.max((blocks[bi].indent || 0) + depthOffset, 0), GONGMUN_LIST_LEVELS - 1));
20659
20969
  const suppress = gongmun.numbering === "standard" ? computeSuppression(depths) : depths.map(() => false);
20660
20970
  const numberer = new GongmunNumberer(gongmun.numbering);
20661
20971
  run.forEach((bi, k) => {
@@ -20666,6 +20976,98 @@ function precomputeGongmunList(blocks, gongmun) {
20666
20976
  return result;
20667
20977
  }
20668
20978
 
20979
+ // src/hwpx/gen-gaejosik.ts
20980
+ function chapterRoman(n) {
20981
+ if (n >= 1 && n <= 12) return String.fromCodePoint(8543 + n);
20982
+ const t = [[10, "\u2169"], [9, "\u2168"], [5, "\u2164"], [4, "\u2163"], [1, "\u2160"]];
20983
+ let s = "";
20984
+ for (const [v, r] of t) while (n >= v) {
20985
+ s += r;
20986
+ n -= v;
20987
+ }
20988
+ return s;
20989
+ }
20990
+ function emptyPara(paraPrId = PARA_NORMAL, pageBreak = false, charPrId = CHAR_NORMAL) {
20991
+ const brk = pageBreak ? ` pageBreak="1"` : "";
20992
+ return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0"${brk}><hp:run charPrIDRef="${charPrId}"><hp:t></hp:t></hp:run></hp:p>`;
20993
+ }
20994
+ var gjTableId = 92e5;
20995
+ function cell(opts) {
20996
+ const paras = opts.paras ?? emptyPara();
20997
+ return `<hp:tc name="" header="0" hasMargin="0" protect="0" editable="1" dirty="0" borderFillIDRef="${opts.bf}"><hp:subList id="" textDirection="HORIZONTAL" lineWrap="BREAK" vertAlign="${opts.vertAlign ?? "CENTER"}" linkListIDRef="0" linkListNextIDRef="0" textWidth="0" textHeight="0" hasTextRef="0" hasNumRef="0">${paras}</hp:subList><hp:cellAddr colAddr="${opts.col}" rowAddr="${opts.row ?? 0}"/><hp:cellSpan colSpan="${opts.colSpan ?? 1}" rowSpan="1"/><hp:cellSz width="${opts.w}" height="${opts.h}"/><hp:cellMargin left="141" right="141" top="141" bottom="141"/></hp:tc>`;
20998
+ }
20999
+ function table(rows, w, h, cols, tblBf = 1) {
21000
+ return `<hp:tbl id="${++gjTableId}" zOrder="0" numberingType="TABLE" textWrap="TOP_AND_BOTTOM" textFlow="BOTH_SIDES" lock="0" dropcapstyle="None" pageBreak="CELL" repeatHeader="0" rowCnt="${rows.length}" colCnt="${cols}" cellSpacing="0" borderFillIDRef="${tblBf}" noAdjust="1"><hp:sz width="${w}" widthRelTo="ABSOLUTE" height="${h}" heightRelTo="ABSOLUTE" protect="0"/><hp:pos treatAsChar="1" affectLSpacing="0" flowWithText="1" allowOverlap="0" holdAnchorAndSO="0" vertRelTo="PARA" horzRelTo="PARA" vertAlign="TOP" horzAlign="LEFT" vertOffset="0" horzOffset="0"/><hp:outMargin left="283" right="283" top="283" bottom="283"/><hp:inMargin left="141" right="141" top="141" bottom="141"/>` + rows.map((r) => `<hp:tr>${r}</hp:tr>`).join("") + `</hp:tbl>`;
21001
+ }
21002
+ function buildGaejosikCover(title, gongmun) {
21003
+ const g = coverGeom(gongmun.bodyHeight, gongmun.sizes);
21004
+ const sz = gaejosikSizes(gongmun.bodyHeight, gongmun.sizes);
21005
+ const innerW = g.totalW - 282;
21006
+ const titleCharPr = simulateWrap(title, innerW, innerW, sz.coverTitle, 100, "keep").lines > 2 ? GJ_CHAR_COVER_SUB : GJ_CHAR_COVER_TITLE;
21007
+ const titlePara = `<hp:p paraPrIDRef="${GJ_PARA_COVER}" styleIDRef="0"><hp:run charPrIDRef="${titleCharPr}"><hp:t>${escapeXml(title)}</hp:t></hp:run></hp:p>`;
21008
+ const barEmpty = emptyPara(GJ_PARA_BAR, false, GJ_CHAR_BAR);
21009
+ 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 });
21010
+ const titleRow = cell({ bf: 1, col: 0, colSpan: 3, row: 1, w: g.totalW, h: g.titleH, paras: titlePara });
21011
+ const botRow = cell({ bf: GJ_BF_BAR_DARK, col: 0, row: 2, w: g.botDarkW, h: g.botBarH, paras: barEmpty }) + cell({ bf: GJ_BF_BAR_LIGHT, col: 1, colSpan: 2, row: 2, w: g.botLightW, h: g.botBarH, paras: barEmpty });
21012
+ const tbl2 = table([topRow, titleRow, botRow], g.totalW, g.barH + g.titleH + g.botBarH, 3);
21013
+ const host = `<hp:p paraPrIDRef="${PARA_NORMAL}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_NORMAL}">${tbl2}</hp:run></hp:p>`;
21014
+ const date = gongmun.cover?.date ?? formatGaejosikDate(/* @__PURE__ */ new Date());
21015
+ const org = gongmun.cover?.org ?? "";
21016
+ 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>`;
21017
+ const subEmpty = emptyPara(GJ_PARA_COVER, false, GJ_CHAR_COVER_SUB);
21018
+ return [
21019
+ ...Array(5).fill(emptyPara()),
21020
+ host,
21021
+ ...Array(5).fill(emptyPara()),
21022
+ sub(date),
21023
+ ...org ? [...Array(4).fill(subEmpty), sub(org)] : []
21024
+ ];
21025
+ }
21026
+ function buildTocBanner(gongmun) {
21027
+ const g = tocBannerGeom(gongmun.bodyHeight, gongmun.sizes);
21028
+ const bfs = [GJ_BF_BAR_DARK, 1, GJ_BF_TOC_STRIPE, 1, GJ_BF_TOC_STRIPE, 1, GJ_BF_BAR_DARK];
21029
+ const filler = emptyPara(GJ_PARA_BAR, false, GJ_CHAR_BAR);
21030
+ const label = `<hp:p paraPrIDRef="${GONGMUN_CENTER}" styleIDRef="0"><hp:run charPrIDRef="${GJ_CHAR_TOC_LABEL}"><hp:t>\uBAA9 \uCC28</hp:t></hp:run></hp:p>`;
21031
+ const row = g.colWs.map(
21032
+ (w, c) => cell({ bf: bfs[c], col: c, w, h: g.h, paras: c === 3 ? label : filler })
21033
+ ).join("");
21034
+ const banner = table([row], g.colWs.reduce((a, b) => a + b, 0), g.h, 7, 2);
21035
+ return `<hp:p paraPrIDRef="${GJ_PARA_BAR}" styleIDRef="0" pageBreak="1"><hp:run charPrIDRef="${CHAR_NORMAL}">${banner}</hp:run></hp:p>`;
21036
+ }
21037
+ function buildGaejosikToc(chapters, gongmun) {
21038
+ const label = buildTocBanner(gongmun);
21039
+ const items = chapters.map(
21040
+ (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>`
21041
+ ).join("");
21042
+ const box = table(
21043
+ [cell({ bf: GJ_BF_TOC_BOX, col: 0, w: TOC_GEOM.boxW, h: TOC_GEOM.boxH, paras: items })],
21044
+ TOC_GEOM.boxW,
21045
+ TOC_GEOM.boxH,
21046
+ 1
21047
+ );
21048
+ const host = `<hp:p paraPrIDRef="${GJ_PARA_BAR}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_NORMAL}">${box}</hp:run></hp:p>`;
21049
+ return [label, emptyPara(GJ_PARA_BAR, false, GJ_CHAR_BAR), host];
21050
+ }
21051
+ function buildGaejosikBodyTitle(title, gongmun) {
21052
+ const g = COVER_GEOM;
21053
+ const bt = bodyTitleGeom(gongmun.bodyHeight, gongmun.sizes);
21054
+ const barEmpty = emptyPara(GJ_PARA_BAR, false, GJ_CHAR_BAR);
21055
+ 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>`;
21056
+ 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 });
21057
+ const titleRow = cell({ bf: 1, col: 0, colSpan: 3, row: 1, w: g.totalW, h: bt.titleH, paras: titlePara });
21058
+ 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 });
21059
+ const box = table([topRow, titleRow, botRow], g.totalW, bt.barH * 2 + bt.titleH, 3);
21060
+ return `<hp:p paraPrIDRef="${PARA_NORMAL}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_NORMAL}">${box}</hp:run></hp:p>`;
21061
+ }
21062
+ function buildGaejosikChapter(n, title, gongmun) {
21063
+ const g = gongmun ? chapterGeom(gongmun.bodyHeight, gongmun.sizes) : chapterGeom(1500);
21064
+ 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>`;
21065
+ 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>`;
21066
+ 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 });
21067
+ const tbl2 = table([row], g.numW + g.gapW + g.titleW, g.rowH, 3);
21068
+ return `<hp:p paraPrIDRef="${GJ_PARA_CHAPTER}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_NORMAL}">${tbl2}</hp:run></hp:p>`;
21069
+ }
21070
+
20669
21071
  // src/diff/text-diff.ts
20670
21072
  function similarity(a, b) {
20671
21073
  if (a === b) return 1;
@@ -20863,8 +21265,8 @@ function summarize(text) {
20863
21265
  const t = text.replace(/\s+/g, " ").trim();
20864
21266
  return t.length > 80 ? t.slice(0, 77) + "..." : t;
20865
21267
  }
20866
- function replicateGfmTable(table) {
20867
- const { cells, rows: numRows, cols: numCols } = table;
21268
+ function replicateGfmTable(table2) {
21269
+ const { cells, rows: numRows, cols: numCols } = table2;
20868
21270
  if (numRows === 0 || numCols === 0) return null;
20869
21271
  if (numRows === 1 && numCols === 1) return null;
20870
21272
  if (numCols === 1) return null;
@@ -20873,28 +21275,28 @@ function replicateGfmTable(table) {
20873
21275
  for (let r = 0; r < numRows; r++) {
20874
21276
  for (let c = 0; c < numCols; c++) {
20875
21277
  if (skip.has(`${r},${c}`)) continue;
20876
- const cell = cells[r]?.[c];
20877
- if (!cell) continue;
21278
+ const cell2 = cells[r]?.[c];
21279
+ if (!cell2) continue;
20878
21280
  display[r][c] = {
20879
- text: escapeGfm(sanitizeText(cell.text)).replace(/\|/g, "\\|").replace(/\n/g, "<br>"),
21281
+ text: escapeGfm(sanitizeText(cell2.text)).replace(/\|/g, "\\|").replace(/\n/g, "<br>"),
20880
21282
  gridR: r,
20881
21283
  gridC: c
20882
21284
  };
20883
- for (let dr = 0; dr < cell.rowSpan; dr++) {
20884
- for (let dc = 0; dc < cell.colSpan; dc++) {
21285
+ for (let dr = 0; dr < cell2.rowSpan; dr++) {
21286
+ for (let dc = 0; dc < cell2.colSpan; dc++) {
20885
21287
  if (dr === 0 && dc === 0) continue;
20886
21288
  if (r + dr < numRows && c + dc < numCols) skip.add(`${r + dr},${c + dc}`);
20887
21289
  }
20888
21290
  }
20889
- c += cell.colSpan - 1;
21291
+ c += cell2.colSpan - 1;
20890
21292
  }
20891
21293
  }
20892
21294
  const uniqueRows = [];
20893
21295
  let pendingLabelRow = null;
20894
21296
  for (let r = 0; r < display.length; r++) {
20895
21297
  const row = display[r];
20896
- if (row.every((cell) => cell.text === "")) continue;
20897
- const nonEmptyCols = row.filter((cell) => cell.text !== "");
21298
+ if (row.every((cell2) => cell2.text === "")) continue;
21299
+ const nonEmptyCols = row.filter((cell2) => cell2.text !== "");
20898
21300
  const hasSkipInRow = row.some((_, c) => skip.has(`${r},${c}`));
20899
21301
  if (!hasSkipInRow && nonEmptyCols.length === 1 && row[0].text !== "" && row.slice(1).every((c) => c.text === "")) {
20900
21302
  if (pendingLabelRow) uniqueRows.push(pendingLabelRow);
@@ -20926,9 +21328,9 @@ function parseGfmTable(lines) {
20926
21328
  function unescapeGfmCell(text) {
20927
21329
  return text.replace(/<br\s*\/?>/gi, "\n").replace(/\\\|/g, "|").replace(/\\([~*])/g, "$1");
20928
21330
  }
20929
- function replicateCellInnerHtml(cell) {
20930
- if (cell.blocks?.length) {
20931
- return cell.blocks.map((b) => {
21331
+ function replicateCellInnerHtml(cell2) {
21332
+ if (cell2.blocks?.length) {
21333
+ return cell2.blocks.map((b) => {
20932
21334
  if (b.type === "table" && b.table) {
20933
21335
  const cap = b.table.caption ? sanitizeText(b.table.caption) : "";
20934
21336
  return (cap ? cap + "<br>" : "") + replicateTableToHtml(b.table);
@@ -20938,27 +21340,27 @@ function replicateCellInnerHtml(cell) {
20938
21340
  return t ? t.replace(/\n/g, "<br>") : "";
20939
21341
  }).filter(Boolean).join("<br>");
20940
21342
  }
20941
- return sanitizeText(cell.text).replace(/\n/g, "<br>");
21343
+ return sanitizeText(cell2.text).replace(/\n/g, "<br>");
20942
21344
  }
20943
- function replicateTableToHtml(table) {
20944
- const rows = replicateHtmlTable(table);
21345
+ function replicateTableToHtml(table2) {
21346
+ const rows = replicateHtmlTable(table2);
20945
21347
  const lines = ["<table>"];
20946
21348
  for (let r = 0; r < rows.length; r++) {
20947
21349
  const tag = rows[r].tag;
20948
- const rowHtml = rows[r].cells.map((cell) => {
21350
+ const rowHtml = rows[r].cells.map((cell2) => {
20949
21351
  const attrs = [];
20950
- if (cell.colSpan > 1) attrs.push(`colspan="${cell.colSpan}"`);
20951
- if (cell.rowSpan > 1) attrs.push(`rowspan="${cell.rowSpan}"`);
21352
+ if (cell2.colSpan > 1) attrs.push(`colspan="${cell2.colSpan}"`);
21353
+ if (cell2.rowSpan > 1) attrs.push(`rowspan="${cell2.rowSpan}"`);
20952
21354
  const attrStr = attrs.length ? " " + attrs.join(" ") : "";
20953
- return `<${tag}${attrStr}>${cell.inner}</${tag}>`;
21355
+ return `<${tag}${attrStr}>${cell2.inner}</${tag}>`;
20954
21356
  });
20955
21357
  if (rowHtml.length) lines.push(`<tr>${rowHtml.join("")}</tr>`);
20956
21358
  }
20957
21359
  lines.push("</table>");
20958
21360
  return lines.join("\n");
20959
21361
  }
20960
- function replicateHtmlTable(table) {
20961
- const { cells, rows: numRows, cols: numCols } = table;
21362
+ function replicateHtmlTable(table2) {
21363
+ const { cells, rows: numRows, cols: numCols } = table2;
20962
21364
  const skip = /* @__PURE__ */ new Set();
20963
21365
  const result = [];
20964
21366
  for (let r = 0; r < numRows; r++) {
@@ -20966,18 +21368,18 @@ function replicateHtmlTable(table) {
20966
21368
  const rowCells = [];
20967
21369
  for (let c = 0; c < numCols; c++) {
20968
21370
  if (skip.has(`${r},${c}`)) continue;
20969
- const cell = cells[r]?.[c];
20970
- if (!cell) continue;
20971
- for (let dr = 0; dr < cell.rowSpan; dr++) {
20972
- for (let dc = 0; dc < cell.colSpan; dc++) {
21371
+ const cell2 = cells[r]?.[c];
21372
+ if (!cell2) continue;
21373
+ for (let dr = 0; dr < cell2.rowSpan; dr++) {
21374
+ for (let dc = 0; dc < cell2.colSpan; dc++) {
20973
21375
  if (dr === 0 && dc === 0) continue;
20974
21376
  if (r + dr < numRows && c + dc < numCols) skip.add(`${r + dr},${c + dc}`);
20975
21377
  }
20976
21378
  }
20977
21379
  rowCells.push({
20978
- inner: replicateCellInnerHtml(cell),
20979
- colSpan: cell.colSpan,
20980
- rowSpan: cell.rowSpan,
21380
+ inner: replicateCellInnerHtml(cell2),
21381
+ colSpan: cell2.colSpan,
21382
+ rowSpan: cell2.rowSpan,
20981
21383
  gridR: r,
20982
21384
  gridC: c
20983
21385
  });
@@ -21082,59 +21484,302 @@ function removeNestedTables(html) {
21082
21484
  return result;
21083
21485
  }
21084
21486
 
21487
+ // src/hwpx/gen-table-bf.ts
21488
+ var THIN = ["0.12 mm", "#000000"];
21489
+ var THICK = ["0.4 mm", "#000000"];
21490
+ var DOUBLE = ["0.5 mm", "#000000", "DOUBLE_SLIM"];
21491
+ var EDGE = { thin: THIN, thick: THICK, double: DOUBLE };
21492
+ function sideOf(kind) {
21493
+ return kind === "none" ? void 0 : EDGE[kind];
21494
+ }
21495
+ var TableBfRegistry = class {
21496
+ constructor(nextId) {
21497
+ this.nextId = nextId;
21498
+ }
21499
+ map = /* @__PURE__ */ new Map();
21500
+ xmls = [];
21501
+ get(spec) {
21502
+ const key = `${spec.t}|${spec.b}|${spec.l}|${spec.r}|${typeof spec.fill === "string" ? spec.fill : spec.fill ? spec.fill.gradient.join("-") : ""}`;
21503
+ const hit = this.map.get(key);
21504
+ if (hit !== void 0) return hit;
21505
+ const id = this.nextId++;
21506
+ this.map.set(key, id);
21507
+ this.xmls.push(
21508
+ borderFillEntry(id, { t: sideOf(spec.t), b: sideOf(spec.b), l: sideOf(spec.l), r: sideOf(spec.r) }, spec.fill)
21509
+ );
21510
+ return id;
21511
+ }
21512
+ /** 등록된 borderFill XML 목록 (등록 순서 = id 순서) */
21513
+ emit() {
21514
+ return this.xmls;
21515
+ }
21516
+ get count() {
21517
+ return this.xmls.length;
21518
+ }
21519
+ };
21520
+ function dataCellSpec(opts) {
21521
+ const { row, rowEnd, col, colEnd, rowCnt, colCnt, headerRows, fill } = opts;
21522
+ const isTop = row === 0;
21523
+ const isBottom = rowEnd === rowCnt - 1;
21524
+ const isHeaderBottom = headerRows > 0 && rowEnd === headerRows - 1;
21525
+ const isBelowHeader = headerRows > 0 && row === headerRows;
21526
+ return {
21527
+ t: isTop ? "thick" : isBelowHeader ? "double" : "thin",
21528
+ b: isBottom ? "thick" : isHeaderBottom ? "double" : "thin",
21529
+ l: col === 0 ? "thick" : "thin",
21530
+ r: colEnd === colCnt - 1 ? "thick" : "thin",
21531
+ fill
21532
+ };
21533
+ }
21534
+
21535
+ // src/hwpx/gen-profile.ts
21536
+ function normalizeAnchor(s) {
21537
+ return s.toLowerCase().replace(/[^\p{L}\p{N}]/gu, "").slice(0, 24);
21538
+ }
21539
+ function takeProfile(remap, rows, cols, anchor, seq) {
21540
+ if (!remap) return null;
21541
+ for (const t of remap.tables) {
21542
+ if (t.used) continue;
21543
+ if (t.rows !== rows || t.cols !== cols) continue;
21544
+ if (t.anchor && anchor) {
21545
+ if (t.anchor !== anchor) continue;
21546
+ } else if (t.index !== seq) {
21547
+ continue;
21548
+ }
21549
+ t.used = true;
21550
+ return t;
21551
+ }
21552
+ return null;
21553
+ }
21554
+ function parseHu(s) {
21555
+ if (s == null) return void 0;
21556
+ const n = parseInt(String(s).trim(), 10);
21557
+ return Number.isFinite(n) ? n : void 0;
21558
+ }
21559
+ function edgeXml(tag, d) {
21560
+ return d ? `<hh:${tag} type="${d.type}" width="${d.width}" color="${d.color}"/>` : `<hh:${tag} type="NONE" width="0.1 mm" color="#000000"/>`;
21561
+ }
21562
+ function borderFillDefToXml(id, def) {
21563
+ const fill = def.fill?.faceColor ? `<hh:fillBrush><hh:winBrush faceColor="${def.fill.faceColor}" hatchColor="#000000" alpha="0"/></hh:fillBrush>` : "";
21564
+ return ` <hh:borderFill id="${id}" threeD="0" shadow="0" centerLine="NONE" breakCellSeparateLine="0">
21565
+ <hh:slash type="NONE" Crooked="0" isCounter="0"/>
21566
+ <hh:backSlash type="NONE" Crooked="0" isCounter="0"/>
21567
+ ${edgeXml("leftBorder", def.leftBorder)}
21568
+ ${edgeXml("rightBorder", def.rightBorder)}
21569
+ ${edgeXml("topBorder", def.topBorder)}
21570
+ ${edgeXml("bottomBorder", def.bottomBorder)}${fill ? `
21571
+ ${fill}` : ""}
21572
+ </hh:borderFill>`;
21573
+ }
21574
+ var PROFILE_FONT_MAX = 2;
21575
+ function profileCharPrXml(id, def) {
21576
+ const height = parseHu(def.height_hwpunit) ?? 1e3;
21577
+ const color = def.textColor ?? "#000000";
21578
+ const rawFont = def.fontRef_hangul != null ? parseInt(def.fontRef_hangul, 10) || 0 : 0;
21579
+ const font = rawFont >= 0 && rawFont <= PROFILE_FONT_MAX ? rawFont : 0;
21580
+ const boldAttr = def.bold ? ` bold="1"` : "";
21581
+ const italicAttr = def.italic ? ` italic="1"` : "";
21582
+ const underline = def.underline ? `
21583
+ <hh:underline type="BOTTOM" shape="SOLID" color="${color}"/>` : "";
21584
+ return ` <hh:charPr id="${id}" height="${height}" textColor="${color}" shadeColor="none" useFontSpace="0" useKerning="0" symMark="NONE" borderFillIDRef="1"${boldAttr}${italicAttr}>
21585
+ <hh:fontRef hangul="${font}" latin="${font}" hanja="${font}" japanese="${font}" other="${font}" symbol="${font}" user="${font}"/>
21586
+ <hh:ratio hangul="100" latin="100" hanja="100" japanese="100" other="100" symbol="100" user="100"/>
21587
+ <hh:spacing hangul="0" latin="0" hanja="0" japanese="0" other="0" symbol="0" user="0"/>
21588
+ <hh:relSz hangul="100" latin="100" hanja="100" japanese="100" other="100" symbol="100" user="100"/>
21589
+ <hh:offset hangul="0" latin="0" hanja="0" japanese="0" other="0" symbol="0" user="0"/>${underline}
21590
+ </hh:charPr>`;
21591
+ }
21592
+ function buildProfileRemap(profile, charPrBase, borderFillBase = 3) {
21593
+ const remap = { borderFillXmls: [], charPrXmls: [], tables: [] };
21594
+ let bfNext = borderFillBase;
21595
+ let charNext = charPrBase;
21596
+ for (const t of profile.tables) {
21597
+ const localBf = {};
21598
+ for (const [key, def] of Object.entries(t.used_border_fills ?? {})) {
21599
+ const gid = bfNext++;
21600
+ remap.borderFillXmls.push(borderFillDefToXml(gid, def));
21601
+ localBf[key] = gid;
21602
+ }
21603
+ const localChar = {};
21604
+ for (const [key, def] of Object.entries(t.used_char_prs ?? {})) {
21605
+ const gid = charNext++;
21606
+ remap.charPrXmls.push(profileCharPrXml(gid, def));
21607
+ localChar[key] = gid;
21608
+ }
21609
+ let colWidths;
21610
+ if (t.col_widths_hwpunit && t.col_widths_hwpunit.length === t.cols) {
21611
+ const parsed = t.col_widths_hwpunit.map(parseHu);
21612
+ if (parsed.every((n) => n != null)) colWidths = parsed;
21613
+ }
21614
+ const tr = {
21615
+ index: t.table_index,
21616
+ rows: t.rows,
21617
+ cols: t.cols,
21618
+ // 재정규화 — 추출기는 정규화해 담지만 손편집된 프로필 JSON도 같은 키 공간으로
21619
+ anchor: t.anchor_text ? normalizeAnchor(t.anchor_text) : void 0,
21620
+ width: parseHu(t.width_hwpunit),
21621
+ colWidths,
21622
+ cellBf: /* @__PURE__ */ new Map(),
21623
+ cellChar: /* @__PURE__ */ new Map(),
21624
+ cellH: /* @__PURE__ */ new Map()
21625
+ };
21626
+ for (const cell2 of t.cells) {
21627
+ const k = `${cell2.row},${cell2.col}`;
21628
+ if (cell2.borderFillIDRef != null && cell2.borderFillIDRef in localBf) {
21629
+ tr.cellBf.set(k, localBf[cell2.borderFillIDRef]);
21630
+ }
21631
+ if (cell2.charPrIDRef != null && cell2.charPrIDRef in localChar) {
21632
+ tr.cellChar.set(k, localChar[cell2.charPrIDRef]);
21633
+ }
21634
+ const h = parseHu(cell2.height_hwpunit);
21635
+ if (h != null) tr.cellH.set(k, h);
21636
+ }
21637
+ remap.tables.push(tr);
21638
+ }
21639
+ return remap;
21640
+ }
21641
+
21085
21642
  // src/hwpx/gen-table.ts
21086
21643
  var TABLE_ID_BASE = 1e3;
21087
21644
  var tableIdCounter = TABLE_ID_BASE;
21088
21645
  function nextTableId() {
21089
21646
  return ++tableIdCounter;
21090
21647
  }
21091
- var warnedTables = /* @__PURE__ */ new Set();
21092
- function warnProfileMismatch(tblId, tp, rowCnt, colCnt) {
21093
- if (warnedTables.has(tblId)) return;
21094
- warnedTables.add(tblId);
21095
- console.warn(`[kordoc] format profile: table ${tp.rows}x${tp.cols} vs document ${rowCnt}x${colCnt} \u2014 \uD504\uB85C\uD544 \uBB34\uC2DC`);
21648
+ var DATA_TABLE_INSET = 1800;
21649
+ function anchorOfMarkdownCell(cell2) {
21650
+ return normalizeAnchor(cell2.replace(/!\[[^\]]*\]\([^)]*\)/g, ""));
21651
+ }
21652
+ function anchorOfHtmlCell(inner) {
21653
+ const noNested = inner.replace(/<table[\s\S]*?<\/table>/gi, "");
21654
+ const { lines } = htmlCellInnerToLines(noNested);
21655
+ return normalizeAnchor(lines.join(""));
21096
21656
  }
21097
- function usableProfile(tp, tblId, rowCnt, colCnt) {
21657
+ function profileColWidths(tp, colCnt) {
21098
21658
  if (!tp) return null;
21099
- if (tp.rows !== rowCnt || tp.cols !== colCnt) {
21100
- warnProfileMismatch(tblId, tp, rowCnt, colCnt);
21101
- return null;
21659
+ if (tp.colWidths && tp.colWidths.length === colCnt) return tp.colWidths;
21660
+ if (tp.width) return Array(colCnt).fill(Math.floor(tp.width / colCnt));
21661
+ return null;
21662
+ }
21663
+ var CELL_PAD = 582;
21664
+ function cellContentWidth(text, charHeight) {
21665
+ let max = 0;
21666
+ for (const seg of text.replace(/\*\*|__|`/g, "").split(/<br\s*\/?>/i)) {
21667
+ const w = measureTextWidth(seg.trim(), charHeight, 100);
21668
+ if (w > max) max = w;
21669
+ }
21670
+ return max;
21671
+ }
21672
+ function computeColWidths(colMax, totalWidth) {
21673
+ const colCnt = colMax.length;
21674
+ const minW = Math.min(Math.max(2e3, Math.round(totalWidth * 0.06)), Math.floor(totalWidth / colCnt));
21675
+ const cap = Math.round(totalWidth * 0.8);
21676
+ const raw = colMax.map((w) => Math.min(Math.max(w + CELL_PAD, minW), cap));
21677
+ const widths = Array(colCnt).fill(0);
21678
+ const free = new Set(raw.map((_, i) => i));
21679
+ let budget = totalWidth;
21680
+ const evenShare = Math.floor(totalWidth / colCnt);
21681
+ for (let i = 0; i < colCnt; i++) {
21682
+ const fixed = Math.min(Math.round(raw[i] * 1.12), evenShare);
21683
+ if (raw[i] <= evenShare && free.size > 1) {
21684
+ widths[i] = fixed;
21685
+ free.delete(i);
21686
+ budget -= fixed;
21687
+ }
21688
+ }
21689
+ if (free.size === 0) {
21690
+ const sumRaw = raw.reduce((a, b) => a + b, 0);
21691
+ for (let i = 0; i < colCnt; i++) widths[i] += Math.floor(raw[i] / sumRaw * (totalWidth - sumRaw));
21692
+ } else {
21693
+ for (; ; ) {
21694
+ const sum2 = [...free].reduce((a, i) => a + raw[i], 0);
21695
+ const short = [...free].filter((i) => raw[i] / sum2 * budget < minW);
21696
+ if (short.length === 0) break;
21697
+ for (const i of short) {
21698
+ widths[i] = minW;
21699
+ free.delete(i);
21700
+ budget -= minW;
21701
+ }
21702
+ if (free.size === 0) break;
21703
+ }
21704
+ const sum = [...free].reduce((a, i) => a + raw[i], 0);
21705
+ for (const i of free) widths[i] = Math.floor(raw[i] / sum * budget);
21102
21706
  }
21103
- return tp;
21707
+ let rem = totalWidth - widths.reduce((a, b) => a + b, 0);
21708
+ const order = [...raw.keys()].sort((a, b) => raw[b] - raw[a]);
21709
+ for (let k = 0; rem > 0; k = (k + 1) % colCnt, rem--) widths[order[k]]++;
21710
+ return widths;
21104
21711
  }
21105
- function resolveColWidths(tp, colCnt, fallbackTotal) {
21106
- if (tp?.colWidths && tp.colWidths.length === colCnt) return tp.colWidths;
21107
- const w = tp?.width ? Math.floor(tp.width / colCnt) : Math.floor(fallbackTotal / colCnt);
21108
- return Array(colCnt).fill(w);
21712
+ function estimateRowHeight(cells, widths, charHeight) {
21713
+ let maxLines = 1;
21714
+ cells.forEach((cell2, c) => {
21715
+ const usable = Math.max((widths[c] ?? widths[widths.length - 1]) - CELL_PAD, 1e3);
21716
+ let lines = 0;
21717
+ for (const seg of cell2.replace(/\*\*|__|`/g, "").split(/<br\s*\/?>/i)) {
21718
+ lines += Math.max(1, Math.ceil(measureTextWidth(seg.trim(), charHeight, 100) / usable));
21719
+ }
21720
+ if (lines > maxLines) maxLines = lines;
21721
+ });
21722
+ return maxLines * Math.round(charHeight * 1.6) + 282;
21109
21723
  }
21110
- function generateTable(rows, theme, tp = null) {
21724
+ function generateTable(rows, theme, style = null, remap = null, seq = 0) {
21111
21725
  const rowCnt = rows.length;
21112
21726
  const colCnt = Math.max(...rows.map((r) => r.length), 1);
21113
- const cellH = 1500;
21727
+ const reg = style?.bfRegistry ?? null;
21728
+ const totalW = style ? reg ? style.totalWidth - DATA_TABLE_INSET : style.totalWidth : 44e3;
21729
+ const measureH = style?.charHeight ?? 1e3;
21730
+ const prof = takeProfile(remap, rowCnt, colCnt, anchorOfMarkdownCell(rows[0]?.[0] ?? ""), seq);
21731
+ const colMax = Array(colCnt).fill(0);
21732
+ const colMaxBody = Array(colCnt).fill(0);
21733
+ rows.forEach((row, r) => row.forEach((cell2, c) => {
21734
+ const w = cellContentWidth(cell2, measureH);
21735
+ if (w > colMax[c]) colMax[c] = w;
21736
+ if (r > 0 && w > colMaxBody[c]) colMaxBody[c] = w;
21737
+ }));
21738
+ const colWidths = profileColWidths(prof, colCnt) ?? computeColWidths(colMax, totalW);
21739
+ const colCentered = colWidths.map((w, c) => colMaxBody[c] + CELL_PAD <= w);
21740
+ const labelCol0 = !!reg && colCnt === 2 && colCentered[0] && rows.every((r) => (r[0] ?? "").replace(/\*\*|__|`/g, "").length <= 12);
21114
21741
  const tblId = nextTableId();
21115
- const prof = usableProfile(tp, tblId, rowCnt, colCnt);
21116
- const colW = resolveColWidths(prof, colCnt, 44e3);
21117
- const tblW = colW.reduce((a, b) => a + b, 0);
21118
- const tblH = cellH * rowCnt;
21119
- const useHeaderStyle = theme.tableHeader !== theme.body || theme.tableHeaderBold;
21742
+ const useHeaderStyle = !style && (theme.tableHeader !== theme.body || theme.tableHeaderBold);
21743
+ const mapId = style ? (id) => id === CHAR_NORMAL ? style.charPr : id === CHAR_BOLD ? style.boldCharPr : id : void 0;
21744
+ const rowHeights = rows.map((row) => style ? estimateRowHeight(row, colWidths, measureH) : 1500);
21120
21745
  const trElements = rows.map((row, rowIdx) => {
21121
21746
  const cells = row.length < colCnt ? [...row, ...Array(colCnt - row.length).fill("")] : row;
21122
21747
  const isHeaderRow = rowIdx === 0;
21123
- const headerCharPr = isHeaderRow && useHeaderStyle ? CHAR_TABLE_HEADER : CHAR_NORMAL;
21124
- const tdElements = cells.map((cell, colIdx) => {
21748
+ const cellH = rowHeights[rowIdx];
21749
+ const baseCharPr = style ? style.charPr : CHAR_NORMAL;
21750
+ const headerCharPr = isHeaderRow && useHeaderStyle ? CHAR_TABLE_HEADER : baseCharPr;
21751
+ const tdElements = cells.map((cell2, colIdx) => {
21125
21752
  const k = `${rowIdx},${colIdx}`;
21126
- const bf = prof?.cellBf.get(k) ?? 2;
21127
- const ch = prof?.cellChar.get(k) ?? headerCharPr;
21753
+ const isLabelCell2 = labelCol0 && colIdx === 0;
21754
+ const defaultCharPr = style ? reg && (isHeaderRow || isLabelCell2) ? style.boldCharPr : style.charPr : isHeaderRow ? headerCharPr : baseCharPr;
21755
+ const cellCharPr = prof?.cellChar.get(k) ?? defaultCharPr;
21756
+ const centered = isHeaderRow || colCentered[colIdx];
21757
+ const paraPrId = style ? centered ? style.tblCenterParaPr ?? style.centerParaPr : reg ? style.tblLeftParaPr ?? PARA_NORMAL : PARA_NORMAL : PARA_NORMAL;
21758
+ const p = cell2.split(/<br\s*\/?>/i).map((seg) => {
21759
+ const runs = generateRuns(seg, cellCharPr, prof?.cellChar.has(k) ? void 0 : mapId);
21760
+ return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0">${runs || `<hp:run charPrIDRef="${cellCharPr}"><hp:t></hp:t></hp:run>`}</hp:p>`;
21761
+ }).join("");
21762
+ const bf = prof?.cellBf.get(k) ?? (reg ? reg.get(dataCellSpec({
21763
+ row: rowIdx,
21764
+ rowEnd: rowIdx,
21765
+ col: colIdx,
21766
+ colEnd: colIdx,
21767
+ rowCnt,
21768
+ colCnt,
21769
+ headerRows: 1,
21770
+ fill: isHeaderRow ? style.headerFill ?? "#E6E6E6" : isLabelCell2 ? style.labelFill ?? "#E7E7E7" : void 0
21771
+ })) : style && isHeaderRow ? style.headerBf : 2);
21128
21772
  const h = prof?.cellH.get(k) ?? cellH;
21129
- const runs = generateRuns(cell, ch);
21130
- const p = `<hp:p paraPrIDRef="0" styleIDRef="0">${runs}</hp:p>`;
21131
- return `<hp:tc name="" header="${isHeaderRow ? 1 : 0}" hasMargin="0" protect="0" editable="1" dirty="0" borderFillIDRef="${bf}"><hp:subList id="" textDirection="HORIZONTAL" lineWrap="BREAK" vertAlign="TOP" linkListIDRef="0" linkListNextIDRef="0" textWidth="0" textHeight="0" hasTextRef="0" hasNumRef="0">${p}</hp:subList><hp:cellAddr colAddr="${colIdx}" rowAddr="${rowIdx}"/><hp:cellSpan colSpan="1" rowSpan="1"/><hp:cellSz width="${colW[colIdx]}" height="${h}"/><hp:cellMargin left="141" right="141" top="141" bottom="141"/></hp:tc>`;
21773
+ return `<hp:tc name="" header="${isHeaderRow ? 1 : 0}" hasMargin="0" protect="0" editable="1" dirty="0" borderFillIDRef="${bf}"><hp:subList id="" textDirection="HORIZONTAL" lineWrap="BREAK" vertAlign="${style ? "CENTER" : "TOP"}" linkListIDRef="0" linkListNextIDRef="0" textWidth="0" textHeight="0" hasTextRef="0" hasNumRef="0">${p}</hp:subList><hp:cellAddr colAddr="${colIdx}" rowAddr="${rowIdx}"/><hp:cellSpan colSpan="1" rowSpan="1"/><hp:cellSz width="${colWidths[colIdx]}" height="${h}"/><hp:cellMargin left="141" right="141" top="141" bottom="141"/></hp:tc>`;
21132
21774
  }).join("");
21133
21775
  return `<hp:tr>${tdElements}</hp:tr>`;
21134
21776
  }).join("");
21777
+ const tblW = colWidths.reduce((a, b) => a + b, 0);
21778
+ const tblH = rowHeights.reduce((a, b) => a + b, 0);
21135
21779
  const tblInner = `<hp:sz width="${tblW}" widthRelTo="ABSOLUTE" height="${tblH}" heightRelTo="ABSOLUTE" protect="0"/><hp:pos treatAsChar="1" affectLSpacing="0" flowWithText="0" allowOverlap="0" holdAnchorAndSO="0" vertRelTo="PARA" horzRelTo="PARA" vertAlign="TOP" horzAlign="LEFT" vertOffset="0" horzOffset="0"/><hp:outMargin left="0" right="0" top="0" bottom="0"/><hp:inMargin left="510" right="510" top="141" bottom="141"/>` + trElements;
21136
- const tbl = `<hp:tbl id="${tblId}" zOrder="0" numberingType="TABLE" pageBreak="CELL" repeatHeader="0" rowCnt="${rowCnt}" colCnt="${colCnt}" cellSpacing="0" borderFillIDRef="2" noShading="0">${tblInner}</hp:tbl>`;
21137
- return `<hp:p paraPrIDRef="0" styleIDRef="0"><hp:run charPrIDRef="0">${tbl}</hp:run></hp:p>`;
21780
+ const tbl2 = `<hp:tbl id="${tblId}" zOrder="0" numberingType="TABLE" pageBreak="CELL" repeatHeader="${style ? 1 : 0}" rowCnt="${rowCnt}" colCnt="${colCnt}" cellSpacing="0" borderFillIDRef="2" noShading="0">${tblInner}</hp:tbl>`;
21781
+ const hostPr = reg && style?.rightParaPr !== void 0 ? style.rightParaPr : 0;
21782
+ return `<hp:p paraPrIDRef="${hostPr}" styleIDRef="0"><hp:run charPrIDRef="0">${tbl2}</hp:run></hp:p>`;
21138
21783
  }
21139
21784
  function layoutHtmlRows(rows) {
21140
21785
  const occupied = /* @__PURE__ */ new Set();
@@ -21142,11 +21787,11 @@ function layoutHtmlRows(rows) {
21142
21787
  let colCnt = 0;
21143
21788
  for (let r = 0; r < rows.length; r++) {
21144
21789
  let c = 0;
21145
- for (const cell of rows[r].cells) {
21790
+ for (const cell2 of rows[r].cells) {
21146
21791
  while (occupied.has(`${r},${c}`)) c++;
21147
- const colSpan = Math.max(1, cell.colSpan);
21148
- const rowSpan = Math.max(1, cell.rowSpan);
21149
- placed.push({ r, c, colSpan, rowSpan, inner: cell.inner, isHeader: rows[r].tag === "th" });
21792
+ const colSpan = Math.max(1, cell2.colSpan);
21793
+ const rowSpan = Math.max(1, cell2.rowSpan);
21794
+ placed.push({ r, c, colSpan, rowSpan, inner: cell2.inner, isHeader: rows[r].tag === "th" });
21150
21795
  for (let dr = 0; dr < rowSpan; dr++) {
21151
21796
  for (let dc = 0; dc < colSpan; dc++) occupied.add(`${r + dr},${c + dc}`);
21152
21797
  }
@@ -21159,49 +21804,135 @@ function layoutHtmlRows(rows) {
21159
21804
  function unescapeHtml(s) {
21160
21805
  return s.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&amp;/g, "&");
21161
21806
  }
21162
- function generateHtmlTableXml(rawHtml, theme, totalWidth = 44e3, tp = null) {
21807
+ function generateHtmlTableXml(rawHtml, theme, totalWidth = 44e3, style = null, remap = null, seq = 0) {
21163
21808
  const rows = parseHtmlTable(rawHtml);
21164
21809
  if (!rows || rows.length === 0) return null;
21165
21810
  const { placed, rowCnt, colCnt } = layoutHtmlRows(rows);
21166
21811
  if (rowCnt === 0 || colCnt === 0) return null;
21167
- const cellH = 1500;
21812
+ const measureH = style?.charHeight ?? 1e3;
21813
+ const first = placed.find((p) => p.r === 0 && p.c === 0) ?? placed[0];
21814
+ const prof = takeProfile(remap, rowCnt, colCnt, first ? anchorOfHtmlCell(first.inner) : "", seq);
21815
+ const colMax = Array(colCnt).fill(0);
21816
+ const colMaxBody = Array(colCnt).fill(0);
21817
+ const cellLines = placed.map((cell2) => htmlCellInnerToLines(cell2.inner).lines);
21818
+ placed.forEach((cell2, i) => {
21819
+ const w = Math.max(...cellLines[i].map((l) => measureTextWidth(unescapeHtml(l).trim(), measureH, 100)), 0) / cell2.colSpan;
21820
+ for (let dc = 0; dc < cell2.colSpan; dc++) {
21821
+ const c = cell2.c + dc;
21822
+ if (w > colMax[c]) colMax[c] = w;
21823
+ if (!cell2.isHeader && w > colMaxBody[c]) colMaxBody[c] = w;
21824
+ }
21825
+ });
21826
+ const colWidths = profileColWidths(prof, colCnt) ?? computeColWidths(colMax, totalWidth);
21827
+ const colCentered = colWidths.map((w, c) => colMaxBody[c] + CELL_PAD <= w);
21828
+ const cellH = style ? Math.round(measureH * 1.6) + 282 : 1500;
21829
+ const tblW = colWidths.reduce((a, b) => a + b, 0);
21168
21830
  const tblId = nextTableId();
21169
- const prof = usableProfile(tp, tblId, rowCnt, colCnt);
21170
- const colW = resolveColWidths(prof, colCnt, totalWidth);
21171
- const tblW = colW.reduce((a, b) => a + b, 0);
21172
- const useHeaderStyle = theme.tableHeader !== theme.body || theme.tableHeaderBold;
21173
- const spanW = (c, colSpan) => colW.slice(c, c + colSpan).reduce((a, b) => a + b, 0);
21174
- const tcXmls = placed.map((cell) => {
21175
- const k = `${cell.r},${cell.c}`;
21176
- const bf = prof?.cellBf.get(k) ?? 2;
21177
- const headerCharPr = cell.isHeader && useHeaderStyle ? CHAR_TABLE_HEADER : CHAR_NORMAL;
21178
- const ch = prof?.cellChar.get(k) ?? headerCharPr;
21179
- const { lines } = htmlCellInnerToLines(cell.inner);
21831
+ const useHeaderStyle = !style && (theme.tableHeader !== theme.body || theme.tableHeaderBold);
21832
+ const spanW = (cell2) => colWidths.slice(cell2.c, cell2.c + cell2.colSpan).reduce((a, b) => a + b, 0);
21833
+ const reg = style?.bfRegistry ?? null;
21834
+ let htmlHeaderRows = 0;
21835
+ while (htmlHeaderRows < rows.length && rows[htmlHeaderRows].tag === "th") htmlHeaderRows++;
21836
+ const tcXmls = placed.map((cell2, i) => {
21837
+ const k = `${cell2.r},${cell2.c}`;
21838
+ const isHeader = cell2.isHeader;
21839
+ const baseCharPr = style ? style.charPr : CHAR_NORMAL;
21840
+ const headerCharPr = isHeader && useHeaderStyle ? CHAR_TABLE_HEADER : baseCharPr;
21841
+ const defaultCharPr = style && reg && isHeader ? style.boldCharPr : isHeader ? headerCharPr : baseCharPr;
21842
+ const charPrId = prof?.cellChar.get(k) ?? defaultCharPr;
21843
+ const centered = isHeader || colCentered[cell2.c];
21844
+ const paraPrId = style ? centered ? reg ? style.tblCenterParaPr ?? style.centerParaPr : style.centerParaPr : reg ? style.tblLeftParaPr ?? PARA_NORMAL : PARA_NORMAL : PARA_NORMAL;
21845
+ const lines = cellLines[i];
21180
21846
  const paras = lines.map(
21181
- (line) => `<hp:p paraPrIDRef="0" styleIDRef="0"><hp:run charPrIDRef="${ch}"><hp:t>${escapeXml(unescapeHtml(line))}</hp:t></hp:run></hp:p>`
21847
+ (line) => `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0"><hp:run charPrIDRef="${charPrId}"><hp:t>${escapeXml(unescapeHtml(line))}</hp:t></hp:run></hp:p>`
21182
21848
  );
21183
- const cellW = spanW(cell.c, cell.colSpan);
21184
21849
  let nestedH = 0;
21185
- for (const nested of extractTopLevelTables(cell.inner)) {
21186
- const nestedXml = generateHtmlTableXml(nested, theme, Math.max(cellW - 1020, 4e3));
21850
+ for (const nested of extractTopLevelTables(cell2.inner)) {
21851
+ const nestedW = Math.max(spanW(cell2) - 1020, 4e3);
21852
+ const nestedXml = generateHtmlTableXml(nested, theme, nestedW, style ? { ...style, totalWidth: nestedW } : null);
21187
21853
  if (nestedXml) {
21188
21854
  paras.push(`<hp:p paraPrIDRef="0" styleIDRef="0"><hp:run charPrIDRef="0">${nestedXml}</hp:run></hp:p>`);
21189
21855
  nestedH += (nested.match(/<tr[\s>]/gi) ?? []).length * cellH + 300;
21190
21856
  }
21191
21857
  }
21192
21858
  if (paras.length === 0) {
21193
- paras.push(`<hp:p paraPrIDRef="0" styleIDRef="0"><hp:run charPrIDRef="${ch}"><hp:t></hp:t></hp:run></hp:p>`);
21859
+ paras.push(`<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0"><hp:run charPrIDRef="${charPrId}"><hp:t></hp:t></hp:run></hp:p>`);
21194
21860
  }
21195
- const contentH = Math.max(cellH * cell.rowSpan, Math.max(lines.length, 1) * 800 + nestedH);
21861
+ const contentH = Math.max(cellH * cell2.rowSpan, Math.max(lines.length, 1) * (style ? Math.round(measureH * 1.6) : 800) + nestedH);
21196
21862
  const cellHeight = Math.max(prof?.cellH.get(k) ?? 0, contentH);
21197
- return `<hp:tc name="" header="${cell.isHeader ? 1 : 0}" hasMargin="0" protect="0" editable="1" dirty="0" borderFillIDRef="${bf}"><hp:subList id="" textDirection="HORIZONTAL" lineWrap="BREAK" vertAlign="TOP" linkListIDRef="0" linkListNextIDRef="0" textWidth="0" textHeight="0" hasTextRef="0" hasNumRef="0">${paras.join("")}</hp:subList><hp:cellAddr colAddr="${cell.c}" rowAddr="${cell.r}"/><hp:cellSpan colSpan="${cell.colSpan}" rowSpan="${cell.rowSpan}"/><hp:cellSz width="${cellW}" height="${cellHeight}"/><hp:cellMargin left="141" right="141" top="141" bottom="141"/></hp:tc>`;
21863
+ const bf = prof?.cellBf.get(k) ?? (reg ? reg.get(dataCellSpec({
21864
+ row: cell2.r,
21865
+ rowEnd: cell2.r + cell2.rowSpan - 1,
21866
+ col: cell2.c,
21867
+ colEnd: cell2.c + cell2.colSpan - 1,
21868
+ rowCnt,
21869
+ colCnt,
21870
+ headerRows: htmlHeaderRows,
21871
+ fill: isHeader ? style.headerFill ?? "#E6E6E6" : void 0
21872
+ })) : style && isHeader ? style.headerBf : 2);
21873
+ return `<hp:tc name="" header="${isHeader ? 1 : 0}" hasMargin="0" protect="0" editable="1" dirty="0" borderFillIDRef="${bf}"><hp:subList id="" textDirection="HORIZONTAL" lineWrap="BREAK" vertAlign="${style ? "CENTER" : "TOP"}" linkListIDRef="0" linkListNextIDRef="0" textWidth="0" textHeight="0" hasTextRef="0" hasNumRef="0">${paras.join("")}</hp:subList><hp:cellAddr colAddr="${cell2.c}" rowAddr="${cell2.r}"/><hp:cellSpan colSpan="${cell2.colSpan}" rowSpan="${cell2.rowSpan}"/><hp:cellSz width="${spanW(cell2)}" height="${cellHeight}"/><hp:cellMargin left="141" right="141" top="141" bottom="141"/></hp:tc>`;
21198
21874
  });
21199
21875
  const trXmls = [];
21200
21876
  for (let r = 0; r < rowCnt; r++) {
21201
21877
  const rowTcs = tcXmls.filter((_, i) => placed[i].r === r);
21202
21878
  trXmls.push(`<hp:tr>${rowTcs.join("")}</hp:tr>`);
21203
21879
  }
21204
- return `<hp:tbl id="${tblId}" zOrder="0" numberingType="TABLE" pageBreak="CELL" repeatHeader="0" rowCnt="${rowCnt}" colCnt="${colCnt}" cellSpacing="0" borderFillIDRef="2" noShading="0"><hp:sz width="${tblW}" widthRelTo="ABSOLUTE" height="${cellH * rowCnt}" heightRelTo="ABSOLUTE" protect="0"/><hp:pos treatAsChar="1" affectLSpacing="0" flowWithText="0" allowOverlap="0" holdAnchorAndSO="0" vertRelTo="PARA" horzRelTo="PARA" vertAlign="TOP" horzAlign="LEFT" vertOffset="0" horzOffset="0"/><hp:outMargin left="0" right="0" top="0" bottom="0"/><hp:inMargin left="510" right="510" top="141" bottom="141"/>` + trXmls.join("") + `</hp:tbl>`;
21880
+ return `<hp:tbl id="${tblId}" zOrder="0" numberingType="TABLE" pageBreak="CELL" repeatHeader="${style ? 1 : 0}" rowCnt="${rowCnt}" colCnt="${colCnt}" cellSpacing="0" borderFillIDRef="2" noShading="0"><hp:sz width="${tblW}" widthRelTo="ABSOLUTE" height="${cellH * rowCnt}" heightRelTo="ABSOLUTE" protect="0"/><hp:pos treatAsChar="1" affectLSpacing="0" flowWithText="0" allowOverlap="0" holdAnchorAndSO="0" vertRelTo="PARA" horzRelTo="PARA" vertAlign="TOP" horzAlign="LEFT" vertOffset="0" horzOffset="0"/><hp:outMargin left="0" right="0" top="0" bottom="0"/><hp:inMargin left="510" right="510" top="141" bottom="141"/>` + trXmls.join("") + `</hp:tbl>`;
21881
+ }
21882
+
21883
+ // src/hwpx/gen-gongmun-extra.ts
21884
+ var extraTableId = 93e5;
21885
+ function tbl(rows, w, h, cols) {
21886
+ return `<hp:tbl id="${++extraTableId}" zOrder="0" numberingType="TABLE" textWrap="TOP_AND_BOTTOM" textFlow="BOTH_SIDES" lock="0" dropcapstyle="None" pageBreak="CELL" repeatHeader="0" rowCnt="${rows.length}" colCnt="${cols}" cellSpacing="0" borderFillIDRef="1" noAdjust="1"><hp:sz width="${w}" widthRelTo="ABSOLUTE" height="${h}" heightRelTo="ABSOLUTE" protect="0"/><hp:pos treatAsChar="1" affectLSpacing="0" flowWithText="1" allowOverlap="0" holdAnchorAndSO="0" vertRelTo="PARA" horzRelTo="PARA" vertAlign="TOP" horzAlign="LEFT" vertOffset="0" horzOffset="0"/><hp:outMargin left="283" right="283" top="283" bottom="283"/><hp:inMargin left="141" right="141" top="141" bottom="141"/>` + rows.map((r) => `<hp:tr>${r}</hp:tr>`).join("") + `</hp:tbl>`;
21887
+ }
21888
+ function tc(opts) {
21889
+ return `<hp:tc name="" header="0" hasMargin="0" protect="0" editable="1" dirty="0" borderFillIDRef="${opts.bf}"><hp:subList id="" textDirection="HORIZONTAL" lineWrap="BREAK" vertAlign="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="1"/><hp:cellSz width="${opts.w}" height="${opts.h}"/><hp:cellMargin left="141" right="141" top="141" bottom="141"/></hp:tc>`;
21890
+ }
21891
+ 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>`;
21893
+ }
21894
+ var APPROVAL_COL_W = 7085;
21895
+ var APPROVAL_LABEL_H = 1100;
21896
+ var APPROVAL_SIGN_H = 4200;
21897
+ function buildApprovalTable(labels, gongmun, reg) {
21898
+ const n = labels.length;
21899
+ const w = APPROVAL_COL_W * n;
21900
+ const bfAt = (row, col) => reg.get({
21901
+ t: row === 0 ? "thick" : "thin",
21902
+ b: row === 1 ? "thick" : "thin",
21903
+ l: col === 0 ? "thick" : "thin",
21904
+ r: col === n - 1 ? "thick" : "thin"
21905
+ });
21906
+ const labelRow = labels.map(
21907
+ (label, c) => tc({ bf: bfAt(0, c), row: 0, col: c, w: APPROVAL_COL_W, h: APPROVAL_LABEL_H, paras: para(label, GONGMUN_TBL_CENTER, CHAR_NORMAL) })
21908
+ ).join("");
21909
+ const signRow = labels.map(
21910
+ (_, c) => tc({ bf: bfAt(1, c), row: 1, col: c, w: APPROVAL_COL_W, h: APPROVAL_SIGN_H, paras: para("", GONGMUN_TBL_CENTER, CHAR_NORMAL) })
21911
+ ).join("");
21912
+ const table2 = tbl([labelRow, signRow], w, APPROVAL_LABEL_H + APPROVAL_SIGN_H, n);
21913
+ return `<hp:p paraPrIDRef="${GONGMUN_RIGHT}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_NORMAL}">${table2}</hp:run></hp:p>`;
21914
+ }
21915
+ function hasEndMark(lastText) {
21916
+ return /끝\s*\.?\s*$/.test(lastText.trim());
21917
+ }
21918
+ function buildEndMark() {
21919
+ return para(" \uB05D.", PARA_NORMAL, CHAR_NORMAL);
21920
+ }
21921
+ var TITLE_BOX = { barH: 382, titleH: 2850, color: "#0080C0", gradient: ["#0080C0", "#3CBFFF"] };
21922
+ function buildTitleBox(title, titleCharPr, bodyWidth, reg) {
21923
+ const w = bodyWidth - 280;
21924
+ const outer = { t: "thin", b: "thin", l: "thin", r: "thin" };
21925
+ const barTop = reg.get({ ...outer, fill: TITLE_BOX.color });
21926
+ const barBottom = reg.get({ ...outer, fill: { gradient: TITLE_BOX.gradient } });
21927
+ const mid = reg.get(outer);
21928
+ const barPara = `<hp:p paraPrIDRef="${GONGMUN_TBL_CENTER}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_NORMAL}"><hp:t></hp:t></hp:run></hp:p>`;
21929
+ const rows = [
21930
+ tc({ bf: barTop, row: 0, col: 0, w, h: TITLE_BOX.barH, paras: barPara }),
21931
+ tc({ bf: mid, row: 1, col: 0, w, h: TITLE_BOX.titleH, paras: para(title, GONGMUN_TBL_CENTER, titleCharPr) }),
21932
+ tc({ bf: barBottom, row: 2, col: 0, w, h: TITLE_BOX.barH, paras: barPara })
21933
+ ];
21934
+ const table2 = tbl(rows, w, TITLE_BOX.barH * 2 + TITLE_BOX.titleH, 1);
21935
+ return `<hp:p paraPrIDRef="${PARA_NORMAL}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_NORMAL}">${table2}</hp:run></hp:p>`;
21205
21936
  }
21206
21937
 
21207
21938
  // src/hwpx/equation-generate.ts
@@ -21491,14 +22222,76 @@ function generateSecPr(gongmun) {
21491
22222
  header: 0,
21492
22223
  footer: 0
21493
22224
  } : { top: 8504, bottom: 4252, left: 5670, right: 4252, header: 2835, footer: 2835 };
21494
- return `<hp:secPr textDirection="HORIZONTAL" spaceColumns="1134" tabStop="8000" outlineShapeIDRef="1" memoShapeIDRef="0" textVerticalWidthHead="0" masterPageCnt="0"><hp:grid lineGrid="0" charGrid="0" wonggojiFormat="0"/><hp:startNum pageStartsOn="BOTH" page="0" pic="0" tbl="0" equation="0"/><hp:visibility hideFirstHeader="0" hideFirstFooter="0" hideFirstMasterPage="0" border="SHOW_ALL" fill="SHOW_ALL" hideFirstPageNum="0" hideFirstEmptyLine="0" showLineNumber="0"/><hp:pagePr landscape="WIDELY" width="59528" height="84188" gutterType="LEFT_ONLY"><hp:margin header="${m.header}" footer="${m.footer}" gutter="0" left="${m.left}" right="${m.right}" top="${m.top}" bottom="${m.bottom}"/></hp:pagePr><hp:footNotePr><hp:autoNumFormat type="DIGIT" userChar="" prefixChar="" suffixChar=")" supscript="0"/><hp:noteLine length="-1" type="SOLID" width="0.12 mm" color="#000000"/><hp:noteSpacing betweenNotes="283" belowLine="567" aboveLine="850"/><hp:numbering type="CONTINUOUS" newNum="1"/><hp:placement place="EACH_COLUMN" beneathText="0"/></hp:footNotePr><hp:endNotePr><hp:autoNumFormat type="DIGIT" userChar="" prefixChar="" suffixChar=")" supscript="0"/><hp:noteLine length="14692344" type="SOLID" width="0.12 mm" color="#000000"/><hp:noteSpacing betweenNotes="0" belowLine="567" aboveLine="850"/><hp:numbering type="CONTINUOUS" newNum="1"/><hp:placement place="END_OF_DOCUMENT" beneathText="0"/></hp:endNotePr></hp:secPr>`;
22225
+ if (gongmun) {
22226
+ m.header = gongmun.headerFooter;
22227
+ m.footer = gongmun.headerFooter;
22228
+ }
22229
+ const secPr = `<hp:secPr textDirection="HORIZONTAL" spaceColumns="1134" tabStop="8000" outlineShapeIDRef="1" memoShapeIDRef="0" textVerticalWidthHead="0" masterPageCnt="0"><hp:grid lineGrid="0" charGrid="0" wonggojiFormat="0"/><hp:startNum pageStartsOn="BOTH" page="0" pic="0" tbl="0" equation="0"/><hp:visibility hideFirstHeader="0" hideFirstFooter="0" hideFirstMasterPage="0" border="SHOW_ALL" fill="SHOW_ALL" hideFirstPageNum="0" hideFirstEmptyLine="0" showLineNumber="0"/><hp:pagePr landscape="WIDELY" width="59528" height="84188" gutterType="LEFT_ONLY"><hp:margin header="${m.header}" footer="${m.footer}" gutter="0" left="${m.left}" right="${m.right}" top="${m.top}" bottom="${m.bottom}"/></hp:pagePr><hp:footNotePr><hp:autoNumFormat type="DIGIT" userChar="" prefixChar="" suffixChar=")" supscript="0"/><hp:noteLine length="-1" type="SOLID" width="0.12 mm" color="#000000"/><hp:noteSpacing betweenNotes="283" belowLine="567" aboveLine="850"/><hp:numbering type="CONTINUOUS" newNum="1"/><hp:placement place="EACH_COLUMN" beneathText="0"/></hp:footNotePr><hp:endNotePr><hp:autoNumFormat type="DIGIT" userChar="" prefixChar="" suffixChar=")" supscript="0"/><hp:noteLine length="14692344" type="SOLID" width="0.12 mm" color="#000000"/><hp:noteSpacing betweenNotes="0" belowLine="567" aboveLine="850"/><hp:numbering type="CONTINUOUS" newNum="1"/><hp:placement place="END_OF_DOCUMENT" beneathText="0"/></hp:endNotePr></hp:secPr>`;
22230
+ return gongmun?.pageNumbers ? secPr + pageNumCtrl() : secPr;
21495
22231
  }
21496
- function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null, fit = null, chartParts = null, remap = null) {
22232
+ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null, fit = null, chartParts = null, bfReg = null, remap = null) {
21497
22233
  const paraXmls = [];
21498
22234
  let isFirst = true;
21499
22235
  let tableSeq = 0;
21500
22236
  const orderedCounters = {};
21501
22237
  let prevWasOrdered = false;
22238
+ const gaejosik = gongmun?.preset === "gaejosik";
22239
+ const vBase = charVariantBase(gaejosik);
22240
+ const tableStyle = gongmun ? {
22241
+ totalWidth: mmToHwpunit(210 - gongmun.margins.left - gongmun.margins.right),
22242
+ charPr: gaejosik ? GJ_CHAR_TABLE : CHAR_NORMAL,
22243
+ boldCharPr: gaejosik ? GJ_CHAR_TABLE_BOLD : CHAR_BOLD,
22244
+ charHeight: gaejosik ? gaejosikSizes(gongmun.bodyHeight, gongmun.sizes).table : gongmun.bodyHeight,
22245
+ headerBf: gongmunTableHeaderBf(gaejosik),
22246
+ centerParaPr: GONGMUN_CENTER,
22247
+ tblCenterParaPr: GONGMUN_TBL_CENTER,
22248
+ tblLeftParaPr: GONGMUN_TBL_LEFT,
22249
+ bfRegistry: bfReg ?? void 0,
22250
+ rightParaPr: GONGMUN_RIGHT
22251
+ } : null;
22252
+ const chamMap = (id) => id === CHAR_BOLD ? GJ_CHAR_CHAM_BOLD : id;
22253
+ let chapterNo = 0;
22254
+ let coverH1Idx = -1;
22255
+ let pendingPageBreak = false;
22256
+ let pendingNewNum = false;
22257
+ let titleBoxH1Idx = -1;
22258
+ let hasFrontPages = false;
22259
+ const preamble = [];
22260
+ if (gongmun?.approval && bfReg) {
22261
+ preamble.push(buildApprovalTable(gongmun.approval, gongmun, bfReg));
22262
+ }
22263
+ if (gaejosik && gongmun) {
22264
+ const h1Idx = blocks.findIndex((b) => b.type === "heading" && (b.level ?? 1) === 1);
22265
+ const chapters = blocks.filter((b) => b.type === "heading" && b.level === 2).map((b) => stripChapterNumber(b.text || ""));
22266
+ let coverTitle = "";
22267
+ const hide = (xml, hideHeader) => gongmun.pageNumbers ? xml.replace(/<hp:run charPrIDRef="(\d+)">/, `<hp:run charPrIDRef="$1">${pageHidingCtrl(hideHeader)}`) : xml;
22268
+ if (gongmun.cover && h1Idx >= 0) {
22269
+ coverTitle = (blocks[h1Idx].text || "").trim();
22270
+ const coverPart = buildGaejosikCover(coverTitle, gongmun);
22271
+ coverPart[0] = hide(coverPart[0], true);
22272
+ preamble.push(...coverPart);
22273
+ coverH1Idx = h1Idx;
22274
+ hasFrontPages = true;
22275
+ }
22276
+ if (gongmun.toc && chapters.length > 0) {
22277
+ const tocPart = buildGaejosikToc(chapters, gongmun);
22278
+ tocPart[0] = hide(tocPart[0], false);
22279
+ preamble.push(...tocPart);
22280
+ hasFrontPages = true;
22281
+ }
22282
+ if (gongmun.bodyTitleBox && coverTitle && hasFrontPages) {
22283
+ preamble.push(buildGaejosikBodyTitle(coverTitle, gongmun).replace(/^<hp:p /, `<hp:p pageBreak="1" `));
22284
+ }
22285
+ } else if (gongmun && !gaejosik && bfReg && (gongmun.preset === "report" || gongmun.preset === "plan" || gongmun.preset === "notice")) {
22286
+ titleBoxH1Idx = blocks.findIndex((b) => b.type === "heading" && (b.level ?? 1) === 1);
22287
+ }
22288
+ if (preamble.length > 0) {
22289
+ preamble[0] = preamble[0].replace(` pageBreak="1"`, "").replace(/<hp:run charPrIDRef="(\d+)">/, `<hp:run charPrIDRef="$1">${generateSecPr(gongmun)}`);
22290
+ isFirst = false;
22291
+ pendingPageBreak = hasFrontPages && !preamble[preamble.length - 1].includes(`pageBreak="1"`);
22292
+ pendingNewNum = !!gongmun.pageNumbers && hasFrontPages;
22293
+ paraXmls.push(...preamble);
22294
+ }
21502
22295
  for (let blockIdx = 0; blockIdx < blocks.length; blockIdx++) {
21503
22296
  const block = blocks[blockIdx];
21504
22297
  let xml = "";
@@ -21510,17 +22303,47 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
21510
22303
  }
21511
22304
  switch (block.type) {
21512
22305
  case "heading": {
22306
+ if (gongmun && blockIdx === titleBoxH1Idx && tableStyle && bfReg) {
22307
+ xml = buildTitleBox((block.text || "").trim(), CHAR_H1, tableStyle.totalWidth, bfReg);
22308
+ break;
22309
+ }
22310
+ if (gaejosik) {
22311
+ const lvl = block.level || 1;
22312
+ if (blockIdx === coverH1Idx) break;
22313
+ if (lvl <= 2) {
22314
+ chapterNo++;
22315
+ xml = buildGaejosikChapter(chapterNo, stripChapterNumber(block.text || ""), gongmun);
22316
+ } else if (lvl === 3) {
22317
+ xml = generateParagraph(
22318
+ `\u25A1 ${block.text || ""}`,
22319
+ GONGMUN_LIST_BASE,
22320
+ GJ_CHAR_DAE,
22321
+ (id) => id === CHAR_BOLD ? GJ_CHAR_DAE_BOLD : id
22322
+ );
22323
+ } else {
22324
+ xml = generateParagraph(`\u25CB ${block.text || ""}`, GONGMUN_LIST_BASE + 1, CHAR_NORMAL);
22325
+ }
22326
+ break;
22327
+ }
21513
22328
  const pId = headingParaPrId(block.level || 1);
21514
22329
  const cId = headingCharPrId(block.level || 1);
21515
- xml = generateParagraph(block.text || "", pId, cId);
22330
+ const styleId = gongmun ? Math.min(block.level || 1, 4) : 0;
22331
+ xml = generateParagraph(block.text || "", pId, cId, void 0, styleId);
21516
22332
  break;
21517
22333
  }
21518
22334
  case "paragraph": {
22335
+ if (gaejosik && (block.text || "").trimStart().startsWith("\u203B")) {
22336
+ xml = generateParagraph((block.text || "").trim(), GJ_PARA_CHAM, GJ_CHAR_CHAM, chamMap);
22337
+ break;
22338
+ }
21519
22339
  const ctr = gongmun && /^<center>([\s\S]*)<\/center>$/i.exec((block.text || "").trim());
22340
+ const rgt = gongmun && /^<right>([\s\S]*)<\/right>$/i.exec((block.text || "").trim());
21520
22341
  if (ctr) {
21521
22342
  xml = generateParagraph(ctr[1].trim(), GONGMUN_CENTER);
22343
+ } else if (rgt) {
22344
+ xml = generateParagraph(rgt[1].trim(), GONGMUN_RIGHT);
21522
22345
  } else {
21523
- xml = generateParagraph(block.text || "", PARA_NORMAL, CHAR_NORMAL, fit ? variantMapper(fit, blockIdx) : void 0);
22346
+ xml = generateParagraph(block.text || "", PARA_NORMAL, CHAR_NORMAL, fit ? variantMapper(fit, blockIdx, vBase) : void 0);
21524
22347
  }
21525
22348
  break;
21526
22349
  }
@@ -21553,22 +22376,37 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
21553
22376
  xml = generateEquationParagraph(block.text || "", blockIdx);
21554
22377
  break;
21555
22378
  }
21556
- case "blockquote":
22379
+ case "blockquote": {
22380
+ if (gaejosik) {
22381
+ const t = (block.text || "").trim();
22382
+ if (t) xml = generateParagraph(t.startsWith("\u203B") ? t : `\u203B ${t}`, GJ_PARA_CHAM, GJ_CHAR_CHAM, chamMap);
22383
+ break;
22384
+ }
21557
22385
  xml = generateParagraph(
21558
22386
  block.text || "",
21559
22387
  PARA_QUOTE,
21560
22388
  theme.hasQuoteOption ? CHAR_QUOTE : CHAR_NORMAL
21561
22389
  );
21562
22390
  break;
22391
+ }
21563
22392
  case "list_item": {
21564
22393
  if (gongmun && gongmunList) {
21565
22394
  const info = gongmunList.get(blockIdx);
21566
22395
  const depth = info?.depth ?? 0;
21567
22396
  const marker2 = info?.marker ?? "";
21568
22397
  const content = block.text || "";
22398
+ if (gaejosik && content.trimStart().startsWith("\u203B")) {
22399
+ xml = generateParagraph(content.trim(), GJ_PARA_CHAM, GJ_CHAR_CHAM, chamMap);
22400
+ break;
22401
+ }
21569
22402
  const text = marker2 ? `${marker2} ${content}` : content;
21570
- const listCharPr = gongmun.numbering === "report" && depth === 0 ? CHAR_BOLD : CHAR_NORMAL;
21571
- xml = generateParagraph(text, GONGMUN_LIST_BASE + depth, listCharPr, fit ? variantMapper(fit, blockIdx) : void 0);
22403
+ let listCharPr = gongmun.numbering === "report" && depth === 0 ? CHAR_BOLD : CHAR_NORMAL;
22404
+ let mapId = fit ? variantMapper(fit, blockIdx, vBase) : void 0;
22405
+ if (gaejosik && depth === 0) {
22406
+ listCharPr = GJ_CHAR_DAE;
22407
+ mapId = (id) => id === CHAR_BOLD ? GJ_CHAR_DAE_BOLD : id;
22408
+ }
22409
+ xml = generateParagraph(text, GONGMUN_LIST_BASE + depth, listCharPr, mapId);
21572
22410
  break;
21573
22411
  }
21574
22412
  const indent = block.indent || 0;
@@ -21595,7 +22433,7 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
21595
22433
  break;
21596
22434
  }
21597
22435
  case "hr":
21598
- xml = `<hp:p paraPrIDRef="0" styleIDRef="0"><hp:run charPrIDRef="0"><hp:t>\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500</hp:t></hp:run></hp:p>`;
22436
+ xml = gongmun ? `<hp:p paraPrIDRef="${PARA_NORMAL}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_NORMAL}"><hp:t></hp:t></hp:run></hp:p>` : `<hp:p paraPrIDRef="0" styleIDRef="0"><hp:run charPrIDRef="0"><hp:t>\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500</hp:t></hp:run></hp:p>`;
21599
22437
  break;
21600
22438
  case "table":
21601
22439
  if (block.rows) {
@@ -21604,20 +22442,19 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
21604
22442
  paraXmls.push(`<hp:p paraPrIDRef="0" styleIDRef="0">${secRun}</hp:p>`);
21605
22443
  isFirst = false;
21606
22444
  }
21607
- xml = generateTable(block.rows, theme, remap?.tables.get(tableSeq) ?? null);
21608
- tableSeq++;
22445
+ xml = generateTable(block.rows, theme, tableStyle, remap, tableSeq++);
21609
22446
  }
21610
22447
  break;
21611
22448
  case "html_table": {
21612
- const tbl = generateHtmlTableXml(block.text || "", theme, 44e3, remap?.tables.get(tableSeq) ?? null);
21613
- if (tbl) {
22449
+ const htmlW = tableStyle ? bfReg ? tableStyle.totalWidth - DATA_TABLE_INSET : tableStyle.totalWidth : 44e3;
22450
+ const tbl2 = generateHtmlTableXml(block.text || "", theme, htmlW, tableStyle, remap, tableSeq++);
22451
+ if (tbl2) {
21614
22452
  if (isFirst) {
21615
22453
  const secRun = `<hp:run charPrIDRef="0">${generateSecPr(gongmun)}<hp:t></hp:t></hp:run>`;
21616
22454
  paraXmls.push(`<hp:p paraPrIDRef="0" styleIDRef="0">${secRun}</hp:p>`);
21617
22455
  isFirst = false;
21618
22456
  }
21619
- xml = `<hp:p paraPrIDRef="0" styleIDRef="0"><hp:run charPrIDRef="0">${tbl}</hp:run></hp:p>`;
21620
- tableSeq++;
22457
+ xml = `<hp:p paraPrIDRef="${tableStyle && bfReg ? GONGMUN_RIGHT : 0}" styleIDRef="0"><hp:run charPrIDRef="0">${tbl2}</hp:run></hp:p>`;
21621
22458
  } else {
21622
22459
  const plain = (block.text || "").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
21623
22460
  xml = plain ? generateParagraph(plain) : "";
@@ -21633,8 +22470,20 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
21633
22470
  );
21634
22471
  isFirst = false;
21635
22472
  }
22473
+ if (pendingPageBreak) {
22474
+ xml = xml.replace(/^<hp:p /, `<hp:p pageBreak="1" `);
22475
+ pendingPageBreak = false;
22476
+ }
22477
+ if (pendingNewNum) {
22478
+ xml = xml.replace(/<hp:run charPrIDRef="(\d+)">/, `<hp:run charPrIDRef="$1">${newPageNumCtrl(1)}`);
22479
+ pendingNewNum = false;
22480
+ }
21636
22481
  paraXmls.push(xml);
21637
22482
  }
22483
+ if (gongmun?.endMark && paraXmls.length > 0) {
22484
+ const lastText = [...blocks].reverse().find((b) => (b.type === "paragraph" || b.type === "list_item") && (b.text || "").trim())?.text ?? "";
22485
+ if (!hasEndMark(lastText)) paraXmls.push(buildEndMark());
22486
+ }
21638
22487
  if (paraXmls.length === 0) {
21639
22488
  paraXmls.push(`<hp:p paraPrIDRef="0" styleIDRef="0"><hp:run charPrIDRef="0">${generateSecPr(gongmun)}<hp:t></hp:t></hp:run></hp:p>`);
21640
22489
  }
@@ -21644,108 +22493,31 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
21644
22493
  </hs:sec>`;
21645
22494
  }
21646
22495
 
21647
- // src/hwpx/gen-profile.ts
21648
- function parseHu(s) {
21649
- if (s == null) return void 0;
21650
- const n = parseInt(String(s).trim(), 10);
21651
- return Number.isFinite(n) ? n : void 0;
21652
- }
21653
- function edgeXml(tag, d) {
21654
- return d ? `<hh:${tag} type="${d.type}" width="${d.width}" color="${d.color}"/>` : `<hh:${tag} type="NONE" width="0.1 mm" color="#000000"/>`;
21655
- }
21656
- function borderFillDefToXml(id, def) {
21657
- const fill = def.fill?.faceColor ? `<hh:fillBrush><hh:winBrush faceColor="${def.fill.faceColor}" hatchColor="#000000" alpha="0"/></hh:fillBrush>` : "";
21658
- return ` <hh:borderFill id="${id}" threeD="0" shadow="0" centerLine="NONE" breakCellSeparateLine="0">
21659
- <hh:slash type="NONE" Crooked="0" isCounter="0"/>
21660
- <hh:backSlash type="NONE" Crooked="0" isCounter="0"/>
21661
- ${edgeXml("leftBorder", def.leftBorder)}
21662
- ${edgeXml("rightBorder", def.rightBorder)}
21663
- ${edgeXml("topBorder", def.topBorder)}
21664
- ${edgeXml("bottomBorder", def.bottomBorder)}${fill ? `
21665
- ${fill}` : ""}
21666
- </hh:borderFill>`;
21667
- }
21668
- function profileCharPrXml(id, def) {
21669
- const height = parseHu(def.height_hwpunit) ?? 1e3;
21670
- const color = def.textColor ?? "#000000";
21671
- const font = def.fontRef_hangul != null ? parseInt(def.fontRef_hangul, 10) || 0 : 0;
21672
- const boldAttr = def.bold ? ` bold="1"` : "";
21673
- const italicAttr = def.italic ? ` italic="1"` : "";
21674
- const underline = def.underline ? `
21675
- <hh:underline type="BOTTOM" shape="SOLID" color="${color}"/>` : "";
21676
- return ` <hh:charPr id="${id}" height="${height}" textColor="${color}" shadeColor="none" useFontSpace="0" useKerning="0" symMark="NONE" borderFillIDRef="1"${boldAttr}${italicAttr}>
21677
- <hh:fontRef hangul="${font}" latin="${font}" hanja="${font}" japanese="${font}" other="${font}" symbol="${font}" user="${font}"/>
21678
- <hh:ratio hangul="100" latin="100" hanja="100" japanese="100" other="100" symbol="100" user="100"/>
21679
- <hh:spacing hangul="0" latin="0" hanja="0" japanese="0" other="0" symbol="0" user="0"/>
21680
- <hh:relSz hangul="100" latin="100" hanja="100" japanese="100" other="100" symbol="100" user="100"/>
21681
- <hh:offset hangul="0" latin="0" hanja="0" japanese="0" other="0" symbol="0" user="0"/>${underline}
21682
- </hh:charPr>`;
21683
- }
21684
- function buildProfileRemap(profile, charPrBase, borderFillBase = 3) {
21685
- const remap = { borderFillXmls: [], charPrXmls: [], tables: /* @__PURE__ */ new Map() };
21686
- let bfNext = borderFillBase;
21687
- let charNext = charPrBase;
21688
- for (const t of profile.tables) {
21689
- const localBf = {};
21690
- for (const [key, def] of Object.entries(t.used_border_fills ?? {})) {
21691
- const gid = bfNext++;
21692
- remap.borderFillXmls.push(borderFillDefToXml(gid, def));
21693
- localBf[key] = gid;
21694
- }
21695
- const localChar = {};
21696
- for (const [key, def] of Object.entries(t.used_char_prs ?? {})) {
21697
- const gid = charNext++;
21698
- remap.charPrXmls.push(profileCharPrXml(gid, def));
21699
- localChar[key] = gid;
21700
- }
21701
- let colWidths;
21702
- if (t.col_widths_hwpunit && t.col_widths_hwpunit.length === t.cols) {
21703
- const parsed = t.col_widths_hwpunit.map(parseHu);
21704
- if (parsed.every((n) => n != null)) colWidths = parsed;
21705
- }
21706
- const tr = {
21707
- rows: t.rows,
21708
- cols: t.cols,
21709
- width: parseHu(t.width_hwpunit),
21710
- colWidths,
21711
- cellBf: /* @__PURE__ */ new Map(),
21712
- cellChar: /* @__PURE__ */ new Map(),
21713
- cellH: /* @__PURE__ */ new Map()
21714
- };
21715
- for (const cell of t.cells) {
21716
- const k = `${cell.row},${cell.col}`;
21717
- if (cell.borderFillIDRef != null && cell.borderFillIDRef in localBf) {
21718
- tr.cellBf.set(k, localBf[cell.borderFillIDRef]);
21719
- }
21720
- if (cell.charPrIDRef != null && cell.charPrIDRef in localChar) {
21721
- tr.cellChar.set(k, localChar[cell.charPrIDRef]);
21722
- }
21723
- const h = parseHu(cell.height_hwpunit);
21724
- if (h != null) tr.cellH.set(k, h);
21725
- }
21726
- remap.tables.set(t.table_index, tr);
21727
- }
21728
- return remap;
21729
- }
21730
- function profileCharPrBase(ratioVariantCount) {
21731
- return CHAR_VARIANT_BASE + ratioVariantCount * 4;
21732
- }
21733
-
21734
22496
  // src/hwpx/generator.ts
21735
22497
  async function markdownToHwpx(markdown, options) {
21736
22498
  const theme = resolveTheme(options?.theme);
21737
22499
  const gongmun = options?.gongmun ? resolveGongmun(options.gongmun) : null;
22500
+ const gaejosik = gongmun?.preset === "gaejosik";
21738
22501
  const blocks = parseMarkdownToBlocks(markdown);
21739
22502
  const gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null;
21740
22503
  const fit = gongmun && gongmunList ? computeGongmunFitPlan(blocks, gongmun, gongmunList) : null;
21741
- const remap = options?.profile ? buildProfileRemap(options.profile, profileCharPrBase(fit?.variants?.length ?? 0)) : null;
22504
+ const staticBfEnd = gongmun ? gaejosik ? 11 : 4 : 3;
22505
+ const remap = options?.profile ? buildProfileRemap(options.profile, charVariantBase(gaejosik) + (fit?.variants?.length ?? 0) * 4, staticBfEnd) : null;
22506
+ const bfReg = gongmun ? new TableBfRegistry(staticBfEnd + (remap?.borderFillXmls.length ?? 0)) : null;
21742
22507
  const chartParts = [];
21743
- const sectionXml = blocksToSectionXml(blocks, theme, gongmun, gongmunList, fit, chartParts, remap);
22508
+ const sectionXml = blocksToSectionXml(blocks, theme, gongmun, gongmunList, fit, chartParts, bfReg, remap);
22509
+ if (remap && remap.tables.length > 0) {
22510
+ const unused = remap.tables.filter((t) => !t.used).length;
22511
+ if (unused === remap.tables.length) {
22512
+ console.warn(`[kordoc] format profile: \uD504\uB85C\uD544 \uD45C ${unused}\uAC1C\uAC00 \uBB38\uC11C \uD45C\uC640 \uB9E4\uCE6D\uB418\uC9C0 \uC54A\uC544 \uBBF8\uC801\uC6A9 (\uD589\xB7\uC5F4/\uCCAB \uC140 \uD14D\uC2A4\uD2B8 \uBD88\uC77C\uCE58)`);
22513
+ }
22514
+ }
22515
+ const extraBorderFills = [...remap?.borderFillXmls ?? [], ...bfReg?.emit() ?? []];
21744
22516
  const zip = new JSZip6();
21745
22517
  zip.file("mimetype", "application/hwp+zip", { compression: "STORE" });
21746
22518
  zip.file("META-INF/container.xml", generateContainerXml());
21747
22519
  zip.file("Contents/content.hpf", generateManifest(chartParts));
21748
- zip.file("Contents/header.xml", generateHeaderXml(theme, gongmun, fit?.variants ?? [], remap));
22520
+ zip.file("Contents/header.xml", generateHeaderXml(theme, gongmun, fit?.variants ?? [], extraBorderFills, remap?.charPrXmls ?? []));
21749
22521
  zip.file("Contents/section0.xml", sectionXml);
21750
22522
  for (const part of chartParts) zip.file(part.name, part.xml);
21751
22523
  zip.file("Preview/PrvText.txt", buildPrvText(blocks));
@@ -21944,8 +22716,8 @@ function parseCharPrs(headerDoc) {
21944
22716
  }
21945
22717
  return map;
21946
22718
  }
21947
- function isTopLevelTable(tbl) {
21948
- let p = tbl.parentNode;
22719
+ function isTopLevelTable(tbl2) {
22720
+ let p = tbl2.parentNode;
21949
22721
  while (p) {
21950
22722
  const tag = (p.tagName || p.localName || "").replace(/^[^:]+:/, "");
21951
22723
  if (tag === "tbl") return false;
@@ -21958,57 +22730,61 @@ function num(s) {
21958
22730
  const n = parseInt(s, 10);
21959
22731
  return Number.isFinite(n) ? n : void 0;
21960
22732
  }
21961
- function parseTable3(tbl, tableIndex, borderFills, charPrs) {
21962
- const rows = num(tbl.getAttribute("rowCnt")) ?? 0;
21963
- const cols = num(tbl.getAttribute("colCnt")) ?? 0;
21964
- const sz = findChildByLocalName(tbl, "sz");
22733
+ function parseTable3(tbl2, tableIndex, borderFills, charPrs) {
22734
+ const rows = num(tbl2.getAttribute("rowCnt")) ?? 0;
22735
+ const cols = num(tbl2.getAttribute("colCnt")) ?? 0;
22736
+ const sz = findChildByLocalName(tbl2, "sz");
21965
22737
  const width = sz?.getAttribute("width") || void 0;
21966
22738
  const cells = [];
21967
22739
  const usedBf = /* @__PURE__ */ new Set();
21968
22740
  const usedCp = /* @__PURE__ */ new Set();
21969
22741
  const colWidths = new Array(cols).fill(void 0);
21970
- for (const tc of elemsByLocal(tbl, "tc")) {
21971
- if (nearestTable(tc) !== tbl) continue;
21972
- const addr = findChildByLocalName(tc, "cellAddr");
21973
- const span = findChildByLocalName(tc, "cellSpan");
21974
- const csz = findChildByLocalName(tc, "cellSz");
22742
+ let anchorText = "";
22743
+ for (const tc2 of elemsByLocal(tbl2, "tc")) {
22744
+ if (nearestTable(tc2) !== tbl2) continue;
22745
+ const addr = findChildByLocalName(tc2, "cellAddr");
22746
+ const span = findChildByLocalName(tc2, "cellSpan");
22747
+ const csz = findChildByLocalName(tc2, "cellSz");
21975
22748
  const row = num(addr?.getAttribute("rowAddr")) ?? 0;
21976
22749
  const col = num(addr?.getAttribute("colAddr")) ?? 0;
22750
+ if (row === 0 && col === 0 && !anchorText) anchorText = directCellText(tc2);
21977
22751
  const colSpan = num(span?.getAttribute("colSpan")) ?? 1;
21978
22752
  const rowSpan = num(span?.getAttribute("rowSpan")) ?? 1;
21979
- const bfId = tc.getAttribute("borderFillIDRef") || void 0;
21980
- const cpId = firstRunCharPr(tc);
21981
- const cell = { row, col, rowSpan, colSpan };
22753
+ const bfId = tc2.getAttribute("borderFillIDRef") || void 0;
22754
+ const cpId = firstRunCharPr(tc2);
22755
+ const cell2 = { row, col, rowSpan, colSpan };
21982
22756
  const w = csz?.getAttribute("width");
21983
22757
  const hh = csz?.getAttribute("height");
21984
- if (w) cell.width_hwpunit = w;
21985
- if (hh) cell.height_hwpunit = hh;
22758
+ if (w) cell2.width_hwpunit = w;
22759
+ if (hh) cell2.height_hwpunit = hh;
21986
22760
  if (bfId) {
21987
- cell.borderFillIDRef = bfId;
22761
+ cell2.borderFillIDRef = bfId;
21988
22762
  usedBf.add(bfId);
21989
22763
  }
21990
22764
  if (cpId) {
21991
- cell.charPrIDRef = cpId;
22765
+ cell2.charPrIDRef = cpId;
21992
22766
  usedCp.add(cpId);
21993
22767
  }
21994
- cells.push(cell);
22768
+ cells.push(cell2);
21995
22769
  if (row === 0 && colSpan === 1 && col < cols && w) colWidths[col] = w;
21996
22770
  }
21997
- const table = {
22771
+ const table2 = {
21998
22772
  table_index: tableIndex,
21999
22773
  rows,
22000
22774
  cols,
22001
22775
  cells,
22002
22776
  used_border_fills: pick(borderFills, usedBf)
22003
22777
  };
22004
- if (width) table.width_hwpunit = width;
22005
- if (colWidths.every((w) => w != null)) table.col_widths_hwpunit = colWidths;
22778
+ const anchor = normalizeAnchor(anchorText);
22779
+ if (anchor) table2.anchor_text = anchor;
22780
+ if (width) table2.width_hwpunit = width;
22781
+ if (colWidths.every((w) => w != null)) table2.col_widths_hwpunit = colWidths;
22006
22782
  const cp = pick(charPrs, usedCp);
22007
- if (Object.keys(cp).length) table.used_char_prs = cp;
22008
- return table;
22783
+ if (Object.keys(cp).length) table2.used_char_prs = cp;
22784
+ return table2;
22009
22785
  }
22010
- function nearestTable(tc) {
22011
- let p = tc.parentNode;
22786
+ function nearestTable(tc2) {
22787
+ let p = tc2.parentNode;
22012
22788
  while (p) {
22013
22789
  const tag = (p.tagName || p.localName || "").replace(/^[^:]+:/, "");
22014
22790
  if (tag === "tbl") return p;
@@ -22016,9 +22792,9 @@ function nearestTable(tc) {
22016
22792
  }
22017
22793
  return null;
22018
22794
  }
22019
- function firstRunCharPr(tc) {
22020
- for (const run of elemsByLocal(tc, "run")) {
22021
- if (nearestCell(run) !== tc) continue;
22795
+ function firstRunCharPr(tc2) {
22796
+ for (const run of elemsByLocal(tc2, "run")) {
22797
+ if (nearestCell(run) !== tc2) continue;
22022
22798
  const id = run.getAttribute("charPrIDRef");
22023
22799
  if (id) return id;
22024
22800
  }
@@ -22033,6 +22809,15 @@ function nearestCell(el) {
22033
22809
  }
22034
22810
  return null;
22035
22811
  }
22812
+ function directCellText(tc2) {
22813
+ let out = "";
22814
+ for (const t of elemsByLocal(tc2, "t")) {
22815
+ if (nearestCell(t) !== tc2) continue;
22816
+ out += t.textContent ?? "";
22817
+ if (out.length >= 64) break;
22818
+ }
22819
+ return out;
22820
+ }
22036
22821
  function pick(map, keys) {
22037
22822
  const out = {};
22038
22823
  for (const k of keys) {
@@ -22056,12 +22841,166 @@ async function hwpxToProfile(input) {
22056
22841
  let tableIndex = 0;
22057
22842
  for (const f of sectionFiles) {
22058
22843
  const doc = parser.parseFromString(await f.async("text"), "text/xml");
22059
- for (const tbl of elemsByLocal(doc, "tbl")) {
22060
- if (!isTopLevelTable(tbl)) continue;
22061
- tables.push(parseTable3(tbl, tableIndex++, borderFills, charPrs));
22844
+ for (const tbl2 of elemsByLocal(doc, "tbl")) {
22845
+ if (!isTopLevelTable(tbl2)) continue;
22846
+ tables.push(parseTable3(tbl2, tableIndex++, borderFills, charPrs));
22062
22847
  }
22063
22848
  }
22064
- return { schema_version: "0.1.0", tables };
22849
+ return { schema_version: "0.2.0", tables };
22850
+ }
22851
+
22852
+ // src/hwpx/font-catalog.ts
22853
+ var HANCOM_BUNDLED = [
22854
+ "\uD568\uCD08\uB86C\uBC14\uD0D5",
22855
+ "\uD568\uCD08\uB86C\uB3CB\uC6C0",
22856
+ "\uD55C\uCEF4\uBC14\uD0D5",
22857
+ "\uD55C\uCEF4\uB3CB\uC6C0",
22858
+ "\uD55C\uCEF4 \uACE0\uB515",
22859
+ "\uD55C\uCEF4\uACE0\uB515",
22860
+ "\uD55C\uCEF4 \uB9D0\uB791\uB9D0\uB791",
22861
+ "\uD55C\uCEF4\uC0B0\uB73B\uB3CB\uC6C0",
22862
+ "\uD55C\uCEF4\uC194\uC78E",
22863
+ "HY\uD5E4\uB4DC\uB77C\uC778M",
22864
+ "HY\uACAC\uACE0\uB515",
22865
+ "HY\uACAC\uBA85\uC870",
22866
+ "HY\uC911\uACE0\uB515",
22867
+ "HY\uC2E0\uBA85\uC870",
22868
+ "HY\uBA85\uC870",
22869
+ "HY\uADF8\uB798\uD53DM",
22870
+ "HY\uAD81\uC11C",
22871
+ "HY\uAC15M",
22872
+ "HY\uAC15B",
22873
+ "HY\uC6B8\uB989\uB3C4M",
22874
+ "HY\uC6B8\uB989\uB3C4B",
22875
+ "HY\uD0DC\uBC31B",
22876
+ "HY\uC218\uD3C9\uC120M",
22877
+ "HY\uC218\uD3C9\uC120B",
22878
+ "HY\uC13C\uC2A4L",
22879
+ "HY\uC595\uC740\uC0D8\uBB3CM",
22880
+ "HY\uBAA9\uD310L",
22881
+ "HY\uC5FD\uC11CM",
22882
+ "HY\uC5FD\uC11CL",
22883
+ "HY\uB3D9\uB158M",
22884
+ "HY\uB3D9\uB158B",
22885
+ "\uD55C\uC591\uC2E0\uBA85\uC870",
22886
+ "\uD55C\uC591\uC911\uACE0\uB515",
22887
+ "\uD55C\uC591\uACAC\uBA85\uC870",
22888
+ "\uD55C\uC591\uACAC\uACE0\uB515",
22889
+ "\uD55C\uC591\uAD81\uC11C",
22890
+ "\uD55C\uC591\uADF8\uB798\uD53D",
22891
+ "\uD734\uBA3C\uBA85\uC870",
22892
+ "\uD734\uBA3C\uACE0\uB515",
22893
+ "\uD734\uBA3C\uAD75\uC740\uD338\uCCB4",
22894
+ "\uD734\uBA3C\uAC00\uB294\uD338\uCCB4",
22895
+ "\uD734\uBA3C\uAD75\uC740\uC0D8\uCCB4",
22896
+ "\uD734\uBA3C\uAC00\uB294\uC0D8\uCCB4",
22897
+ "\uD734\uBA3C\uC61B\uCCB4",
22898
+ "\uD734\uBA3C\uC544\uBBF8\uCCB4",
22899
+ "\uD734\uBA3C\uD3B8\uC9C0\uCCB4",
22900
+ "\uD734\uBA3C\uB465\uADFC\uD5E4\uB4DC\uB77C\uC778",
22901
+ "\uD734\uBA3C\uBAA8\uC74CT",
22902
+ "\uD0DC \uB098\uBB34",
22903
+ "\uD0DC \uADF8\uB298",
22904
+ "\uC591\uC7AC\uAE68\uBE44\uCCB4B",
22905
+ "\uC591\uC7AC\uB09C\uCD08\uCCB4M",
22906
+ "\uC591\uC7AC\uB458\uAE30\uCCB4M",
22907
+ "\uC591\uC7AC\uBE14\uB7ED\uCCB4",
22908
+ "\uBB38\uCCB4\uBD80 \uAD81\uCCB4 \uC815\uC790\uCCB4",
22909
+ "\uBB38\uCCB4\uBD80 \uAD81\uCCB4 \uD758\uB9BC\uCCB4",
22910
+ "\uBB38\uCCB4\uBD80 \uB3CB\uC6C0\uCCB4",
22911
+ "\uBB38\uCCB4\uBD80 \uBC14\uD0D5\uCCB4",
22912
+ "\uBB38\uCCB4\uBD80 \uC4F0\uAE30 \uC815\uCCB4",
22913
+ "\uBB38\uCCB4\uBD80 \uC81C\uBAA9 \uB3CB\uC6C0\uCCB4",
22914
+ "\uBB38\uCCB4\uBD80 \uC81C\uBAA9 \uBC14\uD0D5\uCCB4",
22915
+ "\uC2E0\uBA85 \uC2E0\uBA85\uC870",
22916
+ "\uC2E0\uBA85 \uC2E0\uC2E0\uBA85\uC870",
22917
+ "\uC2E0\uBA85 \uACAC\uBA85\uC870",
22918
+ "\uC2E0\uBA85 \uC911\uACE0\uB515",
22919
+ "\uC2E0\uBA85 \uD0DC\uACE0\uB515",
22920
+ "\uC2E0\uBA85 \uACAC\uACE0\uB515",
22921
+ "\uC2E0\uBA85 \uC2E0\uBB38\uBA85\uC870",
22922
+ "MD\uAC1C\uC131\uCCB4",
22923
+ "MD\uC544\uB871\uCCB4",
22924
+ "MD\uC194\uCCB4",
22925
+ "MD\uC774\uC19D\uCCB4",
22926
+ "MD\uC544\uD2B8\uCCB4",
22927
+ "\uAC00\uB294\uC548\uC0C1\uC218\uCCB4",
22928
+ "\uC911\uAC04\uC548\uC0C1\uC218\uCCB4",
22929
+ "\uAD75\uC740\uC548\uC0C1\uC218\uCCB4",
22930
+ "HCI Poppy",
22931
+ "HCI Tulip",
22932
+ "-\uC544\uC774\uB9AC\uC2A4M"
22933
+ ];
22934
+ var WINDOWS_DEFAULT = [
22935
+ "\uB9D1\uC740 \uACE0\uB515",
22936
+ "\uB9D1\uC740\uACE0\uB515",
22937
+ "Malgun Gothic",
22938
+ "\uAD74\uB9BC",
22939
+ "\uAD74\uB9BC\uCCB4",
22940
+ "\uB3CB\uC6C0",
22941
+ "\uB3CB\uC6C0\uCCB4",
22942
+ "\uBC14\uD0D5",
22943
+ "\uBC14\uD0D5\uCCB4",
22944
+ "\uAD81\uC11C",
22945
+ "\uAD81\uC11C\uCCB4",
22946
+ "Arial",
22947
+ "Arial Black",
22948
+ "Times New Roman",
22949
+ "Courier New",
22950
+ "Consolas",
22951
+ "Calibri",
22952
+ "Cambria",
22953
+ "Segoe UI",
22954
+ "Tahoma",
22955
+ "Verdana",
22956
+ "Georgia",
22957
+ "Symbol"
22958
+ ];
22959
+ var COMMON_FREE = [
22960
+ "\uB098\uB214\uACE0\uB515",
22961
+ "\uB098\uB214\uBA85\uC870",
22962
+ "\uB098\uB214\uBC14\uB978\uACE0\uB515",
22963
+ "\uB098\uB214\uC2A4\uD018\uC5B4",
22964
+ "\uB098\uB214\uC190\uAE00\uC528 \uBD93",
22965
+ "\uB098\uB214\uC190\uAE00\uC528 \uD39C",
22966
+ "NanumGothic",
22967
+ "NanumMyeongjo",
22968
+ "Noto Sans KR",
22969
+ "Noto Serif KR",
22970
+ "\uBCF8\uACE0\uB515",
22971
+ "\uBCF8\uBA85\uC870",
22972
+ "Pretendard",
22973
+ "\uD504\uB9AC\uD150\uB2E4\uB4DC",
22974
+ "KoPub\uB3CB\uC6C0",
22975
+ "KoPub\uBC14\uD0D5",
22976
+ "KoPubWorld\uB3CB\uC6C0",
22977
+ "KoPubWorld\uBC14\uD0D5",
22978
+ "\uC5D0\uC2A4\uCF54\uC5B4 \uB4DC\uB9BC",
22979
+ "S-Core Dream",
22980
+ "G\uB9C8\uCF13 \uC0B0\uC2A4",
22981
+ "Gmarket Sans",
22982
+ "\uC724\uACE0\uB515",
22983
+ "\uC724\uACE0\uB515320",
22984
+ "\uC724\uACE0\uB515330",
22985
+ "\uC724\uACE0\uB515340",
22986
+ "\uC724\uBA85\uC870"
22987
+ ];
22988
+ function norm(name) {
22989
+ return name.replace(/\s+/g, "").toLowerCase();
22990
+ }
22991
+ var KNOWN = new Set([...HANCOM_BUNDLED, ...WINDOWS_DEFAULT, ...COMMON_FREE].map(norm));
22992
+ function isKnownFont(name) {
22993
+ return KNOWN.has(norm(name));
22994
+ }
22995
+ function unknownFontWarnings(fonts) {
22996
+ const warnings = [];
22997
+ for (const [role, name] of Object.entries(fonts)) {
22998
+ if (!name || isKnownFont(name)) continue;
22999
+ warnings.push(
23000
+ `\uD3F0\uD2B8 \uACBD\uACE0: ${role}="${name}" \u2014 \uD55C\uCEF4 \uBC88\uB4E4\xB7\uD1B5\uC0C1 \uC124\uCE58 \uBAA9\uB85D\uC5D0 \uC5C6\uB294 \uD3F0\uD2B8\uBA85\uC785\uB2C8\uB2E4. \uC624\uD0C0\uC774\uAC70\uB098 \uB300\uC0C1 PC\uC5D0 \uBBF8\uC124\uCE58\uBA74 \uD55C\uAE00\uC774 \uAE30\uBCF8 \uD3F0\uD2B8\uB85C \uB300\uCCB4 \uB80C\uB354\uD569\uB2C8\uB2E4 (\uC0DD\uC131\uC740 \uC9C4\uD589\uB428)`
23001
+ );
23002
+ }
23003
+ return warnings;
22065
23004
  }
22066
23005
 
22067
23006
  // src/roundtrip/patcher.ts
@@ -22071,10 +23010,10 @@ import JSZip8 from "jszip";
22071
23010
  var ROW_OBJECT_RE = /<(?:[A-Za-z0-9_]+:)?(?:tbl|pic|equation|ole|container|shape|drawingObject|drawText|video|chart|fieldBegin|fieldEnd|ctrl)\b/;
22072
23011
  var TAG_AT_RE = /<[A-Za-z0-9_:]+(?:"[^"]*"|'[^']*'|[^>"'])*>/y;
22073
23012
  function patchTableRows(input) {
22074
- const { table, scanTable, ctx, skip, origKeys, editedKeys } = input;
23013
+ const { table: table2, scanTable, ctx, skip, origKeys, editedKeys } = input;
22075
23014
  const xml = ctx.scans[scanTable.sectionIndex]?.xml;
22076
23015
  if (!xml) return skip("\uC139\uC158 XML \uB9E4\uD551 \uC2E4\uD328");
22077
- const numRows = table.rows;
23016
+ const numRows = table2.rows;
22078
23017
  if (origKeys.length !== numRows) return skip("\uD45C \uD589 \uC88C\uD45C \uBD88\uC77C\uCE58 \u2014 \uD589 \uCD94\uAC00/\uC0AD\uC81C \uBBF8\uC9C0\uC6D0");
22079
23018
  if (scanTable.rows.length !== numRows || scanTable.rowRanges.length !== numRows) {
22080
23019
  return skip("\uD45C \uD589 \uAD6C\uC870 \uC88C\uD45C \uBD88\uC77C\uCE58 (\uBE48 \uD589/\uBCD1\uD569 \uC18C\uC2E4) \u2014 \uD589 \uCD94\uAC00/\uC0AD\uC81C \uBBF8\uC9C0\uC6D0");
@@ -22145,8 +23084,8 @@ function patchTableRows(input) {
22145
23084
  if (template < 0) template = kept[0];
22146
23085
  const cells = input.editedCells(ins.ei);
22147
23086
  if (!cells) return skip("\uC0BD\uC785 \uD589\uC5D0 \uC774\uBBF8\uC9C0/\uC911\uCCA9\uD45C \uD3EC\uD568 \u2014 \uD589 \uCD94\uAC00 \uBBF8\uC9C0\uC6D0");
22148
- for (const cell of cells) {
22149
- const unstable = cell.lines.find((l) => sanitizeText(l) !== l);
23087
+ for (const cell2 of cells) {
23088
+ const unstable = cell2.lines.find((l) => sanitizeText(l) !== l);
22150
23089
  if (unstable !== void 0) return skip("\uC0BD\uC785 \uD589\uC5D0 \uACF5\uBC31 \uC815\uADDC\uD654 \uBD88\uC548\uC815 \uD14D\uC2A4\uD2B8 \u2014 \uBBF8\uC9C0\uC6D0");
22151
23090
  }
22152
23091
  const tmplCells = scanTable.rows[template];
@@ -22156,7 +23095,7 @@ function patchTableRows(input) {
22156
23095
  }
22157
23096
  if (tmplCells.some((c) => c.rowSpan > 1)) return skip("\uC11C\uC2DD \uAE30\uC900 \uD589\uC5D0 \uC138\uB85C \uBCD1\uD569 \u2014 \uD589 \uCD94\uAC00 \uBBF8\uC9C0\uC6D0");
22158
23097
  const tmplWidth = tmplCells.reduce((s, c) => s + c.colSpan, 0);
22159
- if (tmplWidth !== table.cols) return skip("\uC11C\uC2DD \uAE30\uC900 \uD589\uC774 \uACA9\uC790 \uC804\uCCB4\uB97C \uB36E\uC9C0 \uC54A\uC74C \u2014 \uD589 \uCD94\uAC00 \uBBF8\uC9C0\uC6D0");
23098
+ if (tmplWidth !== table2.cols) return skip("\uC11C\uC2DD \uAE30\uC900 \uD589\uC774 \uACA9\uC790 \uC804\uCCB4\uB97C \uB36E\uC9C0 \uC54A\uC74C \u2014 \uD589 \uCD94\uAC00 \uBBF8\uC9C0\uC6D0");
22160
23099
  if (cells.length !== tmplCells.length) {
22161
23100
  return skip(`\uC0BD\uC785 \uD589 \uC140 \uC218(${cells.length}) \u2260 \uAE30\uC900 \uD589 \uC140 \uC218(${tmplCells.length}) \u2014 \uBBF8\uC9C0\uC6D0`);
22162
23101
  }
@@ -22213,8 +23152,8 @@ function patchTableRows(input) {
22213
23152
  for (const k of keeps) {
22214
23153
  const fi = finalIndex.get(k);
22215
23154
  if (fi === k.oi) continue;
22216
- for (const cell of scanTable.rows[k.oi]) {
22217
- const sp = rowAddrRewrite(xml, cell, fi);
23155
+ for (const cell2 of scanTable.rows[k.oi]) {
23156
+ const sp = rowAddrRewrite(xml, cell2, fi);
22218
23157
  if (sp) splices.push(sp);
22219
23158
  }
22220
23159
  }
@@ -22263,13 +23202,13 @@ function buildRowFragment(xml, scanTable, template, cells, finalRow, hasExplicit
22263
23202
  const patched = applySplices(wrapped, splices);
22264
23203
  return patched.slice(FRAG_OPEN.length, patched.length - FRAG_CLOSE.length);
22265
23204
  }
22266
- function rowAddrRewrite(xml, cell, newRow) {
22267
- if (!cell.addrTagRange) return null;
22268
- const tag = xml.slice(cell.addrTagRange.start, cell.addrTagRange.end);
23205
+ function rowAddrRewrite(xml, cell2, newRow) {
23206
+ if (!cell2.addrTagRange) return null;
23207
+ const tag = xml.slice(cell2.addrTagRange.start, cell2.addrTagRange.end);
22269
23208
  const m = tag.match(/\browAddr\s*=\s*"(\d+)"/);
22270
23209
  if (!m || m.index === void 0) return null;
22271
23210
  if (parseInt(m[1], 10) === newRow) return null;
22272
- const valStart = cell.addrTagRange.start + m.index + m[0].indexOf('"') + 1;
23211
+ const valStart = cell2.addrTagRange.start + m.index + m[0].indexOf('"') + 1;
22273
23212
  return { start: valStart, end: valStart + m[1].length, replacement: String(newRow) };
22274
23213
  }
22275
23214
  function rowHeightOf(fragment) {
@@ -22295,8 +23234,8 @@ function tableSzHeightSplice(xml, scanTable, tblOpenLen, delta) {
22295
23234
  }
22296
23235
 
22297
23236
  // src/roundtrip/table-patch.ts
22298
- function patchGfmTable(table, scanTable, orig, edited, ctx, skip) {
22299
- const replica = replicateGfmTable(table);
23237
+ function patchGfmTable(table2, scanTable, orig, edited, ctx, skip) {
23238
+ const replica = replicateGfmTable(table2);
22300
23239
  if (!replica) return skip("\uD45C \uB80C\uB354 \uACBD\uB85C \uC2DD\uBCC4 \uC2E4\uD328");
22301
23240
  const origRows = parseGfmTable(orig.lines);
22302
23241
  const editedRows = parseGfmTable(edited.lines);
@@ -22304,15 +23243,15 @@ function patchGfmTable(table, scanTable, orig, edited, ctx, skip) {
22304
23243
  return skip("\uD45C \uC88C\uD45C \uC7AC\uD604 \uBD88\uC77C\uCE58 \u2014 \uB9E4\uD551 \uC2E0\uB8B0 \uBD88\uAC00");
22305
23244
  }
22306
23245
  if (editedRows.length !== origRows.length) {
22307
- return patchGfmTableRows(table, scanTable, origRows, editedRows, replica, ctx, skip);
23246
+ return patchGfmTableRows(table2, scanTable, origRows, editedRows, replica, ctx, skip);
22308
23247
  }
22309
23248
  let applied = 0;
22310
23249
  for (let r = 0; r < origRows.length; r++) {
22311
- applied += patchGfmRowPair(table, scanTable, origRows, editedRows, replica, r, r, ctx, skip);
23250
+ applied += patchGfmRowPair(table2, scanTable, origRows, editedRows, replica, r, r, ctx, skip);
22312
23251
  }
22313
23252
  return applied;
22314
23253
  }
22315
- function patchGfmRowPair(table, scanTable, origRows, editedRows, replica, r, er, ctx, skip) {
23254
+ function patchGfmRowPair(table2, scanTable, origRows, editedRows, replica, r, er, ctx, skip) {
22316
23255
  if (editedRows[er].length !== origRows[r].length) {
22317
23256
  skip(`\uD45C ${r + 1}\uD589 \uC5F4 \uC218 \uBCC0\uACBD\uC740 \uBBF8\uC9C0\uC6D0`);
22318
23257
  return 0;
@@ -22329,7 +23268,7 @@ function patchGfmRowPair(table, scanTable, origRows, editedRows, replica, r, er,
22329
23268
  }
22330
23269
  const newLines = unescapeGfmCell(stripCellTokens(editedRows[er][c])).split("\n").map((s) => s.trim()).filter(Boolean);
22331
23270
  const origLines = unescapeGfmCell(stripCellTokens(origRows[r][c])).split("\n").map((s) => s.trim()).filter(Boolean);
22332
- const n = applyCellEdit(table, scanTable, gridR, gridC, newLines, ctx, origRows[r][c], editedRows[er][c], origLines.length);
23271
+ const n = applyCellEdit(table2, scanTable, gridR, gridC, newLines, ctx, origRows[r][c], editedRows[er][c], origLines.length);
22333
23272
  if (n > 0 && origTokens) {
22334
23273
  ctx.skipped.push({
22335
23274
  reason: "\uC140 \uB0B4 \uC774\uBBF8\uC9C0\xB7\uD14D\uC2A4\uD2B8 \uD63C\uC7AC \u2014 \uD14D\uC2A4\uD2B8\uB9CC \uC801\uC6A9 (\uC774\uBBF8\uC9C0 \uC778\uC811 \uBC30\uCE58\uB294 <br> \uBD84\uB9AC\uB85C \uC7AC\uD604\uB428)",
@@ -22342,19 +23281,19 @@ function patchGfmRowPair(table, scanTable, origRows, editedRows, replica, r, er,
22342
23281
  }
22343
23282
  return applied;
22344
23283
  }
22345
- function patchGfmTableRows(table, scanTable, origRows, editedRows, replica, ctx, skip) {
22346
- if (replica.length !== table.rows || replica.some((row, r) => row.some((c) => c.gridR !== r))) {
23284
+ function patchGfmTableRows(table2, scanTable, origRows, editedRows, replica, ctx, skip) {
23285
+ if (replica.length !== table2.rows || replica.some((row, r) => row.some((c) => c.gridR !== r))) {
22347
23286
  return skip("\uD45C \uB80C\uB354 \uD589\uACFC \uACA9\uC790 \uD589 \uBD88\uC77C\uCE58 (\uBE48 \uD589/\uBCD1\uD569) \u2014 \uD589 \uCD94\uAC00/\uC0AD\uC81C \uBBF8\uC9C0\uC6D0");
22348
23287
  }
22349
- if (table.cells.some((row) => row.some((c) => c && (c.colSpan > 1 || c.rowSpan > 1)))) {
23288
+ if (table2.cells.some((row) => row.some((c) => c && (c.colSpan > 1 || c.rowSpan > 1)))) {
22350
23289
  return skip("\uBCD1\uD569 \uC140 \uD45C \u2014 GFM \uD589 \uCD94\uAC00/\uC0AD\uC81C \uBBF8\uC9C0\uC6D0");
22351
23290
  }
22352
- if (!gfmRenderStable(editedRows, table.cols)) {
23291
+ if (!gfmRenderStable(editedRows, table2.cols)) {
22353
23292
  return skip("\uD589 \uBCC0\uACBD \uACB0\uACFC\uAC00 \uD45C \uB80C\uB354\uC5D0\uC11C \uBCC0\uD615\uB428 (\uBE48 \uD589/\uCCAB \uC5F4 \uC804\uD30C/\uC5F4 \uC218 \uBD88\uC77C\uCE58) \u2014 \uBBF8\uC9C0\uC6D0");
22354
23293
  }
22355
23294
  const key = (row) => row.join("\0");
22356
23295
  return patchTableRows({
22357
- table,
23296
+ table: table2,
22358
23297
  scanTable,
22359
23298
  ctx,
22360
23299
  skip,
@@ -22369,7 +23308,7 @@ function patchGfmTableRows(table, scanTable, origRows, editedRows, replica, ctx,
22369
23308
  }
22370
23309
  return cells;
22371
23310
  },
22372
- patchMatched: (oi, ei) => patchGfmRowPair(table, scanTable, origRows, editedRows, replica, oi, ei, ctx, skip)
23311
+ patchMatched: (oi, ei) => patchGfmRowPair(table2, scanTable, origRows, editedRows, replica, oi, ei, ctx, skip)
22373
23312
  });
22374
23313
  }
22375
23314
  function gfmRenderStable(editedRows, cols) {
@@ -22386,13 +23325,13 @@ function gfmRenderStable(editedRows, cols) {
22386
23325
  if (!replica || replica.length !== editedRows.length) return false;
22387
23326
  return replica.every((row, r) => row.length === editedRows[r].length && row.every((c, j) => c.text === editedRows[r][j]));
22388
23327
  }
22389
- function patchHtmlTable(table, scanTable, orig, edited, ctx, skip) {
22390
- return patchHtmlTableRaw(table, scanTable, orig.raw, edited.raw, ctx, skip, 0);
23328
+ function patchHtmlTable(table2, scanTable, orig, edited, ctx, skip) {
23329
+ return patchHtmlTableRaw(table2, scanTable, orig.raw, edited.raw, ctx, skip, 0);
22391
23330
  }
22392
- function patchHtmlTableRaw(table, scanTable, origRaw, editedRaw, ctx, skip, depth) {
23331
+ function patchHtmlTableRaw(table2, scanTable, origRaw, editedRaw, ctx, skip, depth) {
22393
23332
  if (depth > 8) return skip("\uC911\uCCA9\uD45C \uAE4A\uC774 \uCD08\uACFC");
22394
- if (replicateTableToHtml(table) !== origRaw) return skip("\uD45C \uC88C\uD45C \uC7AC\uD604 \uBD88\uC77C\uCE58 \u2014 \uB9E4\uD551 \uC2E0\uB8B0 \uBD88\uAC00");
22395
- const replica = replicateHtmlTable(table);
23333
+ if (replicateTableToHtml(table2) !== origRaw) return skip("\uD45C \uC88C\uD45C \uC7AC\uD604 \uBD88\uC77C\uCE58 \u2014 \uB9E4\uD551 \uC2E0\uB8B0 \uBD88\uAC00");
23334
+ const replica = replicateHtmlTable(table2);
22396
23335
  const origRows = parseHtmlTable(origRaw);
22397
23336
  if (!origRows || origRows.length !== replica.length || origRows.some((r, i) => r.cells.length !== replica[i].cells.length || r.cells.some((c, j) => c.inner !== replica[i].cells[j].inner))) {
22398
23337
  return skip("\uC140 \uACBD\uACC4 \uBAA8\uD638 (\uB9AC\uD130\uB7F4 \uD0DC\uADF8 \uC758\uC2EC) \u2014 \uB9E4\uD551 \uC2E0\uB8B0 \uBD88\uAC00");
@@ -22400,15 +23339,15 @@ function patchHtmlTableRaw(table, scanTable, origRaw, editedRaw, ctx, skip, dept
22400
23339
  const editedRows = parseHtmlTable(editedRaw);
22401
23340
  if (!editedRows) return skip("\uD3B8\uC9D1\uB41C HTML \uD45C \uD30C\uC2F1 \uC2E4\uD328");
22402
23341
  if (editedRows.length !== replica.length) {
22403
- return patchHtmlTableRows(table, scanTable, replica, editedRows, ctx, skip, depth);
23342
+ return patchHtmlTableRows(table2, scanTable, replica, editedRows, ctx, skip, depth);
22404
23343
  }
22405
23344
  let applied = 0;
22406
23345
  for (let r = 0; r < replica.length; r++) {
22407
- applied += patchHtmlRowPair(table, scanTable, replica, editedRows, r, r, ctx, skip, depth);
23346
+ applied += patchHtmlRowPair(table2, scanTable, replica, editedRows, r, r, ctx, skip, depth);
22408
23347
  }
22409
23348
  return applied;
22410
23349
  }
22411
- function patchHtmlRowPair(table, scanTable, replica, editedRows, r, er, ctx, skip, depth) {
23350
+ function patchHtmlRowPair(table2, scanTable, replica, editedRows, r, er, ctx, skip, depth) {
22412
23351
  if (editedRows[er].cells.length !== replica[r].cells.length) {
22413
23352
  skip(`\uD45C ${r + 1}\uD589 \uC140 \uC218 \uBCC0\uACBD\uC740 \uBBF8\uC9C0\uC6D0`);
22414
23353
  return 0;
@@ -22436,23 +23375,23 @@ function patchHtmlRowPair(table, scanTable, replica, editedRows, r, er, ctx, ski
22436
23375
  continue;
22437
23376
  }
22438
23377
  if (origTables.join("\n") !== editedTables.join("\n")) {
22439
- applied += patchNestedTables(table, scanTable, oc, origTables, editedTables, ctx, skip, depth);
23378
+ applied += patchNestedTables(table2, scanTable, oc, origTables, editedTables, ctx, skip, depth);
22440
23379
  }
22441
23380
  }
22442
23381
  if (origContent.lines.join("\n") !== editedContent.lines.join("\n")) {
22443
23382
  const newLines = editedContent.lines.map((l) => unescapeGfm(l));
22444
- applied += applyCellEdit(table, scanTable, oc.gridR, oc.gridC, newLines, ctx, oc.inner, ec.inner, origContent.lines.length);
23383
+ applied += applyCellEdit(table2, scanTable, oc.gridR, oc.gridC, newLines, ctx, oc.inner, ec.inner, origContent.lines.length);
22445
23384
  }
22446
23385
  }
22447
23386
  return applied;
22448
23387
  }
22449
- function patchHtmlTableRows(table, scanTable, replica, editedRows, ctx, skip, depth) {
22450
- if (replica.length !== table.rows || replica.some((row, r) => row.cells.some((c) => c.gridR !== r))) {
23388
+ function patchHtmlTableRows(table2, scanTable, replica, editedRows, ctx, skip, depth) {
23389
+ if (replica.length !== table2.rows || replica.some((row, r) => row.cells.some((c) => c.gridR !== r))) {
22451
23390
  return skip("\uD45C \uB80C\uB354 \uD589\uACFC \uACA9\uC790 \uD589 \uBD88\uC77C\uCE58 (\uBCD1\uD569 \uC18C\uC2E4 \uD589) \u2014 \uD589 \uCD94\uAC00/\uC0AD\uC81C \uBBF8\uC9C0\uC6D0");
22452
23391
  }
22453
23392
  const key = (row) => row.cells.map((c) => `${c.colSpan}x${c.rowSpan}:${c.inner}`).join("\0");
22454
23393
  return patchTableRows({
22455
- table,
23394
+ table: table2,
22456
23395
  scanTable,
22457
23396
  ctx,
22458
23397
  skip,
@@ -22460,18 +23399,18 @@ function patchHtmlTableRows(table, scanTable, replica, editedRows, ctx, skip, de
22460
23399
  editedKeys: editedRows.map(key),
22461
23400
  editedCells: (ei) => {
22462
23401
  const cells = [];
22463
- for (const cell of editedRows[ei].cells) {
22464
- const content = htmlCellInnerToLines(cell.inner);
23402
+ for (const cell2 of editedRows[ei].cells) {
23403
+ const content = htmlCellInnerToLines(cell2.inner);
22465
23404
  if (content.hadNonText) return null;
22466
- cells.push({ lines: content.lines.map((l) => unescapeGfm(l)), colSpan: cell.colSpan, rowSpan: cell.rowSpan });
23405
+ cells.push({ lines: content.lines.map((l) => unescapeGfm(l)), colSpan: cell2.colSpan, rowSpan: cell2.rowSpan });
22467
23406
  }
22468
23407
  return cells;
22469
23408
  },
22470
- patchMatched: (oi, ei) => patchHtmlRowPair(table, scanTable, replica, editedRows, oi, ei, ctx, skip, depth)
23409
+ patchMatched: (oi, ei) => patchHtmlRowPair(table2, scanTable, replica, editedRows, oi, ei, ctx, skip, depth)
22471
23410
  });
22472
23411
  }
22473
- function patchNestedTables(table, scanTable, oc, origTables, editedTables, ctx, skip, depth) {
22474
- const irCell = table.cells[oc.gridR]?.[oc.gridC];
23412
+ function patchNestedTables(table2, scanTable, oc, origTables, editedTables, ctx, skip, depth) {
23413
+ const irCell = table2.cells[oc.gridR]?.[oc.gridC];
22475
23414
  const scanCell = scanTable.cellByAnchor.get(`${oc.gridR},${oc.gridC}`);
22476
23415
  const nestedIRs = (irCell?.blocks ?? []).filter((b) => b.type === "table" && b.table).map((b) => b.table);
22477
23416
  if (!scanCell || nestedIRs.length !== origTables.length || scanCell.tables.length !== origTables.length) {
@@ -22494,9 +23433,9 @@ function extractCellTokens(text) {
22494
23433
  function stripCellTokens(text) {
22495
23434
  return text.replace(CELL_TOKEN_RE, "");
22496
23435
  }
22497
- function patchTextChunkTable(table, scanTable, orig, edited, ctx, skip) {
22498
- if (table.rows === 1 && table.cols === 1) {
22499
- const content = sanitizeText(table.cells[0][0].text);
23436
+ function patchTextChunkTable(table2, scanTable, orig, edited, ctx, skip) {
23437
+ if (table2.rows === 1 && table2.cols === 1) {
23438
+ const content = sanitizeText(table2.cells[0][0].text);
22500
23439
  const replicaLines = content.split(/\n/).map((line) => {
22501
23440
  const t = line.trim();
22502
23441
  if (!t) return "";
@@ -22510,12 +23449,12 @@ function patchTextChunkTable(table, scanTable, orig, edited, ctx, skip) {
22510
23449
  const unwrap = m && /^\d+\.\s/.test(unescapeGfm(m[1]));
22511
23450
  return stripCellTokens(unescapeGfm(unwrap ? m[1] : l)).trim();
22512
23451
  }).filter(Boolean);
22513
- return applyCellEdit(table, scanTable, 0, 0, newLines, ctx, orig.raw, edited.raw, orig.lines.length);
23452
+ return applyCellEdit(table2, scanTable, 0, 0, newLines, ctx, orig.raw, edited.raw, orig.lines.length);
22514
23453
  }
22515
- if (table.cols === 1 && table.rows >= 2) {
23454
+ if (table2.cols === 1 && table2.rows >= 2) {
22516
23455
  const replica = [];
22517
- for (let r = 0; r < table.rows; r++) {
22518
- const line = escapeGfm(sanitizeText(table.cells[r][0].text)).replace(/\n/g, " ");
23456
+ for (let r = 0; r < table2.rows; r++) {
23457
+ const line = escapeGfm(sanitizeText(table2.cells[r][0].text)).replace(/\n/g, " ");
22519
23458
  if (line) replica.push({ line, gridR: r });
22520
23459
  }
22521
23460
  if (replica.map((x) => x.line).join("\n") !== orig.lines.join("\n")) return skip("\uD45C \uC88C\uD45C \uC7AC\uD604 \uBD88\uC77C\uCE58 \u2014 \uB9E4\uD551 \uC2E0\uB8B0 \uBD88\uAC00");
@@ -22528,21 +23467,21 @@ function patchTextChunkTable(table, scanTable, orig, edited, ctx, skip) {
22528
23467
  continue;
22529
23468
  }
22530
23469
  const newLines = [stripCellTokens(unescapeGfm(edited.lines[i])).trim()].filter(Boolean);
22531
- applied += applyCellEdit(table, scanTable, replica[i].gridR, 0, newLines, ctx, replica[i].line, edited.lines[i], 1);
23470
+ applied += applyCellEdit(table2, scanTable, replica[i].gridR, 0, newLines, ctx, replica[i].line, edited.lines[i], 1);
22532
23471
  }
22533
23472
  return applied;
22534
23473
  }
22535
23474
  return skip("\uD45C \uB80C\uB354 \uACBD\uB85C \uC2DD\uBCC4 \uC2E4\uD328");
22536
23475
  }
22537
- function applyCellEdit(table, scanTable, gridR, gridC, newLines, ctx, before, after, origLineCount) {
23476
+ function applyCellEdit(table2, scanTable, gridR, gridC, newLines, ctx, before, after, origLineCount) {
22538
23477
  const skip = (reason) => {
22539
23478
  ctx.skipped.push({ reason, before: summarize(before), after: summarize(after) });
22540
23479
  return 0;
22541
23480
  };
22542
- const cell = scanTable.cellByAnchor.get(`${gridR},${gridC}`);
22543
- if (!cell) return skip("\uC140 \uC88C\uD45C \uB9E4\uD551 \uC2E4\uD328 (\uBCD1\uD569 \uC601\uC5ED\uC758 \uBE48 \uCE78\uC774\uAC70\uB098 \uC88C\uD45C \uBD88\uC77C\uCE58)");
22544
- const irCell = table.cells[gridR]?.[gridC];
22545
- const scanJoined = cell.paragraphs.map((p) => p.text).filter((t) => normForMatch(t)).join("\n");
23481
+ const cell2 = scanTable.cellByAnchor.get(`${gridR},${gridC}`);
23482
+ if (!cell2) return skip("\uC140 \uC88C\uD45C \uB9E4\uD551 \uC2E4\uD328 (\uBCD1\uD569 \uC601\uC5ED\uC758 \uBE48 \uCE78\uC774\uAC70\uB098 \uC88C\uD45C \uBD88\uC77C\uCE58)");
23483
+ const irCell = table2.cells[gridR]?.[gridC];
23484
+ const scanJoined = cell2.paragraphs.map((p) => p.text).filter((t) => normForMatch(t)).join("\n");
22546
23485
  if (irCell && normForMatch(scanJoined) !== normForMatch(stripCellTokens(irCell.text))) {
22547
23486
  if (normForMatch(irCell.text) !== "" || normForMatch(scanJoined) !== "") {
22548
23487
  const flatBlocks = (irCell.blocks ?? []).filter((b) => b.type === "paragraph" || b.type === "heading");
@@ -22552,7 +23491,7 @@ function applyCellEdit(table, scanTable, gridR, gridC, newLines, ctx, before, af
22552
23491
  }
22553
23492
  }
22554
23493
  }
22555
- const nonEmpty = cell.paragraphs.filter((p) => normForMatch(p.text) !== "");
23494
+ const nonEmpty = cell2.paragraphs.filter((p) => normForMatch(p.text) !== "");
22556
23495
  if (origLineCount !== void 0 && nonEmpty.length > 0 && origLineCount !== nonEmpty.length) {
22557
23496
  return skip("\uC140 \uC904 \uACBD\uACC4 \uB9E4\uD551 \uBAA8\uD638 (\uB9AC\uD130\uB7F4 <br>/\uBB38\uB2E8 \uB0B4 \uC904\uBC14\uAFC8) \u2014 \uBBF8\uC9C0\uC6D0");
22558
23497
  }
@@ -22562,7 +23501,7 @@ function applyCellEdit(table, scanTable, gridR, gridC, newLines, ctx, before, af
22562
23501
  if (unstable !== void 0) 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");
22563
23502
  if (nonEmpty.length === 0) {
22564
23503
  if (newLines.length === 0) return 0;
22565
- const target = cell.paragraphs[0];
23504
+ const target = cell2.paragraphs[0];
22566
23505
  if (!target) return skip("\uBE48 \uC140\uC5D0 \uBB38\uB2E8\uC774 \uC5C6\uC5B4 \uD14D\uC2A4\uD2B8 \uC0BD\uC785 \uBD88\uAC00");
22567
23506
  const sp = buildParagraphSplices(target, newLines.join(" "), ctx.scans[target.sectionIndex]?.xml);
22568
23507
  if (sp === null) return skip("\uC140 \uBB38\uB2E8\uC5D0 \uD14D\uC2A4\uD2B8 \uB178\uB4DC\uB97C \uB9CC\uB4E4 \uC218 \uC5C6\uC74C");
@@ -22647,16 +23586,16 @@ function buildTableParagraphXml(rows, opts) {
22647
23586
  const trElements = rows.map((row, rowIdx) => {
22648
23587
  const cells = row.length < colCnt ? [...row, ...Array(colCnt - row.length).fill("")] : row;
22649
23588
  const isHeaderRow = rowIdx === 0;
22650
- const tdElements = cells.map((cell, colIdx) => {
22651
- const text = escapeXmlText(cellPlainText(cell));
23589
+ const tdElements = cells.map((cell2, colIdx) => {
23590
+ const text = escapeXmlText(cellPlainText(cell2));
22652
23591
  const cellP = `<hp:p paraPrIDRef="${cellParaPrId}" styleIDRef="0"><hp:run charPrIDRef="${cellCharPrId}"><hp:t>${text}</hp:t></hp:run></hp:p>`;
22653
23592
  return `<hp:tc name="" header="${isHeaderRow ? 1 : 0}" hasMargin="0" protect="0" editable="1" dirty="0" borderFillIDRef="${borderFillId}"><hp:subList id="" textDirection="HORIZONTAL" lineWrap="BREAK" vertAlign="TOP" linkListIDRef="0" linkListNextIDRef="0" textWidth="0" textHeight="0" hasTextRef="0" hasNumRef="0">${cellP}</hp:subList><hp:cellAddr colAddr="${colIdx}" rowAddr="${rowIdx}"/><hp:cellSpan colSpan="1" rowSpan="1"/><hp:cellSz width="${cellW}" height="${cellH}"/><hp:cellMargin left="141" right="141" top="141" bottom="141"/></hp:tc>`;
22654
23593
  }).join("");
22655
23594
  return `<hp:tr>${tdElements}</hp:tr>`;
22656
23595
  }).join("");
22657
23596
  const tblInner = `<hp:sz width="${tblW}" widthRelTo="ABSOLUTE" height="${tblH}" heightRelTo="ABSOLUTE" protect="0"/><hp:pos treatAsChar="1" affectLSpacing="0" flowWithText="0" allowOverlap="0" holdAnchorAndSO="0" vertRelTo="PARA" horzRelTo="PARA" vertAlign="TOP" horzAlign="LEFT" vertOffset="0" horzOffset="0"/><hp:outMargin left="0" right="0" top="0" bottom="0"/><hp:inMargin left="510" right="510" top="141" bottom="141"/>` + trElements;
22658
- const tbl = `<hp:tbl id="${tableId}" zOrder="0" numberingType="TABLE" pageBreak="CELL" repeatHeader="0" rowCnt="${rowCnt}" colCnt="${colCnt}" cellSpacing="0" borderFillIDRef="${borderFillId}" noShading="0">${tblInner}</hp:tbl>`;
22659
- return `<hp:p paraPrIDRef="${outerParaPrId}" styleIDRef="0"><hp:run charPrIDRef="${cellCharPrId}">${tbl}</hp:run></hp:p>`;
23597
+ const tbl2 = `<hp:tbl id="${tableId}" zOrder="0" numberingType="TABLE" pageBreak="CELL" repeatHeader="0" rowCnt="${rowCnt}" colCnt="${colCnt}" cellSpacing="0" borderFillIDRef="${borderFillId}" noShading="0">${tblInner}</hp:tbl>`;
23598
+ return `<hp:p paraPrIDRef="${outerParaPrId}" styleIDRef="0"><hp:run charPrIDRef="${cellCharPrId}">${tbl2}</hp:run></hp:p>`;
22660
23599
  }
22661
23600
 
22662
23601
  // src/roundtrip/hwpx-entries.ts
@@ -22828,12 +23767,12 @@ function buildTableOrdinals(blocks) {
22828
23767
  function resolveParagraphMappings(blocks, scans) {
22829
23768
  const buckets = /* @__PURE__ */ new Map();
22830
23769
  for (const scan of scans) {
22831
- for (const para of scan.bodyParagraphs) {
22832
- const key = normForMatch(para.text);
23770
+ for (const para2 of scan.bodyParagraphs) {
23771
+ const key = normForMatch(para2.text);
22833
23772
  if (!key) continue;
22834
23773
  let list = buckets.get(key);
22835
23774
  if (!list) buckets.set(key, list = []);
22836
- list.push(para);
23775
+ list.push(para2);
22837
23776
  }
22838
23777
  }
22839
23778
  const headerNorms = new Set(scans.flatMap((s) => s.headerTexts.map(normForMatch)).filter(Boolean));
@@ -22919,11 +23858,11 @@ function convertParagraphToTable(block, orig, edited, ctx, skip) {
22919
23858
  if (!ti) return skip("\uBB38\uB2E8\u2192\uD45C \uBCC0\uD658 \uBD88\uAC00 \u2014 header \uC5D4\uD2B8\uB9AC(borderFills) \uD574\uC11D \uC2E4\uD328");
22920
23859
  const mapping = ctx.paraMap.get(orig.blockIdx);
22921
23860
  if (!mapping?.para) return skip("\uBB38\uB2E8 \uC18C\uC2A4\uB9F5 \uB9E4\uD551 \uC2E4\uD328 (\uBA38\uB9AC\uB9D0/\uAE00\uC0C1\uC790/\uCEA1\uC158 \uC601\uC5ED) \u2014 \uD45C \uBCC0\uD658 \uBD88\uAC00");
22922
- const para = mapping.para;
22923
- if (para.kind !== "body") return skip("\uBCF8\uBB38 \uC678 \uC601\uC5ED(\uD45C \uC140/\uAE00\uC0C1\uC790) \uBB38\uB2E8\uC758 \uD45C \uBCC0\uD658\uC740 \uBBF8\uC9C0\uC6D0");
22924
- const scan = ctx.scans[para.sectionIndex];
23861
+ const para2 = mapping.para;
23862
+ if (para2.kind !== "body") return skip("\uBCF8\uBB38 \uC678 \uC601\uC5ED(\uD45C \uC140/\uAE00\uC0C1\uC790) \uBB38\uB2E8\uC758 \uD45C \uBCC0\uD658\uC740 \uBBF8\uC9C0\uC6D0");
23863
+ const scan = ctx.scans[para2.sectionIndex];
22925
23864
  if (!scan) return skip("\uC139\uC158 \uB9E4\uD551 \uC2E4\uD328");
22926
- const pEnd = findElementEnd(scan.xml, para.start);
23865
+ const pEnd = findElementEnd(scan.xml, para2.start);
22927
23866
  if (pEnd < 0) return skip("\uBB38\uB2E8 \uB05D \uC704\uCE58 \uD0D0\uC0C9 \uC2E4\uD328");
22928
23867
  const rows = parseGfmTable(edited.lines);
22929
23868
  if (rows.length === 0 || rows.every((r) => r.length === 0)) return skip("\uD45C \uB0B4\uC6A9\uC774 \uBE44\uC5B4 \uC788\uC74C");
@@ -22933,7 +23872,7 @@ function convertParagraphToTable(block, orig, edited, ctx, skip) {
22933
23872
  ti.borderFillId = inj.borderFillId;
22934
23873
  ti.headerSplices.push(...inj.headerSplices);
22935
23874
  }
22936
- const outerParaPrId = extractParaPrIdRef(scan.xml, para.start) ?? 0;
23875
+ const outerParaPrId = extractParaPrIdRef(scan.xml, para2.start) ?? 0;
22937
23876
  const tableXml = buildTableParagraphXml(rows, {
22938
23877
  borderFillId: ti.borderFillId,
22939
23878
  outerParaPrId,
@@ -22941,7 +23880,7 @@ function convertParagraphToTable(block, orig, edited, ctx, skip) {
22941
23880
  cellCharPrId: 0,
22942
23881
  tableId: ti.nextId++
22943
23882
  });
22944
- ctx.sectionSplices[para.sectionIndex].push({ start: para.start, end: pEnd, replacement: tableXml });
23883
+ ctx.sectionSplices[para2.sectionIndex].push({ start: para2.start, end: pEnd, replacement: tableXml });
22945
23884
  return 1;
22946
23885
  }
22947
23886
  function patchParagraphUnit(block, orig, edited, ctx, skip) {
@@ -23422,7 +24361,7 @@ function scanSection(stream, sectionIndex, compressed) {
23422
24361
  }
23423
24362
  }
23424
24363
  const kind = !ctrlSeen || !nonGso ? "body" : "other";
23425
- const para = {
24364
+ const para2 = {
23426
24365
  sectionIndex,
23427
24366
  headerIdx: i,
23428
24367
  kind,
@@ -23434,8 +24373,8 @@ function scanSection(stream, sectionIndex, compressed) {
23434
24373
  nCharsRaw: rec.data.readUInt32LE(0),
23435
24374
  rawText: state.text
23436
24375
  };
23437
- paras.push(para);
23438
- parasByHeader.set(i, para);
24376
+ paras.push(para2);
24377
+ parasByHeader.set(i, para2);
23439
24378
  }
23440
24379
  const tables = [];
23441
24380
  for (let i = 0; i < records.length; i++) {
@@ -23588,13 +24527,13 @@ function msg(err) {
23588
24527
  function resolveParaMappings(blocks, scans) {
23589
24528
  const buckets = /* @__PURE__ */ new Map();
23590
24529
  for (const scan of scans) {
23591
- for (const para of scan.paras) {
23592
- if (para.kind === "other") continue;
23593
- const key = normForMatch(para.rawText);
24530
+ for (const para2 of scan.paras) {
24531
+ if (para2.kind === "other") continue;
24532
+ const key = normForMatch(para2.rawText);
23594
24533
  if (!key) continue;
23595
24534
  let list = buckets.get(key);
23596
24535
  if (!list) buckets.set(key, list = []);
23597
- list.push(para);
24536
+ list.push(para2);
23598
24537
  }
23599
24538
  }
23600
24539
  const usable = (list) => list.length === 1 || list.every((p) => p.kind === "body");
@@ -23630,18 +24569,18 @@ function resolveTableMappings(blocks, scanTables) {
23630
24569
  const result = /* @__PURE__ */ new Map();
23631
24570
  let si = 0;
23632
24571
  for (let i = 0; i < blocks.length; i++) {
23633
- const table = blocks[i].table;
23634
- if (blocks[i].type !== "table" || !table) continue;
24572
+ const table2 = blocks[i].table;
24573
+ if (blocks[i].type !== "table" || !table2) continue;
23635
24574
  const cands = [];
23636
24575
  for (let k = si; k < scanTables.length; k++) {
23637
- if (scanTables[k].rows === table.rows && scanTables[k].cols === table.cols) cands.push(k);
24576
+ if (scanTables[k].rows === table2.rows && scanTables[k].cols === table2.cols) cands.push(k);
23638
24577
  }
23639
24578
  if (cands.length === 0) continue;
23640
24579
  let pick2 = cands[0];
23641
24580
  if (cands.length > 1) {
23642
- let best = tableContentScore(table, scanTables[cands[0]]);
24581
+ let best = tableContentScore(table2, scanTables[cands[0]]);
23643
24582
  for (let ci = 1; ci < cands.length; ci++) {
23644
- const sc = tableContentScore(table, scanTables[cands[ci]]);
24583
+ const sc = tableContentScore(table2, scanTables[cands[ci]]);
23645
24584
  if (sc > best) {
23646
24585
  best = sc;
23647
24586
  pick2 = cands[ci];
@@ -23742,14 +24681,14 @@ function patchGfmCells(scanTable, orig, edited, ctx, skip) {
23742
24681
  ctx.skipped.push({ reason, before: summarize(origRows[r][c]), after: summarize(editedRows[r][c]) });
23743
24682
  return 0;
23744
24683
  };
23745
- const cell = scanTable.cells.get(`${r},${c}`);
23746
- if (!cell) {
24684
+ const cell2 = scanTable.cells.get(`${r},${c}`);
24685
+ if (!cell2) {
23747
24686
  cellSkip("\uBCD1\uD569 \uC601\uC5ED \uC140 \u2014 \uC575\uCEE4 \uC140\uC774 \uC544\uB2C8\uBBC0\uB85C \uBBF8\uC9C0\uC6D0");
23748
24687
  continue;
23749
24688
  }
23750
24689
  const beforeParts = origRows[r][c].split(/<br\s*\/?>/i);
23751
24690
  const afterParts = editedRows[r][c].split(/<br\s*\/?>/i);
23752
- if (cell.paras.length === 1) {
24691
+ if (cell2.paras.length === 1) {
23753
24692
  const beforeEach = beforeParts.map(gfmCellToPlain);
23754
24693
  const afterEach = afterParts.map(gfmCellToPlain);
23755
24694
  if (beforeEach.some((p) => p === null) || afterEach.some((p) => p === null)) {
@@ -23759,8 +24698,8 @@ function patchGfmCells(scanTable, orig, edited, ctx, skip) {
23759
24698
  const before = beforeEach.join("\n");
23760
24699
  const after = afterEach.join("\n");
23761
24700
  if (before === after) continue;
23762
- const para = cell.paras[0];
23763
- if (normForMatch(para.rawText) !== normForMatch(before)) {
24701
+ const para2 = cell2.paras[0];
24702
+ if (normForMatch(para2.rawText) !== normForMatch(before)) {
23764
24703
  cellSkip("\uC140 \uD14D\uC2A4\uD2B8 \uBD88\uC77C\uCE58 \u2014 \uC18C\uC2A4\uB9F5 \uC2E0\uB8B0 \uBD88\uAC00");
23765
24704
  continue;
23766
24705
  }
@@ -23768,14 +24707,14 @@ function patchGfmCells(scanTable, orig, edited, ctx, skip) {
23768
24707
  cellSkip("\uACF5\uBC31 \uC815\uADDC\uD654 \uBD88\uC548\uC815 \uD14D\uC2A4\uD2B8 \u2014 \uBBF8\uC9C0\uC6D0");
23769
24708
  continue;
23770
24709
  }
23771
- applied += stageParaPatch(ctx.scans[para.sectionIndex], para, after, cellSkip);
24710
+ applied += stageParaPatch(ctx.scans[para2.sectionIndex], para2, after, cellSkip);
23772
24711
  continue;
23773
24712
  }
23774
- if (beforeParts.length !== cell.paras.length || afterParts.length !== cell.paras.length) {
24713
+ if (beforeParts.length !== cell2.paras.length || afterParts.length !== cell2.paras.length) {
23775
24714
  cellSkip("\uC140 \uBB38\uB2E8 \uC218 \uBCC0\uACBD \u2014 \uBBF8\uC9C0\uC6D0 (\uBB38\uB2E8 \uCD94\uAC00/\uC0AD\uC81C)");
23776
24715
  continue;
23777
24716
  }
23778
- for (let k = 0; k < cell.paras.length; k++) {
24717
+ for (let k = 0; k < cell2.paras.length; k++) {
23779
24718
  const before = gfmCellToPlain(beforeParts[k]);
23780
24719
  const after = gfmCellToPlain(afterParts[k]);
23781
24720
  if (before === null || after === null) {
@@ -23787,8 +24726,8 @@ function patchGfmCells(scanTable, orig, edited, ctx, skip) {
23787
24726
  cellSkip("\uC140 \uB0B4 \uC904\uBC14\uAFC8 \uCD94\uAC00\uB294 \uBBF8\uC9C0\uC6D0 (v1)");
23788
24727
  break;
23789
24728
  }
23790
- const para = cell.paras[k];
23791
- if (normForMatch(para.rawText) !== normForMatch(before)) {
24729
+ const para2 = cell2.paras[k];
24730
+ if (normForMatch(para2.rawText) !== normForMatch(before)) {
23792
24731
  cellSkip("\uC140 \uD14D\uC2A4\uD2B8 \uBD88\uC77C\uCE58 \u2014 \uC18C\uC2A4\uB9F5 \uC2E0\uB8B0 \uBD88\uAC00");
23793
24732
  break;
23794
24733
  }
@@ -23796,15 +24735,15 @@ function patchGfmCells(scanTable, orig, edited, ctx, skip) {
23796
24735
  cellSkip("\uACF5\uBC31 \uC815\uADDC\uD654 \uBD88\uC548\uC815 \uD14D\uC2A4\uD2B8 \u2014 \uBBF8\uC9C0\uC6D0");
23797
24736
  break;
23798
24737
  }
23799
- applied += stageParaPatch(ctx.scans[para.sectionIndex], para, after, cellSkip);
24738
+ applied += stageParaPatch(ctx.scans[para2.sectionIndex], para2, after, cellSkip);
23800
24739
  }
23801
24740
  }
23802
24741
  }
23803
24742
  return applied;
23804
24743
  }
23805
- function patchHtmlCells5(table, scanTable, orig, edited, ctx, skip) {
23806
- if (replicateTableToHtml(table) !== orig.raw) return skip("\uD45C \uC88C\uD45C \uC7AC\uD604 \uBD88\uC77C\uCE58 \u2014 \uB9E4\uD551 \uC2E0\uB8B0 \uBD88\uAC00");
23807
- const replica = replicateHtmlTable(table);
24744
+ function patchHtmlCells5(table2, scanTable, orig, edited, ctx, skip) {
24745
+ if (replicateTableToHtml(table2) !== orig.raw) return skip("\uD45C \uC88C\uD45C \uC7AC\uD604 \uBD88\uC77C\uCE58 \u2014 \uB9E4\uD551 \uC2E0\uB8B0 \uBD88\uAC00");
24746
+ const replica = replicateHtmlTable(table2);
23808
24747
  const origRows = parseHtmlTable(orig.raw);
23809
24748
  if (!origRows || origRows.length !== replica.length || origRows.some((r, i) => r.cells.length !== replica[i].cells.length || r.cells.some((c, j) => c.inner !== replica[i].cells[j].inner))) {
23810
24749
  return skip("\uC140 \uACBD\uACC4 \uBAA8\uD638 (\uB9AC\uD130\uB7F4 \uD0DC\uADF8 \uC758\uC2EC) \u2014 \uB9E4\uD551 \uC2E0\uB8B0 \uBD88\uAC00");
@@ -23840,15 +24779,15 @@ function patchHtmlCells5(table, scanTable, orig, edited, ctx, skip) {
23840
24779
  }
23841
24780
  if (origContent.lines.join("\n") !== editedContent.lines.join("\n")) {
23842
24781
  const newLines = editedContent.lines.map((l) => unescapeGfm(l));
23843
- applied += applyCellEdit5(table, scanTable, oc.gridR, oc.gridC, newLines, ctx, oc.inner, ec.inner, origContent.lines.length);
24782
+ applied += applyCellEdit5(table2, scanTable, oc.gridR, oc.gridC, newLines, ctx, oc.inner, ec.inner, origContent.lines.length);
23844
24783
  }
23845
24784
  }
23846
24785
  }
23847
24786
  return applied;
23848
24787
  }
23849
- function patchTextChunk5(table, scanTable, orig, edited, ctx, skip) {
23850
- if (table.rows === 1 && table.cols === 1) {
23851
- const content = sanitizeText(table.cells[0][0].text);
24788
+ function patchTextChunk5(table2, scanTable, orig, edited, ctx, skip) {
24789
+ if (table2.rows === 1 && table2.cols === 1) {
24790
+ const content = sanitizeText(table2.cells[0][0].text);
23852
24791
  const replicaLines = content.split(/\n/).map((line) => {
23853
24792
  const t = line.trim();
23854
24793
  if (!t) return "";
@@ -23862,12 +24801,12 @@ function patchTextChunk5(table, scanTable, orig, edited, ctx, skip) {
23862
24801
  const unwrap = m && /^\d+\.\s/.test(unescapeGfm(m[1]));
23863
24802
  return stripCellTokens(unescapeGfm(unwrap ? m[1] : l)).trim();
23864
24803
  }).filter(Boolean);
23865
- return applyCellEdit5(table, scanTable, 0, 0, newLines, ctx, orig.raw, edited.raw, orig.lines.length);
24804
+ return applyCellEdit5(table2, scanTable, 0, 0, newLines, ctx, orig.raw, edited.raw, orig.lines.length);
23866
24805
  }
23867
- if (table.cols === 1 && table.rows >= 2) {
24806
+ if (table2.cols === 1 && table2.rows >= 2) {
23868
24807
  const replica = [];
23869
- for (let r = 0; r < table.rows; r++) {
23870
- const line = escapeGfm(sanitizeText(table.cells[r][0].text)).replace(/\n/g, " ");
24808
+ for (let r = 0; r < table2.rows; r++) {
24809
+ const line = escapeGfm(sanitizeText(table2.cells[r][0].text)).replace(/\n/g, " ");
23871
24810
  if (line) replica.push({ line, gridR: r });
23872
24811
  }
23873
24812
  if (replica.map((x) => x.line).join("\n") !== orig.lines.join("\n")) return skip("\uD45C \uC88C\uD45C \uC7AC\uD604 \uBD88\uC77C\uCE58 \u2014 \uB9E4\uD551 \uC2E0\uB8B0 \uBD88\uAC00");
@@ -23880,21 +24819,21 @@ function patchTextChunk5(table, scanTable, orig, edited, ctx, skip) {
23880
24819
  continue;
23881
24820
  }
23882
24821
  const newLines = [stripCellTokens(unescapeGfm(edited.lines[i])).trim()].filter(Boolean);
23883
- applied += applyCellEdit5(table, scanTable, replica[i].gridR, 0, newLines, ctx, replica[i].line, edited.lines[i], 1);
24822
+ applied += applyCellEdit5(table2, scanTable, replica[i].gridR, 0, newLines, ctx, replica[i].line, edited.lines[i], 1);
23884
24823
  }
23885
24824
  return applied;
23886
24825
  }
23887
24826
  return skip("\uD45C \uB80C\uB354 \uACBD\uB85C \uC2DD\uBCC4 \uC2E4\uD328");
23888
24827
  }
23889
- function applyCellEdit5(table, scanTable, gridR, gridC, newLines, ctx, before, after, origLineCount) {
24828
+ function applyCellEdit5(table2, scanTable, gridR, gridC, newLines, ctx, before, after, origLineCount) {
23890
24829
  const skip = (reason) => {
23891
24830
  ctx.skipped.push({ reason, before: summarize(before), after: summarize(after) });
23892
24831
  return 0;
23893
24832
  };
23894
- const cell = scanTable.cells.get(`${gridR},${gridC}`);
23895
- if (!cell) return skip("\uC140 \uC88C\uD45C \uB9E4\uD551 \uC2E4\uD328 (\uBCD1\uD569 \uC601\uC5ED\uC758 \uBE48 \uCE78\uC774\uAC70\uB098 \uC88C\uD45C \uBD88\uC77C\uCE58)");
23896
- const irCell = table.cells[gridR]?.[gridC];
23897
- const scanJoined = cell.paras.map((p) => p.rawText).filter((t) => normForMatch(t)).join("\n");
24833
+ const cell2 = scanTable.cells.get(`${gridR},${gridC}`);
24834
+ if (!cell2) return skip("\uC140 \uC88C\uD45C \uB9E4\uD551 \uC2E4\uD328 (\uBCD1\uD569 \uC601\uC5ED\uC758 \uBE48 \uCE78\uC774\uAC70\uB098 \uC88C\uD45C \uBD88\uC77C\uCE58)");
24835
+ const irCell = table2.cells[gridR]?.[gridC];
24836
+ const scanJoined = cell2.paras.map((p) => p.rawText).filter((t) => normForMatch(t)).join("\n");
23898
24837
  if (irCell && normForMatch(scanJoined) !== normForMatch(stripCellTokens(irCell.text))) {
23899
24838
  if (normForMatch(irCell.text) !== "" || normForMatch(scanJoined) !== "") {
23900
24839
  const flatBlocks = (irCell.blocks ?? []).filter((b) => b.type === "paragraph" || b.type === "heading");
@@ -23904,13 +24843,13 @@ function applyCellEdit5(table, scanTable, gridR, gridC, newLines, ctx, before, a
23904
24843
  }
23905
24844
  }
23906
24845
  }
23907
- const nonEmpty = cell.paras.filter((p) => normForMatch(p.rawText) !== "");
24846
+ const nonEmpty = cell2.paras.filter((p) => normForMatch(p.rawText) !== "");
23908
24847
  if (origLineCount !== void 0 && nonEmpty.length > 0 && origLineCount !== nonEmpty.length) {
23909
24848
  return skip("\uC140 \uC904 \uACBD\uACC4 \uB9E4\uD551 \uBAA8\uD638 (\uBB38\uB2E8 \uB0B4 \uC904\uBC14\uAFC8) \u2014 \uBBF8\uC9C0\uC6D0");
23910
24849
  }
23911
24850
  const unstable = newLines.find((l) => sanitizeText(l) !== l);
23912
24851
  if (unstable !== void 0) 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");
23913
- const targets = nonEmpty.length > 0 ? nonEmpty : cell.paras;
24852
+ const targets = nonEmpty.length > 0 ? nonEmpty : cell2.paras;
23914
24853
  if (targets.length === 0) return skip("\uC140\uC5D0 \uBB38\uB2E8\uC774 \uC5C6\uC74C \u2014 \uBBF8\uC9C0\uC6D0");
23915
24854
  const assigned = [];
23916
24855
  for (let i = 0; i < targets.length; i++) {
@@ -24060,67 +24999,67 @@ function synthesizeLineSegs(lineSegData, newRaw, startUnits) {
24060
24999
  }
24061
25000
  return { buf: Buffer.concat(segs), count: lines.length };
24062
25001
  }
24063
- function stageParaPatch(scan, para, newPlain, skip) {
25002
+ function stageParaPatch(scan, para2, newPlain, skip) {
24064
25003
  if (!scan.safe) return skip("\uC139\uC158 \uB808\uCF54\uB4DC \uC7AC\uC9C1\uB82C\uD654 \uBD88\uC77C\uCE58 \u2014 \uC548\uC804\uC744 \uC704\uD574 \uC774 \uC139\uC158\uC740 \uBBF8\uC9C0\uC6D0");
24065
- if (para.textIdx === -2) return skip("\uBCF5\uC218 PARA_TEXT \uB808\uCF54\uB4DC \uBB38\uB2E8 \u2014 \uBBF8\uC9C0\uC6D0 (v1)");
24066
- if (para.rangeTagCount > 0) return skip("\uBC94\uC704 \uD0DC\uADF8(\uD615\uAD11\uD39C/\uAD50\uC815\uBD80\uD638) \uBB38\uB2E8 \u2014 \uBBF8\uC9C0\uC6D0 (v1)");
24067
- if (para.charShapeIdx < 0 || para.lineSegIdx < 0) return skip("\uBB38\uB2E8 \uB808\uCF54\uB4DC \uAD6C\uC131 \uBE44\uC815\uD615 \u2014 \uBBF8\uC9C0\uC6D0");
24068
- if (scan.repl.has(para.headerIdx)) return skip("\uB3D9\uC77C \uBB38\uB2E8 \uC911\uBCF5 \uC218\uC815 \u2014 \uCCAB \uC218\uC815\uB9CC \uC801\uC6A9");
25004
+ if (para2.textIdx === -2) return skip("\uBCF5\uC218 PARA_TEXT \uB808\uCF54\uB4DC \uBB38\uB2E8 \u2014 \uBBF8\uC9C0\uC6D0 (v1)");
25005
+ if (para2.rangeTagCount > 0) return skip("\uBC94\uC704 \uD0DC\uADF8(\uD615\uAD11\uD39C/\uAD50\uC815\uBD80\uD638) \uBB38\uB2E8 \u2014 \uBBF8\uC9C0\uC6D0 (v1)");
25006
+ if (para2.charShapeIdx < 0 || para2.lineSegIdx < 0) return skip("\uBB38\uB2E8 \uB808\uCF54\uB4DC \uAD6C\uC131 \uBE44\uC815\uD615 \u2014 \uBBF8\uC9C0\uC6D0");
25007
+ if (scan.repl.has(para2.headerIdx)) return skip("\uB3D9\uC77C \uBB38\uB2E8 \uC911\uBCF5 \uC218\uC815 \u2014 \uCCAB \uC218\uC815\uB9CC \uC801\uC6A9");
24069
25008
  if (/[\u0000-\u0009\u000b-\u001f]/.test(newPlain)) return skip("\uC0C8 \uD14D\uC2A4\uD2B8\uC5D0 \uC81C\uC5B4\uBB38\uC790 \uD3EC\uD568 \u2014 \uBBF8\uC9C0\uC6D0");
24070
25009
  const records = scan.records;
24071
- const headerRec = records[para.headerIdx];
24072
- const charShapeRec = records[para.charShapeIdx];
25010
+ const headerRec = records[para2.headerIdx];
25011
+ const charShapeRec = records[para2.charShapeIdx];
24073
25012
  if (charShapeRec.data.length < 8) {
24074
25013
  return skip("CHAR_SHAPE \uB808\uCF54\uB4DC \uBE44\uC815\uD615 \u2014 \uBBF8\uC9C0\uC6D0");
24075
25014
  }
24076
- if (para.textIdx === -1) {
24077
- const nCharsLow = para.nCharsRaw & 2147483647;
25015
+ if (para2.textIdx === -1) {
25016
+ const nCharsLow = para2.nCharsRaw & 2147483647;
24078
25017
  if (nCharsLow > 1) return skip("PARA_TEXT \uC5C6\uB294 \uBB38\uB2E8\uC758 nChars \uBE44\uC815\uD615 \u2014 \uBBF8\uC9C0\uC6D0");
24079
25018
  const paraEnd = nCharsLow === 1 ? Buffer.from([13, 0]) : Buffer.alloc(0);
24080
- const at = para.headerIdx + 1;
25019
+ const at = para2.headerIdx + 1;
24081
25020
  const list = scan.inserts.get(at) ?? [];
24082
25021
  list.push({ tagId: TAG_PARA_TEXT, level: headerRec.level + 1, data: Buffer.concat([Buffer.from(newPlain, "utf16le"), paraEnd]) });
24083
25022
  scan.inserts.set(at, list);
24084
25023
  const newHeader2 = Buffer.from(headerRec.data);
24085
- newHeader2.writeUInt32LE((para.nCharsRaw & 2147483648 | newPlain.length + nCharsLow) >>> 0, 0);
25024
+ newHeader2.writeUInt32LE((para2.nCharsRaw & 2147483648 | newPlain.length + nCharsLow) >>> 0, 0);
24086
25025
  const cs2 = rebuildCharShape(charShapeRec.data, 0);
24087
- scan.repl.set(para.charShapeIdx, cs2.buf);
25026
+ scan.repl.set(para2.charShapeIdx, cs2.buf);
24088
25027
  newHeader2.writeUInt16LE(cs2.count, 12);
24089
25028
  if (newPlain.includes("\n")) {
24090
- const synth = synthesizeLineSegs(records[para.lineSegIdx].data, newPlain, 0);
25029
+ const synth = synthesizeLineSegs(records[para2.lineSegIdx].data, newPlain, 0);
24091
25030
  if (synth) {
24092
- scan.repl.set(para.lineSegIdx, synth.buf);
25031
+ scan.repl.set(para2.lineSegIdx, synth.buf);
24093
25032
  newHeader2.writeUInt16LE(synth.count, 16);
24094
25033
  }
24095
25034
  }
24096
- scan.repl.set(para.headerIdx, newHeader2);
25035
+ scan.repl.set(para2.headerIdx, newHeader2);
24097
25036
  return 1;
24098
25037
  }
24099
- const textRec = records[para.textIdx];
25038
+ const textRec = records[para2.textIdx];
24100
25039
  const seg = splitParaText(textRec.data);
24101
25040
  if (!seg) {
24102
- return skip(para.ctrlMask !== 0 ? "\uCEE8\uD2B8\uB864 \uBB38\uC790(\uD0ED/\uD544\uB4DC/\uD2B9\uC218\uACF5\uBC31 \uB4F1 \uD14D\uC2A4\uD2B8 \uC911\uAC04) \uD3EC\uD568 \uBB38\uB2E8 \u2014 \uBBF8\uC9C0\uC6D0 (v1)" : "PARA_TEXT \uC7AC\uAD6C\uC131 \uBD88\uC77C\uCE58 \u2014 \uC6D0\uBB38 \uBCF4\uC874 \uBD88\uAC00\uB85C \uBBF8\uC9C0\uC6D0");
25041
+ return skip(para2.ctrlMask !== 0 ? "\uCEE8\uD2B8\uB864 \uBB38\uC790(\uD0ED/\uD544\uB4DC/\uD2B9\uC218\uACF5\uBC31 \uB4F1 \uD14D\uC2A4\uD2B8 \uC911\uAC04) \uD3EC\uD568 \uBB38\uB2E8 \u2014 \uBBF8\uC9C0\uC6D0 (v1)" : "PARA_TEXT \uC7AC\uAD6C\uC131 \uBD88\uC77C\uCE58 \u2014 \uC6D0\uBB38 \uBCF4\uC874 \uBD88\uAC00\uB85C \uBBF8\uC9C0\uC6D0");
24103
25042
  }
24104
- if (seg.core !== para.rawText) return skip("PARA_TEXT \uC7AC\uAD6C\uC131 \uBD88\uC77C\uCE58 \u2014 \uC6D0\uBB38 \uBCF4\uC874 \uBD88\uAC00\uB85C \uBBF8\uC9C0\uC6D0");
24105
- const lead = para.rawText.match(/^\s*/)[0];
24106
- const trail = para.rawText.match(/\s*$/)[0];
24107
- const newRaw = para.rawText.trim() === para.rawText ? newPlain : lead + newPlain + trail;
25043
+ if (seg.core !== para2.rawText) return skip("PARA_TEXT \uC7AC\uAD6C\uC131 \uBD88\uC77C\uCE58 \u2014 \uC6D0\uBB38 \uBCF4\uC874 \uBD88\uAC00\uB85C \uBBF8\uC9C0\uC6D0");
25044
+ const lead = para2.rawText.match(/^\s*/)[0];
25045
+ const trail = para2.rawText.match(/\s*$/)[0];
25046
+ const newRaw = para2.rawText.trim() === para2.rawText ? newPlain : lead + newPlain + trail;
24108
25047
  const newText = Buffer.concat([seg.prefix, Buffer.from(newRaw, "utf16le"), seg.suffix]);
24109
- scan.repl.set(para.textIdx, newText);
25048
+ scan.repl.set(para2.textIdx, newText);
24110
25049
  const newHeader = Buffer.from(headerRec.data);
24111
25050
  const nChars = seg.prefixUnits + newRaw.length + seg.suffixUnits;
24112
- newHeader.writeUInt32LE((para.nCharsRaw & 2147483648 | nChars) >>> 0, 0);
25051
+ newHeader.writeUInt32LE((para2.nCharsRaw & 2147483648 | nChars) >>> 0, 0);
24113
25052
  const cs = rebuildCharShape(charShapeRec.data, seg.prefixUnits);
24114
- scan.repl.set(para.charShapeIdx, cs.buf);
25053
+ scan.repl.set(para2.charShapeIdx, cs.buf);
24115
25054
  newHeader.writeUInt16LE(cs.count, 12);
24116
25055
  if (newRaw.includes("\n")) {
24117
- const synth = synthesizeLineSegs(records[para.lineSegIdx].data, newRaw, seg.prefixUnits);
25056
+ const synth = synthesizeLineSegs(records[para2.lineSegIdx].data, newRaw, seg.prefixUnits);
24118
25057
  if (synth) {
24119
- scan.repl.set(para.lineSegIdx, synth.buf);
25058
+ scan.repl.set(para2.lineSegIdx, synth.buf);
24120
25059
  newHeader.writeUInt16LE(synth.count, 16);
24121
25060
  }
24122
25061
  }
24123
- scan.repl.set(para.headerIdx, newHeader);
25062
+ scan.repl.set(para2.headerIdx, newHeader);
24124
25063
  return 1;
24125
25064
  }
24126
25065
 
@@ -24285,9 +25224,9 @@ var HwpxSession = class _HwpxSession {
24285
25224
  const block = st.blocks[blockIndex];
24286
25225
  if (!block) return void 0;
24287
25226
  if (block.type === "paragraph" || block.type === "heading") {
24288
- const para = st.paraMap.get(blockIndex)?.para;
24289
- if (!para) return void 0;
24290
- return { kind: "paragraph", sectionIndex: para.sectionIndex, xmlStart: para.start };
25227
+ const para2 = st.paraMap.get(blockIndex)?.para;
25228
+ if (!para2) return void 0;
25229
+ return { kind: "paragraph", sectionIndex: para2.sectionIndex, xmlStart: para2.start };
24291
25230
  }
24292
25231
  if (block.type === "table" && block.table) {
24293
25232
  if (st.tableOrdinals.size !== st.scanTables.length) return void 0;
@@ -24324,13 +25263,13 @@ var HwpxSession = class _HwpxSession {
24324
25263
  if (!scanTable) {
24325
25264
  return { capability: "locked", reason: "\uD45C \uC18C\uC2A4\uB9F5 \uB9E4\uD551 \uC2E4\uD328" };
24326
25265
  }
24327
- const table = block.table;
25266
+ const table2 = block.table;
24328
25267
  const cells = [];
24329
25268
  let anyEditable = false;
24330
- for (let r = 0; r < table.rows; r++) {
25269
+ for (let r = 0; r < table2.rows; r++) {
24331
25270
  const row = [];
24332
- for (let c = 0; c < table.cols; c++) {
24333
- const info = cellStaticCheck(table, scanTable, r, c);
25271
+ for (let c = 0; c < table2.cols; c++) {
25272
+ const info = cellStaticCheck(table2, scanTable, r, c);
24334
25273
  if (info.editable) anyEditable = true;
24335
25274
  row.push(info);
24336
25275
  }
@@ -24519,12 +25458,12 @@ var HwpxSession = class _HwpxSession {
24519
25458
  return 1;
24520
25459
  }
24521
25460
  };
24522
- function cellStaticCheck(table, scanTable, r, c) {
24523
- const irCell = table.cells[r]?.[c];
25461
+ function cellStaticCheck(table2, scanTable, r, c) {
25462
+ const irCell = table2.cells[r]?.[c];
24524
25463
  if (!irCell) return { editable: false, reason: "\uC140 \uC88C\uD45C \uBC94\uC704 \uBC16" };
24525
- const cell = scanTable.cellByAnchor.get(`${r},${c}`);
24526
- if (!cell) return { editable: false, reason: "\uBCD1\uD569 \uC601\uC5ED\uC758 \uBE48 \uCE78\uC774\uAC70\uB098 \uC88C\uD45C \uBD88\uC77C\uCE58" };
24527
- const scanJoined = cell.paragraphs.map((p) => p.text).filter((t) => normForMatch(t)).join("\n");
25464
+ const cell2 = scanTable.cellByAnchor.get(`${r},${c}`);
25465
+ if (!cell2) return { editable: false, reason: "\uBCD1\uD569 \uC601\uC5ED\uC758 \uBE48 \uCE78\uC774\uAC70\uB098 \uC88C\uD45C \uBD88\uC77C\uCE58" };
25466
+ const scanJoined = cell2.paragraphs.map((p) => p.text).filter((t) => normForMatch(t)).join("\n");
24528
25467
  if (normForMatch(scanJoined) !== normForMatch(stripCellTokens(irCell.text))) {
24529
25468
  if (normForMatch(irCell.text) !== "" || normForMatch(scanJoined) !== "") {
24530
25469
  const flatBlocks = (irCell.blocks ?? []).filter((b) => b.type === "paragraph" || b.type === "heading");
@@ -24534,9 +25473,9 @@ function cellStaticCheck(table, scanTable, r, c) {
24534
25473
  }
24535
25474
  }
24536
25475
  }
24537
- const nonEmpty = cell.paragraphs.filter((p) => normForMatch(p.text) !== "");
25476
+ const nonEmpty = cell2.paragraphs.filter((p) => normForMatch(p.text) !== "");
24538
25477
  if (nonEmpty.length === 0) {
24539
- if (cell.paragraphs.length === 0) {
25478
+ if (cell2.paragraphs.length === 0) {
24540
25479
  return { editable: false, reason: "\uBE48 \uC140\uC5D0 \uBB38\uB2E8\uC774 \uC5C6\uC5B4 \uD14D\uC2A4\uD2B8 \uC0BD\uC785 \uBD88\uAC00" };
24541
25480
  }
24542
25481
  return { editable: true };
@@ -24795,7 +25734,7 @@ async function parseHwp(buffer, options) {
24795
25734
  async function parsePdf(buffer, options) {
24796
25735
  let parsePdfDocument;
24797
25736
  try {
24798
- const mod = await import("./parser-NZAE7PBE.js");
25737
+ const mod = await import("./parser-LHUO6UUA.js");
24799
25738
  parsePdfDocument = mod.parsePdfDocument;
24800
25739
  } catch {
24801
25740
  return {
@@ -24887,7 +25826,6 @@ async function fillForm(input, values, outputFormat = "markdown") {
24887
25826
 
24888
25827
  export {
24889
25828
  extractHwpxMetadataOnly,
24890
- MAX_INLINE_MD_BYTES,
24891
25829
  extractHwp5MetadataOnly,
24892
25830
  formatFillValue,
24893
25831
  ValueCursor,
@@ -24904,6 +25842,8 @@ export {
24904
25842
  compare,
24905
25843
  diffBlocks,
24906
25844
  hwpxToProfile,
25845
+ isKnownFont,
25846
+ unknownFontWarnings,
24907
25847
  patchHwpx,
24908
25848
  patchHwp,
24909
25849
  validateHwpx,
@@ -24924,4 +25864,4 @@ export {
24924
25864
  parseHwpml,
24925
25865
  fillForm
24926
25866
  };
24927
- //# sourceMappingURL=chunk-PWHM3KAA.js.map
25867
+ //# sourceMappingURL=chunk-PGWAF755.js.map