kordoc 3.18.1 → 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/{-V66QW3WA.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-2IBFK5ZO.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-4RGDFDQ2.js → chunk-DVUNWK6W.js} +8 -2
  9. package/dist/chunk-DVUNWK6W.js.map +1 -0
  10. package/dist/{chunk-R2H34FY5.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-UHYPUIRH.js → chunk-IA5UZZKV.js} +2 -2
  14. package/dist/chunk-IA5UZZKV.js.map +1 -0
  15. package/dist/{chunk-QMJJI6TD.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-7K5P4RNT.js → chunk-PGWAF755.js} +1489 -585
  19. package/dist/chunk-PGWAF755.js.map +1 -0
  20. package/dist/{chunk-NZJAXMN7.js → chunk-THZVBYHE.js} +3 -3
  21. package/dist/chunk-THZVBYHE.js.map +1 -0
  22. package/dist/{chunk-UNV7F3FK.js → chunk-ZKG6SBHV.js} +2 -2
  23. package/dist/chunk-ZKG6SBHV.js.map +1 -0
  24. package/dist/cli.js +40 -16
  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 +1876 -966
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.cts +76 -9
  32. package/dist/index.d.ts +76 -9
  33. package/dist/index.js +1648 -738
  34. package/dist/index.js.map +1 -1
  35. package/dist/mcp.js +55 -16
  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-XEY5MRGV.cjs → parser-6TV6JKHF.cjs} +15 -15
  40. package/dist/parser-6TV6JKHF.cjs.map +1 -0
  41. package/dist/{parser-DOBK652H.js → parser-LHUO6UUA.js} +4 -4
  42. package/dist/parser-LHUO6UUA.js.map +1 -0
  43. package/dist/{parser-JBBA5A5E.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-2MNRQWGV.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-2IBFK5ZO.js.map +0 -1
  58. package/dist/chunk-4RGDFDQ2.js.map +0 -1
  59. package/dist/chunk-7K5P4RNT.js.map +0 -1
  60. package/dist/chunk-MEPHGCPQ.js.map +0 -1
  61. package/dist/chunk-NZJAXMN7.js.map +0 -1
  62. package/dist/chunk-QMJJI6TD.js.map +0 -1
  63. package/dist/chunk-R2H34FY5.cjs.map +0 -1
  64. package/dist/chunk-UHYPUIRH.js.map +0 -1
  65. package/dist/chunk-UNV7F3FK.js.map +0 -1
  66. package/dist/parser-DOBK652H.js.map +0 -1
  67. package/dist/parser-JBBA5A5E.js.map +0 -1
  68. package/dist/parser-XEY5MRGV.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-VX4H2S4F.js +0 -10
  73. package/dist/seal-6Z6H4YXN.js +0 -10
  74. package/dist/watch-2MNRQWGV.js.map +0 -1
  75. /package/dist/{-V66QW3WA.js.map → -URVKBXYK.js.map} +0 -0
  76. /package/dist/{detect-RI2MQ33K.js.map → detect-PJZMUL2Z.js.map} +0 -0
  77. /package/dist/{render-VX4H2S4F.js.map → render-T5O6QHBJ.js.map} +0 -0
  78. /package/dist/{seal-6Z6H4YXN.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-2IBFK5ZO.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-NZJAXMN7.js";
35
+ } from "./chunk-THZVBYHE.js";
36
36
  import {
37
37
  SPACE_EM_FIXED,
38
38
  charWidthEm1000,
39
- fitRatioForFewerLines
40
- } from "./chunk-QMJJI6TD.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-4RGDFDQ2.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-UNV7F3FK.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;
@@ -4058,8 +4067,8 @@ function parseParagraph(records, start, end, ctx) {
4058
4067
  function applyCtrlEffect(ctrl, records, ctx) {
4059
4068
  switch (ctrl.id) {
4060
4069
  case CTRL_TBL: {
4061
- const table = parseTableControl(ctrl, records, ctx);
4062
- 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 }];
4063
4072
  return;
4064
4073
  }
4065
4074
  case CTRL_GSO: {
@@ -4278,14 +4287,14 @@ function parseTableControl(ctrl, records, ctx) {
4278
4287
  if (c.isHeader) ir.isHeader = true;
4279
4288
  return ir;
4280
4289
  }));
4281
- const table2 = { rows, cols, cells: irCells, hasHeader: rows > 1 };
4282
- if (caption) table2.caption = caption;
4283
- return table2;
4290
+ const table3 = { rows, cols, cells: irCells, hasHeader: rows > 1 };
4291
+ if (caption) table3.caption = caption;
4292
+ return table3;
4284
4293
  }
4285
4294
  const cellRows = arrangeCells(rows, cols, cells);
4286
- const table = buildTable(cellRows);
4287
- if (caption && table.rows > 0) table.caption = caption;
4288
- 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;
4289
4298
  }
4290
4299
  function parseCell(records, lhIdx, end, ctx) {
4291
4300
  const rec = records[lhIdx];
@@ -4323,22 +4332,22 @@ function parseCell(records, lhIdx, end, ctx) {
4323
4332
  parts.push(t);
4324
4333
  }
4325
4334
  }
4326
- const cell = { text: parts.join("\n"), colSpan, rowSpan, colAddr, rowAddr };
4327
- if (hasStructure && blocks.length > 0) cell.blocks = blocks;
4328
- if (isHeader) cell.isHeader = true;
4329
- 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;
4330
4339
  }
4331
4340
  function arrangeCells(rows, cols, cells) {
4332
4341
  const grid = Array.from({ length: rows }, () => Array(cols).fill(null));
4333
4342
  const hasAddr = cells.some((c) => c.colAddr !== void 0 && c.rowAddr !== void 0);
4334
4343
  if (hasAddr) {
4335
- for (const cell of cells) {
4336
- const r = cell.rowAddr ?? 0;
4337
- const c = cell.colAddr ?? 0;
4344
+ for (const cell2 of cells) {
4345
+ const r = cell2.rowAddr ?? 0;
4346
+ const c = cell2.colAddr ?? 0;
4338
4347
  if (r >= rows || c >= cols) continue;
4339
- grid[r][c] = cell;
4340
- for (let dr = 0; dr < cell.rowSpan; dr++) {
4341
- 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++) {
4342
4351
  if (dr === 0 && dc === 0) continue;
4343
4352
  if (r + dr < rows && c + dc < cols)
4344
4353
  grid[r + dr][c + dc] = { text: "", colSpan: 1, rowSpan: 1 };
@@ -4350,10 +4359,10 @@ function arrangeCells(rows, cols, cells) {
4350
4359
  for (let r = 0; r < rows && cellIdx < cells.length; r++) {
4351
4360
  for (let c = 0; c < cols && cellIdx < cells.length; c++) {
4352
4361
  if (grid[r][c] !== null) continue;
4353
- const cell = cells[cellIdx++];
4354
- grid[r][c] = cell;
4355
- for (let dr = 0; dr < cell.rowSpan; dr++) {
4356
- 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++) {
4357
4366
  if (dr === 0 && dc === 0) continue;
4358
4367
  if (r + dr < rows && c + dc < cols)
4359
4368
  grid[r + dr][c + dc] = { text: "", colSpan: 1, rowSpan: 1 };
@@ -16869,7 +16878,7 @@ function sheetToBlocks(sheetName, grid, merges, maxRow, maxCol, sheetIndex) {
16869
16878
  let lastRow = -1;
16870
16879
  for (let r = 0; r <= maxRow; r++) {
16871
16880
  const row = grid[r];
16872
- if (row && row.some((cell) => cell !== "")) {
16881
+ if (row && row.some((cell2) => cell2 !== "")) {
16873
16882
  if (firstRow === -1) firstRow = r;
16874
16883
  lastRow = r;
16875
16884
  }
@@ -16892,9 +16901,9 @@ function sheetToBlocks(sheetName, grid, merges, maxRow, maxCol, sheetIndex) {
16892
16901
  cellRows.push(row);
16893
16902
  }
16894
16903
  if (cellRows.length > 0) {
16895
- const table = buildTable(cellRows);
16896
- if (table.rows > 0) {
16897
- 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 });
16898
16907
  }
16899
16908
  }
16900
16909
  return blocks;
@@ -17512,9 +17521,9 @@ function sheetToBlocks2(sheetName, sheet, sheetIndex) {
17512
17521
  cellRows.push(row);
17513
17522
  }
17514
17523
  if (cellRows.length > 0) {
17515
- const table = buildTable(cellRows);
17516
- if (table.rows > 0) {
17517
- 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 });
17518
17527
  }
17519
17528
  }
17520
17529
  return blocks;
@@ -18260,8 +18269,8 @@ function collectTextboxParagraphs(node, inTxbx = false, out = [], depth = 0) {
18260
18269
  }
18261
18270
  return out;
18262
18271
  }
18263
- function parseTable(tbl, styles, numbering, footnotes, rels) {
18264
- const trElements = getChildElements(tbl, "tr");
18272
+ function parseTable(tbl2, styles, numbering, footnotes, rels) {
18273
+ const trElements = getChildElements(tbl2, "tr");
18265
18274
  if (trElements.length === 0) return null;
18266
18275
  const rawRows = [];
18267
18276
  for (const tr of trElements) {
@@ -18274,10 +18283,10 @@ function parseTable(tbl, styles, numbering, footnotes, rels) {
18274
18283
  col = Math.max(0, parseInt(getAttr(gridBeforeEls[0], "val") ?? "0", 10) || 0);
18275
18284
  }
18276
18285
  }
18277
- for (const tc of getChildElements(tr, "tc")) {
18286
+ for (const tc2 of getChildElements(tr, "tc")) {
18278
18287
  let colSpan = 1;
18279
18288
  let vMerge = null;
18280
- const tcPrEls = getChildElements(tc, "tcPr");
18289
+ const tcPrEls = getChildElements(tc2, "tcPr");
18281
18290
  if (tcPrEls.length > 0) {
18282
18291
  const gridSpanEls = getChildElements(tcPrEls[0], "gridSpan");
18283
18292
  if (gridSpanEls.length > 0) {
@@ -18288,48 +18297,48 @@ function parseTable(tbl, styles, numbering, footnotes, rels) {
18288
18297
  vMerge = getAttr(vMergeEls[0], "val") === "restart" ? "restart" : "continue";
18289
18298
  }
18290
18299
  }
18291
- const text = collectCellText(tc, styles, numbering, footnotes, rels, 0).join("\n");
18300
+ const text = collectCellText(tc2, styles, numbering, footnotes, rels, 0).join("\n");
18292
18301
  row.push({ col, colSpan, vMerge, text });
18293
18302
  col += colSpan;
18294
18303
  }
18295
18304
  rawRows.push(row);
18296
18305
  }
18297
18306
  for (let r = 0; r < rawRows.length; r++) {
18298
- for (const cell of rawRows[r]) {
18299
- if (cell.vMerge !== "continue" || !cell.text) continue;
18307
+ for (const cell2 of rawRows[r]) {
18308
+ if (cell2.vMerge !== "continue" || !cell2.text) continue;
18300
18309
  let start;
18301
18310
  for (let pr = r - 1; pr >= 0 && !start; pr--) {
18302
- 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");
18303
18312
  }
18304
18313
  if (start) {
18305
18314
  start.text = start.text ? `${start.text}
18306
- ${cell.text}` : cell.text;
18307
- cell.text = "";
18315
+ ${cell2.text}` : cell2.text;
18316
+ cell2.text = "";
18308
18317
  } else {
18309
- cell.vMerge = null;
18318
+ cell2.vMerge = null;
18310
18319
  }
18311
18320
  }
18312
18321
  }
18313
18322
  const cellRows = rawRows.map(
18314
- (row, r) => row.filter((cell) => cell.vMerge !== "continue").map((cell) => {
18323
+ (row, r) => row.filter((cell2) => cell2.vMerge !== "continue").map((cell2) => {
18315
18324
  let rowSpan = 1;
18316
- if (cell.vMerge === "restart") {
18325
+ if (cell2.vMerge === "restart") {
18317
18326
  for (let nr = r + 1; nr < rawRows.length; nr++) {
18318
- 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;
18319
18328
  rowSpan++;
18320
18329
  }
18321
18330
  }
18322
- 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 };
18323
18332
  })
18324
18333
  );
18325
- const table = buildTable(cellRows);
18326
- if (table.rows === 0 || table.cols === 0) return null;
18327
- 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 };
18328
18337
  }
18329
- function collectCellText(tc, styles, numbering, footnotes, rels, depth) {
18338
+ function collectCellText(tc2, styles, numbering, footnotes, rels, depth) {
18330
18339
  const parts = [];
18331
18340
  if (depth > 20) return parts;
18332
- for (const el of effectiveChildElements(tc)) {
18341
+ for (const el of effectiveChildElements(tc2)) {
18333
18342
  if (matchesLocal(el, "p")) {
18334
18343
  const block = parseParagraph2(el, styles, numbering, footnotes, rels);
18335
18344
  if (block?.text) parts.push(block.text);
@@ -18690,13 +18699,13 @@ function parseTable2(el, blocks, paraShapeMap, sectionNum, warnings) {
18690
18699
  }
18691
18700
  if (cells.length === 0) return;
18692
18701
  const grid = Array.from({ length: rowCount }, () => Array(colCount).fill(null));
18693
- for (const cell of cells) {
18694
- const r = cell.rowAddr ?? 0;
18695
- const c = cell.colAddr ?? 0;
18702
+ for (const cell2 of cells) {
18703
+ const r = cell2.rowAddr ?? 0;
18704
+ const c = cell2.colAddr ?? 0;
18696
18705
  if (isNaN(r) || isNaN(c) || r >= rowCount || c >= colCount) continue;
18697
- grid[r][c] = cell;
18698
- for (let dr = 0; dr < cell.rowSpan; dr++) {
18699
- 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++) {
18700
18709
  if (dr === 0 && dc === 0) continue;
18701
18710
  if (r + dr < rowCount && c + dc < colCount) {
18702
18711
  grid[r + dr][c + dc] = { text: "", colSpan: 1, rowSpan: 1 };
@@ -18705,14 +18714,14 @@ function parseTable2(el, blocks, paraShapeMap, sectionNum, warnings) {
18705
18714
  }
18706
18715
  }
18707
18716
  const cellRows = grid.map(
18708
- (row) => row.map((cell) => cell ?? { text: "", colSpan: 1, rowSpan: 1 })
18717
+ (row) => row.map((cell2) => cell2 ?? { text: "", colSpan: 1, rowSpan: 1 })
18709
18718
  );
18710
- const table = buildTable(cellRows);
18719
+ const table2 = buildTable(cellRows);
18711
18720
  const caption = extractShapeCaption(el);
18712
18721
  if (caption.text && caption.before) {
18713
18722
  blocks.push({ type: "paragraph", text: caption.text, pageNumber: sectionNum });
18714
18723
  }
18715
- blocks.push({ type: "table", table, pageNumber: sectionNum });
18724
+ blocks.push({ type: "table", table: table2, pageNumber: sectionNum });
18716
18725
  if (caption.text && !caption.before) {
18717
18726
  blocks.push({ type: "paragraph", text: caption.text, pageNumber: sectionNum });
18718
18727
  }
@@ -19212,13 +19221,13 @@ function extractFormFields(blocks) {
19212
19221
  const confidence = totalTables > 0 ? formTables / totalTables : fields.length > 0 ? 0.3 : 0;
19213
19222
  return { fields, confidence: Math.min(confidence, 1) };
19214
19223
  }
19215
- function extractFromTable(table) {
19224
+ function extractFromTable(table2) {
19216
19225
  const fields = [];
19217
- if (table.cols >= 2) {
19218
- for (let r = 0; r < table.rows; r++) {
19219
- for (let c = 0; c < table.cols - 1; c++) {
19220
- const labelCell = table.cells[r]?.[c];
19221
- 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];
19222
19231
  if (!labelCell || !valueCell) continue;
19223
19232
  if (isLabelCell(labelCell.text)) {
19224
19233
  fields.push({
@@ -19231,17 +19240,17 @@ function extractFromTable(table) {
19231
19240
  }
19232
19241
  }
19233
19242
  }
19234
- if (fields.length === 0 && table.rows >= 2 && table.cols >= 2) {
19235
- const headerRow = table.cells[0];
19236
- const allLabels = headerRow.every((cell) => {
19237
- 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();
19238
19247
  return t.length > 0 && t.length <= 20;
19239
19248
  });
19240
19249
  if (allLabels) {
19241
- for (let r = 1; r < table.rows; r++) {
19242
- 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++) {
19243
19252
  const label = headerRow[c]?.text.trim() ?? "";
19244
- const value = table.cells[r]?.[c]?.text.trim() ?? "";
19253
+ const value = table2.cells[r]?.[c]?.text.trim() ?? "";
19245
19254
  if (label && value) {
19246
19255
  fields.push({ label, value, row: r, col: c });
19247
19256
  }
@@ -19278,9 +19287,9 @@ function inferFieldType(label, value) {
19278
19287
  if (/^[\d,.\s]+(?:원|명|건|개|회|부|매|%)$/.test(v) && /\d/.test(v)) return "amount";
19279
19288
  if (/^\d{1,3}(?:,\d{3})+$/.test(v)) return "amount";
19280
19289
  }
19281
- const norm = label.replace(/\s/g, "");
19290
+ const norm2 = label.replace(/\s/g, "");
19282
19291
  for (const [re, type] of LABEL_TYPE_RULES) {
19283
- if (re.test(norm)) return type;
19292
+ if (re.test(norm2)) return type;
19284
19293
  }
19285
19294
  return "text";
19286
19295
  }
@@ -19331,15 +19340,15 @@ function fillFormFields(blocks, values, blockedLabels) {
19331
19340
  const cursor = new ValueCursor(normalizedValues);
19332
19341
  const allTables = collectIRTables(cloned, 0);
19333
19342
  const patternFilledCells = /* @__PURE__ */ new Set();
19334
- for (const table of allTables) {
19335
- for (let r = 0; r < table.rows; r++) {
19336
- for (let c = 0; c < table.cols; c++) {
19337
- const cell = table.cells[r]?.[c];
19338
- if (!cell) continue;
19339
- 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);
19340
19349
  if (result) {
19341
- cell.text = result.text;
19342
- patternFilledCells.add(cell);
19350
+ cell2.text = result.text;
19351
+ patternFilledCells.add(cell2);
19343
19352
  for (const m of result.matches) {
19344
19353
  filled.push({ label: m.label, value: m.value, row: r, col: c, key: m.key });
19345
19354
  }
@@ -19347,8 +19356,8 @@ function fillFormFields(blocks, values, blockedLabels) {
19347
19356
  }
19348
19357
  }
19349
19358
  }
19350
- for (const table of allTables) {
19351
- fillTable(table, cursor, filled, matchedLabels, patternFilledCells, blockedLabels);
19359
+ for (const table2 of allTables) {
19360
+ fillTable(table2, cursor, filled, matchedLabels, patternFilledCells, blockedLabels);
19352
19361
  }
19353
19362
  for (const block of cloned) {
19354
19363
  if (block.type !== "paragraph" || !block.text) continue;
@@ -19365,44 +19374,44 @@ function collectIRTables(blocks, depth) {
19365
19374
  if (block.type !== "table" || !block.table) continue;
19366
19375
  out.push(block.table);
19367
19376
  for (const row of block.table.cells) {
19368
- for (const cell of row) {
19369
- 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));
19370
19379
  }
19371
19380
  }
19372
19381
  }
19373
19382
  return out;
19374
19383
  }
19375
- function coveredPositions(table) {
19384
+ function coveredPositions(table2) {
19376
19385
  const covered = /* @__PURE__ */ new Set();
19377
- for (let r = 0; r < table.rows; r++) {
19378
- 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++) {
19379
19388
  if (covered.has(`${r},${c}`)) continue;
19380
- const cell = table.cells[r]?.[c];
19381
- if (!cell) continue;
19382
- for (let dr = 0; dr < cell.rowSpan; dr++) {
19383
- 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++) {
19384
19393
  if (dr === 0 && dc === 0) continue;
19385
- 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}`);
19386
19395
  }
19387
19396
  }
19388
- c += cell.colSpan - 1;
19397
+ c += cell2.colSpan - 1;
19389
19398
  }
19390
19399
  }
19391
19400
  return covered;
19392
19401
  }
19393
- function fillTable(table, values, filled, matchedLabels, patternFilledCells, blockedLabels) {
19394
- if (table.cols < 2) return;
19395
- const covered = coveredPositions(table);
19396
- for (let r = 0; r < table.rows; r++) {
19397
- 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++) {
19398
19407
  if (covered.has(`${r},${c}`)) continue;
19399
- const labelCell = table.cells[r][c];
19408
+ const labelCell = table2.cells[r][c];
19400
19409
  if (!labelCell) continue;
19401
19410
  if (!isLabelCell(labelCell.text)) continue;
19402
19411
  let vc = c + labelCell.colSpan;
19403
- while (vc < table.cols && covered.has(`${r},${vc}`)) vc++;
19404
- if (vc >= table.cols) continue;
19405
- 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];
19406
19415
  if (!valueCell) continue;
19407
19416
  if (isKeywordLabel(valueCell.text)) continue;
19408
19417
  const normalizedCellLabel = normalizeLabel(labelCell.text);
@@ -19427,18 +19436,18 @@ function fillTable(table, values, filled, matchedLabels, patternFilledCells, blo
19427
19436
  });
19428
19437
  }
19429
19438
  }
19430
- if (table.rows >= 2 && table.cols >= 2) {
19431
- const headerRow = table.cells[0];
19432
- const allLabels = headerRow.every((cell) => {
19433
- 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();
19434
19443
  return t.length > 0 && t.length <= 20 && isLabelCell(t);
19435
19444
  });
19436
19445
  if (!allLabels) return;
19437
- for (let r = 1; r < table.rows; r++) {
19438
- 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++) {
19439
19448
  if (covered.has(`${r},${c}`)) continue;
19440
19449
  const headerCell = headerRow[c];
19441
- const valueCell = table.cells[r]?.[c];
19450
+ const valueCell = table2.cells[r]?.[c];
19442
19451
  if (!headerCell || !valueCell) continue;
19443
19452
  const headerLabel = normalizeLabel(headerCell.text);
19444
19453
  if (blockedLabels?.has(headerLabel)) continue;
@@ -19509,28 +19518,28 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19509
19518
  return l;
19510
19519
  };
19511
19520
  const matchText = (p) => paraTText(p, xml) ?? p.text;
19512
- 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("");
19513
19522
  const allTables = [];
19514
19523
  const collectTables = (tables, depth) => {
19515
19524
  if (depth > 16) return;
19516
19525
  for (const t of tables) {
19517
19526
  allTables.push(t);
19518
19527
  for (const row of t.rows) {
19519
- for (const cell of row) collectTables(cell.tables, depth + 1);
19528
+ for (const cell2 of row) collectTables(cell2.tables, depth + 1);
19520
19529
  }
19521
19530
  }
19522
19531
  };
19523
19532
  collectTables(scan.tables, 0);
19524
19533
  collectTables(scan.orphanTables, 0);
19525
19534
  const patternApplied = /* @__PURE__ */ new Set();
19526
- for (const table of allTables) {
19527
- for (const row of table.rows) {
19528
- for (const cell of row) {
19529
- for (const para of cell.paragraphs) {
19530
- 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);
19531
19540
  const result = fillInCellPatterns(text, cursor, matchedLabels, blockedLabels);
19532
19541
  if (!result) continue;
19533
- const l = led(para);
19542
+ const l = led(para2);
19534
19543
  if (l.fullText !== void 0) continue;
19535
19544
  const newT = result.text;
19536
19545
  let s = 0;
@@ -19542,7 +19551,7 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19542
19551
  en--;
19543
19552
  }
19544
19553
  l.ranges.push({ start: s, end: eo, replacement: newT.slice(s, en) });
19545
- patternApplied.add(cell);
19554
+ patternApplied.add(cell2);
19546
19555
  for (const m of result.matches) {
19547
19556
  l.filledIdx.push(filled.length);
19548
19557
  l.matchKeys.push(m.key);
@@ -19552,9 +19561,9 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19552
19561
  }
19553
19562
  }
19554
19563
  }
19555
- for (const table of allTables) {
19556
- for (let rowIdx = 0; rowIdx < table.rows.length; rowIdx++) {
19557
- 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];
19558
19567
  for (let colIdx = 0; colIdx < cells.length - 1; colIdx++) {
19559
19568
  const labelText = cellLabelText(cells[colIdx]);
19560
19569
  if (!isLabelCell(labelText)) continue;
@@ -19609,15 +19618,15 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19609
19618
  }
19610
19619
  }
19611
19620
  }
19612
- if (table.rows.length >= 2) {
19613
- const headerCells = table.rows[0];
19614
- const allLabels = headerCells.length > 0 && headerCells.every((cell) => {
19615
- 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();
19616
19625
  return t.length > 0 && t.length <= 20 && isLabelCell(t);
19617
19626
  });
19618
19627
  if (allLabels) {
19619
- for (let rowIdx = 1; rowIdx < table.rows.length; rowIdx++) {
19620
- const dataCells = table.rows[rowIdx];
19628
+ for (let rowIdx = 1; rowIdx < table2.rows.length; rowIdx++) {
19629
+ const dataCells = table2.rows[rowIdx];
19621
19630
  for (let colIdx = 0; colIdx < Math.min(headerCells.length, dataCells.length); colIdx++) {
19622
19631
  const headerLabel = normalizeLabel(cellLabelText(headerCells[colIdx]));
19623
19632
  if (blockedLabels?.has(headerLabel)) continue;
@@ -19651,10 +19660,10 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19651
19660
  }
19652
19661
  }
19653
19662
  }
19654
- for (const para of [...scan.bodyParagraphs, ...scan.excludedParagraphs]) {
19655
- const existing = ledger.get(para);
19663
+ for (const para2 of [...scan.bodyParagraphs, ...scan.excludedParagraphs]) {
19664
+ const existing = ledger.get(para2);
19656
19665
  if (existing?.fullText !== void 0) continue;
19657
- const text = matchText(para);
19666
+ const text = matchText(para2);
19658
19667
  for (const seg of scanInlineSegments(text)) {
19659
19668
  const nlabel = normalizeLabel(seg.label);
19660
19669
  if (blockedLabels?.has(nlabel)) continue;
@@ -19663,7 +19672,7 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19663
19672
  const newValue = cursor.consume(matchKey);
19664
19673
  if (newValue === void 0) continue;
19665
19674
  const replacement = seg.valueStart === seg.valueEnd ? padInsertion(text, seg.valueStart, newValue) : newValue;
19666
- const l = led(para);
19675
+ const l = led(para2);
19667
19676
  l.ranges.push({ start: seg.valueStart, end: seg.valueEnd, replacement });
19668
19677
  matchedLabels.add(matchKey);
19669
19678
  l.filledIdx.push(filled.length);
@@ -19672,10 +19681,10 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19672
19681
  }
19673
19682
  }
19674
19683
  const splices = [];
19675
- for (const [para, l] of ledger) {
19684
+ for (const [para2, l] of ledger) {
19676
19685
  let paraSplices = null;
19677
19686
  if (l.fullText !== void 0) {
19678
- paraSplices = buildParagraphSplices(para, l.fullText, xml);
19687
+ paraSplices = buildParagraphSplices(para2, l.fullText, xml);
19679
19688
  } else if (l.ranges.length > 0) {
19680
19689
  const sorted = [...l.ranges].sort((a, b) => a.start - b.start || a.end - b.end);
19681
19690
  const merged = [];
@@ -19684,11 +19693,11 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19684
19693
  if (prev && r.start < prev.end) continue;
19685
19694
  merged.push(r);
19686
19695
  }
19687
- if (paraTText(para, xml) !== null) {
19696
+ if (paraTText(para2, xml) !== null) {
19688
19697
  const precise = [];
19689
19698
  let ok = true;
19690
19699
  for (const r of merged) {
19691
- const sp = buildRangeSplices(para, xml, r.start, r.end, r.replacement);
19700
+ const sp = buildRangeSplices(para2, xml, r.start, r.end, r.replacement);
19692
19701
  if (!sp) {
19693
19702
  ok = false;
19694
19703
  break;
@@ -19696,13 +19705,13 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19696
19705
  precise.push(...sp);
19697
19706
  }
19698
19707
  paraSplices = ok ? precise : null;
19699
- } else if (paraTextPureT(para, xml)) {
19700
- let text = para.text;
19708
+ } else if (paraTextPureT(para2, xml)) {
19709
+ let text = para2.text;
19701
19710
  for (let k = merged.length - 1; k >= 0; k--) {
19702
19711
  const r = merged[k];
19703
19712
  text = text.slice(0, r.start) + r.replacement + text.slice(r.end);
19704
19713
  }
19705
- paraSplices = buildParagraphSplices(para, text, xml);
19714
+ paraSplices = buildParagraphSplices(para2, text, xml);
19706
19715
  } else {
19707
19716
  paraSplices = null;
19708
19717
  }
@@ -19736,14 +19745,126 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19736
19745
  // src/hwpx/generator.ts
19737
19746
  import JSZip6 from "jszip";
19738
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
+
19739
19857
  // src/hwpx/gongmun.ts
19740
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;
19741
19861
  var PRESET_DEFAULTS = {
19742
19862
  official: { bodyPt: 15, lineSpacing: 160, numbering: "standard" },
19743
19863
  report: { bodyPt: 15, lineSpacing: 160, numbering: "report" },
19744
19864
  plan: { bodyPt: 15, lineSpacing: 160, numbering: "standard" },
19745
19865
  notice: { bodyPt: 15, lineSpacing: 160, numbering: "standard" },
19746
- minutes: { bodyPt: 14, lineSpacing: 130, numbering: "standard" }
19866
+ minutes: { bodyPt: 14, lineSpacing: 130, numbering: "standard" },
19867
+ gaejosik: { bodyPt: 15, lineSpacing: 160, numbering: "gaejosik" }
19747
19868
  };
19748
19869
  var PRESET_ALIAS = {
19749
19870
  official: "official",
@@ -19761,7 +19882,12 @@ var PRESET_ALIAS = {
19761
19882
  \uC54C\uB9BC: "notice",
19762
19883
  \uC548\uB0B4: "notice",
19763
19884
  minutes: "minutes",
19764
- \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"
19765
19891
  };
19766
19892
  function normalizeGongmunPreset(preset) {
19767
19893
  if (!preset) return "official";
@@ -19772,15 +19898,30 @@ function resolveGongmun(opts) {
19772
19898
  const d = PRESET_DEFAULTS[preset];
19773
19899
  const bodyPt = opts.bodyPt ?? d.bodyPt;
19774
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";
19775
19904
  return {
19776
19905
  preset,
19777
19906
  bodyFont: opts.bodyFont ?? "myeongjo",
19778
19907
  bodyHeight: Math.round(bodyPt * 100),
19779
19908
  lineSpacing: opts.lineSpacing ?? d.lineSpacing,
19780
19909
  numbering: opts.numbering ?? d.numbering,
19781
- margins: opts.margins ?? OFFICIAL_MARGINS,
19910
+ margins: opts.margins ?? (gaejosik ? GAEJOSIK_MARGINS : OFFICIAL_MARGINS),
19782
19911
  centerTitle: opts.centerTitle ?? true,
19783
- 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)
19784
19925
  };
19785
19926
  }
19786
19927
  var HANGUL_INITIALS = [0, 2, 3, 5, 6, 7, 9, 11, 12, 14, 15, 16, 17, 18];
@@ -19828,7 +19969,8 @@ function markerWidth(marker, bodyHeight) {
19828
19969
  for (const c of marker) em += charWidthEm1000(c.codePointAt(0));
19829
19970
  return Math.round(em / 1e3 * bodyHeight);
19830
19971
  }
19831
- function levelIndent(depth, bodyHeight, numbering) {
19972
+ function levelIndent(depth, bodyHeight, numbering, sizes = {}) {
19973
+ if (numbering === "gaejosik") return gaejosikLevelIndent(depth, bodyHeight, sizes);
19832
19974
  const marker = numbering === "report" ? reportMarker(depth) : standardMarker(depth, 0);
19833
19975
  return { left: Math.round(depth * bodyHeight), indent: -markerWidth(marker, bodyHeight) };
19834
19976
  }
@@ -19856,6 +19998,7 @@ var GongmunNumberer = class {
19856
19998
  const n = this.counts[depth] ?? 0;
19857
19999
  this.counts[depth] = n + 1;
19858
20000
  if (suppress) return "";
20001
+ if (this.numbering === "gaejosik") return gaejosikMarker(depth);
19859
20002
  return this.numbering === "report" ? reportMarker(depth) : standardMarker(depth, n);
19860
20003
  }
19861
20004
  reset() {
@@ -19923,27 +20066,28 @@ function headingCharPrId(level) {
19923
20066
  if (level === 3) return CHAR_H3;
19924
20067
  return CHAR_H4;
19925
20068
  }
19926
- 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) {
19927
20070
  const boldAttr = bold ? ` bold="1"` : "";
19928
20071
  const italicAttr = italic ? ` italic="1"` : "";
19929
- const effFont = bold ? 2 : fontId;
20072
+ const effFont = bold && !keepFontOnBold ? 2 : fontId;
20073
+ const boldEl = bold ? `<hh:bold/>` : "";
19930
20074
  return ` <hh:charPr id="${id}" height="${height}" textColor="${textColor}" shadeColor="none" useFontSpace="0" useKerning="0" symMark="NONE" borderFillIDRef="1"${boldAttr}${italicAttr}>
19931
20075
  <hh:fontRef hangul="${effFont}" latin="${effFont}" hanja="${effFont}" japanese="${effFont}" other="${effFont}" symbol="${effFont}" user="${effFont}"/>
19932
20076
  <hh:ratio hangul="${ratioPct}" latin="${ratioPct}" hanja="${ratioPct}" japanese="100" other="100" symbol="100" user="100"/>
19933
20077
  <hh:spacing hangul="0" latin="0" hanja="0" japanese="0" other="0" symbol="0" user="0"/>
19934
20078
  <hh:relSz hangul="100" latin="100" hanja="100" japanese="100" other="100" symbol="100" user="100"/>
19935
- <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}
19936
20080
  </hh:charPr>`;
19937
20081
  }
19938
20082
  function paraPr(id, opts = {}) {
19939
- const { align = "JUSTIFY", spaceBefore = 0, spaceAfter = 0, lineSpacing = 160, indent = 0, left = 0, keepWord = false, outlineLevel } = opts;
19940
- 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";
19941
20085
  const snapGrid = keepWord ? "0" : "1";
19942
20086
  const heading = outlineLevel !== void 0 ? `<hh:heading type="OUTLINE" idRef="0" level="${outlineLevel}"/>` : `<hh:heading type="NONE" idRef="0" level="0"/>`;
19943
20087
  return ` <hh:paraPr id="${id}" tabPrIDRef="0" condense="0" fontLineHeight="0" snapToGrid="${snapGrid}" suppressLineNumbers="0" checked="0" textDir="AUTO">
19944
20088
  <hh:align horizontal="${align}" vertical="BASELINE"/>
19945
20089
  ${heading}
19946
- <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"/>
19947
20091
  <hh:autoSpacing eAsianEng="0" eAsianNum="0"/>
19948
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>
19949
20093
  <hh:lineSpacing type="PERCENT" value="${lineSpacing}"/>
@@ -19953,7 +20097,72 @@ function paraPr(id, opts = {}) {
19953
20097
  var GONGMUN_LIST_BASE = 8;
19954
20098
  var GONGMUN_LIST_LEVELS = 8;
19955
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
+ }
19956
20162
  var CHAR_VARIANT_BASE = 11;
20163
+ function charVariantBase(gaejosik) {
20164
+ return gaejosik ? CHAR_VARIANT_BASE + GJ_CHAR_COUNT : CHAR_VARIANT_BASE;
20165
+ }
19957
20166
  var GONGMUN_BODY_RATIO = 95;
19958
20167
 
19959
20168
  // src/hwpx/md-runs.ts
@@ -20167,12 +20376,12 @@ function generateRuns(text, defaultCharPr = CHAR_NORMAL, mapCharId) {
20167
20376
  return `<hp:run charPrIDRef="${charId}"><hp:t>${escapeXml(span.text)}</hp:t></hp:run>`;
20168
20377
  }).join("");
20169
20378
  }
20170
- function generateParagraph(text, paraPrId = PARA_NORMAL, charPrId = CHAR_NORMAL, mapCharId) {
20379
+ function generateParagraph(text, paraPrId = PARA_NORMAL, charPrId = CHAR_NORMAL, mapCharId, styleId = 0) {
20171
20380
  if (paraPrId === PARA_CODE) {
20172
20381
  return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_CODE}"><hp:t>${escapeXml(text)}</hp:t></hp:run></hp:p>`;
20173
20382
  }
20174
20383
  const runs = generateRuns(text, charPrId, mapCharId);
20175
- return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0">${runs}</hp:p>`;
20384
+ return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="${styleId}">${runs}</hp:p>`;
20176
20385
  }
20177
20386
 
20178
20387
  // src/hwpx/gen-header.ts
@@ -20200,6 +20409,7 @@ function generateManifest(chartParts = []) {
20200
20409
  </opf:package>`;
20201
20410
  }
20202
20411
  function buildCharProperties(theme, gongmun, ratioVariants = [], extraCharPrXmls = []) {
20412
+ const gaejosik = gongmun?.preset === "gaejosik";
20203
20413
  let body = 1e3, code = 900, h1 = 1800, h2 = 1400, h3 = 1200, h4 = 1100;
20204
20414
  if (gongmun) {
20205
20415
  body = gongmun.bodyHeight;
@@ -20209,26 +20419,62 @@ function buildCharProperties(theme, gongmun, ratioVariants = [], extraCharPrXmls
20209
20419
  h3 = body;
20210
20420
  h4 = Math.max(body - 100, 1300);
20211
20421
  }
20422
+ const bodyFont = gaejosik ? 4 : 0;
20212
20423
  const bodyRatio = gongmun ? GONGMUN_BODY_RATIO : 100;
20213
20424
  const rows = [
20214
- charPr(0, body, false, false, 0, theme.body, bodyRatio),
20215
- charPr(1, body, true, false, 0, theme.body, bodyRatio),
20216
- charPr(2, body, false, true, 0, theme.body, bodyRatio),
20217
- 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),
20218
20429
  charPr(4, code, false, false, 1),
20219
20430
  charPr(5, h1, true, false, 1, theme.h1),
20220
20431
  charPr(6, h2, true, false, 1, theme.h2),
20221
20432
  charPr(7, h3, true, false, 1, theme.h3),
20222
20433
  charPr(8, h4, true, false, 1, theme.h4),
20223
- charPr(CHAR_TABLE_HEADER, body, theme.tableHeaderBold, false, 0, theme.tableHeader),
20224
- 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)
20225
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
+ }
20226
20472
  for (const r of ratioVariants) {
20227
20473
  rows.push(
20228
- charPr(rows.length, body, false, false, 0, theme.body, r),
20229
- charPr(rows.length + 1, body, true, false, 0, theme.body, r),
20230
- charPr(rows.length + 2, body, false, true, 0, theme.body, r),
20231
- 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)
20232
20478
  );
20233
20479
  }
20234
20480
  rows.push(...extraCharPrXmls);
@@ -20239,14 +20485,14 @@ ${rows.join("\n")}
20239
20485
  function buildParaProperties(gongmun) {
20240
20486
  if (!gongmun) {
20241
20487
  const base2 = [
20242
- paraPr(0),
20243
- paraPr(1, { align: "LEFT", spaceBefore: 800, spaceAfter: 200, lineSpacing: 180, outlineLevel: 0 }),
20244
- paraPr(2, { align: "LEFT", spaceBefore: 600, spaceAfter: 150, lineSpacing: 170, outlineLevel: 1 }),
20245
- paraPr(3, { align: "LEFT", spaceBefore: 400, spaceAfter: 100, lineSpacing: 160, outlineLevel: 2 }),
20246
- paraPr(4, { align: "LEFT", spaceBefore: 300, spaceAfter: 100, lineSpacing: 160, outlineLevel: 3 }),
20247
- paraPr(5, { align: "LEFT", lineSpacing: 130, indent: 400 }),
20248
- paraPr(6, { align: "LEFT", lineSpacing: 150, indent: 600 }),
20249
- 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 })
20250
20496
  ];
20251
20497
  return `<hh:paraProperties itemCnt="${base2.length}">
20252
20498
  ${base2.join("\n")}
@@ -20256,20 +20502,37 @@ ${base2.join("\n")}
20256
20502
  const titleAlign = gongmun.centerTitle ? "CENTER" : "LEFT";
20257
20503
  const base = [
20258
20504
  paraPr(0, { lineSpacing: ls, keepWord: true }),
20259
- paraPr(1, { align: titleAlign, spaceBefore: 400, spaceAfter: 400, lineSpacing: ls, keepWord: true, outlineLevel: 0 }),
20260
- paraPr(2, { align: "LEFT", spaceBefore: 600, spaceAfter: 150, lineSpacing: ls, keepWord: true, outlineLevel: 1 }),
20261
- paraPr(3, { align: "LEFT", spaceBefore: 400, spaceAfter: 100, lineSpacing: ls, keepWord: true, outlineLevel: 2 }),
20262
- 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 }),
20263
20509
  paraPr(5, { align: "LEFT", lineSpacing: 130, indent: 400, keepWord: true }),
20264
20510
  paraPr(6, { align: "LEFT", lineSpacing: ls, indent: 600, keepWord: true }),
20265
20511
  paraPr(7, { align: "LEFT", lineSpacing: ls, indent: 600, keepWord: true })
20266
20512
  ];
20267
20513
  for (let d = 0; d < GONGMUN_LIST_LEVELS; d++) {
20268
- const { left, indent } = levelIndent(d, gongmun.bodyHeight, gongmun.numbering);
20269
- const sectionGap = gongmun.numbering === "report" && d === 0 ? Math.round(gongmun.bodyHeight * 0.5) : 0;
20270
- 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 }));
20271
20518
  }
20272
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
+ }
20273
20536
  return `<hh:paraProperties itemCnt="${base.length}">
20274
20537
  ${base.join("\n")}
20275
20538
  </hh:paraProperties>`;
@@ -20285,25 +20548,37 @@ ${heads}
20285
20548
  </hh:numbering>
20286
20549
  </hh:numberings>`;
20287
20550
  }
20288
- function generateHeaderXml(theme, gongmun, ratioVariants = [], remap = null) {
20289
- const bodyFace = gongmun?.bodyFont === "gothic" ? "\uB9D1\uC740 \uACE0\uB515" : "\uD568\uCD08\uB86C\uBC14\uD0D5";
20290
- const charPropsXml = buildCharProperties(theme, gongmun, ratioVariants, remap?.charPrXmls ?? []);
20291
- const paraPropsXml = buildParaProperties(gongmun);
20292
- return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
20293
- <hh:head xmlns:hh="${NS_HEAD}" xmlns:hp="${NS_PARA}" xmlns:hc="${NS_CORE}" version="1.4" secCnt="1">
20294
- <hh:beginNum page="1" footnote="1" endnote="1" pic="1" tbl="1" equation="1"/>
20295
- <hh:refList>
20296
- <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">
20297
20578
  <hh:fontface lang="HANGUL" fontCnt="3">
20298
- <hh:font id="0" face="${bodyFace}" type="TTF" isEmbedded="0">
20299
- <hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="4" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
20300
- </hh:font>
20301
- <hh:font id="1" face="\uD568\uCD08\uB86C\uB3CB\uC6C0" type="TTF" isEmbedded="0">
20302
- <hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="4" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
20303
- </hh:font>
20304
- <hh:font id="2" face="HY\uACAC\uACE0\uB515" type="TTF" isEmbedded="0">
20305
- <hh:typeInfo familyType="FCAT_GOTHIC" weight="9" proportion="0" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
20306
- </hh:font>
20579
+ ${fontEntry(0, bodyFace)}
20580
+ ${fontEntry(1, "\uD568\uCD08\uB86C\uB3CB\uC6C0")}
20581
+ ${fontEntry(2, "HY\uACAC\uACE0\uB515", 9)}
20307
20582
  </hh:fontface>
20308
20583
  <hh:fontface lang="LATIN" fontCnt="3">
20309
20584
  <hh:font id="0" face="Times New Roman" type="TTF" isEmbedded="0">
@@ -20317,57 +20592,87 @@ function generateHeaderXml(theme, gongmun, ratioVariants = [], remap = null) {
20317
20592
  </hh:font>
20318
20593
  </hh:fontface>
20319
20594
  <hh:fontface lang="HANJA" fontCnt="1">
20320
- <hh:font id="0" face="\uD568\uCD08\uB86C\uBC14\uD0D5" type="TTF" isEmbedded="0">
20321
- <hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="4" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
20322
- </hh:font>
20595
+ ${fontEntry(0, "\uD568\uCD08\uB86C\uBC14\uD0D5")}
20323
20596
  </hh:fontface>
20324
20597
  <hh:fontface lang="JAPANESE" fontCnt="1">
20325
- <hh:font id="0" face="\uAD74\uB9BC" type="TTF" isEmbedded="0">
20326
- <hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="0" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
20327
- </hh:font>
20598
+ ${fontEntry(0, "\uAD74\uB9BC")}
20328
20599
  </hh:fontface>
20329
20600
  <hh:fontface lang="OTHER" fontCnt="1">
20330
- <hh:font id="0" face="\uAD74\uB9BC" type="TTF" isEmbedded="0">
20331
- <hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="0" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
20332
- </hh:font>
20601
+ ${fontEntry(0, "\uAD74\uB9BC")}
20333
20602
  </hh:fontface>
20334
20603
  <hh:fontface lang="SYMBOL" fontCnt="1">
20335
- <hh:font id="0" face="Symbol" type="TTF" isEmbedded="0">
20336
- <hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="0" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
20337
- </hh:font>
20604
+ ${fontEntry(0, "Symbol")}
20338
20605
  </hh:fontface>
20339
20606
  <hh:fontface lang="USER" fontCnt="1">
20340
- <hh:font id="0" face="\uAD74\uB9BC" type="TTF" isEmbedded="0">
20341
- <hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="0" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
20342
- </hh:font>
20607
+ ${fontEntry(0, "\uAD74\uB9BC")}
20343
20608
  </hh:fontface>
20344
- </hh:fontfaces>
20345
- <hh:borderFills itemCnt="${2 + (remap?.borderFillXmls.length ?? 0)}">
20346
- <hh:borderFill id="1" threeD="0" shadow="0" centerLine="NONE" breakCellSeparateLine="0">
20347
- <hh:slash type="NONE" Crooked="0" isCounter="0"/>
20348
- <hh:backSlash type="NONE" Crooked="0" isCounter="0"/>
20349
- <hh:leftBorder type="NONE" width="0.1 mm" color="#000000"/>
20350
- <hh:rightBorder type="NONE" width="0.1 mm" color="#000000"/>
20351
- <hh:topBorder type="NONE" width="0.1 mm" color="#000000"/>
20352
- <hh:bottomBorder type="NONE" width="0.1 mm" color="#000000"/>
20353
- </hh:borderFill>
20354
- <hh:borderFill id="2" threeD="0" shadow="0" centerLine="NONE" breakCellSeparateLine="0">
20355
- <hh:slash type="NONE" Crooked="0" isCounter="0"/>
20356
- <hh:backSlash type="NONE" Crooked="0" isCounter="0"/>
20357
- <hh:leftBorder type="SOLID" width="0.12 mm" color="#000000"/>
20358
- <hh:rightBorder type="SOLID" width="0.12 mm" color="#000000"/>
20359
- <hh:topBorder type="SOLID" width="0.12 mm" color="#000000"/>
20360
- <hh:bottomBorder type="SOLID" width="0.12 mm" color="#000000"/>
20361
- </hh:borderFill>${remap && remap.borderFillXmls.length ? "\n" + remap.borderFillXmls.join("\n") : ""}
20362
- </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)}
20363
20670
  ${charPropsXml}
20364
20671
  <hh:tabProperties itemCnt="0"/>
20365
20672
  ${buildNumberings()}
20366
20673
  <hh:bullets itemCnt="0"/>
20367
20674
  ${paraPropsXml}
20368
- <hh:styles itemCnt="1">
20369
- <hh:style id="0" type="PARA" name="\uBC14\uD0D5\uAE00" engName="Normal" paraPrIDRef="0" charPrIDRef="0" nextStyleIDRef="0" langIDRef="1042" lockForm="0"/>
20370
- </hh:styles>
20675
+ ${buildStyles(gongmun)}
20371
20676
  </hh:refList>
20372
20677
  <hh:compatibleDocument targetProgram="HWP2018"><hh:layoutCompatibility/></hh:compatibleDocument>
20373
20678
  </hh:head>`;
@@ -20603,6 +20908,7 @@ function computeGongmunFitPlan(blocks, gongmun, gongmunList) {
20603
20908
  let contW;
20604
20909
  if (block.type === "list_item" && gongmunList.has(i)) {
20605
20910
  const { marker, depth } = gongmunList.get(i);
20911
+ if (gongmun.numbering === "gaejosik" && (depth === 0 || (block.text || "").trimStart().startsWith("\u203B"))) continue;
20606
20912
  const content = plainRenderText(block.text || "");
20607
20913
  text = marker ? `${marker} ${content}` : content;
20608
20914
  const { left, indent } = levelIndent(depth, gongmun.bodyHeight, gongmun.numbering);
@@ -20611,6 +20917,7 @@ function computeGongmunFitPlan(blocks, gongmun, gongmunList) {
20611
20917
  } else if (block.type === "paragraph") {
20612
20918
  const raw = (block.text || "").trim();
20613
20919
  if (/^<center>[\s\S]*<\/center>$/i.test(raw)) continue;
20920
+ if (gongmun.numbering === "gaejosik" && raw.startsWith("\u203B")) continue;
20614
20921
  text = plainRenderText(raw);
20615
20922
  firstW = contW = pageW;
20616
20923
  } else {
@@ -20624,14 +20931,15 @@ function computeGongmunFitPlan(blocks, gongmun, gongmunList) {
20624
20931
  }
20625
20932
  return ratioByBlock.size > 0 ? { ratioByBlock, variants } : null;
20626
20933
  }
20627
- function variantMapper(fit, blockIdx) {
20934
+ function variantMapper(fit, blockIdx, base = CHAR_VARIANT_BASE) {
20628
20935
  const r = fit.ratioByBlock.get(blockIdx);
20629
20936
  if (r === void 0) return void 0;
20630
20937
  const vi = fit.variants.indexOf(r);
20631
- 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;
20632
20939
  }
20633
20940
  function precomputeGongmunList(blocks, gongmun) {
20634
20941
  const result = /* @__PURE__ */ new Map();
20942
+ const depthOffset = gongmun.numbering === "gaejosik" && blocks.some((b) => b.type === "heading" && b.level === 3) ? 1 : 0;
20635
20943
  let i = 0;
20636
20944
  while (i < blocks.length) {
20637
20945
  if (blocks[i].type !== "list_item") {
@@ -20657,7 +20965,7 @@ function precomputeGongmunList(blocks, gongmun) {
20657
20965
  }
20658
20966
  break;
20659
20967
  }
20660
- 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));
20661
20969
  const suppress = gongmun.numbering === "standard" ? computeSuppression(depths) : depths.map(() => false);
20662
20970
  const numberer = new GongmunNumberer(gongmun.numbering);
20663
20971
  run.forEach((bi, k) => {
@@ -20668,6 +20976,98 @@ function precomputeGongmunList(blocks, gongmun) {
20668
20976
  return result;
20669
20977
  }
20670
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
+
20671
21071
  // src/diff/text-diff.ts
20672
21072
  function similarity(a, b) {
20673
21073
  if (a === b) return 1;
@@ -20865,8 +21265,8 @@ function summarize(text) {
20865
21265
  const t = text.replace(/\s+/g, " ").trim();
20866
21266
  return t.length > 80 ? t.slice(0, 77) + "..." : t;
20867
21267
  }
20868
- function replicateGfmTable(table) {
20869
- const { cells, rows: numRows, cols: numCols } = table;
21268
+ function replicateGfmTable(table2) {
21269
+ const { cells, rows: numRows, cols: numCols } = table2;
20870
21270
  if (numRows === 0 || numCols === 0) return null;
20871
21271
  if (numRows === 1 && numCols === 1) return null;
20872
21272
  if (numCols === 1) return null;
@@ -20875,28 +21275,28 @@ function replicateGfmTable(table) {
20875
21275
  for (let r = 0; r < numRows; r++) {
20876
21276
  for (let c = 0; c < numCols; c++) {
20877
21277
  if (skip.has(`${r},${c}`)) continue;
20878
- const cell = cells[r]?.[c];
20879
- if (!cell) continue;
21278
+ const cell2 = cells[r]?.[c];
21279
+ if (!cell2) continue;
20880
21280
  display[r][c] = {
20881
- text: escapeGfm(sanitizeText(cell.text)).replace(/\|/g, "\\|").replace(/\n/g, "<br>"),
21281
+ text: escapeGfm(sanitizeText(cell2.text)).replace(/\|/g, "\\|").replace(/\n/g, "<br>"),
20882
21282
  gridR: r,
20883
21283
  gridC: c
20884
21284
  };
20885
- for (let dr = 0; dr < cell.rowSpan; dr++) {
20886
- 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++) {
20887
21287
  if (dr === 0 && dc === 0) continue;
20888
21288
  if (r + dr < numRows && c + dc < numCols) skip.add(`${r + dr},${c + dc}`);
20889
21289
  }
20890
21290
  }
20891
- c += cell.colSpan - 1;
21291
+ c += cell2.colSpan - 1;
20892
21292
  }
20893
21293
  }
20894
21294
  const uniqueRows = [];
20895
21295
  let pendingLabelRow = null;
20896
21296
  for (let r = 0; r < display.length; r++) {
20897
21297
  const row = display[r];
20898
- if (row.every((cell) => cell.text === "")) continue;
20899
- const nonEmptyCols = row.filter((cell) => cell.text !== "");
21298
+ if (row.every((cell2) => cell2.text === "")) continue;
21299
+ const nonEmptyCols = row.filter((cell2) => cell2.text !== "");
20900
21300
  const hasSkipInRow = row.some((_, c) => skip.has(`${r},${c}`));
20901
21301
  if (!hasSkipInRow && nonEmptyCols.length === 1 && row[0].text !== "" && row.slice(1).every((c) => c.text === "")) {
20902
21302
  if (pendingLabelRow) uniqueRows.push(pendingLabelRow);
@@ -20928,9 +21328,9 @@ function parseGfmTable(lines) {
20928
21328
  function unescapeGfmCell(text) {
20929
21329
  return text.replace(/<br\s*\/?>/gi, "\n").replace(/\\\|/g, "|").replace(/\\([~*])/g, "$1");
20930
21330
  }
20931
- function replicateCellInnerHtml(cell) {
20932
- if (cell.blocks?.length) {
20933
- return cell.blocks.map((b) => {
21331
+ function replicateCellInnerHtml(cell2) {
21332
+ if (cell2.blocks?.length) {
21333
+ return cell2.blocks.map((b) => {
20934
21334
  if (b.type === "table" && b.table) {
20935
21335
  const cap = b.table.caption ? sanitizeText(b.table.caption) : "";
20936
21336
  return (cap ? cap + "<br>" : "") + replicateTableToHtml(b.table);
@@ -20940,27 +21340,27 @@ function replicateCellInnerHtml(cell) {
20940
21340
  return t ? t.replace(/\n/g, "<br>") : "";
20941
21341
  }).filter(Boolean).join("<br>");
20942
21342
  }
20943
- return sanitizeText(cell.text).replace(/\n/g, "<br>");
21343
+ return sanitizeText(cell2.text).replace(/\n/g, "<br>");
20944
21344
  }
20945
- function replicateTableToHtml(table) {
20946
- const rows = replicateHtmlTable(table);
21345
+ function replicateTableToHtml(table2) {
21346
+ const rows = replicateHtmlTable(table2);
20947
21347
  const lines = ["<table>"];
20948
21348
  for (let r = 0; r < rows.length; r++) {
20949
21349
  const tag = rows[r].tag;
20950
- const rowHtml = rows[r].cells.map((cell) => {
21350
+ const rowHtml = rows[r].cells.map((cell2) => {
20951
21351
  const attrs = [];
20952
- if (cell.colSpan > 1) attrs.push(`colspan="${cell.colSpan}"`);
20953
- 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}"`);
20954
21354
  const attrStr = attrs.length ? " " + attrs.join(" ") : "";
20955
- return `<${tag}${attrStr}>${cell.inner}</${tag}>`;
21355
+ return `<${tag}${attrStr}>${cell2.inner}</${tag}>`;
20956
21356
  });
20957
21357
  if (rowHtml.length) lines.push(`<tr>${rowHtml.join("")}</tr>`);
20958
21358
  }
20959
21359
  lines.push("</table>");
20960
21360
  return lines.join("\n");
20961
21361
  }
20962
- function replicateHtmlTable(table) {
20963
- const { cells, rows: numRows, cols: numCols } = table;
21362
+ function replicateHtmlTable(table2) {
21363
+ const { cells, rows: numRows, cols: numCols } = table2;
20964
21364
  const skip = /* @__PURE__ */ new Set();
20965
21365
  const result = [];
20966
21366
  for (let r = 0; r < numRows; r++) {
@@ -20968,18 +21368,18 @@ function replicateHtmlTable(table) {
20968
21368
  const rowCells = [];
20969
21369
  for (let c = 0; c < numCols; c++) {
20970
21370
  if (skip.has(`${r},${c}`)) continue;
20971
- const cell = cells[r]?.[c];
20972
- if (!cell) continue;
20973
- for (let dr = 0; dr < cell.rowSpan; dr++) {
20974
- 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++) {
20975
21375
  if (dr === 0 && dc === 0) continue;
20976
21376
  if (r + dr < numRows && c + dc < numCols) skip.add(`${r + dr},${c + dc}`);
20977
21377
  }
20978
21378
  }
20979
21379
  rowCells.push({
20980
- inner: replicateCellInnerHtml(cell),
20981
- colSpan: cell.colSpan,
20982
- rowSpan: cell.rowSpan,
21380
+ inner: replicateCellInnerHtml(cell2),
21381
+ colSpan: cell2.colSpan,
21382
+ rowSpan: cell2.rowSpan,
20983
21383
  gridR: r,
20984
21384
  gridC: c
20985
21385
  });
@@ -21084,6 +21484,54 @@ function removeNestedTables(html) {
21084
21484
  return result;
21085
21485
  }
21086
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
+
21087
21535
  // src/hwpx/gen-profile.ts
21088
21536
  function normalizeAnchor(s) {
21089
21537
  return s.toLowerCase().replace(/[^\p{L}\p{N}]/gu, "").slice(0, 24);
@@ -21175,24 +21623,21 @@ function buildProfileRemap(profile, charPrBase, borderFillBase = 3) {
21175
21623
  cellChar: /* @__PURE__ */ new Map(),
21176
21624
  cellH: /* @__PURE__ */ new Map()
21177
21625
  };
21178
- for (const cell of t.cells) {
21179
- const k = `${cell.row},${cell.col}`;
21180
- if (cell.borderFillIDRef != null && cell.borderFillIDRef in localBf) {
21181
- tr.cellBf.set(k, localBf[cell.borderFillIDRef]);
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]);
21182
21630
  }
21183
- if (cell.charPrIDRef != null && cell.charPrIDRef in localChar) {
21184
- tr.cellChar.set(k, localChar[cell.charPrIDRef]);
21631
+ if (cell2.charPrIDRef != null && cell2.charPrIDRef in localChar) {
21632
+ tr.cellChar.set(k, localChar[cell2.charPrIDRef]);
21185
21633
  }
21186
- const h = parseHu(cell.height_hwpunit);
21634
+ const h = parseHu(cell2.height_hwpunit);
21187
21635
  if (h != null) tr.cellH.set(k, h);
21188
21636
  }
21189
21637
  remap.tables.push(tr);
21190
21638
  }
21191
21639
  return remap;
21192
21640
  }
21193
- function profileCharPrBase(ratioVariantCount) {
21194
- return CHAR_VARIANT_BASE + ratioVariantCount * 4;
21195
- }
21196
21641
 
21197
21642
  // src/hwpx/gen-table.ts
21198
21643
  var TABLE_ID_BASE = 1e3;
@@ -21200,47 +21645,141 @@ var tableIdCounter = TABLE_ID_BASE;
21200
21645
  function nextTableId() {
21201
21646
  return ++tableIdCounter;
21202
21647
  }
21203
- function anchorOfMarkdownCell(cell) {
21204
- return normalizeAnchor(cell.replace(/!\[[^\]]*\]\([^)]*\)/g, ""));
21648
+ var DATA_TABLE_INSET = 1800;
21649
+ function anchorOfMarkdownCell(cell2) {
21650
+ return normalizeAnchor(cell2.replace(/!\[[^\]]*\]\([^)]*\)/g, ""));
21205
21651
  }
21206
21652
  function anchorOfHtmlCell(inner) {
21207
21653
  const noNested = inner.replace(/<table[\s\S]*?<\/table>/gi, "");
21208
21654
  const { lines } = htmlCellInnerToLines(noNested);
21209
21655
  return normalizeAnchor(lines.join(""));
21210
21656
  }
21211
- function resolveColWidths(tp, colCnt, fallbackTotal) {
21212
- if (tp?.colWidths && tp.colWidths.length === colCnt) return tp.colWidths;
21213
- const w = tp?.width ? Math.floor(tp.width / colCnt) : Math.floor(fallbackTotal / colCnt);
21214
- return Array(colCnt).fill(w);
21657
+ function profileColWidths(tp, colCnt) {
21658
+ if (!tp) 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);
21706
+ }
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;
21215
21711
  }
21216
- function generateTable(rows, theme, remap = null, seq = 0) {
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;
21723
+ }
21724
+ function generateTable(rows, theme, style = null, remap = null, seq = 0) {
21217
21725
  const rowCnt = rows.length;
21218
21726
  const colCnt = Math.max(...rows.map((r) => r.length), 1);
21219
- const cellH = 1500;
21220
- const tblId = nextTableId();
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;
21221
21730
  const prof = takeProfile(remap, rowCnt, colCnt, anchorOfMarkdownCell(rows[0]?.[0] ?? ""), seq);
21222
- const colW = resolveColWidths(prof, colCnt, 44e3);
21223
- const tblW = colW.reduce((a, b) => a + b, 0);
21224
- const tblH = cellH * rowCnt;
21225
- const useHeaderStyle = theme.tableHeader !== theme.body || theme.tableHeaderBold;
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);
21741
+ const tblId = nextTableId();
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);
21226
21745
  const trElements = rows.map((row, rowIdx) => {
21227
21746
  const cells = row.length < colCnt ? [...row, ...Array(colCnt - row.length).fill("")] : row;
21228
21747
  const isHeaderRow = rowIdx === 0;
21229
- const headerCharPr = isHeaderRow && useHeaderStyle ? CHAR_TABLE_HEADER : CHAR_NORMAL;
21230
- 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) => {
21231
21752
  const k = `${rowIdx},${colIdx}`;
21232
- const bf = prof?.cellBf.get(k) ?? 2;
21233
- 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);
21234
21772
  const h = prof?.cellH.get(k) ?? cellH;
21235
- const runs = generateRuns(cell, ch);
21236
- const p = `<hp:p paraPrIDRef="0" styleIDRef="0">${runs}</hp:p>`;
21237
- 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>`;
21238
21774
  }).join("");
21239
21775
  return `<hp:tr>${tdElements}</hp:tr>`;
21240
21776
  }).join("");
21777
+ const tblW = colWidths.reduce((a, b) => a + b, 0);
21778
+ const tblH = rowHeights.reduce((a, b) => a + b, 0);
21241
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;
21242
- 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>`;
21243
- 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>`;
21244
21783
  }
21245
21784
  function layoutHtmlRows(rows) {
21246
21785
  const occupied = /* @__PURE__ */ new Set();
@@ -21248,11 +21787,11 @@ function layoutHtmlRows(rows) {
21248
21787
  let colCnt = 0;
21249
21788
  for (let r = 0; r < rows.length; r++) {
21250
21789
  let c = 0;
21251
- for (const cell of rows[r].cells) {
21790
+ for (const cell2 of rows[r].cells) {
21252
21791
  while (occupied.has(`${r},${c}`)) c++;
21253
- const colSpan = Math.max(1, cell.colSpan);
21254
- const rowSpan = Math.max(1, cell.rowSpan);
21255
- 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" });
21256
21795
  for (let dr = 0; dr < rowSpan; dr++) {
21257
21796
  for (let dc = 0; dc < colSpan; dc++) occupied.add(`${r + dr},${c + dc}`);
21258
21797
  }
@@ -21265,50 +21804,135 @@ function layoutHtmlRows(rows) {
21265
21804
  function unescapeHtml(s) {
21266
21805
  return s.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&amp;/g, "&");
21267
21806
  }
21268
- function generateHtmlTableXml(rawHtml, theme, totalWidth = 44e3, remap = null, seq = 0) {
21807
+ function generateHtmlTableXml(rawHtml, theme, totalWidth = 44e3, style = null, remap = null, seq = 0) {
21269
21808
  const rows = parseHtmlTable(rawHtml);
21270
21809
  if (!rows || rows.length === 0) return null;
21271
21810
  const { placed, rowCnt, colCnt } = layoutHtmlRows(rows);
21272
21811
  if (rowCnt === 0 || colCnt === 0) return null;
21273
- const cellH = 1500;
21274
- const tblId = nextTableId();
21812
+ const measureH = style?.charHeight ?? 1e3;
21275
21813
  const first = placed.find((p) => p.r === 0 && p.c === 0) ?? placed[0];
21276
21814
  const prof = takeProfile(remap, rowCnt, colCnt, first ? anchorOfHtmlCell(first.inner) : "", seq);
21277
- const colW = resolveColWidths(prof, colCnt, totalWidth);
21278
- const tblW = colW.reduce((a, b) => a + b, 0);
21279
- const useHeaderStyle = theme.tableHeader !== theme.body || theme.tableHeaderBold;
21280
- const spanW = (c, colSpan) => colW.slice(c, c + colSpan).reduce((a, b) => a + b, 0);
21281
- const tcXmls = placed.map((cell) => {
21282
- const k = `${cell.r},${cell.c}`;
21283
- const bf = prof?.cellBf.get(k) ?? 2;
21284
- const headerCharPr = cell.isHeader && useHeaderStyle ? CHAR_TABLE_HEADER : CHAR_NORMAL;
21285
- const ch = prof?.cellChar.get(k) ?? headerCharPr;
21286
- const { lines } = htmlCellInnerToLines(cell.inner);
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);
21830
+ const tblId = nextTableId();
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];
21287
21846
  const paras = lines.map(
21288
- (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>`
21289
21848
  );
21290
- const cellW = spanW(cell.c, cell.colSpan);
21291
21849
  let nestedH = 0;
21292
- for (const nested of extractTopLevelTables(cell.inner)) {
21293
- 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);
21294
21853
  if (nestedXml) {
21295
21854
  paras.push(`<hp:p paraPrIDRef="0" styleIDRef="0"><hp:run charPrIDRef="0">${nestedXml}</hp:run></hp:p>`);
21296
21855
  nestedH += (nested.match(/<tr[\s>]/gi) ?? []).length * cellH + 300;
21297
21856
  }
21298
21857
  }
21299
21858
  if (paras.length === 0) {
21300
- 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>`);
21301
21860
  }
21302
- 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);
21303
21862
  const cellHeight = Math.max(prof?.cellH.get(k) ?? 0, contentH);
21304
- 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>`;
21305
21874
  });
21306
21875
  const trXmls = [];
21307
21876
  for (let r = 0; r < rowCnt; r++) {
21308
21877
  const rowTcs = tcXmls.filter((_, i) => placed[i].r === r);
21309
21878
  trXmls.push(`<hp:tr>${rowTcs.join("")}</hp:tr>`);
21310
21879
  }
21311
- 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>`;
21312
21936
  }
21313
21937
 
21314
21938
  // src/hwpx/equation-generate.ts
@@ -21598,14 +22222,76 @@ function generateSecPr(gongmun) {
21598
22222
  header: 0,
21599
22223
  footer: 0
21600
22224
  } : { top: 8504, bottom: 4252, left: 5670, right: 4252, header: 2835, footer: 2835 };
21601
- 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;
21602
22231
  }
21603
- 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) {
21604
22233
  const paraXmls = [];
21605
22234
  let isFirst = true;
21606
22235
  let tableSeq = 0;
21607
22236
  const orderedCounters = {};
21608
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
+ }
21609
22295
  for (let blockIdx = 0; blockIdx < blocks.length; blockIdx++) {
21610
22296
  const block = blocks[blockIdx];
21611
22297
  let xml = "";
@@ -21617,17 +22303,47 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
21617
22303
  }
21618
22304
  switch (block.type) {
21619
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
+ }
21620
22328
  const pId = headingParaPrId(block.level || 1);
21621
22329
  const cId = headingCharPrId(block.level || 1);
21622
- 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);
21623
22332
  break;
21624
22333
  }
21625
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
+ }
21626
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());
21627
22341
  if (ctr) {
21628
22342
  xml = generateParagraph(ctr[1].trim(), GONGMUN_CENTER);
22343
+ } else if (rgt) {
22344
+ xml = generateParagraph(rgt[1].trim(), GONGMUN_RIGHT);
21629
22345
  } else {
21630
- 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);
21631
22347
  }
21632
22348
  break;
21633
22349
  }
@@ -21660,22 +22376,37 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
21660
22376
  xml = generateEquationParagraph(block.text || "", blockIdx);
21661
22377
  break;
21662
22378
  }
21663
- 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
+ }
21664
22385
  xml = generateParagraph(
21665
22386
  block.text || "",
21666
22387
  PARA_QUOTE,
21667
22388
  theme.hasQuoteOption ? CHAR_QUOTE : CHAR_NORMAL
21668
22389
  );
21669
22390
  break;
22391
+ }
21670
22392
  case "list_item": {
21671
22393
  if (gongmun && gongmunList) {
21672
22394
  const info = gongmunList.get(blockIdx);
21673
22395
  const depth = info?.depth ?? 0;
21674
22396
  const marker2 = info?.marker ?? "";
21675
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
+ }
21676
22402
  const text = marker2 ? `${marker2} ${content}` : content;
21677
- const listCharPr = gongmun.numbering === "report" && depth === 0 ? CHAR_BOLD : CHAR_NORMAL;
21678
- 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);
21679
22410
  break;
21680
22411
  }
21681
22412
  const indent = block.indent || 0;
@@ -21702,7 +22433,7 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
21702
22433
  break;
21703
22434
  }
21704
22435
  case "hr":
21705
- 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>`;
21706
22437
  break;
21707
22438
  case "table":
21708
22439
  if (block.rows) {
@@ -21711,18 +22442,19 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
21711
22442
  paraXmls.push(`<hp:p paraPrIDRef="0" styleIDRef="0">${secRun}</hp:p>`);
21712
22443
  isFirst = false;
21713
22444
  }
21714
- xml = generateTable(block.rows, theme, remap, tableSeq++);
22445
+ xml = generateTable(block.rows, theme, tableStyle, remap, tableSeq++);
21715
22446
  }
21716
22447
  break;
21717
22448
  case "html_table": {
21718
- const tbl = generateHtmlTableXml(block.text || "", theme, 44e3, remap, tableSeq++);
21719
- 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) {
21720
22452
  if (isFirst) {
21721
22453
  const secRun = `<hp:run charPrIDRef="0">${generateSecPr(gongmun)}<hp:t></hp:t></hp:run>`;
21722
22454
  paraXmls.push(`<hp:p paraPrIDRef="0" styleIDRef="0">${secRun}</hp:p>`);
21723
22455
  isFirst = false;
21724
22456
  }
21725
- xml = `<hp:p paraPrIDRef="0" styleIDRef="0"><hp:run charPrIDRef="0">${tbl}</hp:run></hp:p>`;
22457
+ xml = `<hp:p paraPrIDRef="${tableStyle && bfReg ? GONGMUN_RIGHT : 0}" styleIDRef="0"><hp:run charPrIDRef="0">${tbl2}</hp:run></hp:p>`;
21726
22458
  } else {
21727
22459
  const plain = (block.text || "").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
21728
22460
  xml = plain ? generateParagraph(plain) : "";
@@ -21738,8 +22470,20 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
21738
22470
  );
21739
22471
  isFirst = false;
21740
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
+ }
21741
22481
  paraXmls.push(xml);
21742
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
+ }
21743
22487
  if (paraXmls.length === 0) {
21744
22488
  paraXmls.push(`<hp:p paraPrIDRef="0" styleIDRef="0"><hp:run charPrIDRef="0">${generateSecPr(gongmun)}<hp:t></hp:t></hp:run></hp:p>`);
21745
22489
  }
@@ -21753,23 +22497,27 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
21753
22497
  async function markdownToHwpx(markdown, options) {
21754
22498
  const theme = resolveTheme(options?.theme);
21755
22499
  const gongmun = options?.gongmun ? resolveGongmun(options.gongmun) : null;
22500
+ const gaejosik = gongmun?.preset === "gaejosik";
21756
22501
  const blocks = parseMarkdownToBlocks(markdown);
21757
22502
  const gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null;
21758
22503
  const fit = gongmun && gongmunList ? computeGongmunFitPlan(blocks, gongmun, gongmunList) : null;
21759
- 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;
21760
22507
  const chartParts = [];
21761
- const sectionXml = blocksToSectionXml(blocks, theme, gongmun, gongmunList, fit, chartParts, remap);
22508
+ const sectionXml = blocksToSectionXml(blocks, theme, gongmun, gongmunList, fit, chartParts, bfReg, remap);
21762
22509
  if (remap && remap.tables.length > 0) {
21763
22510
  const unused = remap.tables.filter((t) => !t.used).length;
21764
22511
  if (unused === remap.tables.length) {
21765
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)`);
21766
22513
  }
21767
22514
  }
22515
+ const extraBorderFills = [...remap?.borderFillXmls ?? [], ...bfReg?.emit() ?? []];
21768
22516
  const zip = new JSZip6();
21769
22517
  zip.file("mimetype", "application/hwp+zip", { compression: "STORE" });
21770
22518
  zip.file("META-INF/container.xml", generateContainerXml());
21771
22519
  zip.file("Contents/content.hpf", generateManifest(chartParts));
21772
- 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 ?? []));
21773
22521
  zip.file("Contents/section0.xml", sectionXml);
21774
22522
  for (const part of chartParts) zip.file(part.name, part.xml);
21775
22523
  zip.file("Preview/PrvText.txt", buildPrvText(blocks));
@@ -21968,8 +22716,8 @@ function parseCharPrs(headerDoc) {
21968
22716
  }
21969
22717
  return map;
21970
22718
  }
21971
- function isTopLevelTable(tbl) {
21972
- let p = tbl.parentNode;
22719
+ function isTopLevelTable(tbl2) {
22720
+ let p = tbl2.parentNode;
21973
22721
  while (p) {
21974
22722
  const tag = (p.tagName || p.localName || "").replace(/^[^:]+:/, "");
21975
22723
  if (tag === "tbl") return false;
@@ -21982,45 +22730,45 @@ function num(s) {
21982
22730
  const n = parseInt(s, 10);
21983
22731
  return Number.isFinite(n) ? n : void 0;
21984
22732
  }
21985
- function parseTable3(tbl, tableIndex, borderFills, charPrs) {
21986
- const rows = num(tbl.getAttribute("rowCnt")) ?? 0;
21987
- const cols = num(tbl.getAttribute("colCnt")) ?? 0;
21988
- 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");
21989
22737
  const width = sz?.getAttribute("width") || void 0;
21990
22738
  const cells = [];
21991
22739
  const usedBf = /* @__PURE__ */ new Set();
21992
22740
  const usedCp = /* @__PURE__ */ new Set();
21993
22741
  const colWidths = new Array(cols).fill(void 0);
21994
22742
  let anchorText = "";
21995
- for (const tc of elemsByLocal(tbl, "tc")) {
21996
- if (nearestTable(tc) !== tbl) continue;
21997
- const addr = findChildByLocalName(tc, "cellAddr");
21998
- const span = findChildByLocalName(tc, "cellSpan");
21999
- const csz = findChildByLocalName(tc, "cellSz");
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");
22000
22748
  const row = num(addr?.getAttribute("rowAddr")) ?? 0;
22001
22749
  const col = num(addr?.getAttribute("colAddr")) ?? 0;
22002
- if (row === 0 && col === 0 && !anchorText) anchorText = directCellText(tc);
22750
+ if (row === 0 && col === 0 && !anchorText) anchorText = directCellText(tc2);
22003
22751
  const colSpan = num(span?.getAttribute("colSpan")) ?? 1;
22004
22752
  const rowSpan = num(span?.getAttribute("rowSpan")) ?? 1;
22005
- const bfId = tc.getAttribute("borderFillIDRef") || void 0;
22006
- const cpId = firstRunCharPr(tc);
22007
- 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 };
22008
22756
  const w = csz?.getAttribute("width");
22009
22757
  const hh = csz?.getAttribute("height");
22010
- if (w) cell.width_hwpunit = w;
22011
- if (hh) cell.height_hwpunit = hh;
22758
+ if (w) cell2.width_hwpunit = w;
22759
+ if (hh) cell2.height_hwpunit = hh;
22012
22760
  if (bfId) {
22013
- cell.borderFillIDRef = bfId;
22761
+ cell2.borderFillIDRef = bfId;
22014
22762
  usedBf.add(bfId);
22015
22763
  }
22016
22764
  if (cpId) {
22017
- cell.charPrIDRef = cpId;
22765
+ cell2.charPrIDRef = cpId;
22018
22766
  usedCp.add(cpId);
22019
22767
  }
22020
- cells.push(cell);
22768
+ cells.push(cell2);
22021
22769
  if (row === 0 && colSpan === 1 && col < cols && w) colWidths[col] = w;
22022
22770
  }
22023
- const table = {
22771
+ const table2 = {
22024
22772
  table_index: tableIndex,
22025
22773
  rows,
22026
22774
  cols,
@@ -22028,15 +22776,15 @@ function parseTable3(tbl, tableIndex, borderFills, charPrs) {
22028
22776
  used_border_fills: pick(borderFills, usedBf)
22029
22777
  };
22030
22778
  const anchor = normalizeAnchor(anchorText);
22031
- if (anchor) table.anchor_text = anchor;
22032
- if (width) table.width_hwpunit = width;
22033
- if (colWidths.every((w) => w != null)) table.col_widths_hwpunit = colWidths;
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;
22034
22782
  const cp = pick(charPrs, usedCp);
22035
- if (Object.keys(cp).length) table.used_char_prs = cp;
22036
- return table;
22783
+ if (Object.keys(cp).length) table2.used_char_prs = cp;
22784
+ return table2;
22037
22785
  }
22038
- function nearestTable(tc) {
22039
- let p = tc.parentNode;
22786
+ function nearestTable(tc2) {
22787
+ let p = tc2.parentNode;
22040
22788
  while (p) {
22041
22789
  const tag = (p.tagName || p.localName || "").replace(/^[^:]+:/, "");
22042
22790
  if (tag === "tbl") return p;
@@ -22044,9 +22792,9 @@ function nearestTable(tc) {
22044
22792
  }
22045
22793
  return null;
22046
22794
  }
22047
- function firstRunCharPr(tc) {
22048
- for (const run of elemsByLocal(tc, "run")) {
22049
- if (nearestCell(run) !== tc) continue;
22795
+ function firstRunCharPr(tc2) {
22796
+ for (const run of elemsByLocal(tc2, "run")) {
22797
+ if (nearestCell(run) !== tc2) continue;
22050
22798
  const id = run.getAttribute("charPrIDRef");
22051
22799
  if (id) return id;
22052
22800
  }
@@ -22061,10 +22809,10 @@ function nearestCell(el) {
22061
22809
  }
22062
22810
  return null;
22063
22811
  }
22064
- function directCellText(tc) {
22812
+ function directCellText(tc2) {
22065
22813
  let out = "";
22066
- for (const t of elemsByLocal(tc, "t")) {
22067
- if (nearestCell(t) !== tc) continue;
22814
+ for (const t of elemsByLocal(tc2, "t")) {
22815
+ if (nearestCell(t) !== tc2) continue;
22068
22816
  out += t.textContent ?? "";
22069
22817
  if (out.length >= 64) break;
22070
22818
  }
@@ -22093,14 +22841,168 @@ async function hwpxToProfile(input) {
22093
22841
  let tableIndex = 0;
22094
22842
  for (const f of sectionFiles) {
22095
22843
  const doc = parser.parseFromString(await f.async("text"), "text/xml");
22096
- for (const tbl of elemsByLocal(doc, "tbl")) {
22097
- if (!isTopLevelTable(tbl)) continue;
22098
- 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));
22099
22847
  }
22100
22848
  }
22101
22849
  return { schema_version: "0.2.0", tables };
22102
22850
  }
22103
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;
23004
+ }
23005
+
22104
23006
  // src/roundtrip/patcher.ts
22105
23007
  import JSZip8 from "jszip";
22106
23008
 
@@ -22108,10 +23010,10 @@ import JSZip8 from "jszip";
22108
23010
  var ROW_OBJECT_RE = /<(?:[A-Za-z0-9_]+:)?(?:tbl|pic|equation|ole|container|shape|drawingObject|drawText|video|chart|fieldBegin|fieldEnd|ctrl)\b/;
22109
23011
  var TAG_AT_RE = /<[A-Za-z0-9_:]+(?:"[^"]*"|'[^']*'|[^>"'])*>/y;
22110
23012
  function patchTableRows(input) {
22111
- const { table, scanTable, ctx, skip, origKeys, editedKeys } = input;
23013
+ const { table: table2, scanTable, ctx, skip, origKeys, editedKeys } = input;
22112
23014
  const xml = ctx.scans[scanTable.sectionIndex]?.xml;
22113
23015
  if (!xml) return skip("\uC139\uC158 XML \uB9E4\uD551 \uC2E4\uD328");
22114
- const numRows = table.rows;
23016
+ const numRows = table2.rows;
22115
23017
  if (origKeys.length !== numRows) return skip("\uD45C \uD589 \uC88C\uD45C \uBD88\uC77C\uCE58 \u2014 \uD589 \uCD94\uAC00/\uC0AD\uC81C \uBBF8\uC9C0\uC6D0");
22116
23018
  if (scanTable.rows.length !== numRows || scanTable.rowRanges.length !== numRows) {
22117
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");
@@ -22182,8 +23084,8 @@ function patchTableRows(input) {
22182
23084
  if (template < 0) template = kept[0];
22183
23085
  const cells = input.editedCells(ins.ei);
22184
23086
  if (!cells) return skip("\uC0BD\uC785 \uD589\uC5D0 \uC774\uBBF8\uC9C0/\uC911\uCCA9\uD45C \uD3EC\uD568 \u2014 \uD589 \uCD94\uAC00 \uBBF8\uC9C0\uC6D0");
22185
- for (const cell of cells) {
22186
- 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);
22187
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");
22188
23090
  }
22189
23091
  const tmplCells = scanTable.rows[template];
@@ -22193,7 +23095,7 @@ function patchTableRows(input) {
22193
23095
  }
22194
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");
22195
23097
  const tmplWidth = tmplCells.reduce((s, c) => s + c.colSpan, 0);
22196
- 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");
22197
23099
  if (cells.length !== tmplCells.length) {
22198
23100
  return skip(`\uC0BD\uC785 \uD589 \uC140 \uC218(${cells.length}) \u2260 \uAE30\uC900 \uD589 \uC140 \uC218(${tmplCells.length}) \u2014 \uBBF8\uC9C0\uC6D0`);
22199
23101
  }
@@ -22250,8 +23152,8 @@ function patchTableRows(input) {
22250
23152
  for (const k of keeps) {
22251
23153
  const fi = finalIndex.get(k);
22252
23154
  if (fi === k.oi) continue;
22253
- for (const cell of scanTable.rows[k.oi]) {
22254
- const sp = rowAddrRewrite(xml, cell, fi);
23155
+ for (const cell2 of scanTable.rows[k.oi]) {
23156
+ const sp = rowAddrRewrite(xml, cell2, fi);
22255
23157
  if (sp) splices.push(sp);
22256
23158
  }
22257
23159
  }
@@ -22300,13 +23202,13 @@ function buildRowFragment(xml, scanTable, template, cells, finalRow, hasExplicit
22300
23202
  const patched = applySplices(wrapped, splices);
22301
23203
  return patched.slice(FRAG_OPEN.length, patched.length - FRAG_CLOSE.length);
22302
23204
  }
22303
- function rowAddrRewrite(xml, cell, newRow) {
22304
- if (!cell.addrTagRange) return null;
22305
- 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);
22306
23208
  const m = tag.match(/\browAddr\s*=\s*"(\d+)"/);
22307
23209
  if (!m || m.index === void 0) return null;
22308
23210
  if (parseInt(m[1], 10) === newRow) return null;
22309
- const valStart = cell.addrTagRange.start + m.index + m[0].indexOf('"') + 1;
23211
+ const valStart = cell2.addrTagRange.start + m.index + m[0].indexOf('"') + 1;
22310
23212
  return { start: valStart, end: valStart + m[1].length, replacement: String(newRow) };
22311
23213
  }
22312
23214
  function rowHeightOf(fragment) {
@@ -22332,8 +23234,8 @@ function tableSzHeightSplice(xml, scanTable, tblOpenLen, delta) {
22332
23234
  }
22333
23235
 
22334
23236
  // src/roundtrip/table-patch.ts
22335
- function patchGfmTable(table, scanTable, orig, edited, ctx, skip) {
22336
- const replica = replicateGfmTable(table);
23237
+ function patchGfmTable(table2, scanTable, orig, edited, ctx, skip) {
23238
+ const replica = replicateGfmTable(table2);
22337
23239
  if (!replica) return skip("\uD45C \uB80C\uB354 \uACBD\uB85C \uC2DD\uBCC4 \uC2E4\uD328");
22338
23240
  const origRows = parseGfmTable(orig.lines);
22339
23241
  const editedRows = parseGfmTable(edited.lines);
@@ -22341,15 +23243,15 @@ function patchGfmTable(table, scanTable, orig, edited, ctx, skip) {
22341
23243
  return skip("\uD45C \uC88C\uD45C \uC7AC\uD604 \uBD88\uC77C\uCE58 \u2014 \uB9E4\uD551 \uC2E0\uB8B0 \uBD88\uAC00");
22342
23244
  }
22343
23245
  if (editedRows.length !== origRows.length) {
22344
- return patchGfmTableRows(table, scanTable, origRows, editedRows, replica, ctx, skip);
23246
+ return patchGfmTableRows(table2, scanTable, origRows, editedRows, replica, ctx, skip);
22345
23247
  }
22346
23248
  let applied = 0;
22347
23249
  for (let r = 0; r < origRows.length; r++) {
22348
- applied += patchGfmRowPair(table, scanTable, origRows, editedRows, replica, r, r, ctx, skip);
23250
+ applied += patchGfmRowPair(table2, scanTable, origRows, editedRows, replica, r, r, ctx, skip);
22349
23251
  }
22350
23252
  return applied;
22351
23253
  }
22352
- function patchGfmRowPair(table, scanTable, origRows, editedRows, replica, r, er, ctx, skip) {
23254
+ function patchGfmRowPair(table2, scanTable, origRows, editedRows, replica, r, er, ctx, skip) {
22353
23255
  if (editedRows[er].length !== origRows[r].length) {
22354
23256
  skip(`\uD45C ${r + 1}\uD589 \uC5F4 \uC218 \uBCC0\uACBD\uC740 \uBBF8\uC9C0\uC6D0`);
22355
23257
  return 0;
@@ -22366,7 +23268,7 @@ function patchGfmRowPair(table, scanTable, origRows, editedRows, replica, r, er,
22366
23268
  }
22367
23269
  const newLines = unescapeGfmCell(stripCellTokens(editedRows[er][c])).split("\n").map((s) => s.trim()).filter(Boolean);
22368
23270
  const origLines = unescapeGfmCell(stripCellTokens(origRows[r][c])).split("\n").map((s) => s.trim()).filter(Boolean);
22369
- 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);
22370
23272
  if (n > 0 && origTokens) {
22371
23273
  ctx.skipped.push({
22372
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)",
@@ -22379,19 +23281,19 @@ function patchGfmRowPair(table, scanTable, origRows, editedRows, replica, r, er,
22379
23281
  }
22380
23282
  return applied;
22381
23283
  }
22382
- function patchGfmTableRows(table, scanTable, origRows, editedRows, replica, ctx, skip) {
22383
- 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))) {
22384
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");
22385
23287
  }
22386
- 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)))) {
22387
23289
  return skip("\uBCD1\uD569 \uC140 \uD45C \u2014 GFM \uD589 \uCD94\uAC00/\uC0AD\uC81C \uBBF8\uC9C0\uC6D0");
22388
23290
  }
22389
- if (!gfmRenderStable(editedRows, table.cols)) {
23291
+ if (!gfmRenderStable(editedRows, table2.cols)) {
22390
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");
22391
23293
  }
22392
23294
  const key = (row) => row.join("\0");
22393
23295
  return patchTableRows({
22394
- table,
23296
+ table: table2,
22395
23297
  scanTable,
22396
23298
  ctx,
22397
23299
  skip,
@@ -22406,7 +23308,7 @@ function patchGfmTableRows(table, scanTable, origRows, editedRows, replica, ctx,
22406
23308
  }
22407
23309
  return cells;
22408
23310
  },
22409
- 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)
22410
23312
  });
22411
23313
  }
22412
23314
  function gfmRenderStable(editedRows, cols) {
@@ -22423,13 +23325,13 @@ function gfmRenderStable(editedRows, cols) {
22423
23325
  if (!replica || replica.length !== editedRows.length) return false;
22424
23326
  return replica.every((row, r) => row.length === editedRows[r].length && row.every((c, j) => c.text === editedRows[r][j]));
22425
23327
  }
22426
- function patchHtmlTable(table, scanTable, orig, edited, ctx, skip) {
22427
- 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);
22428
23330
  }
22429
- function patchHtmlTableRaw(table, scanTable, origRaw, editedRaw, ctx, skip, depth) {
23331
+ function patchHtmlTableRaw(table2, scanTable, origRaw, editedRaw, ctx, skip, depth) {
22430
23332
  if (depth > 8) return skip("\uC911\uCCA9\uD45C \uAE4A\uC774 \uCD08\uACFC");
22431
- if (replicateTableToHtml(table) !== origRaw) return skip("\uD45C \uC88C\uD45C \uC7AC\uD604 \uBD88\uC77C\uCE58 \u2014 \uB9E4\uD551 \uC2E0\uB8B0 \uBD88\uAC00");
22432
- 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);
22433
23335
  const origRows = parseHtmlTable(origRaw);
22434
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))) {
22435
23337
  return skip("\uC140 \uACBD\uACC4 \uBAA8\uD638 (\uB9AC\uD130\uB7F4 \uD0DC\uADF8 \uC758\uC2EC) \u2014 \uB9E4\uD551 \uC2E0\uB8B0 \uBD88\uAC00");
@@ -22437,15 +23339,15 @@ function patchHtmlTableRaw(table, scanTable, origRaw, editedRaw, ctx, skip, dept
22437
23339
  const editedRows = parseHtmlTable(editedRaw);
22438
23340
  if (!editedRows) return skip("\uD3B8\uC9D1\uB41C HTML \uD45C \uD30C\uC2F1 \uC2E4\uD328");
22439
23341
  if (editedRows.length !== replica.length) {
22440
- return patchHtmlTableRows(table, scanTable, replica, editedRows, ctx, skip, depth);
23342
+ return patchHtmlTableRows(table2, scanTable, replica, editedRows, ctx, skip, depth);
22441
23343
  }
22442
23344
  let applied = 0;
22443
23345
  for (let r = 0; r < replica.length; r++) {
22444
- applied += patchHtmlRowPair(table, scanTable, replica, editedRows, r, r, ctx, skip, depth);
23346
+ applied += patchHtmlRowPair(table2, scanTable, replica, editedRows, r, r, ctx, skip, depth);
22445
23347
  }
22446
23348
  return applied;
22447
23349
  }
22448
- function patchHtmlRowPair(table, scanTable, replica, editedRows, r, er, ctx, skip, depth) {
23350
+ function patchHtmlRowPair(table2, scanTable, replica, editedRows, r, er, ctx, skip, depth) {
22449
23351
  if (editedRows[er].cells.length !== replica[r].cells.length) {
22450
23352
  skip(`\uD45C ${r + 1}\uD589 \uC140 \uC218 \uBCC0\uACBD\uC740 \uBBF8\uC9C0\uC6D0`);
22451
23353
  return 0;
@@ -22473,23 +23375,23 @@ function patchHtmlRowPair(table, scanTable, replica, editedRows, r, er, ctx, ski
22473
23375
  continue;
22474
23376
  }
22475
23377
  if (origTables.join("\n") !== editedTables.join("\n")) {
22476
- applied += patchNestedTables(table, scanTable, oc, origTables, editedTables, ctx, skip, depth);
23378
+ applied += patchNestedTables(table2, scanTable, oc, origTables, editedTables, ctx, skip, depth);
22477
23379
  }
22478
23380
  }
22479
23381
  if (origContent.lines.join("\n") !== editedContent.lines.join("\n")) {
22480
23382
  const newLines = editedContent.lines.map((l) => unescapeGfm(l));
22481
- 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);
22482
23384
  }
22483
23385
  }
22484
23386
  return applied;
22485
23387
  }
22486
- function patchHtmlTableRows(table, scanTable, replica, editedRows, ctx, skip, depth) {
22487
- 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))) {
22488
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");
22489
23391
  }
22490
23392
  const key = (row) => row.cells.map((c) => `${c.colSpan}x${c.rowSpan}:${c.inner}`).join("\0");
22491
23393
  return patchTableRows({
22492
- table,
23394
+ table: table2,
22493
23395
  scanTable,
22494
23396
  ctx,
22495
23397
  skip,
@@ -22497,18 +23399,18 @@ function patchHtmlTableRows(table, scanTable, replica, editedRows, ctx, skip, de
22497
23399
  editedKeys: editedRows.map(key),
22498
23400
  editedCells: (ei) => {
22499
23401
  const cells = [];
22500
- for (const cell of editedRows[ei].cells) {
22501
- const content = htmlCellInnerToLines(cell.inner);
23402
+ for (const cell2 of editedRows[ei].cells) {
23403
+ const content = htmlCellInnerToLines(cell2.inner);
22502
23404
  if (content.hadNonText) return null;
22503
- 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 });
22504
23406
  }
22505
23407
  return cells;
22506
23408
  },
22507
- 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)
22508
23410
  });
22509
23411
  }
22510
- function patchNestedTables(table, scanTable, oc, origTables, editedTables, ctx, skip, depth) {
22511
- 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];
22512
23414
  const scanCell = scanTable.cellByAnchor.get(`${oc.gridR},${oc.gridC}`);
22513
23415
  const nestedIRs = (irCell?.blocks ?? []).filter((b) => b.type === "table" && b.table).map((b) => b.table);
22514
23416
  if (!scanCell || nestedIRs.length !== origTables.length || scanCell.tables.length !== origTables.length) {
@@ -22531,9 +23433,9 @@ function extractCellTokens(text) {
22531
23433
  function stripCellTokens(text) {
22532
23434
  return text.replace(CELL_TOKEN_RE, "");
22533
23435
  }
22534
- function patchTextChunkTable(table, scanTable, orig, edited, ctx, skip) {
22535
- if (table.rows === 1 && table.cols === 1) {
22536
- 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);
22537
23439
  const replicaLines = content.split(/\n/).map((line) => {
22538
23440
  const t = line.trim();
22539
23441
  if (!t) return "";
@@ -22547,12 +23449,12 @@ function patchTextChunkTable(table, scanTable, orig, edited, ctx, skip) {
22547
23449
  const unwrap = m && /^\d+\.\s/.test(unescapeGfm(m[1]));
22548
23450
  return stripCellTokens(unescapeGfm(unwrap ? m[1] : l)).trim();
22549
23451
  }).filter(Boolean);
22550
- 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);
22551
23453
  }
22552
- if (table.cols === 1 && table.rows >= 2) {
23454
+ if (table2.cols === 1 && table2.rows >= 2) {
22553
23455
  const replica = [];
22554
- for (let r = 0; r < table.rows; r++) {
22555
- 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, " ");
22556
23458
  if (line) replica.push({ line, gridR: r });
22557
23459
  }
22558
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");
@@ -22565,21 +23467,21 @@ function patchTextChunkTable(table, scanTable, orig, edited, ctx, skip) {
22565
23467
  continue;
22566
23468
  }
22567
23469
  const newLines = [stripCellTokens(unescapeGfm(edited.lines[i])).trim()].filter(Boolean);
22568
- 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);
22569
23471
  }
22570
23472
  return applied;
22571
23473
  }
22572
23474
  return skip("\uD45C \uB80C\uB354 \uACBD\uB85C \uC2DD\uBCC4 \uC2E4\uD328");
22573
23475
  }
22574
- function applyCellEdit(table, scanTable, gridR, gridC, newLines, ctx, before, after, origLineCount) {
23476
+ function applyCellEdit(table2, scanTable, gridR, gridC, newLines, ctx, before, after, origLineCount) {
22575
23477
  const skip = (reason) => {
22576
23478
  ctx.skipped.push({ reason, before: summarize(before), after: summarize(after) });
22577
23479
  return 0;
22578
23480
  };
22579
- const cell = scanTable.cellByAnchor.get(`${gridR},${gridC}`);
22580
- 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)");
22581
- const irCell = table.cells[gridR]?.[gridC];
22582
- 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");
22583
23485
  if (irCell && normForMatch(scanJoined) !== normForMatch(stripCellTokens(irCell.text))) {
22584
23486
  if (normForMatch(irCell.text) !== "" || normForMatch(scanJoined) !== "") {
22585
23487
  const flatBlocks = (irCell.blocks ?? []).filter((b) => b.type === "paragraph" || b.type === "heading");
@@ -22589,7 +23491,7 @@ function applyCellEdit(table, scanTable, gridR, gridC, newLines, ctx, before, af
22589
23491
  }
22590
23492
  }
22591
23493
  }
22592
- const nonEmpty = cell.paragraphs.filter((p) => normForMatch(p.text) !== "");
23494
+ const nonEmpty = cell2.paragraphs.filter((p) => normForMatch(p.text) !== "");
22593
23495
  if (origLineCount !== void 0 && nonEmpty.length > 0 && origLineCount !== nonEmpty.length) {
22594
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");
22595
23497
  }
@@ -22599,7 +23501,7 @@ function applyCellEdit(table, scanTable, gridR, gridC, newLines, ctx, before, af
22599
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");
22600
23502
  if (nonEmpty.length === 0) {
22601
23503
  if (newLines.length === 0) return 0;
22602
- const target = cell.paragraphs[0];
23504
+ const target = cell2.paragraphs[0];
22603
23505
  if (!target) return skip("\uBE48 \uC140\uC5D0 \uBB38\uB2E8\uC774 \uC5C6\uC5B4 \uD14D\uC2A4\uD2B8 \uC0BD\uC785 \uBD88\uAC00");
22604
23506
  const sp = buildParagraphSplices(target, newLines.join(" "), ctx.scans[target.sectionIndex]?.xml);
22605
23507
  if (sp === null) return skip("\uC140 \uBB38\uB2E8\uC5D0 \uD14D\uC2A4\uD2B8 \uB178\uB4DC\uB97C \uB9CC\uB4E4 \uC218 \uC5C6\uC74C");
@@ -22684,16 +23586,16 @@ function buildTableParagraphXml(rows, opts) {
22684
23586
  const trElements = rows.map((row, rowIdx) => {
22685
23587
  const cells = row.length < colCnt ? [...row, ...Array(colCnt - row.length).fill("")] : row;
22686
23588
  const isHeaderRow = rowIdx === 0;
22687
- const tdElements = cells.map((cell, colIdx) => {
22688
- const text = escapeXmlText(cellPlainText(cell));
23589
+ const tdElements = cells.map((cell2, colIdx) => {
23590
+ const text = escapeXmlText(cellPlainText(cell2));
22689
23591
  const cellP = `<hp:p paraPrIDRef="${cellParaPrId}" styleIDRef="0"><hp:run charPrIDRef="${cellCharPrId}"><hp:t>${text}</hp:t></hp:run></hp:p>`;
22690
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>`;
22691
23593
  }).join("");
22692
23594
  return `<hp:tr>${tdElements}</hp:tr>`;
22693
23595
  }).join("");
22694
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;
22695
- 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>`;
22696
- 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>`;
22697
23599
  }
22698
23600
 
22699
23601
  // src/roundtrip/hwpx-entries.ts
@@ -22865,12 +23767,12 @@ function buildTableOrdinals(blocks) {
22865
23767
  function resolveParagraphMappings(blocks, scans) {
22866
23768
  const buckets = /* @__PURE__ */ new Map();
22867
23769
  for (const scan of scans) {
22868
- for (const para of scan.bodyParagraphs) {
22869
- const key = normForMatch(para.text);
23770
+ for (const para2 of scan.bodyParagraphs) {
23771
+ const key = normForMatch(para2.text);
22870
23772
  if (!key) continue;
22871
23773
  let list = buckets.get(key);
22872
23774
  if (!list) buckets.set(key, list = []);
22873
- list.push(para);
23775
+ list.push(para2);
22874
23776
  }
22875
23777
  }
22876
23778
  const headerNorms = new Set(scans.flatMap((s) => s.headerTexts.map(normForMatch)).filter(Boolean));
@@ -22956,11 +23858,11 @@ function convertParagraphToTable(block, orig, edited, ctx, skip) {
22956
23858
  if (!ti) return skip("\uBB38\uB2E8\u2192\uD45C \uBCC0\uD658 \uBD88\uAC00 \u2014 header \uC5D4\uD2B8\uB9AC(borderFills) \uD574\uC11D \uC2E4\uD328");
22957
23859
  const mapping = ctx.paraMap.get(orig.blockIdx);
22958
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");
22959
- const para = mapping.para;
22960
- 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");
22961
- 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];
22962
23864
  if (!scan) return skip("\uC139\uC158 \uB9E4\uD551 \uC2E4\uD328");
22963
- const pEnd = findElementEnd(scan.xml, para.start);
23865
+ const pEnd = findElementEnd(scan.xml, para2.start);
22964
23866
  if (pEnd < 0) return skip("\uBB38\uB2E8 \uB05D \uC704\uCE58 \uD0D0\uC0C9 \uC2E4\uD328");
22965
23867
  const rows = parseGfmTable(edited.lines);
22966
23868
  if (rows.length === 0 || rows.every((r) => r.length === 0)) return skip("\uD45C \uB0B4\uC6A9\uC774 \uBE44\uC5B4 \uC788\uC74C");
@@ -22970,7 +23872,7 @@ function convertParagraphToTable(block, orig, edited, ctx, skip) {
22970
23872
  ti.borderFillId = inj.borderFillId;
22971
23873
  ti.headerSplices.push(...inj.headerSplices);
22972
23874
  }
22973
- const outerParaPrId = extractParaPrIdRef(scan.xml, para.start) ?? 0;
23875
+ const outerParaPrId = extractParaPrIdRef(scan.xml, para2.start) ?? 0;
22974
23876
  const tableXml = buildTableParagraphXml(rows, {
22975
23877
  borderFillId: ti.borderFillId,
22976
23878
  outerParaPrId,
@@ -22978,7 +23880,7 @@ function convertParagraphToTable(block, orig, edited, ctx, skip) {
22978
23880
  cellCharPrId: 0,
22979
23881
  tableId: ti.nextId++
22980
23882
  });
22981
- 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 });
22982
23884
  return 1;
22983
23885
  }
22984
23886
  function patchParagraphUnit(block, orig, edited, ctx, skip) {
@@ -23459,7 +24361,7 @@ function scanSection(stream, sectionIndex, compressed) {
23459
24361
  }
23460
24362
  }
23461
24363
  const kind = !ctrlSeen || !nonGso ? "body" : "other";
23462
- const para = {
24364
+ const para2 = {
23463
24365
  sectionIndex,
23464
24366
  headerIdx: i,
23465
24367
  kind,
@@ -23471,8 +24373,8 @@ function scanSection(stream, sectionIndex, compressed) {
23471
24373
  nCharsRaw: rec.data.readUInt32LE(0),
23472
24374
  rawText: state.text
23473
24375
  };
23474
- paras.push(para);
23475
- parasByHeader.set(i, para);
24376
+ paras.push(para2);
24377
+ parasByHeader.set(i, para2);
23476
24378
  }
23477
24379
  const tables = [];
23478
24380
  for (let i = 0; i < records.length; i++) {
@@ -23625,13 +24527,13 @@ function msg(err) {
23625
24527
  function resolveParaMappings(blocks, scans) {
23626
24528
  const buckets = /* @__PURE__ */ new Map();
23627
24529
  for (const scan of scans) {
23628
- for (const para of scan.paras) {
23629
- if (para.kind === "other") continue;
23630
- const key = normForMatch(para.rawText);
24530
+ for (const para2 of scan.paras) {
24531
+ if (para2.kind === "other") continue;
24532
+ const key = normForMatch(para2.rawText);
23631
24533
  if (!key) continue;
23632
24534
  let list = buckets.get(key);
23633
24535
  if (!list) buckets.set(key, list = []);
23634
- list.push(para);
24536
+ list.push(para2);
23635
24537
  }
23636
24538
  }
23637
24539
  const usable = (list) => list.length === 1 || list.every((p) => p.kind === "body");
@@ -23667,18 +24569,18 @@ function resolveTableMappings(blocks, scanTables) {
23667
24569
  const result = /* @__PURE__ */ new Map();
23668
24570
  let si = 0;
23669
24571
  for (let i = 0; i < blocks.length; i++) {
23670
- const table = blocks[i].table;
23671
- if (blocks[i].type !== "table" || !table) continue;
24572
+ const table2 = blocks[i].table;
24573
+ if (blocks[i].type !== "table" || !table2) continue;
23672
24574
  const cands = [];
23673
24575
  for (let k = si; k < scanTables.length; k++) {
23674
- 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);
23675
24577
  }
23676
24578
  if (cands.length === 0) continue;
23677
24579
  let pick2 = cands[0];
23678
24580
  if (cands.length > 1) {
23679
- let best = tableContentScore(table, scanTables[cands[0]]);
24581
+ let best = tableContentScore(table2, scanTables[cands[0]]);
23680
24582
  for (let ci = 1; ci < cands.length; ci++) {
23681
- const sc = tableContentScore(table, scanTables[cands[ci]]);
24583
+ const sc = tableContentScore(table2, scanTables[cands[ci]]);
23682
24584
  if (sc > best) {
23683
24585
  best = sc;
23684
24586
  pick2 = cands[ci];
@@ -23779,14 +24681,14 @@ function patchGfmCells(scanTable, orig, edited, ctx, skip) {
23779
24681
  ctx.skipped.push({ reason, before: summarize(origRows[r][c]), after: summarize(editedRows[r][c]) });
23780
24682
  return 0;
23781
24683
  };
23782
- const cell = scanTable.cells.get(`${r},${c}`);
23783
- if (!cell) {
24684
+ const cell2 = scanTable.cells.get(`${r},${c}`);
24685
+ if (!cell2) {
23784
24686
  cellSkip("\uBCD1\uD569 \uC601\uC5ED \uC140 \u2014 \uC575\uCEE4 \uC140\uC774 \uC544\uB2C8\uBBC0\uB85C \uBBF8\uC9C0\uC6D0");
23785
24687
  continue;
23786
24688
  }
23787
24689
  const beforeParts = origRows[r][c].split(/<br\s*\/?>/i);
23788
24690
  const afterParts = editedRows[r][c].split(/<br\s*\/?>/i);
23789
- if (cell.paras.length === 1) {
24691
+ if (cell2.paras.length === 1) {
23790
24692
  const beforeEach = beforeParts.map(gfmCellToPlain);
23791
24693
  const afterEach = afterParts.map(gfmCellToPlain);
23792
24694
  if (beforeEach.some((p) => p === null) || afterEach.some((p) => p === null)) {
@@ -23796,8 +24698,8 @@ function patchGfmCells(scanTable, orig, edited, ctx, skip) {
23796
24698
  const before = beforeEach.join("\n");
23797
24699
  const after = afterEach.join("\n");
23798
24700
  if (before === after) continue;
23799
- const para = cell.paras[0];
23800
- if (normForMatch(para.rawText) !== normForMatch(before)) {
24701
+ const para2 = cell2.paras[0];
24702
+ if (normForMatch(para2.rawText) !== normForMatch(before)) {
23801
24703
  cellSkip("\uC140 \uD14D\uC2A4\uD2B8 \uBD88\uC77C\uCE58 \u2014 \uC18C\uC2A4\uB9F5 \uC2E0\uB8B0 \uBD88\uAC00");
23802
24704
  continue;
23803
24705
  }
@@ -23805,14 +24707,14 @@ function patchGfmCells(scanTable, orig, edited, ctx, skip) {
23805
24707
  cellSkip("\uACF5\uBC31 \uC815\uADDC\uD654 \uBD88\uC548\uC815 \uD14D\uC2A4\uD2B8 \u2014 \uBBF8\uC9C0\uC6D0");
23806
24708
  continue;
23807
24709
  }
23808
- applied += stageParaPatch(ctx.scans[para.sectionIndex], para, after, cellSkip);
24710
+ applied += stageParaPatch(ctx.scans[para2.sectionIndex], para2, after, cellSkip);
23809
24711
  continue;
23810
24712
  }
23811
- if (beforeParts.length !== cell.paras.length || afterParts.length !== cell.paras.length) {
24713
+ if (beforeParts.length !== cell2.paras.length || afterParts.length !== cell2.paras.length) {
23812
24714
  cellSkip("\uC140 \uBB38\uB2E8 \uC218 \uBCC0\uACBD \u2014 \uBBF8\uC9C0\uC6D0 (\uBB38\uB2E8 \uCD94\uAC00/\uC0AD\uC81C)");
23813
24715
  continue;
23814
24716
  }
23815
- for (let k = 0; k < cell.paras.length; k++) {
24717
+ for (let k = 0; k < cell2.paras.length; k++) {
23816
24718
  const before = gfmCellToPlain(beforeParts[k]);
23817
24719
  const after = gfmCellToPlain(afterParts[k]);
23818
24720
  if (before === null || after === null) {
@@ -23824,8 +24726,8 @@ function patchGfmCells(scanTable, orig, edited, ctx, skip) {
23824
24726
  cellSkip("\uC140 \uB0B4 \uC904\uBC14\uAFC8 \uCD94\uAC00\uB294 \uBBF8\uC9C0\uC6D0 (v1)");
23825
24727
  break;
23826
24728
  }
23827
- const para = cell.paras[k];
23828
- if (normForMatch(para.rawText) !== normForMatch(before)) {
24729
+ const para2 = cell2.paras[k];
24730
+ if (normForMatch(para2.rawText) !== normForMatch(before)) {
23829
24731
  cellSkip("\uC140 \uD14D\uC2A4\uD2B8 \uBD88\uC77C\uCE58 \u2014 \uC18C\uC2A4\uB9F5 \uC2E0\uB8B0 \uBD88\uAC00");
23830
24732
  break;
23831
24733
  }
@@ -23833,15 +24735,15 @@ function patchGfmCells(scanTable, orig, edited, ctx, skip) {
23833
24735
  cellSkip("\uACF5\uBC31 \uC815\uADDC\uD654 \uBD88\uC548\uC815 \uD14D\uC2A4\uD2B8 \u2014 \uBBF8\uC9C0\uC6D0");
23834
24736
  break;
23835
24737
  }
23836
- applied += stageParaPatch(ctx.scans[para.sectionIndex], para, after, cellSkip);
24738
+ applied += stageParaPatch(ctx.scans[para2.sectionIndex], para2, after, cellSkip);
23837
24739
  }
23838
24740
  }
23839
24741
  }
23840
24742
  return applied;
23841
24743
  }
23842
- function patchHtmlCells5(table, scanTable, orig, edited, ctx, skip) {
23843
- if (replicateTableToHtml(table) !== orig.raw) return skip("\uD45C \uC88C\uD45C \uC7AC\uD604 \uBD88\uC77C\uCE58 \u2014 \uB9E4\uD551 \uC2E0\uB8B0 \uBD88\uAC00");
23844
- 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);
23845
24747
  const origRows = parseHtmlTable(orig.raw);
23846
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))) {
23847
24749
  return skip("\uC140 \uACBD\uACC4 \uBAA8\uD638 (\uB9AC\uD130\uB7F4 \uD0DC\uADF8 \uC758\uC2EC) \u2014 \uB9E4\uD551 \uC2E0\uB8B0 \uBD88\uAC00");
@@ -23877,15 +24779,15 @@ function patchHtmlCells5(table, scanTable, orig, edited, ctx, skip) {
23877
24779
  }
23878
24780
  if (origContent.lines.join("\n") !== editedContent.lines.join("\n")) {
23879
24781
  const newLines = editedContent.lines.map((l) => unescapeGfm(l));
23880
- 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);
23881
24783
  }
23882
24784
  }
23883
24785
  }
23884
24786
  return applied;
23885
24787
  }
23886
- function patchTextChunk5(table, scanTable, orig, edited, ctx, skip) {
23887
- if (table.rows === 1 && table.cols === 1) {
23888
- 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);
23889
24791
  const replicaLines = content.split(/\n/).map((line) => {
23890
24792
  const t = line.trim();
23891
24793
  if (!t) return "";
@@ -23899,12 +24801,12 @@ function patchTextChunk5(table, scanTable, orig, edited, ctx, skip) {
23899
24801
  const unwrap = m && /^\d+\.\s/.test(unescapeGfm(m[1]));
23900
24802
  return stripCellTokens(unescapeGfm(unwrap ? m[1] : l)).trim();
23901
24803
  }).filter(Boolean);
23902
- 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);
23903
24805
  }
23904
- if (table.cols === 1 && table.rows >= 2) {
24806
+ if (table2.cols === 1 && table2.rows >= 2) {
23905
24807
  const replica = [];
23906
- for (let r = 0; r < table.rows; r++) {
23907
- 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, " ");
23908
24810
  if (line) replica.push({ line, gridR: r });
23909
24811
  }
23910
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");
@@ -23917,21 +24819,21 @@ function patchTextChunk5(table, scanTable, orig, edited, ctx, skip) {
23917
24819
  continue;
23918
24820
  }
23919
24821
  const newLines = [stripCellTokens(unescapeGfm(edited.lines[i])).trim()].filter(Boolean);
23920
- 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);
23921
24823
  }
23922
24824
  return applied;
23923
24825
  }
23924
24826
  return skip("\uD45C \uB80C\uB354 \uACBD\uB85C \uC2DD\uBCC4 \uC2E4\uD328");
23925
24827
  }
23926
- function applyCellEdit5(table, scanTable, gridR, gridC, newLines, ctx, before, after, origLineCount) {
24828
+ function applyCellEdit5(table2, scanTable, gridR, gridC, newLines, ctx, before, after, origLineCount) {
23927
24829
  const skip = (reason) => {
23928
24830
  ctx.skipped.push({ reason, before: summarize(before), after: summarize(after) });
23929
24831
  return 0;
23930
24832
  };
23931
- const cell = scanTable.cells.get(`${gridR},${gridC}`);
23932
- 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)");
23933
- const irCell = table.cells[gridR]?.[gridC];
23934
- 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");
23935
24837
  if (irCell && normForMatch(scanJoined) !== normForMatch(stripCellTokens(irCell.text))) {
23936
24838
  if (normForMatch(irCell.text) !== "" || normForMatch(scanJoined) !== "") {
23937
24839
  const flatBlocks = (irCell.blocks ?? []).filter((b) => b.type === "paragraph" || b.type === "heading");
@@ -23941,13 +24843,13 @@ function applyCellEdit5(table, scanTable, gridR, gridC, newLines, ctx, before, a
23941
24843
  }
23942
24844
  }
23943
24845
  }
23944
- const nonEmpty = cell.paras.filter((p) => normForMatch(p.rawText) !== "");
24846
+ const nonEmpty = cell2.paras.filter((p) => normForMatch(p.rawText) !== "");
23945
24847
  if (origLineCount !== void 0 && nonEmpty.length > 0 && origLineCount !== nonEmpty.length) {
23946
24848
  return skip("\uC140 \uC904 \uACBD\uACC4 \uB9E4\uD551 \uBAA8\uD638 (\uBB38\uB2E8 \uB0B4 \uC904\uBC14\uAFC8) \u2014 \uBBF8\uC9C0\uC6D0");
23947
24849
  }
23948
24850
  const unstable = newLines.find((l) => sanitizeText(l) !== l);
23949
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");
23950
- const targets = nonEmpty.length > 0 ? nonEmpty : cell.paras;
24852
+ const targets = nonEmpty.length > 0 ? nonEmpty : cell2.paras;
23951
24853
  if (targets.length === 0) return skip("\uC140\uC5D0 \uBB38\uB2E8\uC774 \uC5C6\uC74C \u2014 \uBBF8\uC9C0\uC6D0");
23952
24854
  const assigned = [];
23953
24855
  for (let i = 0; i < targets.length; i++) {
@@ -24097,67 +24999,67 @@ function synthesizeLineSegs(lineSegData, newRaw, startUnits) {
24097
24999
  }
24098
25000
  return { buf: Buffer.concat(segs), count: lines.length };
24099
25001
  }
24100
- function stageParaPatch(scan, para, newPlain, skip) {
25002
+ function stageParaPatch(scan, para2, newPlain, skip) {
24101
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");
24102
- if (para.textIdx === -2) return skip("\uBCF5\uC218 PARA_TEXT \uB808\uCF54\uB4DC \uBB38\uB2E8 \u2014 \uBBF8\uC9C0\uC6D0 (v1)");
24103
- if (para.rangeTagCount > 0) return skip("\uBC94\uC704 \uD0DC\uADF8(\uD615\uAD11\uD39C/\uAD50\uC815\uBD80\uD638) \uBB38\uB2E8 \u2014 \uBBF8\uC9C0\uC6D0 (v1)");
24104
- if (para.charShapeIdx < 0 || para.lineSegIdx < 0) return skip("\uBB38\uB2E8 \uB808\uCF54\uB4DC \uAD6C\uC131 \uBE44\uC815\uD615 \u2014 \uBBF8\uC9C0\uC6D0");
24105
- 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");
24106
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");
24107
25009
  const records = scan.records;
24108
- const headerRec = records[para.headerIdx];
24109
- const charShapeRec = records[para.charShapeIdx];
25010
+ const headerRec = records[para2.headerIdx];
25011
+ const charShapeRec = records[para2.charShapeIdx];
24110
25012
  if (charShapeRec.data.length < 8) {
24111
25013
  return skip("CHAR_SHAPE \uB808\uCF54\uB4DC \uBE44\uC815\uD615 \u2014 \uBBF8\uC9C0\uC6D0");
24112
25014
  }
24113
- if (para.textIdx === -1) {
24114
- const nCharsLow = para.nCharsRaw & 2147483647;
25015
+ if (para2.textIdx === -1) {
25016
+ const nCharsLow = para2.nCharsRaw & 2147483647;
24115
25017
  if (nCharsLow > 1) return skip("PARA_TEXT \uC5C6\uB294 \uBB38\uB2E8\uC758 nChars \uBE44\uC815\uD615 \u2014 \uBBF8\uC9C0\uC6D0");
24116
25018
  const paraEnd = nCharsLow === 1 ? Buffer.from([13, 0]) : Buffer.alloc(0);
24117
- const at = para.headerIdx + 1;
25019
+ const at = para2.headerIdx + 1;
24118
25020
  const list = scan.inserts.get(at) ?? [];
24119
25021
  list.push({ tagId: TAG_PARA_TEXT, level: headerRec.level + 1, data: Buffer.concat([Buffer.from(newPlain, "utf16le"), paraEnd]) });
24120
25022
  scan.inserts.set(at, list);
24121
25023
  const newHeader2 = Buffer.from(headerRec.data);
24122
- newHeader2.writeUInt32LE((para.nCharsRaw & 2147483648 | newPlain.length + nCharsLow) >>> 0, 0);
25024
+ newHeader2.writeUInt32LE((para2.nCharsRaw & 2147483648 | newPlain.length + nCharsLow) >>> 0, 0);
24123
25025
  const cs2 = rebuildCharShape(charShapeRec.data, 0);
24124
- scan.repl.set(para.charShapeIdx, cs2.buf);
25026
+ scan.repl.set(para2.charShapeIdx, cs2.buf);
24125
25027
  newHeader2.writeUInt16LE(cs2.count, 12);
24126
25028
  if (newPlain.includes("\n")) {
24127
- const synth = synthesizeLineSegs(records[para.lineSegIdx].data, newPlain, 0);
25029
+ const synth = synthesizeLineSegs(records[para2.lineSegIdx].data, newPlain, 0);
24128
25030
  if (synth) {
24129
- scan.repl.set(para.lineSegIdx, synth.buf);
25031
+ scan.repl.set(para2.lineSegIdx, synth.buf);
24130
25032
  newHeader2.writeUInt16LE(synth.count, 16);
24131
25033
  }
24132
25034
  }
24133
- scan.repl.set(para.headerIdx, newHeader2);
25035
+ scan.repl.set(para2.headerIdx, newHeader2);
24134
25036
  return 1;
24135
25037
  }
24136
- const textRec = records[para.textIdx];
25038
+ const textRec = records[para2.textIdx];
24137
25039
  const seg = splitParaText(textRec.data);
24138
25040
  if (!seg) {
24139
- 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");
24140
25042
  }
24141
- 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");
24142
- const lead = para.rawText.match(/^\s*/)[0];
24143
- const trail = para.rawText.match(/\s*$/)[0];
24144
- 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;
24145
25047
  const newText = Buffer.concat([seg.prefix, Buffer.from(newRaw, "utf16le"), seg.suffix]);
24146
- scan.repl.set(para.textIdx, newText);
25048
+ scan.repl.set(para2.textIdx, newText);
24147
25049
  const newHeader = Buffer.from(headerRec.data);
24148
25050
  const nChars = seg.prefixUnits + newRaw.length + seg.suffixUnits;
24149
- newHeader.writeUInt32LE((para.nCharsRaw & 2147483648 | nChars) >>> 0, 0);
25051
+ newHeader.writeUInt32LE((para2.nCharsRaw & 2147483648 | nChars) >>> 0, 0);
24150
25052
  const cs = rebuildCharShape(charShapeRec.data, seg.prefixUnits);
24151
- scan.repl.set(para.charShapeIdx, cs.buf);
25053
+ scan.repl.set(para2.charShapeIdx, cs.buf);
24152
25054
  newHeader.writeUInt16LE(cs.count, 12);
24153
25055
  if (newRaw.includes("\n")) {
24154
- const synth = synthesizeLineSegs(records[para.lineSegIdx].data, newRaw, seg.prefixUnits);
25056
+ const synth = synthesizeLineSegs(records[para2.lineSegIdx].data, newRaw, seg.prefixUnits);
24155
25057
  if (synth) {
24156
- scan.repl.set(para.lineSegIdx, synth.buf);
25058
+ scan.repl.set(para2.lineSegIdx, synth.buf);
24157
25059
  newHeader.writeUInt16LE(synth.count, 16);
24158
25060
  }
24159
25061
  }
24160
- scan.repl.set(para.headerIdx, newHeader);
25062
+ scan.repl.set(para2.headerIdx, newHeader);
24161
25063
  return 1;
24162
25064
  }
24163
25065
 
@@ -24322,9 +25224,9 @@ var HwpxSession = class _HwpxSession {
24322
25224
  const block = st.blocks[blockIndex];
24323
25225
  if (!block) return void 0;
24324
25226
  if (block.type === "paragraph" || block.type === "heading") {
24325
- const para = st.paraMap.get(blockIndex)?.para;
24326
- if (!para) return void 0;
24327
- 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 };
24328
25230
  }
24329
25231
  if (block.type === "table" && block.table) {
24330
25232
  if (st.tableOrdinals.size !== st.scanTables.length) return void 0;
@@ -24361,13 +25263,13 @@ var HwpxSession = class _HwpxSession {
24361
25263
  if (!scanTable) {
24362
25264
  return { capability: "locked", reason: "\uD45C \uC18C\uC2A4\uB9F5 \uB9E4\uD551 \uC2E4\uD328" };
24363
25265
  }
24364
- const table = block.table;
25266
+ const table2 = block.table;
24365
25267
  const cells = [];
24366
25268
  let anyEditable = false;
24367
- for (let r = 0; r < table.rows; r++) {
25269
+ for (let r = 0; r < table2.rows; r++) {
24368
25270
  const row = [];
24369
- for (let c = 0; c < table.cols; c++) {
24370
- const info = cellStaticCheck(table, scanTable, r, c);
25271
+ for (let c = 0; c < table2.cols; c++) {
25272
+ const info = cellStaticCheck(table2, scanTable, r, c);
24371
25273
  if (info.editable) anyEditable = true;
24372
25274
  row.push(info);
24373
25275
  }
@@ -24556,12 +25458,12 @@ var HwpxSession = class _HwpxSession {
24556
25458
  return 1;
24557
25459
  }
24558
25460
  };
24559
- function cellStaticCheck(table, scanTable, r, c) {
24560
- const irCell = table.cells[r]?.[c];
25461
+ function cellStaticCheck(table2, scanTable, r, c) {
25462
+ const irCell = table2.cells[r]?.[c];
24561
25463
  if (!irCell) return { editable: false, reason: "\uC140 \uC88C\uD45C \uBC94\uC704 \uBC16" };
24562
- const cell = scanTable.cellByAnchor.get(`${r},${c}`);
24563
- if (!cell) return { editable: false, reason: "\uBCD1\uD569 \uC601\uC5ED\uC758 \uBE48 \uCE78\uC774\uAC70\uB098 \uC88C\uD45C \uBD88\uC77C\uCE58" };
24564
- 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");
24565
25467
  if (normForMatch(scanJoined) !== normForMatch(stripCellTokens(irCell.text))) {
24566
25468
  if (normForMatch(irCell.text) !== "" || normForMatch(scanJoined) !== "") {
24567
25469
  const flatBlocks = (irCell.blocks ?? []).filter((b) => b.type === "paragraph" || b.type === "heading");
@@ -24571,9 +25473,9 @@ function cellStaticCheck(table, scanTable, r, c) {
24571
25473
  }
24572
25474
  }
24573
25475
  }
24574
- const nonEmpty = cell.paragraphs.filter((p) => normForMatch(p.text) !== "");
25476
+ const nonEmpty = cell2.paragraphs.filter((p) => normForMatch(p.text) !== "");
24575
25477
  if (nonEmpty.length === 0) {
24576
- if (cell.paragraphs.length === 0) {
25478
+ if (cell2.paragraphs.length === 0) {
24577
25479
  return { editable: false, reason: "\uBE48 \uC140\uC5D0 \uBB38\uB2E8\uC774 \uC5C6\uC5B4 \uD14D\uC2A4\uD2B8 \uC0BD\uC785 \uBD88\uAC00" };
24578
25480
  }
24579
25481
  return { editable: true };
@@ -24832,7 +25734,7 @@ async function parseHwp(buffer, options) {
24832
25734
  async function parsePdf(buffer, options) {
24833
25735
  let parsePdfDocument;
24834
25736
  try {
24835
- const mod = await import("./parser-DOBK652H.js");
25737
+ const mod = await import("./parser-LHUO6UUA.js");
24836
25738
  parsePdfDocument = mod.parsePdfDocument;
24837
25739
  } catch {
24838
25740
  return {
@@ -24940,6 +25842,8 @@ export {
24940
25842
  compare,
24941
25843
  diffBlocks,
24942
25844
  hwpxToProfile,
25845
+ isKnownFont,
25846
+ unknownFontWarnings,
24943
25847
  patchHwpx,
24944
25848
  patchHwp,
24945
25849
  validateHwpx,
@@ -24960,4 +25864,4 @@ export {
24960
25864
  parseHwpml,
24961
25865
  fillForm
24962
25866
  };
24963
- //# sourceMappingURL=chunk-7K5P4RNT.js.map
25867
+ //# sourceMappingURL=chunk-PGWAF755.js.map