kordoc 3.18.1 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/README.md +768 -752
  2. package/dist/{-V66QW3WA.js → -O3AWNVPH.js} +16 -8
  3. package/dist/{chunk-2IBFK5ZO.js → chunk-33OUI7HC.js} +2 -2
  4. package/dist/chunk-33OUI7HC.js.map +1 -0
  5. package/dist/{chunk-UHYPUIRH.js → chunk-3H3CVOZ3.js} +2 -2
  6. package/dist/chunk-3H3CVOZ3.js.map +1 -0
  7. package/dist/{chunk-MEPHGCPQ.js → chunk-5CJGKKMZ.js} +1 -1
  8. package/dist/chunk-5CJGKKMZ.js.map +1 -0
  9. package/dist/{chunk-QMJJI6TD.js → chunk-C5ABJ7PB.js} +6 -4
  10. package/dist/chunk-C5ABJ7PB.js.map +1 -0
  11. package/dist/chunk-DCZVOIEO.cjs.map +1 -1
  12. package/dist/{chunk-UNV7F3FK.js → chunk-EH2KYFFO.js} +2 -2
  13. package/dist/chunk-EH2KYFFO.js.map +1 -0
  14. package/dist/chunk-GS7T56RP.cjs.map +1 -1
  15. package/dist/{chunk-NZJAXMN7.js → chunk-JMLK6NTW.js} +3 -3
  16. package/dist/chunk-JMLK6NTW.js.map +1 -0
  17. package/dist/chunk-MOL7MDBG.js +0 -0
  18. package/dist/{chunk-R2H34FY5.cjs → chunk-NIZXIVEI.cjs} +2 -2
  19. package/dist/chunk-NIZXIVEI.cjs.map +1 -0
  20. package/dist/{chunk-7K5P4RNT.js → chunk-SHVV3BD6.js} +1652 -588
  21. package/dist/chunk-SHVV3BD6.js.map +1 -0
  22. package/dist/{chunk-4RGDFDQ2.js → chunk-YEC7VG6O.js} +8 -2
  23. package/dist/chunk-YEC7VG6O.js.map +1 -0
  24. package/dist/cli.js +76 -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 +2036 -966
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.cts +110 -9
  32. package/dist/index.d.ts +110 -9
  33. package/dist/index.js +1811 -741
  34. package/dist/index.js.map +1 -1
  35. package/dist/mcp.js +60 -17
  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-44OPXZMP.cjs} +15 -15
  40. package/dist/parser-44OPXZMP.cjs.map +1 -0
  41. package/dist/{parser-JBBA5A5E.js → parser-G433UZMX.js} +3 -3
  42. package/dist/parser-G433UZMX.js.map +1 -0
  43. package/dist/{parser-DOBK652H.js → parser-ZOMDHCA7.js} +4 -4
  44. package/dist/parser-ZOMDHCA7.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-SQVQBORJ.js +10 -0
  52. package/dist/seal-6E26L45Z.js +10 -0
  53. package/dist/setup-57FB3LSP.js +0 -0
  54. package/dist/{watch-2MNRQWGV.js → watch-UYT3ZCBM.js} +8 -8
  55. package/dist/watch-UYT3ZCBM.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 → -O3AWNVPH.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-SQVQBORJ.js.map} +0 -0
  78. /package/dist/{seal-6Z6H4YXN.js.map → seal-6E26L45Z.js.map} +0 -0
package/dist/index.js CHANGED
@@ -20,7 +20,7 @@ import {
20
20
  sanitizeHref,
21
21
  stripDtd,
22
22
  toArrayBuffer
23
- } from "./chunk-UHYPUIRH.js";
23
+ } from "./chunk-3H3CVOZ3.js";
24
24
  import {
25
25
  parsePageRange
26
26
  } from "./chunk-GE43BE46.js";
@@ -368,8 +368,8 @@ function comResultToParseResult(pages, pageCount, warnings) {
368
368
  const text = (pages[i] ?? "").trim();
369
369
  if (!text) continue;
370
370
  const paragraphs = text.split(/\n/);
371
- for (const para of paragraphs) {
372
- const trimmed = para.trim();
371
+ for (const para2 of paragraphs) {
372
+ const trimmed = para2.trim();
373
373
  if (!trimmed) continue;
374
374
  blocks.push({ type: "paragraph", text: trimmed, pageNumber: i + 1 });
375
375
  lines.push(trimmed);
@@ -1101,7 +1101,7 @@ var HANGUL_SYLLABLE_SEQ = "\uAC00\uB098\uB2E4\uB77C\uB9C8\uBC14\uC0AC\uC544\uC79
1101
1101
  var HANGUL_JAMO_SEQ = "\u3131\u3134\u3137\u3139\u3141\u3142\u3145\u3147\u3148\u314A\u314B\u314C\u314D\u314E";
1102
1102
  function toRoman(n) {
1103
1103
  if (n <= 0 || n >= 4e3) return String(n);
1104
- const table = [
1104
+ const table2 = [
1105
1105
  [1e3, "M"],
1106
1106
  [900, "CM"],
1107
1107
  [500, "D"],
@@ -1117,7 +1117,7 @@ function toRoman(n) {
1117
1117
  [1, "I"]
1118
1118
  ];
1119
1119
  let out = "";
1120
- for (const [v, s] of table) {
1120
+ for (const [v, s] of table2) {
1121
1121
  while (n >= v) {
1122
1122
  out += s;
1123
1123
  n -= v;
@@ -1159,10 +1159,17 @@ function formatHeadNumber(n, numFormat) {
1159
1159
  function resolveParaHeading(paraEl, ctx) {
1160
1160
  const sm = ctx.styleMap;
1161
1161
  if (!sm) return null;
1162
+ const styleId = paraEl.getAttribute("styleIDRef");
1163
+ let styleHeading;
1164
+ if (styleId && styleId !== "0") {
1165
+ const st = sm.styles.get(styleId);
1166
+ const m = st && /^개요\s*([1-6])$/.exec(st.name);
1167
+ if (m) styleHeading = Math.min(parseInt(m[1], 10), 6);
1168
+ }
1162
1169
  const prId = paraEl.getAttribute("paraPrIDRef");
1163
- if (!prId) return null;
1170
+ if (!prId) return styleHeading ? { headingLevel: styleHeading } : null;
1164
1171
  const ref = sm.paraHeadings.get(prId);
1165
- if (!ref) return null;
1172
+ if (!ref) return styleHeading ? { headingLevel: styleHeading } : null;
1166
1173
  if (ref.type === "BULLET") {
1167
1174
  const char = sm.bullets.get(ref.idRef);
1168
1175
  return char ? { prefix: char } : null;
@@ -1192,24 +1199,24 @@ function resolveParaHeading(paraEl, ctx) {
1192
1199
 
1193
1200
  // src/hwpx/table-build.ts
1194
1201
  function buildTableWithCellMeta(state) {
1195
- const table = buildTable(state.rows);
1196
- if (state.caption) table.caption = state.caption;
1202
+ const table2 = buildTable(state.rows);
1203
+ if (state.caption) table2.caption = state.caption;
1197
1204
  const anchors = [];
1198
1205
  {
1199
1206
  const covered = /* @__PURE__ */ new Set();
1200
- for (let r = 0; r < table.rows; r++) {
1201
- for (let c = 0; c < table.cols; c++) {
1207
+ for (let r = 0; r < table2.rows; r++) {
1208
+ for (let c = 0; c < table2.cols; c++) {
1202
1209
  if (covered.has(`${r},${c}`)) continue;
1203
- const cell = table.cells[r]?.[c];
1204
- if (!cell) continue;
1205
- for (let dr = 0; dr < cell.rowSpan; dr++) {
1206
- for (let dc = 0; dc < cell.colSpan; dc++) {
1210
+ const cell2 = table2.cells[r]?.[c];
1211
+ if (!cell2) continue;
1212
+ for (let dr = 0; dr < cell2.rowSpan; dr++) {
1213
+ for (let dc = 0; dc < cell2.colSpan; dc++) {
1207
1214
  if (dr === 0 && dc === 0) continue;
1208
- if (r + dr < table.rows && c + dc < table.cols) covered.add(`${r + dr},${c + dc}`);
1215
+ if (r + dr < table2.rows && c + dc < table2.cols) covered.add(`${r + dr},${c + dc}`);
1209
1216
  }
1210
1217
  }
1211
- anchors.push(cell);
1212
- c += cell.colSpan - 1;
1218
+ anchors.push(cell2);
1219
+ c += cell2.colSpan - 1;
1213
1220
  }
1214
1221
  }
1215
1222
  }
@@ -1225,11 +1232,11 @@ function buildTableWithCellMeta(state) {
1225
1232
  let target;
1226
1233
  const trimmed = src.text.trim();
1227
1234
  if (src.rowAddr !== void 0 && src.colAddr !== void 0) {
1228
- const cand = table.cells[src.rowAddr]?.[src.colAddr];
1235
+ const cand = table2.cells[src.rowAddr]?.[src.colAddr];
1229
1236
  if (cand && cand.text === trimmed && !claimed.has(cand)) target = cand;
1230
1237
  }
1231
1238
  if (!target) {
1232
- outer: for (const irRow of table.cells) {
1239
+ outer: for (const irRow of table2.cells) {
1233
1240
  for (const cand of irRow) {
1234
1241
  if (!claimed.has(cand) && cand.text === trimmed && cand.colSpan === src.colSpan && cand.rowSpan === src.rowSpan) {
1235
1242
  target = cand;
@@ -1248,7 +1255,7 @@ function buildTableWithCellMeta(state) {
1248
1255
  if (src.isHeader) target.isHeader = true;
1249
1256
  }
1250
1257
  }
1251
- return table;
1258
+ return table2;
1252
1259
  }
1253
1260
  function completeTable(newTable, tableStack, blocks, ctx) {
1254
1261
  const parentTable = tableStack.length > 0 ? tableStack.pop() : null;
@@ -1259,12 +1266,12 @@ function completeTable(newTable, tableStack, blocks, ctx) {
1259
1266
  const ir = buildTableWithCellMeta(newTable);
1260
1267
  const block = { type: "table", table: ir, pageNumber: ctx.sectionNum };
1261
1268
  if (parentTable?.cell) {
1262
- const cell = parentTable.cell;
1263
- (cell.blocks ??= []).push(block);
1264
- cell.hasStructure = true;
1269
+ const cell2 = parentTable.cell;
1270
+ (cell2.blocks ??= []).push(block);
1271
+ cell2.hasStructure = true;
1265
1272
  let flat = convertTableToText(newTable.rows);
1266
1273
  if (newTable.caption) flat = newTable.caption + (flat ? "\n" + flat : "");
1267
- if (flat) cell.text += (cell.text ? "\n" : "") + flat;
1274
+ if (flat) cell2.text += (cell2.text ? "\n" : "") + flat;
1268
1275
  } else {
1269
1276
  blocks.push(block);
1270
1277
  }
@@ -1380,10 +1387,10 @@ function walkSection(node, blocks, tableCtx, tableStack, ctx, depth = 0) {
1380
1387
  }
1381
1388
  if (text) {
1382
1389
  if (tableCtx?.cell) {
1383
- const cell = tableCtx.cell;
1390
+ const cell2 = tableCtx.cell;
1384
1391
  if (footnote) text += ` (\uC8FC: ${footnote})`;
1385
- cell.text += (cell.text ? "\n" : "") + text;
1386
- (cell.blocks ??= []).push({ type: "paragraph", text, pageNumber: ctx.sectionNum });
1392
+ cell2.text += (cell2.text ? "\n" : "") + text;
1393
+ (cell2.blocks ??= []).push({ type: "paragraph", text, pageNumber: ctx.sectionNum });
1387
1394
  } else if (!tableCtx) {
1388
1395
  const block = { type: headingLevel ? "heading" : "paragraph", text, pageNumber: ctx.sectionNum };
1389
1396
  if (headingLevel) block.level = headingLevel;
@@ -1456,18 +1463,18 @@ function userShapeComment(el) {
1456
1463
  if (/^(?:모서리가 둥근 |둥근 )?[^\n]{1,20}입니다\.?$/.test(text)) return void 0;
1457
1464
  return text;
1458
1465
  }
1459
- function mergeBlocksIntoCell(cell, sink) {
1466
+ function mergeBlocksIntoCell(cell2, sink) {
1460
1467
  for (const b of sink) {
1461
1468
  if ((b.type === "paragraph" || b.type === "heading") && b.text) {
1462
- cell.text += (cell.text ? "\n" : "") + b.text;
1463
- (cell.blocks ??= []).push(b);
1469
+ cell2.text += (cell2.text ? "\n" : "") + b.text;
1470
+ (cell2.blocks ??= []).push(b);
1464
1471
  } else if (b.type === "image" || b.type === "table") {
1465
1472
  if (b.type === "image" && b.text) {
1466
- cell.text += (cell.text ? "\n" : "") + `![image](${b.text})`;
1473
+ cell2.text += (cell2.text ? "\n" : "") + `![image](${b.text})`;
1467
1474
  }
1468
1475
  ;
1469
- (cell.blocks ??= []).push(b);
1470
- cell.hasStructure = true;
1476
+ (cell2.blocks ??= []).push(b);
1477
+ cell2.hasStructure = true;
1471
1478
  }
1472
1479
  }
1473
1480
  }
@@ -1596,7 +1603,7 @@ function extractHyperlinkHref(fieldBegin) {
1596
1603
  function isInDeletedRange(ctx) {
1597
1604
  return (ctx?.shared.track.deleteDepth ?? 0) > 0;
1598
1605
  }
1599
- function extractParagraphInfo(para, styleMap, ctx) {
1606
+ function extractParagraphInfo(para2, styleMap, ctx) {
1600
1607
  let text = "";
1601
1608
  let href;
1602
1609
  let footnote;
@@ -1806,7 +1813,7 @@ function extractParagraphInfo(para, styleMap, ctx) {
1806
1813
  }
1807
1814
  }
1808
1815
  };
1809
- walk(para);
1816
+ walk(para2);
1810
1817
  const leaderIdx = text.indexOf("");
1811
1818
  if (leaderIdx >= 0) text = text.substring(0, leaderIdx);
1812
1819
  let cleanText = text.replace(/[ \t]+/g, " ").trim();
@@ -1871,8 +1878,8 @@ function collectImageBlocks(blocks, out, ownerCell, depth = 0) {
1871
1878
  out.push({ block, ownerCell });
1872
1879
  } else if (block.type === "table" && block.table) {
1873
1880
  for (const row of block.table.cells) {
1874
- for (const cell of row) {
1875
- if (cell.blocks?.length) collectImageBlocks(cell.blocks, out, cell, depth + 1);
1881
+ for (const cell2 of row) {
1882
+ if (cell2.blocks?.length) collectImageBlocks(cell2.blocks, out, cell2, depth + 1);
1876
1883
  }
1877
1884
  }
1878
1885
  }
@@ -2520,8 +2527,8 @@ var GANADA = "\uAC00\uB098\uB2E4\uB77C\uB9C8\uBC14\uC0AC\uC544\uC790\uCC28\uCE74
2520
2527
  var CIRCLED_GANADA = "\u326E\u326F\u3270\u3271\u3272\u3273\u3274\u3275\u3276\u3277\u3278\u3279\u327A\u327B";
2521
2528
  var JAMO = "\u3131\u3134\u3137\u3139\u3141\u3142\u3145\u3147\u3148\u314A\u314B\u314C\u314D\u314E";
2522
2529
  var CIRCLED_JAMO = "\u3260\u3261\u3262\u3263\u3264\u3265\u3266\u3267\u3268\u3269\u326A\u326B\u326C\u326D";
2523
- function fromTable(n, table) {
2524
- return n >= 1 && n <= table.length ? table[n - 1] : String(n);
2530
+ function fromTable(n, table2) {
2531
+ return n >= 1 && n <= table2.length ? table2[n - 1] : String(n);
2525
2532
  }
2526
2533
  function formatRoman(n, upper) {
2527
2534
  if (n <= 0 || n > 3999) return String(n);
@@ -2644,8 +2651,8 @@ function collectImageBlocks2(blocks, out) {
2644
2651
  if (b.type === "image") out.push(b);
2645
2652
  if (b.table) {
2646
2653
  for (const row of b.table.cells) {
2647
- for (const cell of row) {
2648
- if (cell.blocks) collectImageBlocks2(cell.blocks, out);
2654
+ for (const cell2 of row) {
2655
+ if (cell2.blocks) collectImageBlocks2(cell2.blocks, out);
2649
2656
  }
2650
2657
  }
2651
2658
  }
@@ -2656,9 +2663,9 @@ function forEachTableCell(blocks, fn) {
2656
2663
  for (const b of blocks) {
2657
2664
  if (b.table) {
2658
2665
  for (const row of b.table.cells) {
2659
- for (const cell of row) {
2660
- fn(cell);
2661
- if (cell.blocks) forEachTableCell(cell.blocks, fn);
2666
+ for (const cell2 of row) {
2667
+ fn(cell2);
2668
+ if (cell2.blocks) forEachTableCell(cell2.blocks, fn);
2662
2669
  }
2663
2670
  }
2664
2671
  }
@@ -2667,9 +2674,9 @@ function forEachTableCell(blocks, fn) {
2667
2674
  }
2668
2675
  var CELL_IMAGE_SENTINEL_RE = /!\[image\]\(hwp5bin:(\d+)\)/g;
2669
2676
  function resolveCellImageSentinels(blocks, renamed) {
2670
- forEachTableCell(blocks, (cell) => {
2671
- if (!cell.text.includes("hwp5bin:")) return;
2672
- cell.text = cell.text.replace(CELL_IMAGE_SENTINEL_RE, (_m, idStr) => {
2677
+ forEachTableCell(blocks, (cell2) => {
2678
+ if (!cell2.text.includes("hwp5bin:")) return;
2679
+ cell2.text = cell2.text.replace(CELL_IMAGE_SENTINEL_RE, (_m, idStr) => {
2673
2680
  const filename = renamed.get(Number(idStr));
2674
2681
  return filename ? `![image](${filename})` : "[\uC774\uBBF8\uC9C0]";
2675
2682
  });
@@ -2760,15 +2767,15 @@ function extractHwp5ImagesLenient(lcfb, blocks, warnings) {
2760
2767
  // src/image/transcode.ts
2761
2768
  import { deflateSync } from "zlib";
2762
2769
  var CRC_TABLE = (() => {
2763
- const table = new Uint32Array(256);
2770
+ const table2 = new Uint32Array(256);
2764
2771
  for (let n = 0; n < 256; n++) {
2765
2772
  let c = n;
2766
2773
  for (let k = 0; k < 8; k++) {
2767
2774
  c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
2768
2775
  }
2769
- table[n] = c >>> 0;
2776
+ table2[n] = c >>> 0;
2770
2777
  }
2771
- return table;
2778
+ return table2;
2772
2779
  })();
2773
2780
  function crc32(bytes) {
2774
2781
  let c = 4294967295;
@@ -4297,8 +4304,8 @@ function parseParagraph(records, start, end, ctx) {
4297
4304
  function applyCtrlEffect(ctrl, records, ctx) {
4298
4305
  switch (ctrl.id) {
4299
4306
  case CTRL_TBL: {
4300
- const table = parseTableControl(ctrl, records, ctx);
4301
- if (table) ctrl.afterBlocks = [{ type: "table", table, pageNumber: ctx.sectionNum }];
4307
+ const table2 = parseTableControl(ctrl, records, ctx);
4308
+ if (table2) ctrl.afterBlocks = [{ type: "table", table: table2, pageNumber: ctx.sectionNum }];
4302
4309
  return;
4303
4310
  }
4304
4311
  case CTRL_GSO: {
@@ -4517,14 +4524,14 @@ function parseTableControl(ctrl, records, ctx) {
4517
4524
  if (c.isHeader) ir.isHeader = true;
4518
4525
  return ir;
4519
4526
  }));
4520
- const table2 = { rows, cols, cells: irCells, hasHeader: rows > 1 };
4521
- if (caption) table2.caption = caption;
4522
- return table2;
4527
+ const table3 = { rows, cols, cells: irCells, hasHeader: rows > 1 };
4528
+ if (caption) table3.caption = caption;
4529
+ return table3;
4523
4530
  }
4524
4531
  const cellRows = arrangeCells(rows, cols, cells);
4525
- const table = buildTable(cellRows);
4526
- if (caption && table.rows > 0) table.caption = caption;
4527
- return table.rows > 0 ? table : null;
4532
+ const table2 = buildTable(cellRows);
4533
+ if (caption && table2.rows > 0) table2.caption = caption;
4534
+ return table2.rows > 0 ? table2 : null;
4528
4535
  }
4529
4536
  function parseCell(records, lhIdx, end, ctx) {
4530
4537
  const rec = records[lhIdx];
@@ -4562,22 +4569,22 @@ function parseCell(records, lhIdx, end, ctx) {
4562
4569
  parts.push(t);
4563
4570
  }
4564
4571
  }
4565
- const cell = { text: parts.join("\n"), colSpan, rowSpan, colAddr, rowAddr };
4566
- if (hasStructure && blocks.length > 0) cell.blocks = blocks;
4567
- if (isHeader) cell.isHeader = true;
4568
- return cell;
4572
+ const cell2 = { text: parts.join("\n"), colSpan, rowSpan, colAddr, rowAddr };
4573
+ if (hasStructure && blocks.length > 0) cell2.blocks = blocks;
4574
+ if (isHeader) cell2.isHeader = true;
4575
+ return cell2;
4569
4576
  }
4570
4577
  function arrangeCells(rows, cols, cells) {
4571
4578
  const grid = Array.from({ length: rows }, () => Array(cols).fill(null));
4572
4579
  const hasAddr = cells.some((c) => c.colAddr !== void 0 && c.rowAddr !== void 0);
4573
4580
  if (hasAddr) {
4574
- for (const cell of cells) {
4575
- const r = cell.rowAddr ?? 0;
4576
- const c = cell.colAddr ?? 0;
4581
+ for (const cell2 of cells) {
4582
+ const r = cell2.rowAddr ?? 0;
4583
+ const c = cell2.colAddr ?? 0;
4577
4584
  if (r >= rows || c >= cols) continue;
4578
- grid[r][c] = cell;
4579
- for (let dr = 0; dr < cell.rowSpan; dr++) {
4580
- for (let dc = 0; dc < cell.colSpan; dc++) {
4585
+ grid[r][c] = cell2;
4586
+ for (let dr = 0; dr < cell2.rowSpan; dr++) {
4587
+ for (let dc = 0; dc < cell2.colSpan; dc++) {
4581
4588
  if (dr === 0 && dc === 0) continue;
4582
4589
  if (r + dr < rows && c + dc < cols)
4583
4590
  grid[r + dr][c + dc] = { text: "", colSpan: 1, rowSpan: 1 };
@@ -4589,10 +4596,10 @@ function arrangeCells(rows, cols, cells) {
4589
4596
  for (let r = 0; r < rows && cellIdx < cells.length; r++) {
4590
4597
  for (let c = 0; c < cols && cellIdx < cells.length; c++) {
4591
4598
  if (grid[r][c] !== null) continue;
4592
- const cell = cells[cellIdx++];
4593
- grid[r][c] = cell;
4594
- for (let dr = 0; dr < cell.rowSpan; dr++) {
4595
- for (let dc = 0; dc < cell.colSpan; dc++) {
4599
+ const cell2 = cells[cellIdx++];
4600
+ grid[r][c] = cell2;
4601
+ for (let dr = 0; dr < cell2.rowSpan; dr++) {
4602
+ for (let dc = 0; dc < cell2.colSpan; dc++) {
4596
4603
  if (dr === 0 && dc === 0) continue;
4597
4604
  if (r + dr < rows && c + dc < cols)
4598
4605
  grid[r + dr][c + dc] = { text: "", colSpan: 1, rowSpan: 1 };
@@ -17108,7 +17115,7 @@ function sheetToBlocks(sheetName, grid, merges, maxRow, maxCol, sheetIndex) {
17108
17115
  let lastRow = -1;
17109
17116
  for (let r = 0; r <= maxRow; r++) {
17110
17117
  const row = grid[r];
17111
- if (row && row.some((cell) => cell !== "")) {
17118
+ if (row && row.some((cell2) => cell2 !== "")) {
17112
17119
  if (firstRow === -1) firstRow = r;
17113
17120
  lastRow = r;
17114
17121
  }
@@ -17131,9 +17138,9 @@ function sheetToBlocks(sheetName, grid, merges, maxRow, maxCol, sheetIndex) {
17131
17138
  cellRows.push(row);
17132
17139
  }
17133
17140
  if (cellRows.length > 0) {
17134
- const table = buildTable(cellRows);
17135
- if (table.rows > 0) {
17136
- blocks.push({ type: "table", table, pageNumber: sheetIndex + 1 });
17141
+ const table2 = buildTable(cellRows);
17142
+ if (table2.rows > 0) {
17143
+ blocks.push({ type: "table", table: table2, pageNumber: sheetIndex + 1 });
17137
17144
  }
17138
17145
  }
17139
17146
  return blocks;
@@ -17751,9 +17758,9 @@ function sheetToBlocks2(sheetName, sheet, sheetIndex) {
17751
17758
  cellRows.push(row);
17752
17759
  }
17753
17760
  if (cellRows.length > 0) {
17754
- const table = buildTable(cellRows);
17755
- if (table.rows > 0) {
17756
- blocks.push({ type: "table", table, pageNumber: sheetIndex + 1 });
17761
+ const table2 = buildTable(cellRows);
17762
+ if (table2.rows > 0) {
17763
+ blocks.push({ type: "table", table: table2, pageNumber: sheetIndex + 1 });
17757
17764
  }
17758
17765
  }
17759
17766
  return blocks;
@@ -18499,8 +18506,8 @@ function collectTextboxParagraphs(node, inTxbx = false, out = [], depth = 0) {
18499
18506
  }
18500
18507
  return out;
18501
18508
  }
18502
- function parseTable(tbl, styles, numbering, footnotes, rels) {
18503
- const trElements = getChildElements(tbl, "tr");
18509
+ function parseTable(tbl2, styles, numbering, footnotes, rels) {
18510
+ const trElements = getChildElements(tbl2, "tr");
18504
18511
  if (trElements.length === 0) return null;
18505
18512
  const rawRows = [];
18506
18513
  for (const tr of trElements) {
@@ -18513,10 +18520,10 @@ function parseTable(tbl, styles, numbering, footnotes, rels) {
18513
18520
  col = Math.max(0, parseInt(getAttr(gridBeforeEls[0], "val") ?? "0", 10) || 0);
18514
18521
  }
18515
18522
  }
18516
- for (const tc of getChildElements(tr, "tc")) {
18523
+ for (const tc2 of getChildElements(tr, "tc")) {
18517
18524
  let colSpan = 1;
18518
18525
  let vMerge = null;
18519
- const tcPrEls = getChildElements(tc, "tcPr");
18526
+ const tcPrEls = getChildElements(tc2, "tcPr");
18520
18527
  if (tcPrEls.length > 0) {
18521
18528
  const gridSpanEls = getChildElements(tcPrEls[0], "gridSpan");
18522
18529
  if (gridSpanEls.length > 0) {
@@ -18527,48 +18534,48 @@ function parseTable(tbl, styles, numbering, footnotes, rels) {
18527
18534
  vMerge = getAttr(vMergeEls[0], "val") === "restart" ? "restart" : "continue";
18528
18535
  }
18529
18536
  }
18530
- const text = collectCellText(tc, styles, numbering, footnotes, rels, 0).join("\n");
18537
+ const text = collectCellText(tc2, styles, numbering, footnotes, rels, 0).join("\n");
18531
18538
  row.push({ col, colSpan, vMerge, text });
18532
18539
  col += colSpan;
18533
18540
  }
18534
18541
  rawRows.push(row);
18535
18542
  }
18536
18543
  for (let r = 0; r < rawRows.length; r++) {
18537
- for (const cell of rawRows[r]) {
18538
- if (cell.vMerge !== "continue" || !cell.text) continue;
18544
+ for (const cell2 of rawRows[r]) {
18545
+ if (cell2.vMerge !== "continue" || !cell2.text) continue;
18539
18546
  let start;
18540
18547
  for (let pr = r - 1; pr >= 0 && !start; pr--) {
18541
- start = rawRows[pr].find((pc) => pc.col === cell.col && pc.vMerge !== "continue");
18548
+ start = rawRows[pr].find((pc) => pc.col === cell2.col && pc.vMerge !== "continue");
18542
18549
  }
18543
18550
  if (start) {
18544
18551
  start.text = start.text ? `${start.text}
18545
- ${cell.text}` : cell.text;
18546
- cell.text = "";
18552
+ ${cell2.text}` : cell2.text;
18553
+ cell2.text = "";
18547
18554
  } else {
18548
- cell.vMerge = null;
18555
+ cell2.vMerge = null;
18549
18556
  }
18550
18557
  }
18551
18558
  }
18552
18559
  const cellRows = rawRows.map(
18553
- (row, r) => row.filter((cell) => cell.vMerge !== "continue").map((cell) => {
18560
+ (row, r) => row.filter((cell2) => cell2.vMerge !== "continue").map((cell2) => {
18554
18561
  let rowSpan = 1;
18555
- if (cell.vMerge === "restart") {
18562
+ if (cell2.vMerge === "restart") {
18556
18563
  for (let nr = r + 1; nr < rawRows.length; nr++) {
18557
- if (!rawRows[nr].some((nc) => nc.col === cell.col && nc.vMerge === "continue")) break;
18564
+ if (!rawRows[nr].some((nc) => nc.col === cell2.col && nc.vMerge === "continue")) break;
18558
18565
  rowSpan++;
18559
18566
  }
18560
18567
  }
18561
- return { text: cell.text, colSpan: cell.colSpan, rowSpan, colAddr: cell.col, rowAddr: r };
18568
+ return { text: cell2.text, colSpan: cell2.colSpan, rowSpan, colAddr: cell2.col, rowAddr: r };
18562
18569
  })
18563
18570
  );
18564
- const table = buildTable(cellRows);
18565
- if (table.rows === 0 || table.cols === 0) return null;
18566
- return { type: "table", table };
18571
+ const table2 = buildTable(cellRows);
18572
+ if (table2.rows === 0 || table2.cols === 0) return null;
18573
+ return { type: "table", table: table2 };
18567
18574
  }
18568
- function collectCellText(tc, styles, numbering, footnotes, rels, depth) {
18575
+ function collectCellText(tc2, styles, numbering, footnotes, rels, depth) {
18569
18576
  const parts = [];
18570
18577
  if (depth > 20) return parts;
18571
- for (const el of effectiveChildElements(tc)) {
18578
+ for (const el of effectiveChildElements(tc2)) {
18572
18579
  if (matchesLocal(el, "p")) {
18573
18580
  const block = parseParagraph2(el, styles, numbering, footnotes, rels);
18574
18581
  if (block?.text) parts.push(block.text);
@@ -18929,13 +18936,13 @@ function parseTable2(el, blocks, paraShapeMap, sectionNum, warnings) {
18929
18936
  }
18930
18937
  if (cells.length === 0) return;
18931
18938
  const grid = Array.from({ length: rowCount }, () => Array(colCount).fill(null));
18932
- for (const cell of cells) {
18933
- const r = cell.rowAddr ?? 0;
18934
- const c = cell.colAddr ?? 0;
18939
+ for (const cell2 of cells) {
18940
+ const r = cell2.rowAddr ?? 0;
18941
+ const c = cell2.colAddr ?? 0;
18935
18942
  if (isNaN(r) || isNaN(c) || r >= rowCount || c >= colCount) continue;
18936
- grid[r][c] = cell;
18937
- for (let dr = 0; dr < cell.rowSpan; dr++) {
18938
- for (let dc = 0; dc < cell.colSpan; dc++) {
18943
+ grid[r][c] = cell2;
18944
+ for (let dr = 0; dr < cell2.rowSpan; dr++) {
18945
+ for (let dc = 0; dc < cell2.colSpan; dc++) {
18939
18946
  if (dr === 0 && dc === 0) continue;
18940
18947
  if (r + dr < rowCount && c + dc < colCount) {
18941
18948
  grid[r + dr][c + dc] = { text: "", colSpan: 1, rowSpan: 1 };
@@ -18944,14 +18951,14 @@ function parseTable2(el, blocks, paraShapeMap, sectionNum, warnings) {
18944
18951
  }
18945
18952
  }
18946
18953
  const cellRows = grid.map(
18947
- (row) => row.map((cell) => cell ?? { text: "", colSpan: 1, rowSpan: 1 })
18954
+ (row) => row.map((cell2) => cell2 ?? { text: "", colSpan: 1, rowSpan: 1 })
18948
18955
  );
18949
- const table = buildTable(cellRows);
18956
+ const table2 = buildTable(cellRows);
18950
18957
  const caption = extractShapeCaption(el);
18951
18958
  if (caption.text && caption.before) {
18952
18959
  blocks.push({ type: "paragraph", text: caption.text, pageNumber: sectionNum });
18953
18960
  }
18954
- blocks.push({ type: "table", table, pageNumber: sectionNum });
18961
+ blocks.push({ type: "table", table: table2, pageNumber: sectionNum });
18955
18962
  if (caption.text && !caption.before) {
18956
18963
  blocks.push({ type: "paragraph", text: caption.text, pageNumber: sectionNum });
18957
18964
  }
@@ -19451,13 +19458,13 @@ function extractFormFields(blocks) {
19451
19458
  const confidence = totalTables > 0 ? formTables / totalTables : fields.length > 0 ? 0.3 : 0;
19452
19459
  return { fields, confidence: Math.min(confidence, 1) };
19453
19460
  }
19454
- function extractFromTable(table) {
19461
+ function extractFromTable(table2) {
19455
19462
  const fields = [];
19456
- if (table.cols >= 2) {
19457
- for (let r = 0; r < table.rows; r++) {
19458
- for (let c = 0; c < table.cols - 1; c++) {
19459
- const labelCell = table.cells[r]?.[c];
19460
- const valueCell = table.cells[r]?.[c + 1];
19463
+ if (table2.cols >= 2) {
19464
+ for (let r = 0; r < table2.rows; r++) {
19465
+ for (let c = 0; c < table2.cols - 1; c++) {
19466
+ const labelCell = table2.cells[r]?.[c];
19467
+ const valueCell = table2.cells[r]?.[c + 1];
19461
19468
  if (!labelCell || !valueCell) continue;
19462
19469
  if (isLabelCell(labelCell.text)) {
19463
19470
  fields.push({
@@ -19470,17 +19477,17 @@ function extractFromTable(table) {
19470
19477
  }
19471
19478
  }
19472
19479
  }
19473
- if (fields.length === 0 && table.rows >= 2 && table.cols >= 2) {
19474
- const headerRow = table.cells[0];
19475
- const allLabels = headerRow.every((cell) => {
19476
- const t = cell.text.trim();
19480
+ if (fields.length === 0 && table2.rows >= 2 && table2.cols >= 2) {
19481
+ const headerRow = table2.cells[0];
19482
+ const allLabels = headerRow.every((cell2) => {
19483
+ const t = cell2.text.trim();
19477
19484
  return t.length > 0 && t.length <= 20;
19478
19485
  });
19479
19486
  if (allLabels) {
19480
- for (let r = 1; r < table.rows; r++) {
19481
- for (let c = 0; c < table.cols; c++) {
19487
+ for (let r = 1; r < table2.rows; r++) {
19488
+ for (let c = 0; c < table2.cols; c++) {
19482
19489
  const label = headerRow[c]?.text.trim() ?? "";
19483
- const value = table.cells[r]?.[c]?.text.trim() ?? "";
19490
+ const value = table2.cells[r]?.[c]?.text.trim() ?? "";
19484
19491
  if (label && value) {
19485
19492
  fields.push({ label, value, row: r, col: c });
19486
19493
  }
@@ -19517,9 +19524,9 @@ function inferFieldType(label, value) {
19517
19524
  if (/^[\d,.\s]+(?:원|명|건|개|회|부|매|%)$/.test(v) && /\d/.test(v)) return "amount";
19518
19525
  if (/^\d{1,3}(?:,\d{3})+$/.test(v)) return "amount";
19519
19526
  }
19520
- const norm = label.replace(/\s/g, "");
19527
+ const norm2 = label.replace(/\s/g, "");
19521
19528
  for (const [re, type] of LABEL_TYPE_RULES) {
19522
- if (re.test(norm)) return type;
19529
+ if (re.test(norm2)) return type;
19523
19530
  }
19524
19531
  return "text";
19525
19532
  }
@@ -19570,15 +19577,15 @@ function fillFormFields(blocks, values, blockedLabels) {
19570
19577
  const cursor = new ValueCursor(normalizedValues);
19571
19578
  const allTables = collectIRTables(cloned, 0);
19572
19579
  const patternFilledCells = /* @__PURE__ */ new Set();
19573
- for (const table of allTables) {
19574
- for (let r = 0; r < table.rows; r++) {
19575
- for (let c = 0; c < table.cols; c++) {
19576
- const cell = table.cells[r]?.[c];
19577
- if (!cell) continue;
19578
- const result = fillInCellPatterns(cell.text, cursor, matchedLabels, blockedLabels);
19580
+ for (const table2 of allTables) {
19581
+ for (let r = 0; r < table2.rows; r++) {
19582
+ for (let c = 0; c < table2.cols; c++) {
19583
+ const cell2 = table2.cells[r]?.[c];
19584
+ if (!cell2) continue;
19585
+ const result = fillInCellPatterns(cell2.text, cursor, matchedLabels, blockedLabels);
19579
19586
  if (result) {
19580
- cell.text = result.text;
19581
- patternFilledCells.add(cell);
19587
+ cell2.text = result.text;
19588
+ patternFilledCells.add(cell2);
19582
19589
  for (const m of result.matches) {
19583
19590
  filled.push({ label: m.label, value: m.value, row: r, col: c, key: m.key });
19584
19591
  }
@@ -19586,8 +19593,8 @@ function fillFormFields(blocks, values, blockedLabels) {
19586
19593
  }
19587
19594
  }
19588
19595
  }
19589
- for (const table of allTables) {
19590
- fillTable(table, cursor, filled, matchedLabels, patternFilledCells, blockedLabels);
19596
+ for (const table2 of allTables) {
19597
+ fillTable(table2, cursor, filled, matchedLabels, patternFilledCells, blockedLabels);
19591
19598
  }
19592
19599
  for (const block of cloned) {
19593
19600
  if (block.type !== "paragraph" || !block.text) continue;
@@ -19604,44 +19611,44 @@ function collectIRTables(blocks, depth) {
19604
19611
  if (block.type !== "table" || !block.table) continue;
19605
19612
  out.push(block.table);
19606
19613
  for (const row of block.table.cells) {
19607
- for (const cell of row) {
19608
- if (cell?.blocks?.length) out.push(...collectIRTables(cell.blocks, depth + 1));
19614
+ for (const cell2 of row) {
19615
+ if (cell2?.blocks?.length) out.push(...collectIRTables(cell2.blocks, depth + 1));
19609
19616
  }
19610
19617
  }
19611
19618
  }
19612
19619
  return out;
19613
19620
  }
19614
- function coveredPositions(table) {
19621
+ function coveredPositions(table2) {
19615
19622
  const covered = /* @__PURE__ */ new Set();
19616
- for (let r = 0; r < table.rows; r++) {
19617
- for (let c = 0; c < table.cols; c++) {
19623
+ for (let r = 0; r < table2.rows; r++) {
19624
+ for (let c = 0; c < table2.cols; c++) {
19618
19625
  if (covered.has(`${r},${c}`)) continue;
19619
- const cell = table.cells[r]?.[c];
19620
- if (!cell) continue;
19621
- for (let dr = 0; dr < cell.rowSpan; dr++) {
19622
- for (let dc = 0; dc < cell.colSpan; dc++) {
19626
+ const cell2 = table2.cells[r]?.[c];
19627
+ if (!cell2) continue;
19628
+ for (let dr = 0; dr < cell2.rowSpan; dr++) {
19629
+ for (let dc = 0; dc < cell2.colSpan; dc++) {
19623
19630
  if (dr === 0 && dc === 0) continue;
19624
- if (r + dr < table.rows && c + dc < table.cols) covered.add(`${r + dr},${c + dc}`);
19631
+ if (r + dr < table2.rows && c + dc < table2.cols) covered.add(`${r + dr},${c + dc}`);
19625
19632
  }
19626
19633
  }
19627
- c += cell.colSpan - 1;
19634
+ c += cell2.colSpan - 1;
19628
19635
  }
19629
19636
  }
19630
19637
  return covered;
19631
19638
  }
19632
- function fillTable(table, values, filled, matchedLabels, patternFilledCells, blockedLabels) {
19633
- if (table.cols < 2) return;
19634
- const covered = coveredPositions(table);
19635
- for (let r = 0; r < table.rows; r++) {
19636
- for (let c = 0; c < table.cols; c++) {
19639
+ function fillTable(table2, values, filled, matchedLabels, patternFilledCells, blockedLabels) {
19640
+ if (table2.cols < 2) return;
19641
+ const covered = coveredPositions(table2);
19642
+ for (let r = 0; r < table2.rows; r++) {
19643
+ for (let c = 0; c < table2.cols; c++) {
19637
19644
  if (covered.has(`${r},${c}`)) continue;
19638
- const labelCell = table.cells[r][c];
19645
+ const labelCell = table2.cells[r][c];
19639
19646
  if (!labelCell) continue;
19640
19647
  if (!isLabelCell(labelCell.text)) continue;
19641
19648
  let vc = c + labelCell.colSpan;
19642
- while (vc < table.cols && covered.has(`${r},${vc}`)) vc++;
19643
- if (vc >= table.cols) continue;
19644
- const valueCell = table.cells[r][vc];
19649
+ while (vc < table2.cols && covered.has(`${r},${vc}`)) vc++;
19650
+ if (vc >= table2.cols) continue;
19651
+ const valueCell = table2.cells[r][vc];
19645
19652
  if (!valueCell) continue;
19646
19653
  if (isKeywordLabel(valueCell.text)) continue;
19647
19654
  const normalizedCellLabel = normalizeLabel(labelCell.text);
@@ -19666,18 +19673,18 @@ function fillTable(table, values, filled, matchedLabels, patternFilledCells, blo
19666
19673
  });
19667
19674
  }
19668
19675
  }
19669
- if (table.rows >= 2 && table.cols >= 2) {
19670
- const headerRow = table.cells[0];
19671
- const allLabels = headerRow.every((cell) => {
19672
- const t = cell.text.trim();
19676
+ if (table2.rows >= 2 && table2.cols >= 2) {
19677
+ const headerRow = table2.cells[0];
19678
+ const allLabels = headerRow.every((cell2) => {
19679
+ const t = cell2.text.trim();
19673
19680
  return t.length > 0 && t.length <= 20 && isLabelCell(t);
19674
19681
  });
19675
19682
  if (!allLabels) return;
19676
- for (let r = 1; r < table.rows; r++) {
19677
- for (let c = 0; c < table.cols; c++) {
19683
+ for (let r = 1; r < table2.rows; r++) {
19684
+ for (let c = 0; c < table2.cols; c++) {
19678
19685
  if (covered.has(`${r},${c}`)) continue;
19679
19686
  const headerCell = headerRow[c];
19680
- const valueCell = table.cells[r]?.[c];
19687
+ const valueCell = table2.cells[r]?.[c];
19681
19688
  if (!headerCell || !valueCell) continue;
19682
19689
  const headerLabel = normalizeLabel(headerCell.text);
19683
19690
  if (blockedLabels?.has(headerLabel)) continue;
@@ -19858,9 +19865,9 @@ function scanSectionXml(xml, sectionIndex) {
19858
19865
  if (closeName !== void 0) {
19859
19866
  const local2 = localOf(closeName);
19860
19867
  if (local2 === "t" && pendingT) {
19861
- const { para, contentStart: contentStart2 } = pendingT;
19862
- para.tRanges.push({ contentStart: contentStart2, contentEnd: m.index });
19863
- para.text += tContentToText(xml.slice(contentStart2, m.index));
19868
+ const { para: para2, contentStart: contentStart2 } = pendingT;
19869
+ para2.tRanges.push({ contentStart: contentStart2, contentEnd: m.index });
19870
+ para2.text += tContentToText(xml.slice(contentStart2, m.index));
19864
19871
  pendingT = null;
19865
19872
  }
19866
19873
  for (let i = stack.length - 1; i >= 0; i--) {
@@ -19870,35 +19877,35 @@ function scanSectionXml(xml, sectionIndex) {
19870
19877
  }
19871
19878
  }
19872
19879
  if (local2 === "p") {
19873
- const para = paraStack.pop();
19874
- if (para && para.kind === "excluded") {
19880
+ const para2 = paraStack.pop();
19881
+ if (para2 && para2.kind === "excluded") {
19875
19882
  const sub = currentCtrlSub();
19876
- if (sub && para.text.trim()) sub.texts.push(para.text);
19883
+ if (sub && para2.text.trim()) sub.texts.push(para2.text);
19877
19884
  }
19878
19885
  } else if (local2 === "tc") {
19879
- const cell = cellStack.pop();
19886
+ const cell2 = cellStack.pop();
19880
19887
  const row = rowStack[rowStack.length - 1];
19881
- if (cell && row) row.push(cell);
19888
+ if (cell2 && row) row.push(cell2);
19882
19889
  } else if (local2 === "tr") {
19883
19890
  const row = rowStack[rowStack.length - 1];
19884
- const table = tableStack[tableStack.length - 1];
19885
- if (row && table && row.length > 0) {
19886
- table.rows.push(row);
19891
+ const table2 = tableStack[tableStack.length - 1];
19892
+ if (row && table2 && row.length > 0) {
19893
+ table2.rows.push(row);
19887
19894
  const trStart = trStartStack[trStartStack.length - 1];
19888
- if (trStart >= 0) table.rowRanges.push({ start: trStart, end: m.index + full.length });
19895
+ if (trStart >= 0) table2.rowRanges.push({ start: trStart, end: m.index + full.length });
19889
19896
  }
19890
19897
  if (rowStack.length > 0) rowStack[rowStack.length - 1] = [];
19891
19898
  if (trStartStack.length > 0) trStartStack[trStartStack.length - 1] = -1;
19892
19899
  } else if (local2 === "tbl") {
19893
- const table = tableStack.pop();
19900
+ const table2 = tableStack.pop();
19894
19901
  rowStack.pop();
19895
19902
  trStartStack.pop();
19896
- if (table) {
19897
- finalizeTable(table);
19898
- if (!table.topLevel) {
19899
- const cell = cellStack[cellStack.length - 1];
19900
- if (cell) cell.tables.push(table);
19901
- else orphanTables.push(table);
19903
+ if (table2) {
19904
+ finalizeTable(table2);
19905
+ if (!table2.topLevel) {
19906
+ const cell2 = cellStack[cellStack.length - 1];
19907
+ if (cell2) cell2.tables.push(table2);
19908
+ else orphanTables.push(table2);
19902
19909
  }
19903
19910
  }
19904
19911
  } else if (local2 === "header" || local2 === "footer") {
@@ -19918,45 +19925,45 @@ function scanSectionXml(xml, sectionIndex) {
19918
19925
  const contentStart = m.index + full.length;
19919
19926
  if (isSelfClose) {
19920
19927
  if (local === "t") {
19921
- const para = owningPara();
19922
- if (para) para.tRanges.push({ contentStart: m.index, contentEnd: m.index + full.length, selfClosing: true, prefix: prefixOf(qname) });
19928
+ const para2 = owningPara();
19929
+ if (para2) para2.tRanges.push({ contentStart: m.index, contentEnd: m.index + full.length, selfClosing: true, prefix: prefixOf(qname) });
19923
19930
  } else if (local === "tab" || local === "fwSpace" || local === "hwSpace" || local === "br" || local === "lineBreak") {
19924
19931
  if (!pendingT) {
19925
- const para = owningPara();
19926
- if (para) para.text += " ";
19932
+ const para2 = owningPara();
19933
+ if (para2) para2.text += " ";
19927
19934
  }
19928
19935
  } else if (local === "run" || local === "r") {
19929
- const para = owningPara();
19930
- if (para && !para.selfCloseRun) para.selfCloseRun = { start: m.index, end: m.index + full.length };
19936
+ const para2 = owningPara();
19937
+ if (para2 && !para2.selfCloseRun) para2.selfCloseRun = { start: m.index, end: m.index + full.length };
19931
19938
  } else if (local === "cellAddr") {
19932
- const cell = cellStack[cellStack.length - 1];
19933
- if (cell && insideCurrentTable(stack, tableStack)) {
19939
+ const cell2 = cellStack[cellStack.length - 1];
19940
+ if (cell2 && insideCurrentTable(stack, tableStack)) {
19934
19941
  const ca = parseInt(getAttr2(attrsRaw, "colAddr") || "", 10);
19935
19942
  const ra = parseInt(getAttr2(attrsRaw, "rowAddr") || "", 10);
19936
- if (!isNaN(ca)) cell.colAddr = ca;
19937
- if (!isNaN(ra)) cell.rowAddr = ra;
19938
- cell.addrTagRange = { start: m.index, end: m.index + full.length };
19943
+ if (!isNaN(ca)) cell2.colAddr = ca;
19944
+ if (!isNaN(ra)) cell2.rowAddr = ra;
19945
+ cell2.addrTagRange = { start: m.index, end: m.index + full.length };
19939
19946
  }
19940
19947
  } else if (local === "cellSpan") {
19941
- const cell = cellStack[cellStack.length - 1];
19942
- if (cell && insideCurrentTable(stack, tableStack)) {
19948
+ const cell2 = cellStack[cellStack.length - 1];
19949
+ if (cell2 && insideCurrentTable(stack, tableStack)) {
19943
19950
  const cs = parseInt(getAttr2(attrsRaw, "colSpan") || "1", 10);
19944
19951
  const rs = parseInt(getAttr2(attrsRaw, "rowSpan") || "1", 10);
19945
- cell.colSpan = isNaN(cs) || cs < 1 ? 1 : cs;
19946
- cell.rowSpan = isNaN(rs) || rs < 1 ? 1 : rs;
19952
+ cell2.colSpan = isNaN(cs) || cs < 1 ? 1 : cs;
19953
+ cell2.rowSpan = isNaN(rs) || rs < 1 ? 1 : rs;
19947
19954
  }
19948
19955
  }
19949
19956
  continue;
19950
19957
  }
19951
19958
  if (local === "t") {
19952
- const para = owningPara();
19953
- if (para) pendingT = { para, contentStart };
19959
+ const para2 = owningPara();
19960
+ if (para2) pendingT = { para: para2, contentStart };
19954
19961
  stack.push({ local, qname, contentStart });
19955
19962
  continue;
19956
19963
  }
19957
19964
  stack.push({ local, qname, contentStart });
19958
19965
  if (local === "p") {
19959
- const para = {
19966
+ const para2 = {
19960
19967
  sectionIndex,
19961
19968
  kind: "excluded",
19962
19969
  // 분류는 push 직후 스택 기준 (자기 자신 제외)
@@ -19966,22 +19973,22 @@ function scanSectionXml(xml, sectionIndex) {
19966
19973
  };
19967
19974
  stack.pop();
19968
19975
  const cls = classifyPara();
19969
- para.kind = cls.kind;
19970
- if (cls.inTextbox) para.inTextbox = true;
19976
+ para2.kind = cls.kind;
19977
+ if (cls.inTextbox) para2.inTextbox = true;
19971
19978
  stack.push({ local, qname, contentStart });
19972
- paraStack.push(para);
19973
- if (para.kind === "body" || para.kind === "draw") bodyParagraphs.push(para);
19974
- else if (para.kind === "cell") {
19975
- const cell = cellStack[cellStack.length - 1];
19976
- if (cell) cell.paragraphs.push(para);
19977
- } else if (para.kind === "excluded") {
19978
- excludedParagraphs.push(para);
19979
+ paraStack.push(para2);
19980
+ if (para2.kind === "body" || para2.kind === "draw") bodyParagraphs.push(para2);
19981
+ else if (para2.kind === "cell") {
19982
+ const cell2 = cellStack[cellStack.length - 1];
19983
+ if (cell2) cell2.paragraphs.push(para2);
19984
+ } else if (para2.kind === "excluded") {
19985
+ excludedParagraphs.push(para2);
19979
19986
  }
19980
19987
  } else if (local === "run" || local === "r") {
19981
- const para = owningPara();
19982
- if (para && para.runPrefix === void 0) para.runPrefix = prefixOf(qname);
19988
+ const para2 = owningPara();
19989
+ if (para2 && para2.runPrefix === void 0) para2.runPrefix = prefixOf(qname);
19983
19990
  } else if (local === "tbl") {
19984
- const table = {
19991
+ const table2 = {
19985
19992
  sectionIndex,
19986
19993
  start: m.index,
19987
19994
  topLevel: false,
@@ -19990,31 +19997,31 @@ function scanSectionXml(xml, sectionIndex) {
19990
19997
  cellByAnchor: /* @__PURE__ */ new Map()
19991
19998
  };
19992
19999
  stack.pop();
19993
- table.topLevel = isTableTopLevel();
20000
+ table2.topLevel = isTableTopLevel();
19994
20001
  stack.push({ local, qname, contentStart });
19995
- tableStack.push(table);
20002
+ tableStack.push(table2);
19996
20003
  rowStack.push([]);
19997
20004
  trStartStack.push(-1);
19998
- if (table.topLevel) tables.push(table);
20005
+ if (table2.topLevel) tables.push(table2);
19999
20006
  } else if (local === "tr") {
20000
20007
  if (rowStack.length > 0) rowStack[rowStack.length - 1] = [];
20001
20008
  if (trStartStack.length > 0) trStartStack[trStartStack.length - 1] = m.index;
20002
20009
  } else if (local === "tc") {
20003
20010
  cellStack.push({ colSpan: 1, rowSpan: 1, paragraphs: [], tables: [] });
20004
20011
  } else if (local === "cellAddr" || local === "cellSpan") {
20005
- const cell = cellStack[cellStack.length - 1];
20006
- if (cell && insideCurrentTable(stack, tableStack)) {
20012
+ const cell2 = cellStack[cellStack.length - 1];
20013
+ if (cell2 && insideCurrentTable(stack, tableStack)) {
20007
20014
  if (local === "cellAddr") {
20008
20015
  const ca = parseInt(getAttr2(attrsRaw, "colAddr") || "", 10);
20009
20016
  const ra = parseInt(getAttr2(attrsRaw, "rowAddr") || "", 10);
20010
- if (!isNaN(ca)) cell.colAddr = ca;
20011
- if (!isNaN(ra)) cell.rowAddr = ra;
20012
- cell.addrTagRange = { start: m.index, end: contentStart };
20017
+ if (!isNaN(ca)) cell2.colAddr = ca;
20018
+ if (!isNaN(ra)) cell2.rowAddr = ra;
20019
+ cell2.addrTagRange = { start: m.index, end: contentStart };
20013
20020
  } else {
20014
20021
  const cs = parseInt(getAttr2(attrsRaw, "colSpan") || "1", 10);
20015
20022
  const rs = parseInt(getAttr2(attrsRaw, "rowSpan") || "1", 10);
20016
- cell.colSpan = isNaN(cs) || cs < 1 ? 1 : cs;
20017
- cell.rowSpan = isNaN(rs) || rs < 1 ? 1 : rs;
20023
+ cell2.colSpan = isNaN(cs) || cs < 1 ? 1 : cs;
20024
+ cell2.rowSpan = isNaN(rs) || rs < 1 ? 1 : rs;
20018
20025
  }
20019
20026
  }
20020
20027
  } else if (local === "header" || local === "footer") {
@@ -20022,23 +20029,23 @@ function scanSectionXml(xml, sectionIndex) {
20022
20029
  ctrlSubStack.push({ kind: local, texts: [] });
20023
20030
  }
20024
20031
  } else if (local === "tab" || local === "fwSpace" || local === "hwSpace" || local === "br" || local === "lineBreak") {
20025
- const para = owningPara();
20026
- if (para) para.text += " ";
20032
+ const para2 = owningPara();
20033
+ if (para2) para2.text += " ";
20027
20034
  }
20028
20035
  }
20029
- for (const para of bodyParagraphs) fillRunInsertPos(para, xml);
20030
- for (const para of excludedParagraphs) fillRunInsertPos(para, xml);
20031
- const fillTableInsertPos = (table, depth = 0) => {
20036
+ for (const para2 of bodyParagraphs) fillRunInsertPos(para2, xml);
20037
+ for (const para2 of excludedParagraphs) fillRunInsertPos(para2, xml);
20038
+ const fillTableInsertPos = (table2, depth = 0) => {
20032
20039
  if (depth > 16) return;
20033
- for (const row of table.rows) {
20034
- for (const cell of row) {
20035
- for (const para of cell.paragraphs) fillRunInsertPos(para, xml);
20036
- for (const nested of cell.tables) fillTableInsertPos(nested, depth + 1);
20040
+ for (const row of table2.rows) {
20041
+ for (const cell2 of row) {
20042
+ for (const para2 of cell2.paragraphs) fillRunInsertPos(para2, xml);
20043
+ for (const nested of cell2.tables) fillTableInsertPos(nested, depth + 1);
20037
20044
  }
20038
20045
  }
20039
20046
  };
20040
- for (const table of tables) fillTableInsertPos(table);
20041
- for (const table of orphanTables) fillTableInsertPos(table);
20047
+ for (const table2 of tables) fillTableInsertPos(table2);
20048
+ for (const table2 of orphanTables) fillTableInsertPos(table2);
20042
20049
  return { sectionIndex, xml, bodyParagraphs, tables, headerTexts, footerTexts, excludedParagraphs, orphanTables };
20043
20050
  }
20044
20051
  function getAttr2(attrsRaw, name) {
@@ -20055,19 +20062,19 @@ function insideCurrentTable(stack, tableStack) {
20055
20062
  }
20056
20063
  return false;
20057
20064
  }
20058
- function fillRunInsertPos(para, xml) {
20059
- if (para.tRanges.length > 0) return;
20060
- const pEnd = findElementEnd(xml, para.start);
20065
+ function fillRunInsertPos(para2, xml) {
20066
+ if (para2.tRanges.length > 0) return;
20067
+ const pEnd = findElementEnd(xml, para2.start);
20061
20068
  if (pEnd < 0) return;
20062
- const slice = xml.slice(para.start, pEnd);
20069
+ const slice = xml.slice(para2.start, pEnd);
20063
20070
  const runOpen = slice.match(/<((?:[A-Za-z0-9_]+:)?run)(?:\s(?:"[^"]*"|'[^']*'|[^>"'])*?)?(\/?)>/);
20064
20071
  if (!runOpen || runOpen.index === void 0) return;
20065
20072
  if (runOpen[2] === "/") return;
20066
20073
  const qname = runOpen[1];
20067
20074
  const closeIdx = slice.indexOf(`</${qname}>`, runOpen.index);
20068
20075
  if (closeIdx < 0) return;
20069
- para.runInsertPos = para.start + closeIdx;
20070
- para.runPrefix = prefixOf(qname);
20076
+ para2.runInsertPos = para2.start + closeIdx;
20077
+ para2.runPrefix = prefixOf(qname);
20071
20078
  }
20072
20079
  function findElementEnd(xml, start) {
20073
20080
  const open = xml.slice(start).match(/^<([^\s/>!?]+)/);
@@ -20087,39 +20094,39 @@ function findElementEnd(xml, start) {
20087
20094
  }
20088
20095
  return -1;
20089
20096
  }
20090
- function finalizeTable(table) {
20091
- const hasAddr = table.rows.some((row) => row.some((c) => c.colAddr !== void 0 && c.rowAddr !== void 0));
20097
+ function finalizeTable(table2) {
20098
+ const hasAddr = table2.rows.some((row) => row.some((c) => c.colAddr !== void 0 && c.rowAddr !== void 0));
20092
20099
  if (hasAddr) {
20093
- for (const row of table.rows) {
20094
- for (const cell of row) {
20095
- if (cell.rowAddr !== void 0 && cell.colAddr !== void 0) {
20096
- table.cellByAnchor.set(`${cell.rowAddr},${cell.colAddr}`, cell);
20100
+ for (const row of table2.rows) {
20101
+ for (const cell2 of row) {
20102
+ if (cell2.rowAddr !== void 0 && cell2.colAddr !== void 0) {
20103
+ table2.cellByAnchor.set(`${cell2.rowAddr},${cell2.colAddr}`, cell2);
20097
20104
  }
20098
20105
  }
20099
20106
  }
20100
20107
  return;
20101
20108
  }
20102
- const numRows = table.rows.length;
20109
+ const numRows = table2.rows.length;
20103
20110
  const occupied = Array.from({ length: numRows }, () => []);
20104
20111
  for (let rowIdx = 0; rowIdx < numRows; rowIdx++) {
20105
20112
  let colIdx = 0;
20106
- for (const cell of table.rows[rowIdx]) {
20113
+ for (const cell2 of table2.rows[rowIdx]) {
20107
20114
  while (occupied[rowIdx][colIdx]) colIdx++;
20108
- cell.rowAddr = rowIdx;
20109
- cell.colAddr = colIdx;
20110
- table.cellByAnchor.set(`${rowIdx},${colIdx}`, cell);
20111
- for (let r = rowIdx; r < Math.min(rowIdx + cell.rowSpan, numRows); r++) {
20112
- for (let c = colIdx; c < colIdx + cell.colSpan; c++) {
20115
+ cell2.rowAddr = rowIdx;
20116
+ cell2.colAddr = colIdx;
20117
+ table2.cellByAnchor.set(`${rowIdx},${colIdx}`, cell2);
20118
+ for (let r = rowIdx; r < Math.min(rowIdx + cell2.rowSpan, numRows); r++) {
20119
+ for (let c = colIdx; c < colIdx + cell2.colSpan; c++) {
20113
20120
  occupied[r][c] = true;
20114
20121
  }
20115
20122
  }
20116
- colIdx += cell.colSpan;
20123
+ colIdx += cell2.colSpan;
20117
20124
  }
20118
20125
  }
20119
20126
  }
20120
- function buildParagraphSplices(para, newText, xml) {
20127
+ function buildParagraphSplices(para2, newText, xml) {
20121
20128
  if (newText && xml) {
20122
- const orig = paraTText(para, xml);
20129
+ const orig = paraTText(para2, xml);
20123
20130
  if (orig && orig.trim() !== "") {
20124
20131
  const lead = orig.match(/^\s*/)[0];
20125
20132
  const trail = orig.match(/\s*$/)[0];
@@ -20129,31 +20136,31 @@ function buildParagraphSplices(para, newText, xml) {
20129
20136
  }
20130
20137
  }
20131
20138
  const escaped = escapeXmlText(newText);
20132
- if (para.tRanges.length > 0) {
20139
+ if (para2.tRanges.length > 0) {
20133
20140
  const splices = [];
20134
- const first = para.tRanges[0];
20141
+ const first = para2.tRanges[0];
20135
20142
  if (first.selfClosing) {
20136
20143
  const prefix = first.prefix ? first.prefix + ":" : "";
20137
20144
  splices.push({ start: first.contentStart, end: first.contentEnd, replacement: `<${prefix}t>${escaped}</${prefix}t>` });
20138
20145
  } else {
20139
20146
  splices.push({ start: first.contentStart, end: first.contentEnd, replacement: escaped });
20140
20147
  }
20141
- for (let i = 1; i < para.tRanges.length; i++) {
20142
- const r = para.tRanges[i];
20148
+ for (let i = 1; i < para2.tRanges.length; i++) {
20149
+ const r = para2.tRanges[i];
20143
20150
  if (!r.selfClosing && r.contentStart < r.contentEnd) {
20144
20151
  splices.push({ start: r.contentStart, end: r.contentEnd, replacement: "" });
20145
20152
  }
20146
20153
  }
20147
20154
  return splices;
20148
20155
  }
20149
- if (para.runInsertPos !== void 0) {
20156
+ if (para2.runInsertPos !== void 0) {
20150
20157
  if (!newText) return [];
20151
- const prefix = para.runPrefix ? para.runPrefix + ":" : "";
20152
- return [{ start: para.runInsertPos, end: para.runInsertPos, replacement: `<${prefix}t>${escaped}</${prefix}t>` }];
20158
+ const prefix = para2.runPrefix ? para2.runPrefix + ":" : "";
20159
+ return [{ start: para2.runInsertPos, end: para2.runInsertPos, replacement: `<${prefix}t>${escaped}</${prefix}t>` }];
20153
20160
  }
20154
- if (para.selfCloseRun && xml) {
20161
+ if (para2.selfCloseRun && xml) {
20155
20162
  if (!newText) return [];
20156
- const { start, end } = para.selfCloseRun;
20163
+ const { start, end } = para2.selfCloseRun;
20157
20164
  const tag = xml.slice(start, end);
20158
20165
  const qm = tag.match(/^<([^\s/>]+)/);
20159
20166
  if (!qm || !tag.endsWith("/>")) return null;
@@ -20165,9 +20172,9 @@ function buildParagraphSplices(para, newText, xml) {
20165
20172
  }
20166
20173
  return newText ? null : [];
20167
20174
  }
20168
- function paraTText(para, xml) {
20175
+ function paraTText(para2, xml) {
20169
20176
  let text = "";
20170
- for (const t of para.tRanges) {
20177
+ for (const t of para2.tRanges) {
20171
20178
  if (t.selfClosing) continue;
20172
20179
  const raw = xml.slice(t.contentStart, t.contentEnd);
20173
20180
  if (/[<&]/.test(raw)) return null;
@@ -20175,19 +20182,19 @@ function paraTText(para, xml) {
20175
20182
  }
20176
20183
  return text;
20177
20184
  }
20178
- function paraTextPureT(para, xml) {
20185
+ function paraTextPureT(para2, xml) {
20179
20186
  let len = 0;
20180
- for (const t of para.tRanges) {
20187
+ for (const t of para2.tRanges) {
20181
20188
  if (t.selfClosing) continue;
20182
20189
  len += tContentToText(xml.slice(t.contentStart, t.contentEnd)).length;
20183
20190
  }
20184
- return len === para.text.length;
20191
+ return len === para2.text.length;
20185
20192
  }
20186
- function buildRangeSplices(para, xml, start, end, replacement) {
20193
+ function buildRangeSplices(para2, xml, start, end, replacement) {
20187
20194
  if (start < 0 || end < start) return null;
20188
20195
  const segs = [];
20189
20196
  let offset = 0;
20190
- for (const t of para.tRanges) {
20197
+ for (const t of para2.tRanges) {
20191
20198
  if (t.selfClosing) continue;
20192
20199
  const raw = xml.slice(t.contentStart, t.contentEnd);
20193
20200
  if (/[<&]/.test(raw)) return null;
@@ -20307,13 +20314,13 @@ function parseCentralDirectory(buf) {
20307
20314
  return { entries, cdOffset, cdSize, eocdOffset };
20308
20315
  }
20309
20316
  var CRC_TABLE2 = (() => {
20310
- const table = new Uint32Array(256);
20317
+ const table2 = new Uint32Array(256);
20311
20318
  for (let n = 0; n < 256; n++) {
20312
20319
  let c = n;
20313
20320
  for (let k = 0; k < 8; k++) c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
20314
- table[n] = c >>> 0;
20321
+ table2[n] = c >>> 0;
20315
20322
  }
20316
- return table;
20323
+ return table2;
20317
20324
  })();
20318
20325
  function crc322(data) {
20319
20326
  let crc = 4294967295;
@@ -20475,28 +20482,28 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
20475
20482
  return l;
20476
20483
  };
20477
20484
  const matchText = (p) => paraTText(p, xml) ?? p.text;
20478
- const cellLabelText = (cell) => cell.paragraphs.filter((p) => !p.inTextbox).map((p) => matchText(p)).join("");
20485
+ const cellLabelText = (cell2) => cell2.paragraphs.filter((p) => !p.inTextbox).map((p) => matchText(p)).join("");
20479
20486
  const allTables = [];
20480
20487
  const collectTables = (tables, depth) => {
20481
20488
  if (depth > 16) return;
20482
20489
  for (const t of tables) {
20483
20490
  allTables.push(t);
20484
20491
  for (const row of t.rows) {
20485
- for (const cell of row) collectTables(cell.tables, depth + 1);
20492
+ for (const cell2 of row) collectTables(cell2.tables, depth + 1);
20486
20493
  }
20487
20494
  }
20488
20495
  };
20489
20496
  collectTables(scan.tables, 0);
20490
20497
  collectTables(scan.orphanTables, 0);
20491
20498
  const patternApplied = /* @__PURE__ */ new Set();
20492
- for (const table of allTables) {
20493
- for (const row of table.rows) {
20494
- for (const cell of row) {
20495
- for (const para of cell.paragraphs) {
20496
- const text = matchText(para);
20499
+ for (const table2 of allTables) {
20500
+ for (const row of table2.rows) {
20501
+ for (const cell2 of row) {
20502
+ for (const para2 of cell2.paragraphs) {
20503
+ const text = matchText(para2);
20497
20504
  const result = fillInCellPatterns(text, cursor, matchedLabels, blockedLabels);
20498
20505
  if (!result) continue;
20499
- const l = led(para);
20506
+ const l = led(para2);
20500
20507
  if (l.fullText !== void 0) continue;
20501
20508
  const newT = result.text;
20502
20509
  let s = 0;
@@ -20508,7 +20515,7 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
20508
20515
  en--;
20509
20516
  }
20510
20517
  l.ranges.push({ start: s, end: eo, replacement: newT.slice(s, en) });
20511
- patternApplied.add(cell);
20518
+ patternApplied.add(cell2);
20512
20519
  for (const m of result.matches) {
20513
20520
  l.filledIdx.push(filled.length);
20514
20521
  l.matchKeys.push(m.key);
@@ -20518,9 +20525,9 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
20518
20525
  }
20519
20526
  }
20520
20527
  }
20521
- for (const table of allTables) {
20522
- for (let rowIdx = 0; rowIdx < table.rows.length; rowIdx++) {
20523
- const cells = table.rows[rowIdx];
20528
+ for (const table2 of allTables) {
20529
+ for (let rowIdx = 0; rowIdx < table2.rows.length; rowIdx++) {
20530
+ const cells = table2.rows[rowIdx];
20524
20531
  for (let colIdx = 0; colIdx < cells.length - 1; colIdx++) {
20525
20532
  const labelText = cellLabelText(cells[colIdx]);
20526
20533
  if (!isLabelCell(labelText)) continue;
@@ -20575,15 +20582,15 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
20575
20582
  }
20576
20583
  }
20577
20584
  }
20578
- if (table.rows.length >= 2) {
20579
- const headerCells = table.rows[0];
20580
- const allLabels = headerCells.length > 0 && headerCells.every((cell) => {
20581
- const t = cellLabelText(cell).trim();
20585
+ if (table2.rows.length >= 2) {
20586
+ const headerCells = table2.rows[0];
20587
+ const allLabels = headerCells.length > 0 && headerCells.every((cell2) => {
20588
+ const t = cellLabelText(cell2).trim();
20582
20589
  return t.length > 0 && t.length <= 20 && isLabelCell(t);
20583
20590
  });
20584
20591
  if (allLabels) {
20585
- for (let rowIdx = 1; rowIdx < table.rows.length; rowIdx++) {
20586
- const dataCells = table.rows[rowIdx];
20592
+ for (let rowIdx = 1; rowIdx < table2.rows.length; rowIdx++) {
20593
+ const dataCells = table2.rows[rowIdx];
20587
20594
  for (let colIdx = 0; colIdx < Math.min(headerCells.length, dataCells.length); colIdx++) {
20588
20595
  const headerLabel = normalizeLabel(cellLabelText(headerCells[colIdx]));
20589
20596
  if (blockedLabels?.has(headerLabel)) continue;
@@ -20617,10 +20624,10 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
20617
20624
  }
20618
20625
  }
20619
20626
  }
20620
- for (const para of [...scan.bodyParagraphs, ...scan.excludedParagraphs]) {
20621
- const existing = ledger.get(para);
20627
+ for (const para2 of [...scan.bodyParagraphs, ...scan.excludedParagraphs]) {
20628
+ const existing = ledger.get(para2);
20622
20629
  if (existing?.fullText !== void 0) continue;
20623
- const text = matchText(para);
20630
+ const text = matchText(para2);
20624
20631
  for (const seg of scanInlineSegments(text)) {
20625
20632
  const nlabel = normalizeLabel(seg.label);
20626
20633
  if (blockedLabels?.has(nlabel)) continue;
@@ -20629,7 +20636,7 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
20629
20636
  const newValue = cursor.consume(matchKey);
20630
20637
  if (newValue === void 0) continue;
20631
20638
  const replacement = seg.valueStart === seg.valueEnd ? padInsertion(text, seg.valueStart, newValue) : newValue;
20632
- const l = led(para);
20639
+ const l = led(para2);
20633
20640
  l.ranges.push({ start: seg.valueStart, end: seg.valueEnd, replacement });
20634
20641
  matchedLabels.add(matchKey);
20635
20642
  l.filledIdx.push(filled.length);
@@ -20638,10 +20645,10 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
20638
20645
  }
20639
20646
  }
20640
20647
  const splices = [];
20641
- for (const [para, l] of ledger) {
20648
+ for (const [para2, l] of ledger) {
20642
20649
  let paraSplices = null;
20643
20650
  if (l.fullText !== void 0) {
20644
- paraSplices = buildParagraphSplices(para, l.fullText, xml);
20651
+ paraSplices = buildParagraphSplices(para2, l.fullText, xml);
20645
20652
  } else if (l.ranges.length > 0) {
20646
20653
  const sorted = [...l.ranges].sort((a, b) => a.start - b.start || a.end - b.end);
20647
20654
  const merged = [];
@@ -20650,11 +20657,11 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
20650
20657
  if (prev && r.start < prev.end) continue;
20651
20658
  merged.push(r);
20652
20659
  }
20653
- if (paraTText(para, xml) !== null) {
20660
+ if (paraTText(para2, xml) !== null) {
20654
20661
  const precise = [];
20655
20662
  let ok = true;
20656
20663
  for (const r of merged) {
20657
- const sp = buildRangeSplices(para, xml, r.start, r.end, r.replacement);
20664
+ const sp = buildRangeSplices(para2, xml, r.start, r.end, r.replacement);
20658
20665
  if (!sp) {
20659
20666
  ok = false;
20660
20667
  break;
@@ -20662,13 +20669,13 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
20662
20669
  precise.push(...sp);
20663
20670
  }
20664
20671
  paraSplices = ok ? precise : null;
20665
- } else if (paraTextPureT(para, xml)) {
20666
- let text = para.text;
20672
+ } else if (paraTextPureT(para2, xml)) {
20673
+ let text = para2.text;
20667
20674
  for (let k = merged.length - 1; k >= 0; k--) {
20668
20675
  const r = merged[k];
20669
20676
  text = text.slice(0, r.start) + r.replacement + text.slice(r.end);
20670
20677
  }
20671
- paraSplices = buildParagraphSplices(para, text, xml);
20678
+ paraSplices = buildParagraphSplices(para2, text, xml);
20672
20679
  } else {
20673
20680
  paraSplices = null;
20674
20681
  }
@@ -20850,6 +20857,7 @@ function charWidthEm1000(cp) {
20850
20857
  if (cp >= 19968 && cp <= 40959 || cp >= 63744 && cp <= 64255) return 1e3;
20851
20858
  if (cp >= 12296 && cp <= 12305 || cp >= 12308 && cp <= 12315) return 500;
20852
20859
  if (cp === 12288) return 970;
20860
+ if (cp >= 8544 && cp <= 8579) return 970;
20853
20861
  if (cp >= 8592 && cp <= 8959) return 970;
20854
20862
  if (cp >= 9312 && cp <= 9471) return 970;
20855
20863
  if (cp >= 9632 && cp <= 9983) return 970;
@@ -20941,14 +20949,126 @@ function fitRatioForFewerLines(text, firstWidth, contWidth, height, baseRatio, m
20941
20949
  return null;
20942
20950
  }
20943
20951
 
20952
+ // src/hwpx/gaejosik.ts
20953
+ var GAEJOSIK_BULLETS = ["\u25A1", "\u25CB", "-", "\u318D"];
20954
+ function gaejosikMarker(depth) {
20955
+ return GAEJOSIK_BULLETS[Math.min(depth, GAEJOSIK_BULLETS.length - 1)];
20956
+ }
20957
+ function gaejosikSizes(bodyHeight, ov = {}) {
20958
+ const s = bodyHeight / 1500;
20959
+ const r = (v, pt2) => pt2 ? Math.round(pt2 * 100) : Math.round(v * s);
20960
+ return {
20961
+ /** □ 대항목 — HY헤드라인M 16pt */
20962
+ dae: r(1600, ov.dae),
20963
+ /** ※ 참고 — 한양중고딕 13pt */
20964
+ cham: r(1300, ov.cham),
20965
+ /** 장 헤더(로마숫자·제목) 17pt */
20966
+ chapter: r(1700, ov.chapter),
20967
+ /** 표지 제목 30pt */
20968
+ coverTitle: r(3e3, ov.coverTitle),
20969
+ /** 표지 날짜·기관명 25pt */
20970
+ coverSub: r(2500, ov.coverSub),
20971
+ /** 목차 라벨 "목 차" 28pt */
20972
+ tocLabel: r(2800, ov.tocLabel),
20973
+ /** 목차 로마숫자 21pt(한양신명조) */
20974
+ tocRoman: r(2100, ov.tocRoman),
20975
+ /** 목차 항목 18pt */
20976
+ tocItem: r(1800, ov.tocItem),
20977
+ /** 표 셀 — 맑은 고딕 12pt (실측: 정부 양식 표) */
20978
+ table: r(1200, ov.table),
20979
+ /** 표지 장식 바 셀 빈 문단 — 6pt (실측: 바 높이 818 안에 줄높이 수납) */
20980
+ bar: r(600),
20981
+ /** 본문 첫 페이지 제목 박스 — HY헤드라인M 22pt (실측: GT3 표④) */
20982
+ bodyTitle: r(2200, ov.bodyTitle)
20983
+ };
20984
+ }
20985
+ function gaejosikSpaceBefore(depth, bodyHeight) {
20986
+ const s = bodyHeight / 1500;
20987
+ const ui = [3e3, 2e3, 1200, 600][Math.min(depth, 3)];
20988
+ return Math.round(ui * s);
20989
+ }
20990
+ function gaejosikLevelIndent(depth, bodyHeight, sizes = {}) {
20991
+ const lefts = [0, 1, 1.5, 2];
20992
+ const left = depth <= 3 ? Math.round(lefts[depth] * bodyHeight) : Math.round((2 + (depth - 3) * 0.5) * bodyHeight);
20993
+ const h = depth === 0 ? gaejosikSizes(bodyHeight, sizes).dae : bodyHeight;
20994
+ return { left, indent: -markerWidth(gaejosikMarker(depth), h) };
20995
+ }
20996
+ function gaejosikChamIndent(bodyHeight, sizes = {}) {
20997
+ const cham = gaejosikSizes(bodyHeight, sizes).cham;
20998
+ return { left: Math.round(2.5 * cham), indent: -markerWidth("\u203B", cham) };
20999
+ }
21000
+ function gaejosikTocItemIndent(bodyHeight, sizes = {}) {
21001
+ const sz = gaejosikSizes(bodyHeight, sizes);
21002
+ const hang = markerWidth("\u2167.", sz.tocRoman);
21003
+ return { left: 2e3 + hang, indent: -hang };
21004
+ }
21005
+ function formatGaejosikDate(d) {
21006
+ return `${d.getFullYear()}. ${d.getMonth() + 1}. ${d.getDate()}.`;
21007
+ }
21008
+ function stripChapterNumber(title) {
21009
+ return title.replace(/^\s*(?:\d+|[ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩ]+)\s*[.)]\s*/u, "").trim();
21010
+ }
21011
+ var GAEJOSIK_COLORS = {
21012
+ /** 장헤더 로마숫자 셀·표지 진한 바 음영 */
21013
+ primary: "#193AAA",
21014
+ /** 장헤더 셀 테두리 */
21015
+ border: "#006699",
21016
+ /** 표지 연한 바 */
21017
+ accent: "#A0B4E6",
21018
+ /** 장헤더 제목 셀 음영 */
21019
+ titleFill: "#F2F2F2",
21020
+ /** 장헤더 제목 셀 상하선 */
21021
+ titleLine: "#A6A6A6",
21022
+ /** 목차 박스 테두리 */
21023
+ tocBorder: "#514BAC",
21024
+ /** 목차 배너 라벤더 스트라이프 (실측: GT3 표②) */
21025
+ tocStripe: "#E0E5FA"
21026
+ };
21027
+ var CHAPTER_GEOM = { numW: 3327, gapW: 848, titleW: 43513, rowH: 2832 };
21028
+ var COVER_GEOM = {
21029
+ totalW: 48180,
21030
+ topDarkW: 38219,
21031
+ topLightW: 9961,
21032
+ barH: 818,
21033
+ titleH: 11060,
21034
+ botDarkW: 10466,
21035
+ botLightW: 37714,
21036
+ botBarH: 812
21037
+ };
21038
+ var TOC_GEOM = { boxW: 46492, boxH: 57840 };
21039
+ function chapterGeom(bodyHeight, ov = {}) {
21040
+ const s = gaejosikSizes(bodyHeight, ov).chapter / 1700;
21041
+ return { ...CHAPTER_GEOM, rowH: Math.round(CHAPTER_GEOM.rowH * s) };
21042
+ }
21043
+ function coverGeom(bodyHeight, ov = {}) {
21044
+ const s = gaejosikSizes(bodyHeight, ov).coverTitle / 3e3;
21045
+ return { ...COVER_GEOM, titleH: Math.round(COVER_GEOM.titleH * s) };
21046
+ }
21047
+ var TOC_BANNER_GEOM = {
21048
+ colWs: [565, 565, 1414, 13191, 1414, 565, 565],
21049
+ h: 3931
21050
+ };
21051
+ function tocBannerGeom(bodyHeight, ov = {}) {
21052
+ const s = gaejosikSizes(bodyHeight, ov).tocLabel / 2800;
21053
+ return { colWs: TOC_BANNER_GEOM.colWs, h: Math.round(TOC_BANNER_GEOM.h * s) };
21054
+ }
21055
+ var BODY_TITLE_GEOM = { barH: 600, titleH: 3566 };
21056
+ function bodyTitleGeom(bodyHeight, ov = {}) {
21057
+ const s = gaejosikSizes(bodyHeight, ov).bodyTitle / 2200;
21058
+ return { barH: BODY_TITLE_GEOM.barH, titleH: Math.round(BODY_TITLE_GEOM.titleH * s) };
21059
+ }
21060
+
20944
21061
  // src/hwpx/gongmun.ts
20945
21062
  var OFFICIAL_MARGINS = { top: 20, bottom: 10, left: 20, right: 20 };
21063
+ var GAEJOSIK_MARGINS = { top: 15, bottom: 15, left: 20, right: 20 };
21064
+ var GAEJOSIK_HEADER_FOOTER = 4251;
20946
21065
  var PRESET_DEFAULTS = {
20947
21066
  official: { bodyPt: 15, lineSpacing: 160, numbering: "standard" },
20948
21067
  report: { bodyPt: 15, lineSpacing: 160, numbering: "report" },
20949
21068
  plan: { bodyPt: 15, lineSpacing: 160, numbering: "standard" },
20950
21069
  notice: { bodyPt: 15, lineSpacing: 160, numbering: "standard" },
20951
- minutes: { bodyPt: 14, lineSpacing: 130, numbering: "standard" }
21070
+ minutes: { bodyPt: 14, lineSpacing: 130, numbering: "standard" },
21071
+ gaejosik: { bodyPt: 15, lineSpacing: 160, numbering: "gaejosik" }
20952
21072
  };
20953
21073
  var PRESET_ALIAS = {
20954
21074
  official: "official",
@@ -20966,26 +21086,51 @@ var PRESET_ALIAS = {
20966
21086
  \uC54C\uB9BC: "notice",
20967
21087
  \uC548\uB0B4: "notice",
20968
21088
  minutes: "minutes",
20969
- \uD68C\uC758\uB85D: "minutes"
21089
+ \uD68C\uC758\uB85D: "minutes",
21090
+ gaejosik: "gaejosik",
21091
+ \uAC1C\uC870\uC2DD: "gaejosik",
21092
+ \uAC1C\uC870\uC2DD\uBCF4\uACE0\uC11C: "gaejosik",
21093
+ \uC815\uBD80\uBCF4\uACE0\uC11C: "gaejosik",
21094
+ \uC815\uBD80\uD45C\uC900\uAC1C\uC870\uC2DD\uBCF4\uACE0\uC11C: "gaejosik"
20970
21095
  };
20971
21096
  function normalizeGongmunPreset(preset) {
20972
21097
  if (!preset) return "official";
20973
21098
  return PRESET_ALIAS[preset.trim()] ?? "official";
20974
21099
  }
21100
+ function usesReportFonts(preset) {
21101
+ return preset === "gaejosik" || preset === "report" || preset === "plan";
21102
+ }
20975
21103
  function resolveGongmun(opts) {
20976
21104
  const preset = normalizeGongmunPreset(opts.preset);
20977
21105
  const d = PRESET_DEFAULTS[preset];
20978
21106
  const bodyPt = opts.bodyPt ?? d.bodyPt;
20979
21107
  const autoFitMinRatio = opts.autoFit === false ? null : typeof opts.autoFit === "object" ? Math.min(Math.max(opts.autoFit.minRatio ?? 90, 50), 99) : 90;
21108
+ const coverOn = opts.cover !== void 0 ? opts.cover !== false : preset === "gaejosik";
21109
+ const coverOpts = typeof opts.cover === "object" ? opts.cover : {};
21110
+ const gaejosik = preset === "gaejosik";
20980
21111
  return {
20981
21112
  preset,
20982
21113
  bodyFont: opts.bodyFont ?? "myeongjo",
20983
21114
  bodyHeight: Math.round(bodyPt * 100),
20984
21115
  lineSpacing: opts.lineSpacing ?? d.lineSpacing,
20985
21116
  numbering: opts.numbering ?? d.numbering,
20986
- margins: opts.margins ?? OFFICIAL_MARGINS,
21117
+ margins: opts.margins ?? (gaejosik ? GAEJOSIK_MARGINS : OFFICIAL_MARGINS),
20987
21118
  centerTitle: opts.centerTitle ?? true,
20988
- autoFitMinRatio
21119
+ autoFitMinRatio,
21120
+ cover: coverOn ? { date: coverOpts.date ?? null, org: coverOpts.org ?? "" } : null,
21121
+ toc: opts.toc ?? gaejosik,
21122
+ fonts: opts.fonts ?? {},
21123
+ sizes: opts.sizes ?? {},
21124
+ // 쪽번호 — 보고서 계열 관행(실측: 2_보고서 양식·추진계획·공고문 전부 하단 중앙)
21125
+ pageNumbers: opts.pageNumbers ?? (gaejosik || preset === "report" || preset === "plan"),
21126
+ headerFooter: gaejosik ? GAEJOSIK_HEADER_FOOTER : 0,
21127
+ // "끝." — 기안문 규정(본문 끝 2타+"끝."). 그 외는 opt-in
21128
+ endMark: opts.endMark ?? preset === "official",
21129
+ approval: opts.approval && opts.approval.length > 0 ? opts.approval : null,
21130
+ // 본문 제목박스 — 실측(GT3·GT12): 목차 뒤 본문 시작에 제목 반복. 표지 켜진 개조식 기본
21131
+ bodyTitleBox: opts.bodyTitleBox ?? (gaejosik && coverOn),
21132
+ // h2 말머리 — 실측 보고서 양식(부처별 3종)의 섹션 제목이 곧 □ 대항목 (QA-2)
21133
+ h2Marker: opts.h2Marker ?? (preset === "report" || preset === "plan" ? "box" : "none")
20989
21134
  };
20990
21135
  }
20991
21136
  var HANGUL_INITIALS = [0, 2, 3, 5, 6, 7, 9, 11, 12, 14, 15, 16, 17, 18];
@@ -21033,7 +21178,8 @@ function markerWidth(marker, bodyHeight) {
21033
21178
  for (const c of marker) em += charWidthEm1000(c.codePointAt(0));
21034
21179
  return Math.round(em / 1e3 * bodyHeight);
21035
21180
  }
21036
- function levelIndent(depth, bodyHeight, numbering) {
21181
+ function levelIndent(depth, bodyHeight, numbering, sizes = {}) {
21182
+ if (numbering === "gaejosik") return gaejosikLevelIndent(depth, bodyHeight, sizes);
21037
21183
  const marker = numbering === "report" ? reportMarker(depth) : standardMarker(depth, 0);
21038
21184
  return { left: Math.round(depth * bodyHeight), indent: -markerWidth(marker, bodyHeight) };
21039
21185
  }
@@ -21061,6 +21207,7 @@ var GongmunNumberer = class {
21061
21207
  const n = this.counts[depth] ?? 0;
21062
21208
  this.counts[depth] = n + 1;
21063
21209
  if (suppress) return "";
21210
+ if (this.numbering === "gaejosik") return gaejosikMarker(depth);
21064
21211
  return this.numbering === "report" ? reportMarker(depth) : standardMarker(depth, n);
21065
21212
  }
21066
21213
  reset() {
@@ -21131,24 +21278,25 @@ function headingCharPrId(level) {
21131
21278
  function charPr(id, height, bold, italic, fontId = 0, textColor = DEFAULT_TEXT_COLOR, ratioPct = 100) {
21132
21279
  const boldAttr = bold ? ` bold="1"` : "";
21133
21280
  const italicAttr = italic ? ` italic="1"` : "";
21134
- const effFont = bold ? 2 : fontId;
21281
+ const effFont = fontId;
21282
+ const boldEl = bold ? `<hh:bold/>` : "";
21135
21283
  return ` <hh:charPr id="${id}" height="${height}" textColor="${textColor}" shadeColor="none" useFontSpace="0" useKerning="0" symMark="NONE" borderFillIDRef="1"${boldAttr}${italicAttr}>
21136
21284
  <hh:fontRef hangul="${effFont}" latin="${effFont}" hanja="${effFont}" japanese="${effFont}" other="${effFont}" symbol="${effFont}" user="${effFont}"/>
21137
21285
  <hh:ratio hangul="${ratioPct}" latin="${ratioPct}" hanja="${ratioPct}" japanese="100" other="100" symbol="100" user="100"/>
21138
21286
  <hh:spacing hangul="0" latin="0" hanja="0" japanese="0" other="0" symbol="0" user="0"/>
21139
21287
  <hh:relSz hangul="100" latin="100" hanja="100" japanese="100" other="100" symbol="100" user="100"/>
21140
- <hh:offset hangul="0" latin="0" hanja="0" japanese="0" other="0" symbol="0" user="0"/>
21288
+ <hh:offset hangul="0" latin="0" hanja="0" japanese="0" other="0" symbol="0" user="0"/>${boldEl}
21141
21289
  </hh:charPr>`;
21142
21290
  }
21143
21291
  function paraPr(id, opts = {}) {
21144
- const { align = "JUSTIFY", spaceBefore = 0, spaceAfter = 0, lineSpacing = 160, indent = 0, left = 0, keepWord = false, outlineLevel } = opts;
21145
- const breakNonLatin = keepWord ? "KEEP_WORD" : "BREAK_WORD";
21292
+ const { align = "JUSTIFY", spaceBefore = 0, spaceAfter = 0, lineSpacing = 160, indent = 0, left = 0, keepWord = false, keepWithNext = false, outlineLevel } = opts;
21293
+ const breakNonLatin = keepWord ? "BREAK_WORD" : "KEEP_WORD";
21146
21294
  const snapGrid = keepWord ? "0" : "1";
21147
21295
  const heading = outlineLevel !== void 0 ? `<hh:heading type="OUTLINE" idRef="0" level="${outlineLevel}"/>` : `<hh:heading type="NONE" idRef="0" level="0"/>`;
21148
21296
  return ` <hh:paraPr id="${id}" tabPrIDRef="0" condense="0" fontLineHeight="0" snapToGrid="${snapGrid}" suppressLineNumbers="0" checked="0" textDir="AUTO">
21149
21297
  <hh:align horizontal="${align}" vertical="BASELINE"/>
21150
21298
  ${heading}
21151
- <hh:breakSetting breakLatinWord="KEEP_WORD" breakNonLatinWord="${breakNonLatin}" widowOrphan="0" keepWithNext="0" keepLines="0" pageBreakBefore="0" lineWrap="BREAK"/>
21299
+ <hh:breakSetting breakLatinWord="KEEP_WORD" breakNonLatinWord="${breakNonLatin}" widowOrphan="0" keepWithNext="${keepWithNext ? 1 : 0}" keepLines="0" pageBreakBefore="0" lineWrap="BREAK"/>
21152
21300
  <hh:autoSpacing eAsianEng="0" eAsianNum="0"/>
21153
21301
  <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>
21154
21302
  <hh:lineSpacing type="PERCENT" value="${lineSpacing}"/>
@@ -21158,7 +21306,72 @@ function paraPr(id, opts = {}) {
21158
21306
  var GONGMUN_LIST_BASE = 8;
21159
21307
  var GONGMUN_LIST_LEVELS = 8;
21160
21308
  var GONGMUN_CENTER = GONGMUN_LIST_BASE + GONGMUN_LIST_LEVELS;
21309
+ var GONGMUN_RIGHT = GONGMUN_CENTER + 1;
21310
+ var GONGMUN_TBL_CENTER = GONGMUN_RIGHT + 1;
21311
+ var GONGMUN_TBL_LEFT = GONGMUN_TBL_CENTER + 1;
21312
+ var GJ_CHAR_DAE = 11;
21313
+ var GJ_CHAR_DAE_BOLD = 12;
21314
+ var GJ_CHAR_CHAM = 13;
21315
+ var GJ_CHAR_CHAM_BOLD = 14;
21316
+ var GJ_CHAR_CHAPTER_NUM = 15;
21317
+ var GJ_CHAR_CHAPTER_TITLE = 16;
21318
+ var GJ_CHAR_COVER_TITLE = 17;
21319
+ var GJ_CHAR_COVER_SUB = 18;
21320
+ var GJ_CHAR_TOC_LABEL = 19;
21321
+ var GJ_CHAR_TOC_ROMAN = 20;
21322
+ var GJ_CHAR_TOC_ITEM = 21;
21323
+ var GJ_CHAR_TABLE = 22;
21324
+ var GJ_CHAR_TABLE_BOLD = 23;
21325
+ var GJ_CHAR_BAR = 24;
21326
+ var GJ_CHAR_BODY_TITLE = 25;
21327
+ var GJ_CHAR_COUNT = 15;
21328
+ var GJ_PARA_CHAM = 20;
21329
+ var GJ_PARA_COVER = 21;
21330
+ var GJ_PARA_TOC_ITEM = 22;
21331
+ var GJ_PARA_CHAPTER = 23;
21332
+ var GJ_PARA_BAR = 24;
21333
+ var GJ_BF_CHAPTER_NUM = 3;
21334
+ var GJ_BF_CHAPTER_GAP = 4;
21335
+ var GJ_BF_CHAPTER_TITLE = 5;
21336
+ var GJ_BF_BAR_DARK = 6;
21337
+ var GJ_BF_BAR_LIGHT = 7;
21338
+ var GJ_BF_TOC_BOX = 8;
21339
+ var GJ_BF_TOC_STRIPE = 9;
21340
+ function gongmunTableHeaderBf(gaejosik) {
21341
+ return gaejosik ? 10 : 3;
21342
+ }
21343
+ function borderFillEntry(id, b, fill) {
21344
+ 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"/>`;
21345
+ let brush = "";
21346
+ if (typeof fill === "string") {
21347
+ brush = `
21348
+ <hc:fillBrush><hc:winBrush faceColor="${fill}" hatchColor="#000000" alpha="0"/></hc:fillBrush>`;
21349
+ } else if (fill) {
21350
+ brush = `
21351
+ <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>`;
21352
+ }
21353
+ return ` <hh:borderFill id="${id}" threeD="0" shadow="0" centerLine="NONE" breakCellSeparateLine="0">
21354
+ <hh:slash type="NONE" Crooked="0" isCounter="0"/>
21355
+ <hh:backSlash type="NONE" Crooked="0" isCounter="0"/>
21356
+ ${side("leftBorder", b.l)}
21357
+ ${side("rightBorder", b.r)}
21358
+ ${side("topBorder", b.t)}
21359
+ ${side("bottomBorder", b.b)}${brush}
21360
+ </hh:borderFill>`;
21361
+ }
21362
+ function pageNumCtrl() {
21363
+ return `<hp:ctrl><hp:pageNum pos="BOTTOM_CENTER" formatType="DIGIT" sideChar="-"/></hp:ctrl>`;
21364
+ }
21365
+ function newPageNumCtrl(num4 = 1) {
21366
+ return `<hp:ctrl><hp:newNum num="${num4}" numType="PAGE"/></hp:ctrl>`;
21367
+ }
21368
+ function pageHidingCtrl(hideHeader = false) {
21369
+ return `<hp:ctrl><hp:pageHiding hideHeader="${hideHeader ? 1 : 0}" hideFooter="0" hideMasterPage="0" hideBorder="0" hideFill="0" hidePageNum="1"/></hp:ctrl>`;
21370
+ }
21161
21371
  var CHAR_VARIANT_BASE = 11;
21372
+ function charVariantBase(measured) {
21373
+ return measured ? CHAR_VARIANT_BASE + GJ_CHAR_COUNT : CHAR_VARIANT_BASE;
21374
+ }
21162
21375
  var GONGMUN_BODY_RATIO = 95;
21163
21376
 
21164
21377
  // src/hwpx/md-runs.ts
@@ -21372,12 +21585,12 @@ function generateRuns(text, defaultCharPr = CHAR_NORMAL, mapCharId) {
21372
21585
  return `<hp:run charPrIDRef="${charId}"><hp:t>${escapeXml(span.text)}</hp:t></hp:run>`;
21373
21586
  }).join("");
21374
21587
  }
21375
- function generateParagraph(text, paraPrId = PARA_NORMAL, charPrId = CHAR_NORMAL, mapCharId) {
21588
+ function generateParagraph(text, paraPrId = PARA_NORMAL, charPrId = CHAR_NORMAL, mapCharId, styleId = 0) {
21376
21589
  if (paraPrId === PARA_CODE) {
21377
21590
  return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_CODE}"><hp:t>${escapeXml(text)}</hp:t></hp:run></hp:p>`;
21378
21591
  }
21379
21592
  const runs = generateRuns(text, charPrId, mapCharId);
21380
- return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0">${runs}</hp:p>`;
21593
+ return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="${styleId}">${runs}</hp:p>`;
21381
21594
  }
21382
21595
 
21383
21596
  // src/hwpx/gen-header.ts
@@ -21405,6 +21618,7 @@ function generateManifest(chartParts = []) {
21405
21618
  </opf:package>`;
21406
21619
  }
21407
21620
  function buildCharProperties(theme, gongmun, ratioVariants = [], extraCharPrXmls = []) {
21621
+ const measured = !!gongmun && usesReportFonts(gongmun.preset);
21408
21622
  let body = 1e3, code = 900, h1 = 1800, h2 = 1400, h3 = 1200, h4 = 1100;
21409
21623
  if (gongmun) {
21410
21624
  body = gongmun.bodyHeight;
@@ -21414,26 +21628,64 @@ function buildCharProperties(theme, gongmun, ratioVariants = [], extraCharPrXmls
21414
21628
  h3 = body;
21415
21629
  h4 = Math.max(body - 100, 1300);
21416
21630
  }
21631
+ const bodyFont = measured ? 4 : 0;
21632
+ const hFont = measured ? 3 : 1;
21633
+ const hBold = !measured;
21417
21634
  const bodyRatio = gongmun ? GONGMUN_BODY_RATIO : 100;
21418
21635
  const rows = [
21419
- charPr(0, body, false, false, 0, theme.body, bodyRatio),
21420
- charPr(1, body, true, false, 0, theme.body, bodyRatio),
21421
- charPr(2, body, false, true, 0, theme.body, bodyRatio),
21422
- charPr(3, body, true, true, 0, theme.body, bodyRatio),
21636
+ charPr(0, body, false, false, bodyFont, theme.body, bodyRatio),
21637
+ charPr(1, body, true, false, bodyFont, theme.body, bodyRatio),
21638
+ charPr(2, body, false, true, bodyFont, theme.body, bodyRatio),
21639
+ charPr(3, body, true, true, bodyFont, theme.body, bodyRatio),
21423
21640
  charPr(4, code, false, false, 1),
21424
- charPr(5, h1, true, false, 1, theme.h1),
21425
- charPr(6, h2, true, false, 1, theme.h2),
21426
- charPr(7, h3, true, false, 1, theme.h3),
21427
- charPr(8, h4, true, false, 1, theme.h4),
21428
- charPr(CHAR_TABLE_HEADER, body, theme.tableHeaderBold, false, 0, theme.tableHeader),
21429
- charPr(CHAR_QUOTE, body, false, true, 0, theme.quote)
21641
+ charPr(5, h1, hBold, false, hFont, theme.h1),
21642
+ charPr(6, h2, hBold, false, hFont, theme.h2),
21643
+ charPr(7, h3, hBold, false, hFont, theme.h3),
21644
+ charPr(8, h4, hBold, false, hFont, theme.h4),
21645
+ charPr(CHAR_TABLE_HEADER, body, theme.tableHeaderBold, false, bodyFont, theme.tableHeader),
21646
+ charPr(CHAR_QUOTE, body, false, true, bodyFont, theme.quote)
21430
21647
  ];
21648
+ if (measured) {
21649
+ const sz = gaejosikSizes(body, gongmun.sizes);
21650
+ rows.push(
21651
+ charPr(11, sz.dae, false, false, 3),
21652
+ // □ HY헤드라인M
21653
+ charPr(12, sz.dae, true, false, 3),
21654
+ // □ bold
21655
+ charPr(13, sz.cham, false, false, 5),
21656
+ // ※ 한양중고딕
21657
+ charPr(14, sz.cham, true, false, 5),
21658
+ // ※ bold
21659
+ charPr(15, sz.chapter, true, false, 4, "#FFFFFF"),
21660
+ // 장 로마숫자(흰)
21661
+ charPr(16, sz.chapter, false, false, 3),
21662
+ // 장 제목
21663
+ charPr(17, sz.coverTitle, false, false, 3),
21664
+ // 표지 제목
21665
+ charPr(18, sz.coverSub, false, false, 3),
21666
+ // 표지 날짜·기관명
21667
+ charPr(19, sz.tocLabel, true, false, 3),
21668
+ // 목 차
21669
+ charPr(20, sz.tocRoman, true, false, 6),
21670
+ // 목차 로마숫자(한양신명조)
21671
+ charPr(21, sz.tocItem, false, false, 3),
21672
+ // 목차 항목
21673
+ charPr(22, sz.table, false, false, 7),
21674
+ // 표 셀(맑은 고딕 12pt)
21675
+ charPr(23, sz.table, true, false, 7),
21676
+ // 표 셀 bold
21677
+ charPr(24, sz.bar, false, false, 4),
21678
+ // 표지 바 셀 빈 문단(6pt)
21679
+ charPr(25, sz.bodyTitle, false, false, 3)
21680
+ // 본문 제목박스(HY헤드라인M 22pt, 실측 GT3 표④)
21681
+ );
21682
+ }
21431
21683
  for (const r of ratioVariants) {
21432
21684
  rows.push(
21433
- charPr(rows.length, body, false, false, 0, theme.body, r),
21434
- charPr(rows.length + 1, body, true, false, 0, theme.body, r),
21435
- charPr(rows.length + 2, body, false, true, 0, theme.body, r),
21436
- charPr(rows.length + 3, body, true, true, 0, theme.body, r)
21685
+ charPr(rows.length, body, false, false, bodyFont, theme.body, r),
21686
+ charPr(rows.length + 1, body, true, false, bodyFont, theme.body, r),
21687
+ charPr(rows.length + 2, body, false, true, bodyFont, theme.body, r),
21688
+ charPr(rows.length + 3, body, true, true, bodyFont, theme.body, r)
21437
21689
  );
21438
21690
  }
21439
21691
  rows.push(...extraCharPrXmls);
@@ -21444,14 +21696,14 @@ ${rows.join("\n")}
21444
21696
  function buildParaProperties(gongmun) {
21445
21697
  if (!gongmun) {
21446
21698
  const base2 = [
21447
- paraPr(0),
21448
- paraPr(1, { align: "LEFT", spaceBefore: 800, spaceAfter: 200, lineSpacing: 180, outlineLevel: 0 }),
21449
- paraPr(2, { align: "LEFT", spaceBefore: 600, spaceAfter: 150, lineSpacing: 170, outlineLevel: 1 }),
21450
- paraPr(3, { align: "LEFT", spaceBefore: 400, spaceAfter: 100, lineSpacing: 160, outlineLevel: 2 }),
21451
- paraPr(4, { align: "LEFT", spaceBefore: 300, spaceAfter: 100, lineSpacing: 160, outlineLevel: 3 }),
21452
- paraPr(5, { align: "LEFT", lineSpacing: 130, indent: 400 }),
21453
- paraPr(6, { align: "LEFT", lineSpacing: 150, indent: 600 }),
21454
- paraPr(7, { align: "LEFT", lineSpacing: 160, indent: 600 })
21699
+ paraPr(0, { keepWord: true }),
21700
+ paraPr(1, { align: "LEFT", spaceBefore: 800, spaceAfter: 200, lineSpacing: 180, outlineLevel: 0, keepWord: true }),
21701
+ paraPr(2, { align: "LEFT", spaceBefore: 600, spaceAfter: 150, lineSpacing: 170, outlineLevel: 1, keepWord: true }),
21702
+ paraPr(3, { align: "LEFT", spaceBefore: 400, spaceAfter: 100, lineSpacing: 160, outlineLevel: 2, keepWord: true }),
21703
+ paraPr(4, { align: "LEFT", spaceBefore: 300, spaceAfter: 100, lineSpacing: 160, outlineLevel: 3, keepWord: true }),
21704
+ paraPr(5, { align: "LEFT", lineSpacing: 130, indent: 400, keepWord: true }),
21705
+ paraPr(6, { align: "LEFT", lineSpacing: 150, indent: 600, keepWord: true }),
21706
+ paraPr(7, { align: "LEFT", lineSpacing: 160, indent: 600, keepWord: true })
21455
21707
  ];
21456
21708
  return `<hh:paraProperties itemCnt="${base2.length}">
21457
21709
  ${base2.join("\n")}
@@ -21459,22 +21711,45 @@ ${base2.join("\n")}
21459
21711
  }
21460
21712
  const ls = gongmun.lineSpacing;
21461
21713
  const titleAlign = gongmun.centerTitle ? "CENTER" : "LEFT";
21714
+ const h2Geom = gongmun.h2Marker !== "none" ? { spaceBefore: Math.round(gongmun.bodyHeight * 2), spaceAfter: 0, indent: -markerWidth(gongmun.h2Marker === "box" ? "\u25A1" : "1.", 1600) } : { spaceBefore: 600, spaceAfter: 150 };
21462
21715
  const base = [
21463
21716
  paraPr(0, { lineSpacing: ls, keepWord: true }),
21464
- paraPr(1, { align: titleAlign, spaceBefore: 400, spaceAfter: 400, lineSpacing: ls, keepWord: true, outlineLevel: 0 }),
21465
- paraPr(2, { align: "LEFT", spaceBefore: 600, spaceAfter: 150, lineSpacing: ls, keepWord: true, outlineLevel: 1 }),
21466
- paraPr(3, { align: "LEFT", spaceBefore: 400, spaceAfter: 100, lineSpacing: ls, keepWord: true, outlineLevel: 2 }),
21467
- paraPr(4, { align: "LEFT", spaceBefore: 300, spaceAfter: 100, lineSpacing: ls, keepWord: true, outlineLevel: 3 }),
21717
+ paraPr(1, { align: titleAlign, spaceBefore: 400, spaceAfter: 400, lineSpacing: ls, keepWord: true }),
21718
+ paraPr(2, { align: "LEFT", ...h2Geom, lineSpacing: ls, keepWord: true }),
21719
+ paraPr(3, { align: "LEFT", spaceBefore: 400, spaceAfter: 100, lineSpacing: ls, keepWord: true }),
21720
+ paraPr(4, { align: "LEFT", spaceBefore: 300, spaceAfter: 100, lineSpacing: ls, keepWord: true }),
21468
21721
  paraPr(5, { align: "LEFT", lineSpacing: 130, indent: 400, keepWord: true }),
21469
21722
  paraPr(6, { align: "LEFT", lineSpacing: ls, indent: 600, keepWord: true }),
21470
21723
  paraPr(7, { align: "LEFT", lineSpacing: ls, indent: 600, keepWord: true })
21471
21724
  ];
21472
21725
  for (let d = 0; d < GONGMUN_LIST_LEVELS; d++) {
21473
- const { left, indent } = levelIndent(d, gongmun.bodyHeight, gongmun.numbering);
21474
- const sectionGap = gongmun.numbering === "report" && d === 0 ? Math.round(gongmun.bodyHeight * 0.5) : 0;
21475
- base.push(paraPr(GONGMUN_LIST_BASE + d, { align: "JUSTIFY", lineSpacing: ls, left, indent, spaceBefore: sectionGap, keepWord: true }));
21726
+ const { left, indent } = levelIndent(d, gongmun.bodyHeight, gongmun.numbering, gongmun.sizes);
21727
+ const sectionGap = gongmun.numbering === "gaejosik" ? gaejosikSpaceBefore(d, gongmun.bodyHeight) : gongmun.numbering === "report" && d === 0 ? Math.round(gongmun.bodyHeight * 0.5) : 0;
21728
+ const keepNext = gongmun.numbering === "gaejosik" && d === 0;
21729
+ base.push(paraPr(GONGMUN_LIST_BASE + d, { align: "JUSTIFY", lineSpacing: ls, left, indent, spaceBefore: sectionGap, keepWord: true, keepWithNext: keepNext }));
21476
21730
  }
21477
21731
  base.push(paraPr(GONGMUN_CENTER, { align: "CENTER", lineSpacing: ls, keepWord: true }));
21732
+ base.push(paraPr(GONGMUN_RIGHT, { align: "RIGHT", lineSpacing: ls, keepWord: true }));
21733
+ base.push(paraPr(GONGMUN_TBL_CENTER, { align: "CENTER", lineSpacing: 130, keepWord: true }));
21734
+ base.push(paraPr(GONGMUN_TBL_LEFT, { align: "LEFT", lineSpacing: 130, keepWord: true }));
21735
+ if (gongmun.preset === "gaejosik") {
21736
+ const cham = gaejosikChamIndent(gongmun.bodyHeight, gongmun.sizes);
21737
+ const toc = gaejosikTocItemIndent(gongmun.bodyHeight, gongmun.sizes);
21738
+ base.push(
21739
+ paraPr(GJ_PARA_CHAM, { align: "JUSTIFY", lineSpacing: ls, left: cham.left, indent: cham.indent, spaceBefore: gaejosikSpaceBefore(3, gongmun.bodyHeight), keepWord: true }),
21740
+ paraPr(GJ_PARA_COVER, { align: "CENTER", lineSpacing: 130, keepWord: true }),
21741
+ paraPr(GJ_PARA_TOC_ITEM, { align: "LEFT", lineSpacing: 160, left: toc.left, indent: toc.indent, spaceBefore: 1800, keepWord: true }),
21742
+ // 장 헤더는 다음 문단과 같은 쪽에 — 쪽 하단 고아 헤더 방지 (실렌더 확인 이슈)
21743
+ paraPr(GJ_PARA_CHAPTER, { align: "LEFT", lineSpacing: ls, spaceBefore: 2400, spaceAfter: 600, keepWord: true, keepWithNext: true }),
21744
+ // 표지 장식 바 셀 빈 문단 — 저줄간격(실측 71%)으로 바 높이 818 안에 수납
21745
+ paraPr(GJ_PARA_BAR, { align: "CENTER", lineSpacing: 70, keepWord: true })
21746
+ );
21747
+ } else if (usesReportFonts(gongmun.preset)) {
21748
+ const cham = gaejosikChamIndent(gongmun.bodyHeight, gongmun.sizes);
21749
+ base.push(
21750
+ paraPr(GJ_PARA_CHAM, { align: "JUSTIFY", lineSpacing: ls, left: cham.left, indent: cham.indent, spaceBefore: gaejosikSpaceBefore(3, gongmun.bodyHeight), keepWord: true })
21751
+ );
21752
+ }
21478
21753
  return `<hh:paraProperties itemCnt="${base.length}">
21479
21754
  ${base.join("\n")}
21480
21755
  </hh:paraProperties>`;
@@ -21490,25 +21765,38 @@ ${heads}
21490
21765
  </hh:numbering>
21491
21766
  </hh:numberings>`;
21492
21767
  }
21493
- function generateHeaderXml(theme, gongmun, ratioVariants = [], remap = null) {
21494
- const bodyFace = gongmun?.bodyFont === "gothic" ? "\uB9D1\uC740 \uACE0\uB515" : "\uD568\uCD08\uB86C\uBC14\uD0D5";
21495
- const charPropsXml = buildCharProperties(theme, gongmun, ratioVariants, remap?.charPrXmls ?? []);
21496
- const paraPropsXml = buildParaProperties(gongmun);
21497
- return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
21498
- <hh:head xmlns:hh="${NS_HEAD}" xmlns:hp="${NS_PARA}" xmlns:hc="${NS_CORE}" version="1.4" secCnt="1">
21499
- <hh:beginNum page="1" footnote="1" endnote="1" pic="1" tbl="1" equation="1"/>
21500
- <hh:refList>
21501
- <hh:fontfaces itemCnt="7">
21768
+ function fontEntry(id, face, weight = 6) {
21769
+ return ` <hh:font id="${id}" face="${face}" type="TTF" isEmbedded="0">
21770
+ <hh:typeInfo familyType="FCAT_GOTHIC" weight="${weight}" proportion="4" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
21771
+ </hh:font>`;
21772
+ }
21773
+ function buildFontFaces(gongmun, bodyFace) {
21774
+ if (gongmun && usesReportFonts(gongmun.preset)) {
21775
+ const ov = gongmun.fonts;
21776
+ const bodyDefault = gongmun.preset !== "gaejosik" && gongmun.bodyFont === "gothic" ? "\uB9D1\uC740 \uACE0\uB515" : "\uD734\uBA3C\uBA85\uC870";
21777
+ const faces = [
21778
+ "\uD568\uCD08\uB86C\uBC14\uD0D5",
21779
+ "\uD568\uCD08\uB86C\uB3CB\uC6C0",
21780
+ "HY\uACAC\uACE0\uB515",
21781
+ ov.heading ?? "HY\uD5E4\uB4DC\uB77C\uC778M",
21782
+ ov.body ?? bodyDefault,
21783
+ ov.ref ?? "\uD55C\uC591\uC911\uACE0\uB515",
21784
+ "\uD55C\uC591\uC2E0\uBA85\uC870",
21785
+ ov.table ?? "\uB9D1\uC740 \uACE0\uB515"
21786
+ ];
21787
+ const list = faces.map((f, i) => fontEntry(i, f, i === 2 || i === 3 ? 9 : 6)).join("\n");
21788
+ const langs = ["HANGUL", "LATIN", "HANJA", "JAPANESE", "OTHER", "SYMBOL", "USER"];
21789
+ return `<hh:fontfaces itemCnt="${langs.length}">
21790
+ ` + langs.map((l) => ` <hh:fontface lang="${l}" fontCnt="${faces.length}">
21791
+ ${list}
21792
+ </hh:fontface>`).join("\n") + `
21793
+ </hh:fontfaces>`;
21794
+ }
21795
+ return `<hh:fontfaces itemCnt="7">
21502
21796
  <hh:fontface lang="HANGUL" fontCnt="3">
21503
- <hh:font id="0" face="${bodyFace}" type="TTF" isEmbedded="0">
21504
- <hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="4" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
21505
- </hh:font>
21506
- <hh:font id="1" face="\uD568\uCD08\uB86C\uB3CB\uC6C0" type="TTF" isEmbedded="0">
21507
- <hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="4" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
21508
- </hh:font>
21509
- <hh:font id="2" face="HY\uACAC\uACE0\uB515" type="TTF" isEmbedded="0">
21510
- <hh:typeInfo familyType="FCAT_GOTHIC" weight="9" proportion="0" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
21511
- </hh:font>
21797
+ ${fontEntry(0, bodyFace)}
21798
+ ${fontEntry(1, "\uD568\uCD08\uB86C\uB3CB\uC6C0")}
21799
+ ${fontEntry(2, "HY\uACAC\uACE0\uB515", 9)}
21512
21800
  </hh:fontface>
21513
21801
  <hh:fontface lang="LATIN" fontCnt="3">
21514
21802
  <hh:font id="0" face="Times New Roman" type="TTF" isEmbedded="0">
@@ -21522,57 +21810,87 @@ function generateHeaderXml(theme, gongmun, ratioVariants = [], remap = null) {
21522
21810
  </hh:font>
21523
21811
  </hh:fontface>
21524
21812
  <hh:fontface lang="HANJA" fontCnt="1">
21525
- <hh:font id="0" face="\uD568\uCD08\uB86C\uBC14\uD0D5" type="TTF" isEmbedded="0">
21526
- <hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="4" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
21527
- </hh:font>
21813
+ ${fontEntry(0, "\uD568\uCD08\uB86C\uBC14\uD0D5")}
21528
21814
  </hh:fontface>
21529
21815
  <hh:fontface lang="JAPANESE" fontCnt="1">
21530
- <hh:font id="0" face="\uAD74\uB9BC" type="TTF" isEmbedded="0">
21531
- <hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="0" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
21532
- </hh:font>
21816
+ ${fontEntry(0, "\uAD74\uB9BC")}
21533
21817
  </hh:fontface>
21534
21818
  <hh:fontface lang="OTHER" fontCnt="1">
21535
- <hh:font id="0" face="\uAD74\uB9BC" type="TTF" isEmbedded="0">
21536
- <hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="0" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
21537
- </hh:font>
21819
+ ${fontEntry(0, "\uAD74\uB9BC")}
21538
21820
  </hh:fontface>
21539
21821
  <hh:fontface lang="SYMBOL" fontCnt="1">
21540
- <hh:font id="0" face="Symbol" type="TTF" isEmbedded="0">
21541
- <hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="0" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
21542
- </hh:font>
21822
+ ${fontEntry(0, "Symbol")}
21543
21823
  </hh:fontface>
21544
21824
  <hh:fontface lang="USER" fontCnt="1">
21545
- <hh:font id="0" face="\uAD74\uB9BC" type="TTF" isEmbedded="0">
21546
- <hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="0" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
21547
- </hh:font>
21825
+ ${fontEntry(0, "\uAD74\uB9BC")}
21548
21826
  </hh:fontface>
21549
- </hh:fontfaces>
21550
- <hh:borderFills itemCnt="${2 + (remap?.borderFillXmls.length ?? 0)}">
21551
- <hh:borderFill id="1" threeD="0" shadow="0" centerLine="NONE" breakCellSeparateLine="0">
21552
- <hh:slash type="NONE" Crooked="0" isCounter="0"/>
21553
- <hh:backSlash type="NONE" Crooked="0" isCounter="0"/>
21554
- <hh:leftBorder type="NONE" width="0.1 mm" color="#000000"/>
21555
- <hh:rightBorder type="NONE" width="0.1 mm" color="#000000"/>
21556
- <hh:topBorder type="NONE" width="0.1 mm" color="#000000"/>
21557
- <hh:bottomBorder type="NONE" width="0.1 mm" color="#000000"/>
21558
- </hh:borderFill>
21559
- <hh:borderFill id="2" threeD="0" shadow="0" centerLine="NONE" breakCellSeparateLine="0">
21560
- <hh:slash type="NONE" Crooked="0" isCounter="0"/>
21561
- <hh:backSlash type="NONE" Crooked="0" isCounter="0"/>
21562
- <hh:leftBorder type="SOLID" width="0.12 mm" color="#000000"/>
21563
- <hh:rightBorder type="SOLID" width="0.12 mm" color="#000000"/>
21564
- <hh:topBorder type="SOLID" width="0.12 mm" color="#000000"/>
21565
- <hh:bottomBorder type="SOLID" width="0.12 mm" color="#000000"/>
21566
- </hh:borderFill>${remap && remap.borderFillXmls.length ? "\n" + remap.borderFillXmls.join("\n") : ""}
21567
- </hh:borderFills>
21827
+ </hh:fontfaces>`;
21828
+ }
21829
+ function buildBorderFills(gongmun, extra = []) {
21830
+ const thin = ["0.12 mm", "#000000"];
21831
+ const items = [
21832
+ borderFillEntry(1, {}),
21833
+ borderFillEntry(2, { l: thin, r: thin, t: thin, b: thin })
21834
+ ];
21835
+ if (gongmun?.preset === "gaejosik") {
21836
+ const c = GAEJOSIK_COLORS;
21837
+ const edge = ["0.12 mm", c.border];
21838
+ const grayLine = ["0.1 mm", c.titleLine];
21839
+ const tocEdge = ["0.4 mm", c.tocBorder];
21840
+ items.push(
21841
+ borderFillEntry(3, { l: edge, r: edge, t: edge, b: edge }, c.primary),
21842
+ // 로마숫자
21843
+ borderFillEntry(4, { l: edge }),
21844
+ // 간격 (좌선)
21845
+ borderFillEntry(5, { t: grayLine, b: grayLine }, c.titleFill),
21846
+ // 장 제목 셀
21847
+ borderFillEntry(6, {}, c.primary),
21848
+ // 표지 진한 바
21849
+ borderFillEntry(7, {}, c.accent),
21850
+ // 표지 연한 바
21851
+ borderFillEntry(8, { l: tocEdge, r: tocEdge, t: tocEdge, b: tocEdge }),
21852
+ // 목차 박스
21853
+ borderFillEntry(9, {}, c.tocStripe)
21854
+ // 목차 배너 라벤더 스트라이프
21855
+ );
21856
+ }
21857
+ if (gongmun) {
21858
+ items.push(borderFillEntry(items.length + 1, { l: thin, r: thin, t: thin, b: thin }, "#E6E6E6"));
21859
+ }
21860
+ items.push(...extra);
21861
+ return `<hh:borderFills itemCnt="${items.length}">
21862
+ ${items.join("\n")}
21863
+ </hh:borderFills>`;
21864
+ }
21865
+ function buildStyles(gongmun) {
21866
+ const items = [
21867
+ `<hh:style id="0" type="PARA" name="\uBC14\uD0D5\uAE00" engName="Normal" paraPrIDRef="0" charPrIDRef="0" nextStyleIDRef="0" langIDRef="1042" lockForm="0"/>`
21868
+ ];
21869
+ if (gongmun) {
21870
+ for (let lvl = 1; lvl <= 4; lvl++) {
21871
+ 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"/>`);
21872
+ }
21873
+ }
21874
+ return `<hh:styles itemCnt="${items.length}">
21875
+ ${items.join("\n ")}
21876
+ </hh:styles>`;
21877
+ }
21878
+ function generateHeaderXml(theme, gongmun, ratioVariants = [], extraBorderFills = [], extraCharPrXmls = []) {
21879
+ const bodyFace = gongmun?.fonts.body ?? (gongmun?.bodyFont === "gothic" ? "\uB9D1\uC740 \uACE0\uB515" : "\uD568\uCD08\uB86C\uBC14\uD0D5");
21880
+ const charPropsXml = buildCharProperties(theme, gongmun, ratioVariants, extraCharPrXmls);
21881
+ const paraPropsXml = buildParaProperties(gongmun);
21882
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
21883
+ <hh:head xmlns:hh="${NS_HEAD}" xmlns:hp="${NS_PARA}" xmlns:hc="${NS_CORE}" version="1.4" secCnt="1">
21884
+ <hh:beginNum page="1" footnote="1" endnote="1" pic="1" tbl="1" equation="1"/>
21885
+ <hh:refList>
21886
+ ${buildFontFaces(gongmun, bodyFace)}
21887
+ ${buildBorderFills(gongmun, extraBorderFills)}
21568
21888
  ${charPropsXml}
21569
21889
  <hh:tabProperties itemCnt="0"/>
21570
21890
  ${buildNumberings()}
21571
21891
  <hh:bullets itemCnt="0"/>
21572
21892
  ${paraPropsXml}
21573
- <hh:styles itemCnt="1">
21574
- <hh:style id="0" type="PARA" name="\uBC14\uD0D5\uAE00" engName="Normal" paraPrIDRef="0" charPrIDRef="0" nextStyleIDRef="0" langIDRef="1042" lockForm="0"/>
21575
- </hh:styles>
21893
+ ${buildStyles(gongmun)}
21576
21894
  </hh:refList>
21577
21895
  <hh:compatibleDocument targetProgram="HWP2018"><hh:layoutCompatibility/></hh:compatibleDocument>
21578
21896
  </hh:head>`;
@@ -21808,6 +22126,7 @@ function computeGongmunFitPlan(blocks, gongmun, gongmunList) {
21808
22126
  let contW;
21809
22127
  if (block.type === "list_item" && gongmunList.has(i)) {
21810
22128
  const { marker, depth } = gongmunList.get(i);
22129
+ if (gongmun.numbering === "gaejosik" && (depth === 0 || (block.text || "").trimStart().startsWith("\u203B"))) continue;
21811
22130
  const content = plainRenderText(block.text || "");
21812
22131
  text = marker ? `${marker} ${content}` : content;
21813
22132
  const { left, indent } = levelIndent(depth, gongmun.bodyHeight, gongmun.numbering);
@@ -21816,6 +22135,7 @@ function computeGongmunFitPlan(blocks, gongmun, gongmunList) {
21816
22135
  } else if (block.type === "paragraph") {
21817
22136
  const raw = (block.text || "").trim();
21818
22137
  if (/^<center>[\s\S]*<\/center>$/i.test(raw)) continue;
22138
+ if (gongmun.numbering === "gaejosik" && raw.startsWith("\u203B")) continue;
21819
22139
  text = plainRenderText(raw);
21820
22140
  firstW = contW = pageW;
21821
22141
  } else {
@@ -21829,14 +22149,15 @@ function computeGongmunFitPlan(blocks, gongmun, gongmunList) {
21829
22149
  }
21830
22150
  return ratioByBlock.size > 0 ? { ratioByBlock, variants } : null;
21831
22151
  }
21832
- function variantMapper(fit, blockIdx) {
22152
+ function variantMapper(fit, blockIdx, base = CHAR_VARIANT_BASE) {
21833
22153
  const r = fit.ratioByBlock.get(blockIdx);
21834
22154
  if (r === void 0) return void 0;
21835
22155
  const vi = fit.variants.indexOf(r);
21836
- return (id) => id >= 0 && id <= 3 ? CHAR_VARIANT_BASE + vi * 4 + id : id;
22156
+ return (id) => id >= 0 && id <= 3 ? base + vi * 4 + id : id;
21837
22157
  }
21838
22158
  function precomputeGongmunList(blocks, gongmun) {
21839
22159
  const result = /* @__PURE__ */ new Map();
22160
+ const depthOffset = gongmun.numbering === "gaejosik" && blocks.some((b) => b.type === "heading" && b.level === 3) ? 1 : 0;
21840
22161
  let i = 0;
21841
22162
  while (i < blocks.length) {
21842
22163
  if (blocks[i].type !== "list_item") {
@@ -21862,7 +22183,7 @@ function precomputeGongmunList(blocks, gongmun) {
21862
22183
  }
21863
22184
  break;
21864
22185
  }
21865
- const depths = run.map((bi) => Math.min(Math.max(blocks[bi].indent || 0, 0), GONGMUN_LIST_LEVELS - 1));
22186
+ const depths = run.map((bi) => Math.min(Math.max((blocks[bi].indent || 0) + depthOffset, 0), GONGMUN_LIST_LEVELS - 1));
21866
22187
  const suppress = gongmun.numbering === "standard" ? computeSuppression(depths) : depths.map(() => false);
21867
22188
  const numberer = new GongmunNumberer(gongmun.numbering);
21868
22189
  run.forEach((bi, k) => {
@@ -21873,6 +22194,98 @@ function precomputeGongmunList(blocks, gongmun) {
21873
22194
  return result;
21874
22195
  }
21875
22196
 
22197
+ // src/hwpx/gen-gaejosik.ts
22198
+ function chapterRoman(n) {
22199
+ if (n >= 1 && n <= 12) return String.fromCodePoint(8543 + n);
22200
+ const t = [[10, "\u2169"], [9, "\u2168"], [5, "\u2164"], [4, "\u2163"], [1, "\u2160"]];
22201
+ let s = "";
22202
+ for (const [v, r] of t) while (n >= v) {
22203
+ s += r;
22204
+ n -= v;
22205
+ }
22206
+ return s;
22207
+ }
22208
+ function emptyPara(paraPrId = PARA_NORMAL, pageBreak = false, charPrId = CHAR_NORMAL) {
22209
+ const brk = pageBreak ? ` pageBreak="1"` : "";
22210
+ return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0"${brk}><hp:run charPrIDRef="${charPrId}"><hp:t></hp:t></hp:run></hp:p>`;
22211
+ }
22212
+ var gjTableId = 92e5;
22213
+ function cell(opts) {
22214
+ const paras = opts.paras ?? emptyPara();
22215
+ 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>`;
22216
+ }
22217
+ function table(rows, w, h, cols, tblBf = 1) {
22218
+ 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>`;
22219
+ }
22220
+ function buildGaejosikCover(title, gongmun) {
22221
+ const g = coverGeom(gongmun.bodyHeight, gongmun.sizes);
22222
+ const sz = gaejosikSizes(gongmun.bodyHeight, gongmun.sizes);
22223
+ const innerW = g.totalW - 282;
22224
+ const titleCharPr = simulateWrap(title, innerW, innerW, sz.coverTitle, 100, "keep").lines > 2 ? GJ_CHAR_COVER_SUB : GJ_CHAR_COVER_TITLE;
22225
+ const titlePara = `<hp:p paraPrIDRef="${GJ_PARA_COVER}" styleIDRef="0"><hp:run charPrIDRef="${titleCharPr}"><hp:t>${escapeXml(title)}</hp:t></hp:run></hp:p>`;
22226
+ const barEmpty = emptyPara(GJ_PARA_BAR, false, GJ_CHAR_BAR);
22227
+ 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 });
22228
+ const titleRow = cell({ bf: 1, col: 0, colSpan: 3, row: 1, w: g.totalW, h: g.titleH, paras: titlePara });
22229
+ 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 });
22230
+ const tbl2 = table([topRow, titleRow, botRow], g.totalW, g.barH + g.titleH + g.botBarH, 3);
22231
+ const host = `<hp:p paraPrIDRef="${PARA_NORMAL}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_NORMAL}">${tbl2}</hp:run></hp:p>`;
22232
+ const date = gongmun.cover?.date ?? formatGaejosikDate(/* @__PURE__ */ new Date());
22233
+ const org = gongmun.cover?.org ?? "";
22234
+ 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>`;
22235
+ const subEmpty = emptyPara(GJ_PARA_COVER, false, GJ_CHAR_COVER_SUB);
22236
+ return [
22237
+ ...Array(5).fill(emptyPara()),
22238
+ host,
22239
+ ...Array(5).fill(emptyPara()),
22240
+ sub(date),
22241
+ ...org ? [...Array(4).fill(subEmpty), sub(org)] : []
22242
+ ];
22243
+ }
22244
+ function buildTocBanner(gongmun) {
22245
+ const g = tocBannerGeom(gongmun.bodyHeight, gongmun.sizes);
22246
+ const bfs = [GJ_BF_BAR_DARK, 1, GJ_BF_TOC_STRIPE, 1, GJ_BF_TOC_STRIPE, 1, GJ_BF_BAR_DARK];
22247
+ const filler = emptyPara(GJ_PARA_BAR, false, GJ_CHAR_BAR);
22248
+ 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>`;
22249
+ const row = g.colWs.map(
22250
+ (w, c) => cell({ bf: bfs[c], col: c, w, h: g.h, paras: c === 3 ? label : filler })
22251
+ ).join("");
22252
+ const banner = table([row], g.colWs.reduce((a, b) => a + b, 0), g.h, 7, 2);
22253
+ return `<hp:p paraPrIDRef="${GJ_PARA_BAR}" styleIDRef="0" pageBreak="1"><hp:run charPrIDRef="${CHAR_NORMAL}">${banner}</hp:run></hp:p>`;
22254
+ }
22255
+ function buildGaejosikToc(chapters, gongmun) {
22256
+ const label = buildTocBanner(gongmun);
22257
+ const items = chapters.map(
22258
+ (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>`
22259
+ ).join("");
22260
+ const box = table(
22261
+ [cell({ bf: GJ_BF_TOC_BOX, col: 0, w: TOC_GEOM.boxW, h: TOC_GEOM.boxH, paras: items })],
22262
+ TOC_GEOM.boxW,
22263
+ TOC_GEOM.boxH,
22264
+ 1
22265
+ );
22266
+ const host = `<hp:p paraPrIDRef="${GJ_PARA_BAR}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_NORMAL}">${box}</hp:run></hp:p>`;
22267
+ return [label, emptyPara(GJ_PARA_BAR, false, GJ_CHAR_BAR), host];
22268
+ }
22269
+ function buildGaejosikBodyTitle(title, gongmun) {
22270
+ const g = COVER_GEOM;
22271
+ const bt = bodyTitleGeom(gongmun.bodyHeight, gongmun.sizes);
22272
+ const barEmpty = emptyPara(GJ_PARA_BAR, false, GJ_CHAR_BAR);
22273
+ 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>`;
22274
+ 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 });
22275
+ const titleRow = cell({ bf: 1, col: 0, colSpan: 3, row: 1, w: g.totalW, h: bt.titleH, paras: titlePara });
22276
+ 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 });
22277
+ const box = table([topRow, titleRow, botRow], g.totalW, bt.barH * 2 + bt.titleH, 3);
22278
+ return `<hp:p paraPrIDRef="${PARA_NORMAL}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_NORMAL}">${box}</hp:run></hp:p>`;
22279
+ }
22280
+ function buildGaejosikChapter(n, title, gongmun) {
22281
+ const g = gongmun ? chapterGeom(gongmun.bodyHeight, gongmun.sizes) : chapterGeom(1500);
22282
+ 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>`;
22283
+ 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>`;
22284
+ 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 });
22285
+ const tbl2 = table([row], g.numW + g.gapW + g.titleW, g.rowH, 3);
22286
+ return `<hp:p paraPrIDRef="${GJ_PARA_CHAPTER}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_NORMAL}">${tbl2}</hp:run></hp:p>`;
22287
+ }
22288
+
21876
22289
  // src/diff/text-diff.ts
21877
22290
  function similarity(a, b) {
21878
22291
  if (a === b) return 1;
@@ -22070,8 +22483,8 @@ function summarize(text) {
22070
22483
  const t = text.replace(/\s+/g, " ").trim();
22071
22484
  return t.length > 80 ? t.slice(0, 77) + "..." : t;
22072
22485
  }
22073
- function replicateGfmTable(table) {
22074
- const { cells, rows: numRows, cols: numCols } = table;
22486
+ function replicateGfmTable(table2) {
22487
+ const { cells, rows: numRows, cols: numCols } = table2;
22075
22488
  if (numRows === 0 || numCols === 0) return null;
22076
22489
  if (numRows === 1 && numCols === 1) return null;
22077
22490
  if (numCols === 1) return null;
@@ -22080,28 +22493,28 @@ function replicateGfmTable(table) {
22080
22493
  for (let r = 0; r < numRows; r++) {
22081
22494
  for (let c = 0; c < numCols; c++) {
22082
22495
  if (skip.has(`${r},${c}`)) continue;
22083
- const cell = cells[r]?.[c];
22084
- if (!cell) continue;
22496
+ const cell2 = cells[r]?.[c];
22497
+ if (!cell2) continue;
22085
22498
  display[r][c] = {
22086
- text: escapeGfm(sanitizeText(cell.text)).replace(/\|/g, "\\|").replace(/\n/g, "<br>"),
22499
+ text: escapeGfm(sanitizeText(cell2.text)).replace(/\|/g, "\\|").replace(/\n/g, "<br>"),
22087
22500
  gridR: r,
22088
22501
  gridC: c
22089
22502
  };
22090
- for (let dr = 0; dr < cell.rowSpan; dr++) {
22091
- for (let dc = 0; dc < cell.colSpan; dc++) {
22503
+ for (let dr = 0; dr < cell2.rowSpan; dr++) {
22504
+ for (let dc = 0; dc < cell2.colSpan; dc++) {
22092
22505
  if (dr === 0 && dc === 0) continue;
22093
22506
  if (r + dr < numRows && c + dc < numCols) skip.add(`${r + dr},${c + dc}`);
22094
22507
  }
22095
22508
  }
22096
- c += cell.colSpan - 1;
22509
+ c += cell2.colSpan - 1;
22097
22510
  }
22098
22511
  }
22099
22512
  const uniqueRows = [];
22100
22513
  let pendingLabelRow = null;
22101
22514
  for (let r = 0; r < display.length; r++) {
22102
22515
  const row = display[r];
22103
- if (row.every((cell) => cell.text === "")) continue;
22104
- const nonEmptyCols = row.filter((cell) => cell.text !== "");
22516
+ if (row.every((cell2) => cell2.text === "")) continue;
22517
+ const nonEmptyCols = row.filter((cell2) => cell2.text !== "");
22105
22518
  const hasSkipInRow = row.some((_, c) => skip.has(`${r},${c}`));
22106
22519
  if (!hasSkipInRow && nonEmptyCols.length === 1 && row[0].text !== "" && row.slice(1).every((c) => c.text === "")) {
22107
22520
  if (pendingLabelRow) uniqueRows.push(pendingLabelRow);
@@ -22133,9 +22546,9 @@ function parseGfmTable(lines) {
22133
22546
  function unescapeGfmCell(text) {
22134
22547
  return text.replace(/<br\s*\/?>/gi, "\n").replace(/\\\|/g, "|").replace(/\\([~*])/g, "$1");
22135
22548
  }
22136
- function replicateCellInnerHtml(cell) {
22137
- if (cell.blocks?.length) {
22138
- return cell.blocks.map((b) => {
22549
+ function replicateCellInnerHtml(cell2) {
22550
+ if (cell2.blocks?.length) {
22551
+ return cell2.blocks.map((b) => {
22139
22552
  if (b.type === "table" && b.table) {
22140
22553
  const cap = b.table.caption ? sanitizeText(b.table.caption) : "";
22141
22554
  return (cap ? cap + "<br>" : "") + replicateTableToHtml(b.table);
@@ -22145,27 +22558,27 @@ function replicateCellInnerHtml(cell) {
22145
22558
  return t ? t.replace(/\n/g, "<br>") : "";
22146
22559
  }).filter(Boolean).join("<br>");
22147
22560
  }
22148
- return sanitizeText(cell.text).replace(/\n/g, "<br>");
22561
+ return sanitizeText(cell2.text).replace(/\n/g, "<br>");
22149
22562
  }
22150
- function replicateTableToHtml(table) {
22151
- const rows = replicateHtmlTable(table);
22563
+ function replicateTableToHtml(table2) {
22564
+ const rows = replicateHtmlTable(table2);
22152
22565
  const lines = ["<table>"];
22153
22566
  for (let r = 0; r < rows.length; r++) {
22154
22567
  const tag = rows[r].tag;
22155
- const rowHtml = rows[r].cells.map((cell) => {
22568
+ const rowHtml = rows[r].cells.map((cell2) => {
22156
22569
  const attrs = [];
22157
- if (cell.colSpan > 1) attrs.push(`colspan="${cell.colSpan}"`);
22158
- if (cell.rowSpan > 1) attrs.push(`rowspan="${cell.rowSpan}"`);
22570
+ if (cell2.colSpan > 1) attrs.push(`colspan="${cell2.colSpan}"`);
22571
+ if (cell2.rowSpan > 1) attrs.push(`rowspan="${cell2.rowSpan}"`);
22159
22572
  const attrStr = attrs.length ? " " + attrs.join(" ") : "";
22160
- return `<${tag}${attrStr}>${cell.inner}</${tag}>`;
22573
+ return `<${tag}${attrStr}>${cell2.inner}</${tag}>`;
22161
22574
  });
22162
22575
  if (rowHtml.length) lines.push(`<tr>${rowHtml.join("")}</tr>`);
22163
22576
  }
22164
22577
  lines.push("</table>");
22165
22578
  return lines.join("\n");
22166
22579
  }
22167
- function replicateHtmlTable(table) {
22168
- const { cells, rows: numRows, cols: numCols } = table;
22580
+ function replicateHtmlTable(table2) {
22581
+ const { cells, rows: numRows, cols: numCols } = table2;
22169
22582
  const skip = /* @__PURE__ */ new Set();
22170
22583
  const result = [];
22171
22584
  for (let r = 0; r < numRows; r++) {
@@ -22173,18 +22586,18 @@ function replicateHtmlTable(table) {
22173
22586
  const rowCells = [];
22174
22587
  for (let c = 0; c < numCols; c++) {
22175
22588
  if (skip.has(`${r},${c}`)) continue;
22176
- const cell = cells[r]?.[c];
22177
- if (!cell) continue;
22178
- for (let dr = 0; dr < cell.rowSpan; dr++) {
22179
- for (let dc = 0; dc < cell.colSpan; dc++) {
22589
+ const cell2 = cells[r]?.[c];
22590
+ if (!cell2) continue;
22591
+ for (let dr = 0; dr < cell2.rowSpan; dr++) {
22592
+ for (let dc = 0; dc < cell2.colSpan; dc++) {
22180
22593
  if (dr === 0 && dc === 0) continue;
22181
22594
  if (r + dr < numRows && c + dc < numCols) skip.add(`${r + dr},${c + dc}`);
22182
22595
  }
22183
22596
  }
22184
22597
  rowCells.push({
22185
- inner: replicateCellInnerHtml(cell),
22186
- colSpan: cell.colSpan,
22187
- rowSpan: cell.rowSpan,
22598
+ inner: replicateCellInnerHtml(cell2),
22599
+ colSpan: cell2.colSpan,
22600
+ rowSpan: cell2.rowSpan,
22188
22601
  gridR: r,
22189
22602
  gridC: c
22190
22603
  });
@@ -22289,6 +22702,54 @@ function removeNestedTables(html) {
22289
22702
  return result;
22290
22703
  }
22291
22704
 
22705
+ // src/hwpx/gen-table-bf.ts
22706
+ var THIN = ["0.12 mm", "#000000"];
22707
+ var THICK = ["0.4 mm", "#000000"];
22708
+ var DOUBLE = ["0.5 mm", "#000000", "DOUBLE_SLIM"];
22709
+ var EDGE = { thin: THIN, thick: THICK, double: DOUBLE };
22710
+ function sideOf(kind) {
22711
+ return kind === "none" ? void 0 : EDGE[kind];
22712
+ }
22713
+ var TableBfRegistry = class {
22714
+ constructor(nextId) {
22715
+ this.nextId = nextId;
22716
+ }
22717
+ map = /* @__PURE__ */ new Map();
22718
+ xmls = [];
22719
+ get(spec) {
22720
+ const key = `${spec.t}|${spec.b}|${spec.l}|${spec.r}|${typeof spec.fill === "string" ? spec.fill : spec.fill ? spec.fill.gradient.join("-") : ""}`;
22721
+ const hit = this.map.get(key);
22722
+ if (hit !== void 0) return hit;
22723
+ const id = this.nextId++;
22724
+ this.map.set(key, id);
22725
+ this.xmls.push(
22726
+ borderFillEntry(id, { t: sideOf(spec.t), b: sideOf(spec.b), l: sideOf(spec.l), r: sideOf(spec.r) }, spec.fill)
22727
+ );
22728
+ return id;
22729
+ }
22730
+ /** 등록된 borderFill XML 목록 (등록 순서 = id 순서) */
22731
+ emit() {
22732
+ return this.xmls;
22733
+ }
22734
+ get count() {
22735
+ return this.xmls.length;
22736
+ }
22737
+ };
22738
+ function dataCellSpec(opts) {
22739
+ const { row, rowEnd, col, colEnd, rowCnt, colCnt, headerRows, fill } = opts;
22740
+ const isTop = row === 0;
22741
+ const isBottom = rowEnd === rowCnt - 1;
22742
+ const isHeaderBottom = headerRows > 0 && rowEnd === headerRows - 1;
22743
+ const isBelowHeader = headerRows > 0 && row === headerRows;
22744
+ return {
22745
+ t: isTop ? "thick" : isBelowHeader ? "double" : "thin",
22746
+ b: isBottom ? "thick" : isHeaderBottom ? "double" : "thin",
22747
+ l: col === 0 ? "thick" : "thin",
22748
+ r: colEnd === colCnt - 1 ? "thick" : "thin",
22749
+ fill
22750
+ };
22751
+ }
22752
+
22292
22753
  // src/hwpx/gen-profile.ts
22293
22754
  function normalizeAnchor(s) {
22294
22755
  return s.toLowerCase().replace(/[^\p{L}\p{N}]/gu, "").slice(0, 24);
@@ -22380,24 +22841,21 @@ function buildProfileRemap(profile, charPrBase, borderFillBase = 3) {
22380
22841
  cellChar: /* @__PURE__ */ new Map(),
22381
22842
  cellH: /* @__PURE__ */ new Map()
22382
22843
  };
22383
- for (const cell of t.cells) {
22384
- const k = `${cell.row},${cell.col}`;
22385
- if (cell.borderFillIDRef != null && cell.borderFillIDRef in localBf) {
22386
- tr.cellBf.set(k, localBf[cell.borderFillIDRef]);
22844
+ for (const cell2 of t.cells) {
22845
+ const k = `${cell2.row},${cell2.col}`;
22846
+ if (cell2.borderFillIDRef != null && cell2.borderFillIDRef in localBf) {
22847
+ tr.cellBf.set(k, localBf[cell2.borderFillIDRef]);
22387
22848
  }
22388
- if (cell.charPrIDRef != null && cell.charPrIDRef in localChar) {
22389
- tr.cellChar.set(k, localChar[cell.charPrIDRef]);
22849
+ if (cell2.charPrIDRef != null && cell2.charPrIDRef in localChar) {
22850
+ tr.cellChar.set(k, localChar[cell2.charPrIDRef]);
22390
22851
  }
22391
- const h = parseHu(cell.height_hwpunit);
22852
+ const h = parseHu(cell2.height_hwpunit);
22392
22853
  if (h != null) tr.cellH.set(k, h);
22393
22854
  }
22394
22855
  remap.tables.push(tr);
22395
22856
  }
22396
22857
  return remap;
22397
22858
  }
22398
- function profileCharPrBase(ratioVariantCount) {
22399
- return CHAR_VARIANT_BASE + ratioVariantCount * 4;
22400
- }
22401
22859
 
22402
22860
  // src/hwpx/gen-table.ts
22403
22861
  var TABLE_ID_BASE = 1e3;
@@ -22405,47 +22863,141 @@ var tableIdCounter = TABLE_ID_BASE;
22405
22863
  function nextTableId() {
22406
22864
  return ++tableIdCounter;
22407
22865
  }
22408
- function anchorOfMarkdownCell(cell) {
22409
- return normalizeAnchor(cell.replace(/!\[[^\]]*\]\([^)]*\)/g, ""));
22866
+ var DATA_TABLE_INSET = 1800;
22867
+ function anchorOfMarkdownCell(cell2) {
22868
+ return normalizeAnchor(cell2.replace(/!\[[^\]]*\]\([^)]*\)/g, ""));
22410
22869
  }
22411
22870
  function anchorOfHtmlCell(inner) {
22412
22871
  const noNested = inner.replace(/<table[\s\S]*?<\/table>/gi, "");
22413
22872
  const { lines } = htmlCellInnerToLines(noNested);
22414
22873
  return normalizeAnchor(lines.join(""));
22415
22874
  }
22416
- function resolveColWidths(tp, colCnt, fallbackTotal) {
22417
- if (tp?.colWidths && tp.colWidths.length === colCnt) return tp.colWidths;
22418
- const w = tp?.width ? Math.floor(tp.width / colCnt) : Math.floor(fallbackTotal / colCnt);
22419
- return Array(colCnt).fill(w);
22875
+ function profileColWidths(tp, colCnt) {
22876
+ if (!tp) return null;
22877
+ if (tp.colWidths && tp.colWidths.length === colCnt) return tp.colWidths;
22878
+ if (tp.width) return Array(colCnt).fill(Math.floor(tp.width / colCnt));
22879
+ return null;
22880
+ }
22881
+ var CELL_PAD = 582;
22882
+ function cellContentWidth(text, charHeight) {
22883
+ let max = 0;
22884
+ for (const seg of text.replace(/\*\*|__|`/g, "").split(/<br\s*\/?>/i)) {
22885
+ const w = measureTextWidth(seg.trim(), charHeight, 100);
22886
+ if (w > max) max = w;
22887
+ }
22888
+ return max;
22889
+ }
22890
+ function computeColWidths(colMax, totalWidth) {
22891
+ const colCnt = colMax.length;
22892
+ const minW = Math.min(Math.max(2e3, Math.round(totalWidth * 0.06)), Math.floor(totalWidth / colCnt));
22893
+ const cap = Math.round(totalWidth * 0.8);
22894
+ const raw = colMax.map((w) => Math.min(Math.max(w + CELL_PAD, minW), cap));
22895
+ const widths = Array(colCnt).fill(0);
22896
+ const free = new Set(raw.map((_, i) => i));
22897
+ let budget = totalWidth;
22898
+ const evenShare = Math.floor(totalWidth / colCnt);
22899
+ for (let i = 0; i < colCnt; i++) {
22900
+ const fixed = Math.min(Math.round(raw[i] * 1.12), evenShare);
22901
+ if (raw[i] <= evenShare && free.size > 1) {
22902
+ widths[i] = fixed;
22903
+ free.delete(i);
22904
+ budget -= fixed;
22905
+ }
22906
+ }
22907
+ if (free.size === 0) {
22908
+ const sumRaw = raw.reduce((a, b) => a + b, 0);
22909
+ for (let i = 0; i < colCnt; i++) widths[i] += Math.floor(raw[i] / sumRaw * (totalWidth - sumRaw));
22910
+ } else {
22911
+ for (; ; ) {
22912
+ const sum2 = [...free].reduce((a, i) => a + raw[i], 0);
22913
+ const short = [...free].filter((i) => raw[i] / sum2 * budget < minW);
22914
+ if (short.length === 0) break;
22915
+ for (const i of short) {
22916
+ widths[i] = minW;
22917
+ free.delete(i);
22918
+ budget -= minW;
22919
+ }
22920
+ if (free.size === 0) break;
22921
+ }
22922
+ const sum = [...free].reduce((a, i) => a + raw[i], 0);
22923
+ for (const i of free) widths[i] = Math.floor(raw[i] / sum * budget);
22924
+ }
22925
+ let rem = totalWidth - widths.reduce((a, b) => a + b, 0);
22926
+ const order = [...raw.keys()].sort((a, b) => raw[b] - raw[a]);
22927
+ for (let k = 0; rem > 0; k = (k + 1) % colCnt, rem--) widths[order[k]]++;
22928
+ return widths;
22929
+ }
22930
+ function estimateRowHeight(cells, widths, charHeight) {
22931
+ let maxLines = 1;
22932
+ cells.forEach((cell2, c) => {
22933
+ const usable = Math.max((widths[c] ?? widths[widths.length - 1]) - CELL_PAD, 1e3);
22934
+ let lines = 0;
22935
+ for (const seg of cell2.replace(/\*\*|__|`/g, "").split(/<br\s*\/?>/i)) {
22936
+ lines += Math.max(1, Math.ceil(measureTextWidth(seg.trim(), charHeight, 100) / usable));
22937
+ }
22938
+ if (lines > maxLines) maxLines = lines;
22939
+ });
22940
+ return maxLines * Math.round(charHeight * 1.6) + 282;
22420
22941
  }
22421
- function generateTable(rows, theme, remap = null, seq = 0) {
22942
+ function generateTable(rows, theme, style = null, remap = null, seq = 0) {
22422
22943
  const rowCnt = rows.length;
22423
22944
  const colCnt = Math.max(...rows.map((r) => r.length), 1);
22424
- const cellH = 1500;
22425
- const tblId = nextTableId();
22945
+ const reg = style?.bfRegistry ?? null;
22946
+ const totalW = style ? reg ? style.totalWidth - DATA_TABLE_INSET : style.totalWidth : 44e3;
22947
+ const measureH = style?.charHeight ?? 1e3;
22426
22948
  const prof = takeProfile(remap, rowCnt, colCnt, anchorOfMarkdownCell(rows[0]?.[0] ?? ""), seq);
22427
- const colW = resolveColWidths(prof, colCnt, 44e3);
22428
- const tblW = colW.reduce((a, b) => a + b, 0);
22429
- const tblH = cellH * rowCnt;
22430
- const useHeaderStyle = theme.tableHeader !== theme.body || theme.tableHeaderBold;
22949
+ const colMax = Array(colCnt).fill(0);
22950
+ const colMaxBody = Array(colCnt).fill(0);
22951
+ rows.forEach((row, r) => row.forEach((cell2, c) => {
22952
+ const w = cellContentWidth(cell2, measureH);
22953
+ if (w > colMax[c]) colMax[c] = w;
22954
+ if (r > 0 && w > colMaxBody[c]) colMaxBody[c] = w;
22955
+ }));
22956
+ const colWidths = profileColWidths(prof, colCnt) ?? computeColWidths(colMax, totalW);
22957
+ const colCentered = colWidths.map((w, c) => colMaxBody[c] + CELL_PAD <= w);
22958
+ const labelCol0 = !!reg && colCnt === 2 && colCentered[0] && rows.every((r) => (r[0] ?? "").replace(/\*\*|__|`/g, "").length <= 12);
22959
+ const tblId = nextTableId();
22960
+ const useHeaderStyle = !style && (theme.tableHeader !== theme.body || theme.tableHeaderBold);
22961
+ const mapId = style ? (id) => id === CHAR_NORMAL ? style.charPr : id === CHAR_BOLD ? style.boldCharPr : id : void 0;
22962
+ const rowHeights = rows.map((row) => style ? estimateRowHeight(row, colWidths, measureH) : 1500);
22431
22963
  const trElements = rows.map((row, rowIdx) => {
22432
22964
  const cells = row.length < colCnt ? [...row, ...Array(colCnt - row.length).fill("")] : row;
22433
22965
  const isHeaderRow = rowIdx === 0;
22434
- const headerCharPr = isHeaderRow && useHeaderStyle ? CHAR_TABLE_HEADER : CHAR_NORMAL;
22435
- const tdElements = cells.map((cell, colIdx) => {
22966
+ const cellH = rowHeights[rowIdx];
22967
+ const baseCharPr = style ? style.charPr : CHAR_NORMAL;
22968
+ const headerCharPr = isHeaderRow && useHeaderStyle ? CHAR_TABLE_HEADER : baseCharPr;
22969
+ const tdElements = cells.map((cell2, colIdx) => {
22436
22970
  const k = `${rowIdx},${colIdx}`;
22437
- const bf = prof?.cellBf.get(k) ?? 2;
22438
- const ch = prof?.cellChar.get(k) ?? headerCharPr;
22971
+ const isLabelCell2 = labelCol0 && colIdx === 0;
22972
+ const defaultCharPr = style ? reg && (isHeaderRow || isLabelCell2) ? style.boldCharPr : style.charPr : isHeaderRow ? headerCharPr : baseCharPr;
22973
+ const cellCharPr = prof?.cellChar.get(k) ?? defaultCharPr;
22974
+ const centered = isHeaderRow || colCentered[colIdx];
22975
+ const paraPrId = style ? centered ? style.tblCenterParaPr ?? style.centerParaPr : reg ? style.tblLeftParaPr ?? PARA_NORMAL : PARA_NORMAL : PARA_NORMAL;
22976
+ const p = cell2.split(/<br\s*\/?>/i).map((seg) => {
22977
+ const runs = generateRuns(seg, cellCharPr, prof?.cellChar.has(k) ? void 0 : mapId);
22978
+ return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0">${runs || `<hp:run charPrIDRef="${cellCharPr}"><hp:t></hp:t></hp:run>`}</hp:p>`;
22979
+ }).join("");
22980
+ const bf = prof?.cellBf.get(k) ?? (reg ? reg.get(dataCellSpec({
22981
+ row: rowIdx,
22982
+ rowEnd: rowIdx,
22983
+ col: colIdx,
22984
+ colEnd: colIdx,
22985
+ rowCnt,
22986
+ colCnt,
22987
+ headerRows: 1,
22988
+ fill: isHeaderRow ? style.headerFill ?? "#E6E6E6" : isLabelCell2 ? style.labelFill ?? "#E7E7E7" : void 0
22989
+ })) : style && isHeaderRow ? style.headerBf : 2);
22439
22990
  const h = prof?.cellH.get(k) ?? cellH;
22440
- const runs = generateRuns(cell, ch);
22441
- const p = `<hp:p paraPrIDRef="0" styleIDRef="0">${runs}</hp:p>`;
22442
- 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>`;
22991
+ 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>`;
22443
22992
  }).join("");
22444
22993
  return `<hp:tr>${tdElements}</hp:tr>`;
22445
22994
  }).join("");
22995
+ const tblW = colWidths.reduce((a, b) => a + b, 0);
22996
+ const tblH = rowHeights.reduce((a, b) => a + b, 0);
22446
22997
  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;
22447
- 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>`;
22448
- return `<hp:p paraPrIDRef="0" styleIDRef="0"><hp:run charPrIDRef="0">${tbl}</hp:run></hp:p>`;
22998
+ 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>`;
22999
+ const hostPr = reg && style?.rightParaPr !== void 0 ? style.rightParaPr : 0;
23000
+ return `<hp:p paraPrIDRef="${hostPr}" styleIDRef="0"><hp:run charPrIDRef="0">${tbl2}</hp:run></hp:p>`;
22449
23001
  }
22450
23002
  function layoutHtmlRows(rows) {
22451
23003
  const occupied = /* @__PURE__ */ new Set();
@@ -22453,11 +23005,11 @@ function layoutHtmlRows(rows) {
22453
23005
  let colCnt = 0;
22454
23006
  for (let r = 0; r < rows.length; r++) {
22455
23007
  let c = 0;
22456
- for (const cell of rows[r].cells) {
23008
+ for (const cell2 of rows[r].cells) {
22457
23009
  while (occupied.has(`${r},${c}`)) c++;
22458
- const colSpan = Math.max(1, cell.colSpan);
22459
- const rowSpan = Math.max(1, cell.rowSpan);
22460
- placed.push({ r, c, colSpan, rowSpan, inner: cell.inner, isHeader: rows[r].tag === "th" });
23010
+ const colSpan = Math.max(1, cell2.colSpan);
23011
+ const rowSpan = Math.max(1, cell2.rowSpan);
23012
+ placed.push({ r, c, colSpan, rowSpan, inner: cell2.inner, isHeader: rows[r].tag === "th" });
22461
23013
  for (let dr = 0; dr < rowSpan; dr++) {
22462
23014
  for (let dc = 0; dc < colSpan; dc++) occupied.add(`${r + dr},${c + dc}`);
22463
23015
  }
@@ -22470,50 +23022,135 @@ function layoutHtmlRows(rows) {
22470
23022
  function unescapeHtml(s) {
22471
23023
  return s.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&amp;/g, "&");
22472
23024
  }
22473
- function generateHtmlTableXml(rawHtml, theme, totalWidth = 44e3, remap = null, seq = 0) {
23025
+ function generateHtmlTableXml(rawHtml, theme, totalWidth = 44e3, style = null, remap = null, seq = 0) {
22474
23026
  const rows = parseHtmlTable(rawHtml);
22475
23027
  if (!rows || rows.length === 0) return null;
22476
23028
  const { placed, rowCnt, colCnt } = layoutHtmlRows(rows);
22477
23029
  if (rowCnt === 0 || colCnt === 0) return null;
22478
- const cellH = 1500;
22479
- const tblId = nextTableId();
23030
+ const measureH = style?.charHeight ?? 1e3;
22480
23031
  const first = placed.find((p) => p.r === 0 && p.c === 0) ?? placed[0];
22481
23032
  const prof = takeProfile(remap, rowCnt, colCnt, first ? anchorOfHtmlCell(first.inner) : "", seq);
22482
- const colW = resolveColWidths(prof, colCnt, totalWidth);
22483
- const tblW = colW.reduce((a, b) => a + b, 0);
22484
- const useHeaderStyle = theme.tableHeader !== theme.body || theme.tableHeaderBold;
22485
- const spanW = (c, colSpan) => colW.slice(c, c + colSpan).reduce((a, b) => a + b, 0);
22486
- const tcXmls = placed.map((cell) => {
22487
- const k = `${cell.r},${cell.c}`;
22488
- const bf = prof?.cellBf.get(k) ?? 2;
22489
- const headerCharPr = cell.isHeader && useHeaderStyle ? CHAR_TABLE_HEADER : CHAR_NORMAL;
22490
- const ch = prof?.cellChar.get(k) ?? headerCharPr;
22491
- const { lines } = htmlCellInnerToLines(cell.inner);
23033
+ const colMax = Array(colCnt).fill(0);
23034
+ const colMaxBody = Array(colCnt).fill(0);
23035
+ const cellLines = placed.map((cell2) => htmlCellInnerToLines(cell2.inner).lines);
23036
+ placed.forEach((cell2, i) => {
23037
+ const w = Math.max(...cellLines[i].map((l) => measureTextWidth(unescapeHtml(l).trim(), measureH, 100)), 0) / cell2.colSpan;
23038
+ for (let dc = 0; dc < cell2.colSpan; dc++) {
23039
+ const c = cell2.c + dc;
23040
+ if (w > colMax[c]) colMax[c] = w;
23041
+ if (!cell2.isHeader && w > colMaxBody[c]) colMaxBody[c] = w;
23042
+ }
23043
+ });
23044
+ const colWidths = profileColWidths(prof, colCnt) ?? computeColWidths(colMax, totalWidth);
23045
+ const colCentered = colWidths.map((w, c) => colMaxBody[c] + CELL_PAD <= w);
23046
+ const cellH = style ? Math.round(measureH * 1.6) + 282 : 1500;
23047
+ const tblW = colWidths.reduce((a, b) => a + b, 0);
23048
+ const tblId = nextTableId();
23049
+ const useHeaderStyle = !style && (theme.tableHeader !== theme.body || theme.tableHeaderBold);
23050
+ const spanW = (cell2) => colWidths.slice(cell2.c, cell2.c + cell2.colSpan).reduce((a, b) => a + b, 0);
23051
+ const reg = style?.bfRegistry ?? null;
23052
+ let htmlHeaderRows = 0;
23053
+ while (htmlHeaderRows < rows.length && rows[htmlHeaderRows].tag === "th") htmlHeaderRows++;
23054
+ const tcXmls = placed.map((cell2, i) => {
23055
+ const k = `${cell2.r},${cell2.c}`;
23056
+ const isHeader = cell2.isHeader;
23057
+ const baseCharPr = style ? style.charPr : CHAR_NORMAL;
23058
+ const headerCharPr = isHeader && useHeaderStyle ? CHAR_TABLE_HEADER : baseCharPr;
23059
+ const defaultCharPr = style && reg && isHeader ? style.boldCharPr : isHeader ? headerCharPr : baseCharPr;
23060
+ const charPrId = prof?.cellChar.get(k) ?? defaultCharPr;
23061
+ const centered = isHeader || colCentered[cell2.c];
23062
+ const paraPrId = style ? centered ? reg ? style.tblCenterParaPr ?? style.centerParaPr : style.centerParaPr : reg ? style.tblLeftParaPr ?? PARA_NORMAL : PARA_NORMAL : PARA_NORMAL;
23063
+ const lines = cellLines[i];
22492
23064
  const paras = lines.map(
22493
- (line) => `<hp:p paraPrIDRef="0" styleIDRef="0"><hp:run charPrIDRef="${ch}"><hp:t>${escapeXml(unescapeHtml(line))}</hp:t></hp:run></hp:p>`
23065
+ (line) => `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0"><hp:run charPrIDRef="${charPrId}"><hp:t>${escapeXml(unescapeHtml(line))}</hp:t></hp:run></hp:p>`
22494
23066
  );
22495
- const cellW = spanW(cell.c, cell.colSpan);
22496
23067
  let nestedH = 0;
22497
- for (const nested of extractTopLevelTables(cell.inner)) {
22498
- const nestedXml = generateHtmlTableXml(nested, theme, Math.max(cellW - 1020, 4e3));
23068
+ for (const nested of extractTopLevelTables(cell2.inner)) {
23069
+ const nestedW = Math.max(spanW(cell2) - 1020, 4e3);
23070
+ const nestedXml = generateHtmlTableXml(nested, theme, nestedW, style ? { ...style, totalWidth: nestedW } : null);
22499
23071
  if (nestedXml) {
22500
23072
  paras.push(`<hp:p paraPrIDRef="0" styleIDRef="0"><hp:run charPrIDRef="0">${nestedXml}</hp:run></hp:p>`);
22501
23073
  nestedH += (nested.match(/<tr[\s>]/gi) ?? []).length * cellH + 300;
22502
23074
  }
22503
23075
  }
22504
23076
  if (paras.length === 0) {
22505
- paras.push(`<hp:p paraPrIDRef="0" styleIDRef="0"><hp:run charPrIDRef="${ch}"><hp:t></hp:t></hp:run></hp:p>`);
23077
+ paras.push(`<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0"><hp:run charPrIDRef="${charPrId}"><hp:t></hp:t></hp:run></hp:p>`);
22506
23078
  }
22507
- const contentH = Math.max(cellH * cell.rowSpan, Math.max(lines.length, 1) * 800 + nestedH);
23079
+ const contentH = Math.max(cellH * cell2.rowSpan, Math.max(lines.length, 1) * (style ? Math.round(measureH * 1.6) : 800) + nestedH);
22508
23080
  const cellHeight = Math.max(prof?.cellH.get(k) ?? 0, contentH);
22509
- 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>`;
23081
+ const bf = prof?.cellBf.get(k) ?? (reg ? reg.get(dataCellSpec({
23082
+ row: cell2.r,
23083
+ rowEnd: cell2.r + cell2.rowSpan - 1,
23084
+ col: cell2.c,
23085
+ colEnd: cell2.c + cell2.colSpan - 1,
23086
+ rowCnt,
23087
+ colCnt,
23088
+ headerRows: htmlHeaderRows,
23089
+ fill: isHeader ? style.headerFill ?? "#E6E6E6" : void 0
23090
+ })) : style && isHeader ? style.headerBf : 2);
23091
+ 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>`;
22510
23092
  });
22511
23093
  const trXmls = [];
22512
23094
  for (let r = 0; r < rowCnt; r++) {
22513
23095
  const rowTcs = tcXmls.filter((_, i) => placed[i].r === r);
22514
23096
  trXmls.push(`<hp:tr>${rowTcs.join("")}</hp:tr>`);
22515
23097
  }
22516
- 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>`;
23098
+ 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>`;
23099
+ }
23100
+
23101
+ // src/hwpx/gen-gongmun-extra.ts
23102
+ var extraTableId = 93e5;
23103
+ function tbl(rows, w, h, cols) {
23104
+ 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>`;
23105
+ }
23106
+ function tc(opts) {
23107
+ 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>`;
23108
+ }
23109
+ function para(text, paraPrId, charPrId) {
23110
+ return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0"><hp:run charPrIDRef="${charPrId}"><hp:t>${escapeXml(text)}</hp:t></hp:run></hp:p>`;
23111
+ }
23112
+ var APPROVAL_COL_W = 7085;
23113
+ var APPROVAL_LABEL_H = 1100;
23114
+ var APPROVAL_SIGN_H = 4200;
23115
+ function buildApprovalTable(labels, gongmun, reg) {
23116
+ const n = labels.length;
23117
+ const w = APPROVAL_COL_W * n;
23118
+ const bfAt = (row, col) => reg.get({
23119
+ t: row === 0 ? "thick" : "thin",
23120
+ b: row === 1 ? "thick" : "thin",
23121
+ l: col === 0 ? "thick" : "thin",
23122
+ r: col === n - 1 ? "thick" : "thin"
23123
+ });
23124
+ const labelRow = labels.map(
23125
+ (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) })
23126
+ ).join("");
23127
+ const signRow = labels.map(
23128
+ (_, 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) })
23129
+ ).join("");
23130
+ const table2 = tbl([labelRow, signRow], w, APPROVAL_LABEL_H + APPROVAL_SIGN_H, n);
23131
+ return `<hp:p paraPrIDRef="${GONGMUN_RIGHT}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_NORMAL}">${table2}</hp:run></hp:p>`;
23132
+ }
23133
+ function hasEndMark(lastText) {
23134
+ return /끝\s*\.?\s*$/.test(lastText.trim());
23135
+ }
23136
+ function buildEndMark() {
23137
+ return para(" \uB05D.", PARA_NORMAL, CHAR_NORMAL);
23138
+ }
23139
+ var TITLE_BOX = { barH: 382, titleH: 2850, color: "#0080C0", gradient: ["#0080C0", "#3CBFFF"] };
23140
+ function buildTitleBox(title, titleCharPr, bodyWidth, reg) {
23141
+ const w = bodyWidth - 280;
23142
+ const outer = { t: "thin", b: "thin", l: "thin", r: "thin" };
23143
+ const barTop = reg.get({ ...outer, fill: TITLE_BOX.color });
23144
+ const barBottom = reg.get({ ...outer, fill: { gradient: TITLE_BOX.gradient } });
23145
+ const mid = reg.get(outer);
23146
+ const barPara = `<hp:p paraPrIDRef="${GONGMUN_TBL_CENTER}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_NORMAL}"><hp:t></hp:t></hp:run></hp:p>`;
23147
+ const rows = [
23148
+ tc({ bf: barTop, row: 0, col: 0, w, h: TITLE_BOX.barH, paras: barPara }),
23149
+ tc({ bf: mid, row: 1, col: 0, w, h: TITLE_BOX.titleH, paras: para(title, GONGMUN_TBL_CENTER, titleCharPr) }),
23150
+ tc({ bf: barBottom, row: 2, col: 0, w, h: TITLE_BOX.barH, paras: barPara })
23151
+ ];
23152
+ const table2 = tbl(rows, w, TITLE_BOX.barH * 2 + TITLE_BOX.titleH, 1);
23153
+ return `<hp:p paraPrIDRef="${PARA_NORMAL}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_NORMAL}">${table2}</hp:run></hp:p>`;
22517
23154
  }
22518
23155
 
22519
23156
  // src/hwpx/equation-generate.ts
@@ -22803,14 +23440,78 @@ function generateSecPr(gongmun) {
22803
23440
  header: 0,
22804
23441
  footer: 0
22805
23442
  } : { top: 8504, bottom: 4252, left: 5670, right: 4252, header: 2835, footer: 2835 };
22806
- 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>`;
23443
+ if (gongmun) {
23444
+ m.header = gongmun.headerFooter;
23445
+ m.footer = gongmun.headerFooter;
23446
+ }
23447
+ 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>`;
23448
+ return gongmun?.pageNumbers ? secPr + pageNumCtrl() : secPr;
22807
23449
  }
22808
- function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null, fit = null, chartParts = null, remap = null) {
23450
+ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null, fit = null, chartParts = null, bfReg = null, remap = null) {
22809
23451
  const paraXmls = [];
22810
23452
  let isFirst = true;
22811
23453
  let tableSeq = 0;
22812
23454
  const orderedCounters = {};
22813
23455
  let prevWasOrdered = false;
23456
+ const gaejosik = gongmun?.preset === "gaejosik";
23457
+ const measured = !!gongmun && usesReportFonts(gongmun.preset);
23458
+ const vBase = charVariantBase(measured);
23459
+ const tableStyle = gongmun ? {
23460
+ totalWidth: mmToHwpunit(210 - gongmun.margins.left - gongmun.margins.right),
23461
+ charPr: measured ? GJ_CHAR_TABLE : CHAR_NORMAL,
23462
+ boldCharPr: measured ? GJ_CHAR_TABLE_BOLD : CHAR_BOLD,
23463
+ charHeight: measured ? gaejosikSizes(gongmun.bodyHeight, gongmun.sizes).table : gongmun.bodyHeight,
23464
+ headerBf: gongmunTableHeaderBf(gaejosik),
23465
+ centerParaPr: GONGMUN_CENTER,
23466
+ tblCenterParaPr: GONGMUN_TBL_CENTER,
23467
+ tblLeftParaPr: GONGMUN_TBL_LEFT,
23468
+ bfRegistry: bfReg ?? void 0,
23469
+ rightParaPr: GONGMUN_RIGHT
23470
+ } : null;
23471
+ const chamMap = (id) => id === CHAR_BOLD ? GJ_CHAR_CHAM_BOLD : id;
23472
+ let chapterNo = 0;
23473
+ let h2Seq = 0;
23474
+ let coverH1Idx = -1;
23475
+ let pendingPageBreak = false;
23476
+ let pendingNewNum = false;
23477
+ let titleBoxH1Idx = -1;
23478
+ let hasFrontPages = false;
23479
+ const preamble = [];
23480
+ if (gongmun?.approval && bfReg) {
23481
+ preamble.push(buildApprovalTable(gongmun.approval, gongmun, bfReg));
23482
+ }
23483
+ if (gaejosik && gongmun) {
23484
+ const h1Idx = blocks.findIndex((b) => b.type === "heading" && (b.level ?? 1) === 1);
23485
+ const chapters = blocks.filter((b) => b.type === "heading" && b.level === 2).map((b) => stripChapterNumber(b.text || ""));
23486
+ let coverTitle = "";
23487
+ const hide = (xml, hideHeader) => gongmun.pageNumbers ? xml.replace(/<hp:run charPrIDRef="(\d+)">/, `<hp:run charPrIDRef="$1">${pageHidingCtrl(hideHeader)}`) : xml;
23488
+ if (gongmun.cover && h1Idx >= 0) {
23489
+ coverTitle = (blocks[h1Idx].text || "").trim();
23490
+ const coverPart = buildGaejosikCover(coverTitle, gongmun);
23491
+ coverPart[0] = hide(coverPart[0], true);
23492
+ preamble.push(...coverPart);
23493
+ coverH1Idx = h1Idx;
23494
+ hasFrontPages = true;
23495
+ }
23496
+ if (gongmun.toc && chapters.length > 0) {
23497
+ const tocPart = buildGaejosikToc(chapters, gongmun);
23498
+ tocPart[0] = hide(tocPart[0], false);
23499
+ preamble.push(...tocPart);
23500
+ hasFrontPages = true;
23501
+ }
23502
+ if (gongmun.bodyTitleBox && coverTitle && hasFrontPages) {
23503
+ preamble.push(buildGaejosikBodyTitle(coverTitle, gongmun).replace(/^<hp:p /, `<hp:p pageBreak="1" `));
23504
+ }
23505
+ } else if (gongmun && !gaejosik && bfReg && (gongmun.preset === "report" || gongmun.preset === "plan" || gongmun.preset === "notice")) {
23506
+ titleBoxH1Idx = blocks.findIndex((b) => b.type === "heading" && (b.level ?? 1) === 1);
23507
+ }
23508
+ if (preamble.length > 0) {
23509
+ preamble[0] = preamble[0].replace(` pageBreak="1"`, "").replace(/<hp:run charPrIDRef="(\d+)">/, `<hp:run charPrIDRef="$1">${generateSecPr(gongmun)}`);
23510
+ isFirst = false;
23511
+ pendingPageBreak = hasFrontPages && !preamble[preamble.length - 1].includes(`pageBreak="1"`);
23512
+ pendingNewNum = !!gongmun.pageNumbers && hasFrontPages;
23513
+ paraXmls.push(...preamble);
23514
+ }
22814
23515
  for (let blockIdx = 0; blockIdx < blocks.length; blockIdx++) {
22815
23516
  const block = blocks[blockIdx];
22816
23517
  let xml = "";
@@ -22822,17 +23523,52 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
22822
23523
  }
22823
23524
  switch (block.type) {
22824
23525
  case "heading": {
23526
+ if (gongmun && blockIdx === titleBoxH1Idx && tableStyle && bfReg) {
23527
+ xml = buildTitleBox((block.text || "").trim(), measured ? GJ_CHAR_BODY_TITLE : CHAR_H1, tableStyle.totalWidth, bfReg);
23528
+ break;
23529
+ }
23530
+ if (gaejosik) {
23531
+ const lvl = block.level || 1;
23532
+ if (blockIdx === coverH1Idx) break;
23533
+ if (lvl <= 2) {
23534
+ chapterNo++;
23535
+ xml = buildGaejosikChapter(chapterNo, stripChapterNumber(block.text || ""), gongmun);
23536
+ } else if (lvl === 3) {
23537
+ xml = generateParagraph(
23538
+ `\u25A1 ${block.text || ""}`,
23539
+ GONGMUN_LIST_BASE,
23540
+ GJ_CHAR_DAE,
23541
+ (id) => id === CHAR_BOLD ? GJ_CHAR_DAE_BOLD : id
23542
+ );
23543
+ } else {
23544
+ xml = generateParagraph(`\u25CB ${block.text || ""}`, GONGMUN_LIST_BASE + 1, CHAR_NORMAL);
23545
+ }
23546
+ break;
23547
+ }
22825
23548
  const pId = headingParaPrId(block.level || 1);
22826
23549
  const cId = headingCharPrId(block.level || 1);
22827
- xml = generateParagraph(block.text || "", pId, cId);
23550
+ const styleId = gongmun ? Math.min(block.level || 1, 4) : 0;
23551
+ let hText = block.text || "";
23552
+ if (gongmun && (block.level || 1) === 2 && gongmun.h2Marker !== "none") {
23553
+ const title = stripChapterNumber(hText);
23554
+ hText = gongmun.h2Marker === "box" ? `\u25A1 ${title}` : `${++h2Seq}. ${title}`;
23555
+ }
23556
+ xml = generateParagraph(hText, pId, cId, void 0, styleId);
22828
23557
  break;
22829
23558
  }
22830
23559
  case "paragraph": {
23560
+ if (measured && (block.text || "").trimStart().startsWith("\u203B")) {
23561
+ xml = generateParagraph((block.text || "").trim(), GJ_PARA_CHAM, GJ_CHAR_CHAM, chamMap);
23562
+ break;
23563
+ }
22831
23564
  const ctr = gongmun && /^<center>([\s\S]*)<\/center>$/i.exec((block.text || "").trim());
23565
+ const rgt = gongmun && /^<right>([\s\S]*)<\/right>$/i.exec((block.text || "").trim());
22832
23566
  if (ctr) {
22833
23567
  xml = generateParagraph(ctr[1].trim(), GONGMUN_CENTER);
23568
+ } else if (rgt) {
23569
+ xml = generateParagraph(rgt[1].trim(), GONGMUN_RIGHT);
22834
23570
  } else {
22835
- xml = generateParagraph(block.text || "", PARA_NORMAL, CHAR_NORMAL, fit ? variantMapper(fit, blockIdx) : void 0);
23571
+ xml = generateParagraph(block.text || "", PARA_NORMAL, CHAR_NORMAL, fit ? variantMapper(fit, blockIdx, vBase) : void 0);
22836
23572
  }
22837
23573
  break;
22838
23574
  }
@@ -22865,22 +23601,37 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
22865
23601
  xml = generateEquationParagraph(block.text || "", blockIdx);
22866
23602
  break;
22867
23603
  }
22868
- case "blockquote":
23604
+ case "blockquote": {
23605
+ if (measured) {
23606
+ const t = (block.text || "").trim();
23607
+ if (t) xml = generateParagraph(t.startsWith("\u203B") ? t : `\u203B ${t}`, GJ_PARA_CHAM, GJ_CHAR_CHAM, chamMap);
23608
+ break;
23609
+ }
22869
23610
  xml = generateParagraph(
22870
23611
  block.text || "",
22871
23612
  PARA_QUOTE,
22872
23613
  theme.hasQuoteOption ? CHAR_QUOTE : CHAR_NORMAL
22873
23614
  );
22874
23615
  break;
23616
+ }
22875
23617
  case "list_item": {
22876
23618
  if (gongmun && gongmunList) {
22877
23619
  const info = gongmunList.get(blockIdx);
22878
23620
  const depth = info?.depth ?? 0;
22879
23621
  const marker2 = info?.marker ?? "";
22880
23622
  const content = block.text || "";
23623
+ if (measured && content.trimStart().startsWith("\u203B")) {
23624
+ xml = generateParagraph(content.trim(), GJ_PARA_CHAM, GJ_CHAR_CHAM, chamMap);
23625
+ break;
23626
+ }
22881
23627
  const text = marker2 ? `${marker2} ${content}` : content;
22882
- const listCharPr = gongmun.numbering === "report" && depth === 0 ? CHAR_BOLD : CHAR_NORMAL;
22883
- xml = generateParagraph(text, GONGMUN_LIST_BASE + depth, listCharPr, fit ? variantMapper(fit, blockIdx) : void 0);
23628
+ let listCharPr = gongmun.numbering === "report" && depth === 0 ? CHAR_BOLD : CHAR_NORMAL;
23629
+ let mapId = fit ? variantMapper(fit, blockIdx, vBase) : void 0;
23630
+ if (measured && depth === 0 && gongmun.numbering !== "standard") {
23631
+ listCharPr = GJ_CHAR_DAE;
23632
+ mapId = (id) => id === CHAR_BOLD ? GJ_CHAR_DAE_BOLD : id;
23633
+ }
23634
+ xml = generateParagraph(text, GONGMUN_LIST_BASE + depth, listCharPr, mapId);
22884
23635
  break;
22885
23636
  }
22886
23637
  const indent = block.indent || 0;
@@ -22907,7 +23658,7 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
22907
23658
  break;
22908
23659
  }
22909
23660
  case "hr":
22910
- 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>`;
23661
+ 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>`;
22911
23662
  break;
22912
23663
  case "table":
22913
23664
  if (block.rows) {
@@ -22916,18 +23667,19 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
22916
23667
  paraXmls.push(`<hp:p paraPrIDRef="0" styleIDRef="0">${secRun}</hp:p>`);
22917
23668
  isFirst = false;
22918
23669
  }
22919
- xml = generateTable(block.rows, theme, remap, tableSeq++);
23670
+ xml = generateTable(block.rows, theme, tableStyle, remap, tableSeq++);
22920
23671
  }
22921
23672
  break;
22922
23673
  case "html_table": {
22923
- const tbl = generateHtmlTableXml(block.text || "", theme, 44e3, remap, tableSeq++);
22924
- if (tbl) {
23674
+ const htmlW = tableStyle ? bfReg ? tableStyle.totalWidth - DATA_TABLE_INSET : tableStyle.totalWidth : 44e3;
23675
+ const tbl2 = generateHtmlTableXml(block.text || "", theme, htmlW, tableStyle, remap, tableSeq++);
23676
+ if (tbl2) {
22925
23677
  if (isFirst) {
22926
23678
  const secRun = `<hp:run charPrIDRef="0">${generateSecPr(gongmun)}<hp:t></hp:t></hp:run>`;
22927
23679
  paraXmls.push(`<hp:p paraPrIDRef="0" styleIDRef="0">${secRun}</hp:p>`);
22928
23680
  isFirst = false;
22929
23681
  }
22930
- xml = `<hp:p paraPrIDRef="0" styleIDRef="0"><hp:run charPrIDRef="0">${tbl}</hp:run></hp:p>`;
23682
+ xml = `<hp:p paraPrIDRef="${tableStyle && bfReg ? GONGMUN_RIGHT : 0}" styleIDRef="0"><hp:run charPrIDRef="0">${tbl2}</hp:run></hp:p>`;
22931
23683
  } else {
22932
23684
  const plain = (block.text || "").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
22933
23685
  xml = plain ? generateParagraph(plain) : "";
@@ -22943,8 +23695,20 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
22943
23695
  );
22944
23696
  isFirst = false;
22945
23697
  }
23698
+ if (pendingPageBreak) {
23699
+ xml = xml.replace(/^<hp:p /, `<hp:p pageBreak="1" `);
23700
+ pendingPageBreak = false;
23701
+ }
23702
+ if (pendingNewNum) {
23703
+ xml = xml.replace(/<hp:run charPrIDRef="(\d+)">/, `<hp:run charPrIDRef="$1">${newPageNumCtrl(1)}`);
23704
+ pendingNewNum = false;
23705
+ }
22946
23706
  paraXmls.push(xml);
22947
23707
  }
23708
+ if (gongmun?.endMark && paraXmls.length > 0) {
23709
+ const lastText = [...blocks].reverse().find((b) => (b.type === "paragraph" || b.type === "list_item") && (b.text || "").trim())?.text ?? "";
23710
+ if (!hasEndMark(lastText)) paraXmls.push(buildEndMark());
23711
+ }
22948
23712
  if (paraXmls.length === 0) {
22949
23713
  paraXmls.push(`<hp:p paraPrIDRef="0" styleIDRef="0"><hp:run charPrIDRef="0">${generateSecPr(gongmun)}<hp:t></hp:t></hp:run></hp:p>`);
22950
23714
  }
@@ -22958,23 +23722,28 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
22958
23722
  async function markdownToHwpx(markdown, options) {
22959
23723
  const theme = resolveTheme(options?.theme);
22960
23724
  const gongmun = options?.gongmun ? resolveGongmun(options.gongmun) : null;
23725
+ const gaejosik = gongmun?.preset === "gaejosik";
23726
+ const measured = !!gongmun && usesReportFonts(gongmun.preset);
22961
23727
  const blocks = parseMarkdownToBlocks(markdown);
22962
23728
  const gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null;
22963
23729
  const fit = gongmun && gongmunList ? computeGongmunFitPlan(blocks, gongmun, gongmunList) : null;
22964
- const remap = options?.profile ? buildProfileRemap(options.profile, profileCharPrBase(fit?.variants?.length ?? 0)) : null;
23730
+ const staticBfEnd = gongmun ? gaejosik ? 11 : 4 : 3;
23731
+ const remap = options?.profile ? buildProfileRemap(options.profile, charVariantBase(measured) + (fit?.variants?.length ?? 0) * 4, staticBfEnd) : null;
23732
+ const bfReg = gongmun ? new TableBfRegistry(staticBfEnd + (remap?.borderFillXmls.length ?? 0)) : null;
22965
23733
  const chartParts = [];
22966
- const sectionXml = blocksToSectionXml(blocks, theme, gongmun, gongmunList, fit, chartParts, remap);
23734
+ const sectionXml = blocksToSectionXml(blocks, theme, gongmun, gongmunList, fit, chartParts, bfReg, remap);
22967
23735
  if (remap && remap.tables.length > 0) {
22968
23736
  const unused = remap.tables.filter((t) => !t.used).length;
22969
23737
  if (unused === remap.tables.length) {
22970
23738
  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)`);
22971
23739
  }
22972
23740
  }
23741
+ const extraBorderFills = [...remap?.borderFillXmls ?? [], ...bfReg?.emit() ?? []];
22973
23742
  const zip = new JSZip7();
22974
23743
  zip.file("mimetype", "application/hwp+zip", { compression: "STORE" });
22975
23744
  zip.file("META-INF/container.xml", generateContainerXml());
22976
23745
  zip.file("Contents/content.hpf", generateManifest(chartParts));
22977
- zip.file("Contents/header.xml", generateHeaderXml(theme, gongmun, fit?.variants ?? [], remap));
23746
+ zip.file("Contents/header.xml", generateHeaderXml(theme, gongmun, fit?.variants ?? [], extraBorderFills, remap?.charPrXmls ?? []));
22978
23747
  zip.file("Contents/section0.xml", sectionXml);
22979
23748
  for (const part of chartParts) zip.file(part.name, part.xml);
22980
23749
  zip.file("Preview/PrvText.txt", buildPrvText(blocks));
@@ -23244,6 +24013,12 @@ function parseParaGeom(el) {
23244
24013
  g.spaceBefore = v("prev");
23245
24014
  g.spaceAfter = v("next");
23246
24015
  }
24016
+ const bs = findDeep(el, "breakSetting");
24017
+ if (bs) {
24018
+ const nl = bs.getAttribute("breakNonLatinWord");
24019
+ if (nl === "BREAK_WORD") g.wrapMode = "keep";
24020
+ else if (nl === "KEEP_WORD") g.wrapMode = "charAll";
24021
+ }
23247
24022
  return g;
23248
24023
  }
23249
24024
  function parseRenderStyles(headXml) {
@@ -23351,9 +24126,9 @@ function collectSites(scan) {
23351
24126
  if (depth > 16) return;
23352
24127
  for (const t of tables) {
23353
24128
  for (const row of t.rows) {
23354
- for (const cell of row) {
23355
- for (const p of cell.paragraphs) sites.push({ para: p, cell, table: t, nested: depth > 0, outer: outer.length ? outer : void 0 });
23356
- walkTables(cell.tables, depth + 1, [...outer, { cell, table: t }]);
24129
+ for (const cell2 of row) {
24130
+ for (const p of cell2.paragraphs) sites.push({ para: p, cell: cell2, table: t, nested: depth > 0, outer: outer.length ? outer : void 0 });
24131
+ walkTables(cell2.tables, depth + 1, [...outer, { cell: cell2, table: t }]);
23357
24132
  }
23358
24133
  }
23359
24134
  }
@@ -23367,18 +24142,18 @@ function attrOf(openTag, name) {
23367
24142
  const m = openTag.match(new RegExp(`\\b${name}="([^"]*)"`));
23368
24143
  return m?.[1];
23369
24144
  }
23370
- function paraOpenTag(xml, para) {
23371
- const end = xml.indexOf(">", para.start);
23372
- return end === -1 ? "" : xml.slice(para.start, end + 1);
24145
+ function paraOpenTag(xml, para2) {
24146
+ const end = xml.indexOf(">", para2.start);
24147
+ return end === -1 ? "" : xml.slice(para2.start, end + 1);
23373
24148
  }
23374
- function anchorRunInfo(xml, para, anchor) {
23375
- let tr = para.tRanges.find((r) => !r.selfClosing && xml.slice(r.contentStart, r.contentEnd).includes(anchor));
24149
+ function anchorRunInfo(xml, para2, anchor) {
24150
+ let tr = para2.tRanges.find((r) => !r.selfClosing && xml.slice(r.contentStart, r.contentEnd).includes(anchor));
23376
24151
  if (!tr) {
23377
24152
  const head = anchor[0];
23378
- tr = para.tRanges.find((r) => !r.selfClosing && xml.slice(r.contentStart, r.contentEnd).includes(head)) ?? para.tRanges[para.tRanges.length - 1];
24153
+ tr = para2.tRanges.find((r) => !r.selfClosing && xml.slice(r.contentStart, r.contentEnd).includes(head)) ?? para2.tRanges[para2.tRanges.length - 1];
23379
24154
  }
23380
24155
  if (!tr) return null;
23381
- const before = xml.slice(Math.max(0, para.start), tr.contentStart);
24156
+ const before = xml.slice(Math.max(0, para2.start), tr.contentStart);
23382
24157
  const runOpen = [...before.matchAll(/<([A-Za-z0-9]+):run\b[^>]*>/g)].pop();
23383
24158
  const prefix = runOpen?.[1] ?? tr.prefix ?? "hp";
23384
24159
  const charPr2 = runOpen && attrOf(runOpen[0], "charPrIDRef") || "0";
@@ -23386,37 +24161,37 @@ function anchorRunInfo(xml, para, anchor) {
23386
24161
  if (close === -1) return null;
23387
24162
  return { charPr: charPr2, prefix, insertAt: close + `</${prefix}:run>`.length };
23388
24163
  }
23389
- function cellAddrWindow(xml, cell) {
23390
- if (!cell.addrTagRange) return null;
23391
- return xml.slice(cell.addrTagRange.end, cell.addrTagRange.end + 400);
24164
+ function cellAddrWindow(xml, cell2) {
24165
+ if (!cell2.addrTagRange) return null;
24166
+ return xml.slice(cell2.addrTagRange.end, cell2.addrTagRange.end + 400);
23392
24167
  }
23393
- function cellSzWidthHu(xml, cell) {
23394
- const win = cellAddrWindow(xml, cell);
24168
+ function cellSzWidthHu(xml, cell2) {
24169
+ const win = cellAddrWindow(xml, cell2);
23395
24170
  if (win) {
23396
24171
  const m = win.match(/<[A-Za-z0-9]+:cellSz\b[^>]*\bwidth="(\d+)"/);
23397
24172
  if (m) return Number(m[1]);
23398
24173
  }
23399
- const firstPara = cell.paragraphs[0];
24174
+ const firstPara = cell2.paragraphs[0];
23400
24175
  if (!firstPara) return null;
23401
24176
  const upto = xml.slice(0, firstPara.start);
23402
24177
  const szMatch = [...upto.matchAll(/<[A-Za-z0-9]+:cellSz\b[^>]*\bwidth="(\d+)"[^>]*>/g)].pop();
23403
24178
  return szMatch ? Number(szMatch[1]) : null;
23404
24179
  }
23405
- function cellContentWidthMm(xml, cell) {
23406
- const width = cellSzWidthHu(xml, cell);
24180
+ function cellContentWidthMm(xml, cell2) {
24181
+ const width = cellSzWidthHu(xml, cell2);
23407
24182
  if (width === null) return null;
23408
24183
  let content = width;
23409
- const win = cellAddrWindow(xml, cell);
24184
+ const win = cellAddrWindow(xml, cell2);
23410
24185
  const mg = win?.match(/<[A-Za-z0-9]+:cellMargin\b[^>]*>/);
23411
24186
  if (mg) {
23412
24187
  content -= Number(attrOf(mg[0], "left") ?? 0) + Number(attrOf(mg[0], "right") ?? 0);
23413
24188
  }
23414
24189
  return content > 0 ? content / HU_PER_MM2 : null;
23415
24190
  }
23416
- function cellLeftOffsetMm(xml, table, cell) {
23417
- if (cell.colAddr === void 0) return 0;
24191
+ function cellLeftOffsetMm(xml, table2, cell2) {
24192
+ if (cell2.colAddr === void 0) return 0;
23418
24193
  const colW = /* @__PURE__ */ new Map();
23419
- for (const row of table.rows) {
24194
+ for (const row of table2.rows) {
23420
24195
  for (const c of row) {
23421
24196
  if (c.colAddr === void 0 || colW.has(c.colAddr)) continue;
23422
24197
  if (c.colSpan > 1) continue;
@@ -23425,7 +24200,7 @@ function cellLeftOffsetMm(xml, table, cell) {
23425
24200
  }
23426
24201
  }
23427
24202
  let sum = 0;
23428
- for (let col = 0; col < cell.colAddr; col++) sum += colW.get(col) ?? 0;
24203
+ for (let col = 0; col < cell2.colAddr; col++) sum += colW.get(col) ?? 0;
23429
24204
  return sum / HU_PER_MM2;
23430
24205
  }
23431
24206
  function bodyColumnWidthMm(xml) {
@@ -23664,8 +24439,8 @@ function parseCharPrs(headerDoc) {
23664
24439
  }
23665
24440
  return map;
23666
24441
  }
23667
- function isTopLevelTable(tbl) {
23668
- let p = tbl.parentNode;
24442
+ function isTopLevelTable(tbl2) {
24443
+ let p = tbl2.parentNode;
23669
24444
  while (p) {
23670
24445
  const tag = (p.tagName || p.localName || "").replace(/^[^:]+:/, "");
23671
24446
  if (tag === "tbl") return false;
@@ -23678,45 +24453,45 @@ function num(s) {
23678
24453
  const n = parseInt(s, 10);
23679
24454
  return Number.isFinite(n) ? n : void 0;
23680
24455
  }
23681
- function parseTable3(tbl, tableIndex, borderFills, charPrs) {
23682
- const rows = num(tbl.getAttribute("rowCnt")) ?? 0;
23683
- const cols = num(tbl.getAttribute("colCnt")) ?? 0;
23684
- const sz = findChildByLocalName(tbl, "sz");
24456
+ function parseTable3(tbl2, tableIndex, borderFills, charPrs) {
24457
+ const rows = num(tbl2.getAttribute("rowCnt")) ?? 0;
24458
+ const cols = num(tbl2.getAttribute("colCnt")) ?? 0;
24459
+ const sz = findChildByLocalName(tbl2, "sz");
23685
24460
  const width = sz?.getAttribute("width") || void 0;
23686
24461
  const cells = [];
23687
24462
  const usedBf = /* @__PURE__ */ new Set();
23688
24463
  const usedCp = /* @__PURE__ */ new Set();
23689
24464
  const colWidths = new Array(cols).fill(void 0);
23690
24465
  let anchorText = "";
23691
- for (const tc of elemsByLocal(tbl, "tc")) {
23692
- if (nearestTable(tc) !== tbl) continue;
23693
- const addr = findChildByLocalName(tc, "cellAddr");
23694
- const span = findChildByLocalName(tc, "cellSpan");
23695
- const csz = findChildByLocalName(tc, "cellSz");
24466
+ for (const tc2 of elemsByLocal(tbl2, "tc")) {
24467
+ if (nearestTable(tc2) !== tbl2) continue;
24468
+ const addr = findChildByLocalName(tc2, "cellAddr");
24469
+ const span = findChildByLocalName(tc2, "cellSpan");
24470
+ const csz = findChildByLocalName(tc2, "cellSz");
23696
24471
  const row = num(addr?.getAttribute("rowAddr")) ?? 0;
23697
24472
  const col = num(addr?.getAttribute("colAddr")) ?? 0;
23698
- if (row === 0 && col === 0 && !anchorText) anchorText = directCellText(tc);
24473
+ if (row === 0 && col === 0 && !anchorText) anchorText = directCellText(tc2);
23699
24474
  const colSpan = num(span?.getAttribute("colSpan")) ?? 1;
23700
24475
  const rowSpan = num(span?.getAttribute("rowSpan")) ?? 1;
23701
- const bfId = tc.getAttribute("borderFillIDRef") || void 0;
23702
- const cpId = firstRunCharPr(tc);
23703
- const cell = { row, col, rowSpan, colSpan };
24476
+ const bfId = tc2.getAttribute("borderFillIDRef") || void 0;
24477
+ const cpId = firstRunCharPr(tc2);
24478
+ const cell2 = { row, col, rowSpan, colSpan };
23704
24479
  const w = csz?.getAttribute("width");
23705
24480
  const hh = csz?.getAttribute("height");
23706
- if (w) cell.width_hwpunit = w;
23707
- if (hh) cell.height_hwpunit = hh;
24481
+ if (w) cell2.width_hwpunit = w;
24482
+ if (hh) cell2.height_hwpunit = hh;
23708
24483
  if (bfId) {
23709
- cell.borderFillIDRef = bfId;
24484
+ cell2.borderFillIDRef = bfId;
23710
24485
  usedBf.add(bfId);
23711
24486
  }
23712
24487
  if (cpId) {
23713
- cell.charPrIDRef = cpId;
24488
+ cell2.charPrIDRef = cpId;
23714
24489
  usedCp.add(cpId);
23715
24490
  }
23716
- cells.push(cell);
24491
+ cells.push(cell2);
23717
24492
  if (row === 0 && colSpan === 1 && col < cols && w) colWidths[col] = w;
23718
24493
  }
23719
- const table = {
24494
+ const table2 = {
23720
24495
  table_index: tableIndex,
23721
24496
  rows,
23722
24497
  cols,
@@ -23724,15 +24499,15 @@ function parseTable3(tbl, tableIndex, borderFills, charPrs) {
23724
24499
  used_border_fills: pick(borderFills, usedBf)
23725
24500
  };
23726
24501
  const anchor = normalizeAnchor(anchorText);
23727
- if (anchor) table.anchor_text = anchor;
23728
- if (width) table.width_hwpunit = width;
23729
- if (colWidths.every((w) => w != null)) table.col_widths_hwpunit = colWidths;
24502
+ if (anchor) table2.anchor_text = anchor;
24503
+ if (width) table2.width_hwpunit = width;
24504
+ if (colWidths.every((w) => w != null)) table2.col_widths_hwpunit = colWidths;
23730
24505
  const cp = pick(charPrs, usedCp);
23731
- if (Object.keys(cp).length) table.used_char_prs = cp;
23732
- return table;
24506
+ if (Object.keys(cp).length) table2.used_char_prs = cp;
24507
+ return table2;
23733
24508
  }
23734
- function nearestTable(tc) {
23735
- let p = tc.parentNode;
24509
+ function nearestTable(tc2) {
24510
+ let p = tc2.parentNode;
23736
24511
  while (p) {
23737
24512
  const tag = (p.tagName || p.localName || "").replace(/^[^:]+:/, "");
23738
24513
  if (tag === "tbl") return p;
@@ -23740,9 +24515,9 @@ function nearestTable(tc) {
23740
24515
  }
23741
24516
  return null;
23742
24517
  }
23743
- function firstRunCharPr(tc) {
23744
- for (const run of elemsByLocal(tc, "run")) {
23745
- if (nearestCell(run) !== tc) continue;
24518
+ function firstRunCharPr(tc2) {
24519
+ for (const run of elemsByLocal(tc2, "run")) {
24520
+ if (nearestCell(run) !== tc2) continue;
23746
24521
  const id = run.getAttribute("charPrIDRef");
23747
24522
  if (id) return id;
23748
24523
  }
@@ -23757,10 +24532,10 @@ function nearestCell(el) {
23757
24532
  }
23758
24533
  return null;
23759
24534
  }
23760
- function directCellText(tc) {
24535
+ function directCellText(tc2) {
23761
24536
  let out = "";
23762
- for (const t of elemsByLocal(tc, "t")) {
23763
- if (nearestCell(t) !== tc) continue;
24537
+ for (const t of elemsByLocal(tc2, "t")) {
24538
+ if (nearestCell(t) !== tc2) continue;
23764
24539
  out += t.textContent ?? "";
23765
24540
  if (out.length >= 64) break;
23766
24541
  }
@@ -23789,14 +24564,304 @@ async function hwpxToProfile(input) {
23789
24564
  let tableIndex = 0;
23790
24565
  for (const f of sectionFiles) {
23791
24566
  const doc = parser.parseFromString(await f.async("text"), "text/xml");
23792
- for (const tbl of elemsByLocal(doc, "tbl")) {
23793
- if (!isTopLevelTable(tbl)) continue;
23794
- tables.push(parseTable3(tbl, tableIndex++, borderFills, charPrs));
24567
+ for (const tbl2 of elemsByLocal(doc, "tbl")) {
24568
+ if (!isTopLevelTable(tbl2)) continue;
24569
+ tables.push(parseTable3(tbl2, tableIndex++, borderFills, charPrs));
23795
24570
  }
23796
24571
  }
23797
24572
  return { schema_version: "0.2.0", tables };
23798
24573
  }
23799
24574
 
24575
+ // src/hwpx/font-catalog.ts
24576
+ var HANCOM_BUNDLED = [
24577
+ "\uD568\uCD08\uB86C\uBC14\uD0D5",
24578
+ "\uD568\uCD08\uB86C\uB3CB\uC6C0",
24579
+ "\uD55C\uCEF4\uBC14\uD0D5",
24580
+ "\uD55C\uCEF4\uB3CB\uC6C0",
24581
+ "\uD55C\uCEF4 \uACE0\uB515",
24582
+ "\uD55C\uCEF4\uACE0\uB515",
24583
+ "\uD55C\uCEF4 \uB9D0\uB791\uB9D0\uB791",
24584
+ "\uD55C\uCEF4\uC0B0\uB73B\uB3CB\uC6C0",
24585
+ "\uD55C\uCEF4\uC194\uC78E",
24586
+ "HY\uD5E4\uB4DC\uB77C\uC778M",
24587
+ "HY\uACAC\uACE0\uB515",
24588
+ "HY\uACAC\uBA85\uC870",
24589
+ "HY\uC911\uACE0\uB515",
24590
+ "HY\uC2E0\uBA85\uC870",
24591
+ "HY\uBA85\uC870",
24592
+ "HY\uADF8\uB798\uD53DM",
24593
+ "HY\uAD81\uC11C",
24594
+ "HY\uAC15M",
24595
+ "HY\uAC15B",
24596
+ "HY\uC6B8\uB989\uB3C4M",
24597
+ "HY\uC6B8\uB989\uB3C4B",
24598
+ "HY\uD0DC\uBC31B",
24599
+ "HY\uC218\uD3C9\uC120M",
24600
+ "HY\uC218\uD3C9\uC120B",
24601
+ "HY\uC13C\uC2A4L",
24602
+ "HY\uC595\uC740\uC0D8\uBB3CM",
24603
+ "HY\uBAA9\uD310L",
24604
+ "HY\uC5FD\uC11CM",
24605
+ "HY\uC5FD\uC11CL",
24606
+ "HY\uB3D9\uB158M",
24607
+ "HY\uB3D9\uB158B",
24608
+ "\uD55C\uC591\uC2E0\uBA85\uC870",
24609
+ "\uD55C\uC591\uC911\uACE0\uB515",
24610
+ "\uD55C\uC591\uACAC\uBA85\uC870",
24611
+ "\uD55C\uC591\uACAC\uACE0\uB515",
24612
+ "\uD55C\uC591\uAD81\uC11C",
24613
+ "\uD55C\uC591\uADF8\uB798\uD53D",
24614
+ "\uD734\uBA3C\uBA85\uC870",
24615
+ "\uD734\uBA3C\uACE0\uB515",
24616
+ "\uD734\uBA3C\uAD75\uC740\uD338\uCCB4",
24617
+ "\uD734\uBA3C\uAC00\uB294\uD338\uCCB4",
24618
+ "\uD734\uBA3C\uAD75\uC740\uC0D8\uCCB4",
24619
+ "\uD734\uBA3C\uAC00\uB294\uC0D8\uCCB4",
24620
+ "\uD734\uBA3C\uC61B\uCCB4",
24621
+ "\uD734\uBA3C\uC544\uBBF8\uCCB4",
24622
+ "\uD734\uBA3C\uD3B8\uC9C0\uCCB4",
24623
+ "\uD734\uBA3C\uB465\uADFC\uD5E4\uB4DC\uB77C\uC778",
24624
+ "\uD734\uBA3C\uBAA8\uC74CT",
24625
+ "\uD0DC \uB098\uBB34",
24626
+ "\uD0DC \uADF8\uB298",
24627
+ "\uC591\uC7AC\uAE68\uBE44\uCCB4B",
24628
+ "\uC591\uC7AC\uB09C\uCD08\uCCB4M",
24629
+ "\uC591\uC7AC\uB458\uAE30\uCCB4M",
24630
+ "\uC591\uC7AC\uBE14\uB7ED\uCCB4",
24631
+ "\uBB38\uCCB4\uBD80 \uAD81\uCCB4 \uC815\uC790\uCCB4",
24632
+ "\uBB38\uCCB4\uBD80 \uAD81\uCCB4 \uD758\uB9BC\uCCB4",
24633
+ "\uBB38\uCCB4\uBD80 \uB3CB\uC6C0\uCCB4",
24634
+ "\uBB38\uCCB4\uBD80 \uBC14\uD0D5\uCCB4",
24635
+ "\uBB38\uCCB4\uBD80 \uC4F0\uAE30 \uC815\uCCB4",
24636
+ "\uBB38\uCCB4\uBD80 \uC81C\uBAA9 \uB3CB\uC6C0\uCCB4",
24637
+ "\uBB38\uCCB4\uBD80 \uC81C\uBAA9 \uBC14\uD0D5\uCCB4",
24638
+ "\uC2E0\uBA85 \uC2E0\uBA85\uC870",
24639
+ "\uC2E0\uBA85 \uC2E0\uC2E0\uBA85\uC870",
24640
+ "\uC2E0\uBA85 \uACAC\uBA85\uC870",
24641
+ "\uC2E0\uBA85 \uC911\uACE0\uB515",
24642
+ "\uC2E0\uBA85 \uD0DC\uACE0\uB515",
24643
+ "\uC2E0\uBA85 \uACAC\uACE0\uB515",
24644
+ "\uC2E0\uBA85 \uC2E0\uBB38\uBA85\uC870",
24645
+ "MD\uAC1C\uC131\uCCB4",
24646
+ "MD\uC544\uB871\uCCB4",
24647
+ "MD\uC194\uCCB4",
24648
+ "MD\uC774\uC19D\uCCB4",
24649
+ "MD\uC544\uD2B8\uCCB4",
24650
+ "\uAC00\uB294\uC548\uC0C1\uC218\uCCB4",
24651
+ "\uC911\uAC04\uC548\uC0C1\uC218\uCCB4",
24652
+ "\uAD75\uC740\uC548\uC0C1\uC218\uCCB4",
24653
+ "HCI Poppy",
24654
+ "HCI Tulip",
24655
+ "-\uC544\uC774\uB9AC\uC2A4M"
24656
+ ];
24657
+ var WINDOWS_DEFAULT = [
24658
+ "\uB9D1\uC740 \uACE0\uB515",
24659
+ "\uB9D1\uC740\uACE0\uB515",
24660
+ "Malgun Gothic",
24661
+ "\uAD74\uB9BC",
24662
+ "\uAD74\uB9BC\uCCB4",
24663
+ "\uB3CB\uC6C0",
24664
+ "\uB3CB\uC6C0\uCCB4",
24665
+ "\uBC14\uD0D5",
24666
+ "\uBC14\uD0D5\uCCB4",
24667
+ "\uAD81\uC11C",
24668
+ "\uAD81\uC11C\uCCB4",
24669
+ "Arial",
24670
+ "Arial Black",
24671
+ "Times New Roman",
24672
+ "Courier New",
24673
+ "Consolas",
24674
+ "Calibri",
24675
+ "Cambria",
24676
+ "Segoe UI",
24677
+ "Tahoma",
24678
+ "Verdana",
24679
+ "Georgia",
24680
+ "Symbol"
24681
+ ];
24682
+ var COMMON_FREE = [
24683
+ "\uB098\uB214\uACE0\uB515",
24684
+ "\uB098\uB214\uBA85\uC870",
24685
+ "\uB098\uB214\uBC14\uB978\uACE0\uB515",
24686
+ "\uB098\uB214\uC2A4\uD018\uC5B4",
24687
+ "\uB098\uB214\uC190\uAE00\uC528 \uBD93",
24688
+ "\uB098\uB214\uC190\uAE00\uC528 \uD39C",
24689
+ "NanumGothic",
24690
+ "NanumMyeongjo",
24691
+ "Noto Sans KR",
24692
+ "Noto Serif KR",
24693
+ "\uBCF8\uACE0\uB515",
24694
+ "\uBCF8\uBA85\uC870",
24695
+ "Pretendard",
24696
+ "\uD504\uB9AC\uD150\uB2E4\uB4DC",
24697
+ "KoPub\uB3CB\uC6C0",
24698
+ "KoPub\uBC14\uD0D5",
24699
+ "KoPubWorld\uB3CB\uC6C0",
24700
+ "KoPubWorld\uBC14\uD0D5",
24701
+ "\uC5D0\uC2A4\uCF54\uC5B4 \uB4DC\uB9BC",
24702
+ "S-Core Dream",
24703
+ "G\uB9C8\uCF13 \uC0B0\uC2A4",
24704
+ "Gmarket Sans",
24705
+ "\uC724\uACE0\uB515",
24706
+ "\uC724\uACE0\uB515320",
24707
+ "\uC724\uACE0\uB515330",
24708
+ "\uC724\uACE0\uB515340",
24709
+ "\uC724\uBA85\uC870"
24710
+ ];
24711
+ function norm(name) {
24712
+ return name.replace(/\s+/g, "").toLowerCase();
24713
+ }
24714
+ var KNOWN = new Set([...HANCOM_BUNDLED, ...WINDOWS_DEFAULT, ...COMMON_FREE].map(norm));
24715
+ function isKnownFont(name) {
24716
+ return KNOWN.has(norm(name));
24717
+ }
24718
+ function unknownFontWarnings(fonts) {
24719
+ const warnings = [];
24720
+ for (const [role, name] of Object.entries(fonts)) {
24721
+ if (!name || isKnownFont(name)) continue;
24722
+ warnings.push(
24723
+ `\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)`
24724
+ );
24725
+ }
24726
+ return warnings;
24727
+ }
24728
+
24729
+ // src/hwpx/gongmun-lint.ts
24730
+ var RULES = [
24731
+ // 날짜 ─ 온점 뒤 한 칸, 0 패딩 금지, 연도 4자리, 끝 마침표
24732
+ {
24733
+ code: "DATE_NO_SPACE",
24734
+ severity: "error",
24735
+ pattern: /\b\d{4}\.\d{1,2}\.\d{1,2}\.?/g,
24736
+ message: "\uB0A0\uC9DC \uC628\uC810 \uB4A4\uC5D0 \uD55C \uCE78\uC529 \uB744\uC6CC\uC57C \uD568",
24737
+ suggest: "\uC608) 2025. 1. 6."
24738
+ },
24739
+ {
24740
+ code: "DATE_ZERO_PAD",
24741
+ severity: "error",
24742
+ pattern: /\b\d{4}\.\s*0\d\.|\.\s*0\d\./g,
24743
+ message: "\uC6D4\xB7\uC77C \uC55E\uC758 '0'\uC740 \uD45C\uAE30\uD558\uC9C0 \uC54A\uC74C",
24744
+ suggest: "\uC608) 2025. 1. 6. (2025. 01. 06. \u2715)"
24745
+ },
24746
+ {
24747
+ code: "DATE_2DIGIT_YR",
24748
+ severity: "error",
24749
+ pattern: /(?<!\d)['’]\d{2}\.\s*\d/g,
24750
+ message: "\uC5F0\uB3C4\uB294 \uB124 \uC790\uB9AC\uB85C \uD45C\uAE30('24 \u2715)",
24751
+ suggest: "\uC608) 2025. 1. 6."
24752
+ },
24753
+ {
24754
+ code: "DATE_NO_END_DOT",
24755
+ severity: "warning",
24756
+ pattern: /\b\d{4}\.\s\d{1,2}\.\s\d{1,2}(?!\s*[.\d(])/g,
24757
+ message: "\uB0A0\uC9DC\uC758 '\uC77C' \uB2E4\uC74C\uC5D0 \uB9C8\uCE68\uD45C(.)\uB97C \uCC0D\uC5B4\uC57C \uD568",
24758
+ suggest: "\uC608) 2025. 1. 6."
24759
+ },
24760
+ // 시간 ─ 24시각제, 쌍점 붙여쓰기
24761
+ {
24762
+ code: "TIME_AMPM",
24763
+ severity: "error",
24764
+ pattern: /(오전|오후|아침|밤|낮)\s*\d{1,2}\s*시/g,
24765
+ message: "24\uC2DC\uAC01\uC81C \uC22B\uC790\uB85C \uD45C\uAE30(\uC624\uC804/\uC624\uD6C4 \uC0AC\uC6A9 \uC548 \uD568)",
24766
+ suggest: "\uC608) 09:00, 15:30"
24767
+ },
24768
+ {
24769
+ code: "TIME_24H",
24770
+ severity: "warning",
24771
+ pattern: /(?<!\d)24\s*시(?!각)/g,
24772
+ message: "'24\uC2DC'\uBCF4\uB2E4 \uC775\uC77C 00:00 \uB610\uB294 '18:00\uAE4C\uC9C0' \uAD8C\uC7A5",
24773
+ suggest: "\uC608) 18:00"
24774
+ },
24775
+ {
24776
+ code: "TIME_COLON_SP",
24777
+ severity: "error",
24778
+ pattern: /\b\d{1,2}\s+:\s*\d{2}\b|\b\d{1,2}:\s+\d{2}\b/g,
24779
+ message: "\uC2DC\uC640 \uBD84 \uC0AC\uC774 \uC30D\uC810\uC740 \uC591\uCABD\uC744 \uBD99\uC5EC \uC500",
24780
+ suggest: "\uC608) 13:20"
24781
+ },
24782
+ // 금액 ─ '천원' 금지, 금+숫자 붙여쓰기
24783
+ {
24784
+ code: "MONEY_CHEONWON",
24785
+ severity: "error",
24786
+ pattern: /\d+\s*천\s*원/g,
24787
+ message: "\uAE08\uC561\uC740 '\uCC9C\uC6D0'\uC73C\uB85C \uC904\uC774\uC9C0 \uC54A\uACE0 \uC544\uB77C\uBE44\uC544 \uC22B\uC790\uB85C",
24788
+ suggest: "\uC608) 345,000\uC6D0"
24789
+ },
24790
+ {
24791
+ code: "MONEY_GEUM_SP",
24792
+ severity: "warning",
24793
+ pattern: /금\s+\d/g,
24794
+ message: "'\uAE08'\uACFC \uC22B\uC790 \uC0AC\uC774\uB294 \uBD99\uC5EC \uC4F0\uB294 \uAC83\uC774 \uC6D0\uCE59",
24795
+ suggest: "\uC608) \uAE08113,560\uC6D0"
24796
+ },
24797
+ // 붙임 ─ 쌍점 금지(2타 띄움)
24798
+ {
24799
+ code: "BUNIM_COLON",
24800
+ severity: "error",
24801
+ pattern: /붙\s*임\s*:/g,
24802
+ message: "'\uBD99\uC784' \uB2E4\uC74C\uC5D0 \uC30D\uC810(:)\uC744 \uBD99\uC774\uC9C0 \uC54A\uC74C(2\uD0C0 \uB744\uC6C0)",
24803
+ suggest: "\uC608) \uBD99\uC784 \uACC4\uD68D\uC11C 1\uBD80."
24804
+ },
24805
+ // 표기 ─ 물결표+까지 중복, 한글 먼저, 쌍점 띄어쓰기
24806
+ {
24807
+ code: "KKAJI_DUP",
24808
+ severity: "error",
24809
+ pattern: /[∼~~][^\n]{0,20}?까지/g,
24810
+ message: "\uBB3C\uACB0\uD45C(\u223C)\uC640 '\uAE4C\uC9C0'\uB97C \uD568\uAED8 \uC4F0\uC9C0 \uC54A\uC74C",
24811
+ suggest: "\uC608) 2. 20.\u223C2. 24."
24812
+ },
24813
+ {
24814
+ code: "FOREIGN_FIRST",
24815
+ severity: "warning",
24816
+ pattern: /\b[A-Z]{2,5}\s*\([가-힣]/g,
24817
+ message: "\uD55C\uAE00\uC744 \uBA3C\uC800 \uC4F0\uACE0 \uAD04\uD638 \uC548\uC5D0 \uC678\uAD6D\uC5B4\uB97C \uBCD1\uAE30",
24818
+ suggest: "\uC608) \uC5C5\uBB34 \uD611\uC57D(MOU)"
24819
+ },
24820
+ // 쌍점 — URL(https:// 등)·시각(13:20)은 제외
24821
+ {
24822
+ code: "COLON_SPACE",
24823
+ severity: "warning",
24824
+ pattern: /\S\s+:\S|\S:(?!\/\/)[^\s\d]/g,
24825
+ message: "\uC30D\uC810\uC740 \uC55E\uB9D0\uC5D0 \uBD99\uC774\uACE0 \uB4A4\uB294 \uD55C \uCE78 \uB744\uC6C0",
24826
+ suggest: "\uC608) \uC6D0\uC7A5: \uAE40\uAC11\uB3D9"
24827
+ }
24828
+ ];
24829
+ function lintGongmunText(text) {
24830
+ const findings = [];
24831
+ let inFence = false;
24832
+ const lines = text.split(/\r?\n/);
24833
+ for (let i = 0; i < lines.length; i++) {
24834
+ const line = lines[i];
24835
+ if (/^\s*(```|~~~)/.test(line)) {
24836
+ inFence = !inFence;
24837
+ continue;
24838
+ }
24839
+ if (inFence) continue;
24840
+ for (const r of RULES) {
24841
+ r.pattern.lastIndex = 0;
24842
+ for (const m of line.matchAll(r.pattern)) {
24843
+ findings.push({
24844
+ line: i + 1,
24845
+ match: m[0].trim(),
24846
+ rule: r.code,
24847
+ severity: r.severity,
24848
+ message: r.message,
24849
+ suggest: r.suggest
24850
+ });
24851
+ }
24852
+ }
24853
+ }
24854
+ return findings;
24855
+ }
24856
+ function gongmunLintWarnings(text, limit = 10) {
24857
+ const findings = lintGongmunText(text);
24858
+ const shown = findings.slice(0, limit).map(
24859
+ (f) => `\uD45C\uAE30\uBC95 [${f.rule}] L${f.line} "${f.match}" \u2014 ${f.message}${f.suggest ? ` (${f.suggest})` : ""}`
24860
+ );
24861
+ if (findings.length > limit) shown.push(`\uD45C\uAE30\uBC95 \uACBD\uACE0 ${findings.length - limit}\uAC74 \uB354 \uC788\uC74C \u2014 kordoc lint\uB85C \uC804\uCCB4 \uD655\uC778`);
24862
+ return shown;
24863
+ }
24864
+
23800
24865
  // src/roundtrip/patcher.ts
23801
24866
  import JSZip10 from "jszip";
23802
24867
 
@@ -23804,10 +24869,10 @@ import JSZip10 from "jszip";
23804
24869
  var ROW_OBJECT_RE = /<(?:[A-Za-z0-9_]+:)?(?:tbl|pic|equation|ole|container|shape|drawingObject|drawText|video|chart|fieldBegin|fieldEnd|ctrl)\b/;
23805
24870
  var TAG_AT_RE = /<[A-Za-z0-9_:]+(?:"[^"]*"|'[^']*'|[^>"'])*>/y;
23806
24871
  function patchTableRows(input) {
23807
- const { table, scanTable, ctx, skip, origKeys, editedKeys } = input;
24872
+ const { table: table2, scanTable, ctx, skip, origKeys, editedKeys } = input;
23808
24873
  const xml = ctx.scans[scanTable.sectionIndex]?.xml;
23809
24874
  if (!xml) return skip("\uC139\uC158 XML \uB9E4\uD551 \uC2E4\uD328");
23810
- const numRows = table.rows;
24875
+ const numRows = table2.rows;
23811
24876
  if (origKeys.length !== numRows) return skip("\uD45C \uD589 \uC88C\uD45C \uBD88\uC77C\uCE58 \u2014 \uD589 \uCD94\uAC00/\uC0AD\uC81C \uBBF8\uC9C0\uC6D0");
23812
24877
  if (scanTable.rows.length !== numRows || scanTable.rowRanges.length !== numRows) {
23813
24878
  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");
@@ -23878,8 +24943,8 @@ function patchTableRows(input) {
23878
24943
  if (template < 0) template = kept[0];
23879
24944
  const cells = input.editedCells(ins.ei);
23880
24945
  if (!cells) return skip("\uC0BD\uC785 \uD589\uC5D0 \uC774\uBBF8\uC9C0/\uC911\uCCA9\uD45C \uD3EC\uD568 \u2014 \uD589 \uCD94\uAC00 \uBBF8\uC9C0\uC6D0");
23881
- for (const cell of cells) {
23882
- const unstable = cell.lines.find((l) => sanitizeText(l) !== l);
24946
+ for (const cell2 of cells) {
24947
+ const unstable = cell2.lines.find((l) => sanitizeText(l) !== l);
23883
24948
  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");
23884
24949
  }
23885
24950
  const tmplCells = scanTable.rows[template];
@@ -23889,7 +24954,7 @@ function patchTableRows(input) {
23889
24954
  }
23890
24955
  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");
23891
24956
  const tmplWidth = tmplCells.reduce((s, c) => s + c.colSpan, 0);
23892
- 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");
24957
+ 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");
23893
24958
  if (cells.length !== tmplCells.length) {
23894
24959
  return skip(`\uC0BD\uC785 \uD589 \uC140 \uC218(${cells.length}) \u2260 \uAE30\uC900 \uD589 \uC140 \uC218(${tmplCells.length}) \u2014 \uBBF8\uC9C0\uC6D0`);
23895
24960
  }
@@ -23946,8 +25011,8 @@ function patchTableRows(input) {
23946
25011
  for (const k of keeps) {
23947
25012
  const fi = finalIndex.get(k);
23948
25013
  if (fi === k.oi) continue;
23949
- for (const cell of scanTable.rows[k.oi]) {
23950
- const sp = rowAddrRewrite(xml, cell, fi);
25014
+ for (const cell2 of scanTable.rows[k.oi]) {
25015
+ const sp = rowAddrRewrite(xml, cell2, fi);
23951
25016
  if (sp) splices.push(sp);
23952
25017
  }
23953
25018
  }
@@ -23996,13 +25061,13 @@ function buildRowFragment(xml, scanTable, template, cells, finalRow, hasExplicit
23996
25061
  const patched = applySplices(wrapped, splices);
23997
25062
  return patched.slice(FRAG_OPEN.length, patched.length - FRAG_CLOSE.length);
23998
25063
  }
23999
- function rowAddrRewrite(xml, cell, newRow) {
24000
- if (!cell.addrTagRange) return null;
24001
- const tag = xml.slice(cell.addrTagRange.start, cell.addrTagRange.end);
25064
+ function rowAddrRewrite(xml, cell2, newRow) {
25065
+ if (!cell2.addrTagRange) return null;
25066
+ const tag = xml.slice(cell2.addrTagRange.start, cell2.addrTagRange.end);
24002
25067
  const m = tag.match(/\browAddr\s*=\s*"(\d+)"/);
24003
25068
  if (!m || m.index === void 0) return null;
24004
25069
  if (parseInt(m[1], 10) === newRow) return null;
24005
- const valStart = cell.addrTagRange.start + m.index + m[0].indexOf('"') + 1;
25070
+ const valStart = cell2.addrTagRange.start + m.index + m[0].indexOf('"') + 1;
24006
25071
  return { start: valStart, end: valStart + m[1].length, replacement: String(newRow) };
24007
25072
  }
24008
25073
  function rowHeightOf(fragment) {
@@ -24028,8 +25093,8 @@ function tableSzHeightSplice(xml, scanTable, tblOpenLen, delta) {
24028
25093
  }
24029
25094
 
24030
25095
  // src/roundtrip/table-patch.ts
24031
- function patchGfmTable(table, scanTable, orig, edited, ctx, skip) {
24032
- const replica = replicateGfmTable(table);
25096
+ function patchGfmTable(table2, scanTable, orig, edited, ctx, skip) {
25097
+ const replica = replicateGfmTable(table2);
24033
25098
  if (!replica) return skip("\uD45C \uB80C\uB354 \uACBD\uB85C \uC2DD\uBCC4 \uC2E4\uD328");
24034
25099
  const origRows = parseGfmTable(orig.lines);
24035
25100
  const editedRows = parseGfmTable(edited.lines);
@@ -24037,15 +25102,15 @@ function patchGfmTable(table, scanTable, orig, edited, ctx, skip) {
24037
25102
  return skip("\uD45C \uC88C\uD45C \uC7AC\uD604 \uBD88\uC77C\uCE58 \u2014 \uB9E4\uD551 \uC2E0\uB8B0 \uBD88\uAC00");
24038
25103
  }
24039
25104
  if (editedRows.length !== origRows.length) {
24040
- return patchGfmTableRows(table, scanTable, origRows, editedRows, replica, ctx, skip);
25105
+ return patchGfmTableRows(table2, scanTable, origRows, editedRows, replica, ctx, skip);
24041
25106
  }
24042
25107
  let applied = 0;
24043
25108
  for (let r = 0; r < origRows.length; r++) {
24044
- applied += patchGfmRowPair(table, scanTable, origRows, editedRows, replica, r, r, ctx, skip);
25109
+ applied += patchGfmRowPair(table2, scanTable, origRows, editedRows, replica, r, r, ctx, skip);
24045
25110
  }
24046
25111
  return applied;
24047
25112
  }
24048
- function patchGfmRowPair(table, scanTable, origRows, editedRows, replica, r, er, ctx, skip) {
25113
+ function patchGfmRowPair(table2, scanTable, origRows, editedRows, replica, r, er, ctx, skip) {
24049
25114
  if (editedRows[er].length !== origRows[r].length) {
24050
25115
  skip(`\uD45C ${r + 1}\uD589 \uC5F4 \uC218 \uBCC0\uACBD\uC740 \uBBF8\uC9C0\uC6D0`);
24051
25116
  return 0;
@@ -24062,7 +25127,7 @@ function patchGfmRowPair(table, scanTable, origRows, editedRows, replica, r, er,
24062
25127
  }
24063
25128
  const newLines = unescapeGfmCell(stripCellTokens(editedRows[er][c])).split("\n").map((s) => s.trim()).filter(Boolean);
24064
25129
  const origLines = unescapeGfmCell(stripCellTokens(origRows[r][c])).split("\n").map((s) => s.trim()).filter(Boolean);
24065
- const n = applyCellEdit(table, scanTable, gridR, gridC, newLines, ctx, origRows[r][c], editedRows[er][c], origLines.length);
25130
+ const n = applyCellEdit(table2, scanTable, gridR, gridC, newLines, ctx, origRows[r][c], editedRows[er][c], origLines.length);
24066
25131
  if (n > 0 && origTokens) {
24067
25132
  ctx.skipped.push({
24068
25133
  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)",
@@ -24075,19 +25140,19 @@ function patchGfmRowPair(table, scanTable, origRows, editedRows, replica, r, er,
24075
25140
  }
24076
25141
  return applied;
24077
25142
  }
24078
- function patchGfmTableRows(table, scanTable, origRows, editedRows, replica, ctx, skip) {
24079
- if (replica.length !== table.rows || replica.some((row, r) => row.some((c) => c.gridR !== r))) {
25143
+ function patchGfmTableRows(table2, scanTable, origRows, editedRows, replica, ctx, skip) {
25144
+ if (replica.length !== table2.rows || replica.some((row, r) => row.some((c) => c.gridR !== r))) {
24080
25145
  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");
24081
25146
  }
24082
- if (table.cells.some((row) => row.some((c) => c && (c.colSpan > 1 || c.rowSpan > 1)))) {
25147
+ if (table2.cells.some((row) => row.some((c) => c && (c.colSpan > 1 || c.rowSpan > 1)))) {
24083
25148
  return skip("\uBCD1\uD569 \uC140 \uD45C \u2014 GFM \uD589 \uCD94\uAC00/\uC0AD\uC81C \uBBF8\uC9C0\uC6D0");
24084
25149
  }
24085
- if (!gfmRenderStable(editedRows, table.cols)) {
25150
+ if (!gfmRenderStable(editedRows, table2.cols)) {
24086
25151
  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");
24087
25152
  }
24088
25153
  const key = (row) => row.join("\0");
24089
25154
  return patchTableRows({
24090
- table,
25155
+ table: table2,
24091
25156
  scanTable,
24092
25157
  ctx,
24093
25158
  skip,
@@ -24102,7 +25167,7 @@ function patchGfmTableRows(table, scanTable, origRows, editedRows, replica, ctx,
24102
25167
  }
24103
25168
  return cells;
24104
25169
  },
24105
- patchMatched: (oi, ei) => patchGfmRowPair(table, scanTable, origRows, editedRows, replica, oi, ei, ctx, skip)
25170
+ patchMatched: (oi, ei) => patchGfmRowPair(table2, scanTable, origRows, editedRows, replica, oi, ei, ctx, skip)
24106
25171
  });
24107
25172
  }
24108
25173
  function gfmRenderStable(editedRows, cols) {
@@ -24119,13 +25184,13 @@ function gfmRenderStable(editedRows, cols) {
24119
25184
  if (!replica || replica.length !== editedRows.length) return false;
24120
25185
  return replica.every((row, r) => row.length === editedRows[r].length && row.every((c, j) => c.text === editedRows[r][j]));
24121
25186
  }
24122
- function patchHtmlTable(table, scanTable, orig, edited, ctx, skip) {
24123
- return patchHtmlTableRaw(table, scanTable, orig.raw, edited.raw, ctx, skip, 0);
25187
+ function patchHtmlTable(table2, scanTable, orig, edited, ctx, skip) {
25188
+ return patchHtmlTableRaw(table2, scanTable, orig.raw, edited.raw, ctx, skip, 0);
24124
25189
  }
24125
- function patchHtmlTableRaw(table, scanTable, origRaw, editedRaw, ctx, skip, depth) {
25190
+ function patchHtmlTableRaw(table2, scanTable, origRaw, editedRaw, ctx, skip, depth) {
24126
25191
  if (depth > 8) return skip("\uC911\uCCA9\uD45C \uAE4A\uC774 \uCD08\uACFC");
24127
- if (replicateTableToHtml(table) !== origRaw) return skip("\uD45C \uC88C\uD45C \uC7AC\uD604 \uBD88\uC77C\uCE58 \u2014 \uB9E4\uD551 \uC2E0\uB8B0 \uBD88\uAC00");
24128
- const replica = replicateHtmlTable(table);
25192
+ if (replicateTableToHtml(table2) !== origRaw) return skip("\uD45C \uC88C\uD45C \uC7AC\uD604 \uBD88\uC77C\uCE58 \u2014 \uB9E4\uD551 \uC2E0\uB8B0 \uBD88\uAC00");
25193
+ const replica = replicateHtmlTable(table2);
24129
25194
  const origRows = parseHtmlTable(origRaw);
24130
25195
  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))) {
24131
25196
  return skip("\uC140 \uACBD\uACC4 \uBAA8\uD638 (\uB9AC\uD130\uB7F4 \uD0DC\uADF8 \uC758\uC2EC) \u2014 \uB9E4\uD551 \uC2E0\uB8B0 \uBD88\uAC00");
@@ -24133,15 +25198,15 @@ function patchHtmlTableRaw(table, scanTable, origRaw, editedRaw, ctx, skip, dept
24133
25198
  const editedRows = parseHtmlTable(editedRaw);
24134
25199
  if (!editedRows) return skip("\uD3B8\uC9D1\uB41C HTML \uD45C \uD30C\uC2F1 \uC2E4\uD328");
24135
25200
  if (editedRows.length !== replica.length) {
24136
- return patchHtmlTableRows(table, scanTable, replica, editedRows, ctx, skip, depth);
25201
+ return patchHtmlTableRows(table2, scanTable, replica, editedRows, ctx, skip, depth);
24137
25202
  }
24138
25203
  let applied = 0;
24139
25204
  for (let r = 0; r < replica.length; r++) {
24140
- applied += patchHtmlRowPair(table, scanTable, replica, editedRows, r, r, ctx, skip, depth);
25205
+ applied += patchHtmlRowPair(table2, scanTable, replica, editedRows, r, r, ctx, skip, depth);
24141
25206
  }
24142
25207
  return applied;
24143
25208
  }
24144
- function patchHtmlRowPair(table, scanTable, replica, editedRows, r, er, ctx, skip, depth) {
25209
+ function patchHtmlRowPair(table2, scanTable, replica, editedRows, r, er, ctx, skip, depth) {
24145
25210
  if (editedRows[er].cells.length !== replica[r].cells.length) {
24146
25211
  skip(`\uD45C ${r + 1}\uD589 \uC140 \uC218 \uBCC0\uACBD\uC740 \uBBF8\uC9C0\uC6D0`);
24147
25212
  return 0;
@@ -24169,23 +25234,23 @@ function patchHtmlRowPair(table, scanTable, replica, editedRows, r, er, ctx, ski
24169
25234
  continue;
24170
25235
  }
24171
25236
  if (origTables.join("\n") !== editedTables.join("\n")) {
24172
- applied += patchNestedTables(table, scanTable, oc, origTables, editedTables, ctx, skip, depth);
25237
+ applied += patchNestedTables(table2, scanTable, oc, origTables, editedTables, ctx, skip, depth);
24173
25238
  }
24174
25239
  }
24175
25240
  if (origContent.lines.join("\n") !== editedContent.lines.join("\n")) {
24176
25241
  const newLines = editedContent.lines.map((l) => unescapeGfm(l));
24177
- applied += applyCellEdit(table, scanTable, oc.gridR, oc.gridC, newLines, ctx, oc.inner, ec.inner, origContent.lines.length);
25242
+ applied += applyCellEdit(table2, scanTable, oc.gridR, oc.gridC, newLines, ctx, oc.inner, ec.inner, origContent.lines.length);
24178
25243
  }
24179
25244
  }
24180
25245
  return applied;
24181
25246
  }
24182
- function patchHtmlTableRows(table, scanTable, replica, editedRows, ctx, skip, depth) {
24183
- if (replica.length !== table.rows || replica.some((row, r) => row.cells.some((c) => c.gridR !== r))) {
25247
+ function patchHtmlTableRows(table2, scanTable, replica, editedRows, ctx, skip, depth) {
25248
+ if (replica.length !== table2.rows || replica.some((row, r) => row.cells.some((c) => c.gridR !== r))) {
24184
25249
  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");
24185
25250
  }
24186
25251
  const key = (row) => row.cells.map((c) => `${c.colSpan}x${c.rowSpan}:${c.inner}`).join("\0");
24187
25252
  return patchTableRows({
24188
- table,
25253
+ table: table2,
24189
25254
  scanTable,
24190
25255
  ctx,
24191
25256
  skip,
@@ -24193,18 +25258,18 @@ function patchHtmlTableRows(table, scanTable, replica, editedRows, ctx, skip, de
24193
25258
  editedKeys: editedRows.map(key),
24194
25259
  editedCells: (ei) => {
24195
25260
  const cells = [];
24196
- for (const cell of editedRows[ei].cells) {
24197
- const content = htmlCellInnerToLines(cell.inner);
25261
+ for (const cell2 of editedRows[ei].cells) {
25262
+ const content = htmlCellInnerToLines(cell2.inner);
24198
25263
  if (content.hadNonText) return null;
24199
- cells.push({ lines: content.lines.map((l) => unescapeGfm(l)), colSpan: cell.colSpan, rowSpan: cell.rowSpan });
25264
+ cells.push({ lines: content.lines.map((l) => unescapeGfm(l)), colSpan: cell2.colSpan, rowSpan: cell2.rowSpan });
24200
25265
  }
24201
25266
  return cells;
24202
25267
  },
24203
- patchMatched: (oi, ei) => patchHtmlRowPair(table, scanTable, replica, editedRows, oi, ei, ctx, skip, depth)
25268
+ patchMatched: (oi, ei) => patchHtmlRowPair(table2, scanTable, replica, editedRows, oi, ei, ctx, skip, depth)
24204
25269
  });
24205
25270
  }
24206
- function patchNestedTables(table, scanTable, oc, origTables, editedTables, ctx, skip, depth) {
24207
- const irCell = table.cells[oc.gridR]?.[oc.gridC];
25271
+ function patchNestedTables(table2, scanTable, oc, origTables, editedTables, ctx, skip, depth) {
25272
+ const irCell = table2.cells[oc.gridR]?.[oc.gridC];
24208
25273
  const scanCell = scanTable.cellByAnchor.get(`${oc.gridR},${oc.gridC}`);
24209
25274
  const nestedIRs = (irCell?.blocks ?? []).filter((b) => b.type === "table" && b.table).map((b) => b.table);
24210
25275
  if (!scanCell || nestedIRs.length !== origTables.length || scanCell.tables.length !== origTables.length) {
@@ -24227,9 +25292,9 @@ function extractCellTokens(text) {
24227
25292
  function stripCellTokens(text) {
24228
25293
  return text.replace(CELL_TOKEN_RE, "");
24229
25294
  }
24230
- function patchTextChunkTable(table, scanTable, orig, edited, ctx, skip) {
24231
- if (table.rows === 1 && table.cols === 1) {
24232
- const content = sanitizeText(table.cells[0][0].text);
25295
+ function patchTextChunkTable(table2, scanTable, orig, edited, ctx, skip) {
25296
+ if (table2.rows === 1 && table2.cols === 1) {
25297
+ const content = sanitizeText(table2.cells[0][0].text);
24233
25298
  const replicaLines = content.split(/\n/).map((line) => {
24234
25299
  const t = line.trim();
24235
25300
  if (!t) return "";
@@ -24243,12 +25308,12 @@ function patchTextChunkTable(table, scanTable, orig, edited, ctx, skip) {
24243
25308
  const unwrap = m && /^\d+\.\s/.test(unescapeGfm(m[1]));
24244
25309
  return stripCellTokens(unescapeGfm(unwrap ? m[1] : l)).trim();
24245
25310
  }).filter(Boolean);
24246
- return applyCellEdit(table, scanTable, 0, 0, newLines, ctx, orig.raw, edited.raw, orig.lines.length);
25311
+ return applyCellEdit(table2, scanTable, 0, 0, newLines, ctx, orig.raw, edited.raw, orig.lines.length);
24247
25312
  }
24248
- if (table.cols === 1 && table.rows >= 2) {
25313
+ if (table2.cols === 1 && table2.rows >= 2) {
24249
25314
  const replica = [];
24250
- for (let r = 0; r < table.rows; r++) {
24251
- const line = escapeGfm(sanitizeText(table.cells[r][0].text)).replace(/\n/g, " ");
25315
+ for (let r = 0; r < table2.rows; r++) {
25316
+ const line = escapeGfm(sanitizeText(table2.cells[r][0].text)).replace(/\n/g, " ");
24252
25317
  if (line) replica.push({ line, gridR: r });
24253
25318
  }
24254
25319
  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");
@@ -24261,21 +25326,21 @@ function patchTextChunkTable(table, scanTable, orig, edited, ctx, skip) {
24261
25326
  continue;
24262
25327
  }
24263
25328
  const newLines = [stripCellTokens(unescapeGfm(edited.lines[i])).trim()].filter(Boolean);
24264
- applied += applyCellEdit(table, scanTable, replica[i].gridR, 0, newLines, ctx, replica[i].line, edited.lines[i], 1);
25329
+ applied += applyCellEdit(table2, scanTable, replica[i].gridR, 0, newLines, ctx, replica[i].line, edited.lines[i], 1);
24265
25330
  }
24266
25331
  return applied;
24267
25332
  }
24268
25333
  return skip("\uD45C \uB80C\uB354 \uACBD\uB85C \uC2DD\uBCC4 \uC2E4\uD328");
24269
25334
  }
24270
- function applyCellEdit(table, scanTable, gridR, gridC, newLines, ctx, before, after, origLineCount) {
25335
+ function applyCellEdit(table2, scanTable, gridR, gridC, newLines, ctx, before, after, origLineCount) {
24271
25336
  const skip = (reason) => {
24272
25337
  ctx.skipped.push({ reason, before: summarize(before), after: summarize(after) });
24273
25338
  return 0;
24274
25339
  };
24275
- const cell = scanTable.cellByAnchor.get(`${gridR},${gridC}`);
24276
- 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)");
24277
- const irCell = table.cells[gridR]?.[gridC];
24278
- const scanJoined = cell.paragraphs.map((p) => p.text).filter((t) => normForMatch(t)).join("\n");
25340
+ const cell2 = scanTable.cellByAnchor.get(`${gridR},${gridC}`);
25341
+ 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)");
25342
+ const irCell = table2.cells[gridR]?.[gridC];
25343
+ const scanJoined = cell2.paragraphs.map((p) => p.text).filter((t) => normForMatch(t)).join("\n");
24279
25344
  if (irCell && normForMatch(scanJoined) !== normForMatch(stripCellTokens(irCell.text))) {
24280
25345
  if (normForMatch(irCell.text) !== "" || normForMatch(scanJoined) !== "") {
24281
25346
  const flatBlocks = (irCell.blocks ?? []).filter((b) => b.type === "paragraph" || b.type === "heading");
@@ -24285,7 +25350,7 @@ function applyCellEdit(table, scanTable, gridR, gridC, newLines, ctx, before, af
24285
25350
  }
24286
25351
  }
24287
25352
  }
24288
- const nonEmpty = cell.paragraphs.filter((p) => normForMatch(p.text) !== "");
25353
+ const nonEmpty = cell2.paragraphs.filter((p) => normForMatch(p.text) !== "");
24289
25354
  if (origLineCount !== void 0 && nonEmpty.length > 0 && origLineCount !== nonEmpty.length) {
24290
25355
  return skip("\uC140 \uC904 \uACBD\uACC4 \uB9E4\uD551 \uBAA8\uD638 (\uB9AC\uD130\uB7F4 <br>/\uBB38\uB2E8 \uB0B4 \uC904\uBC14\uAFC8) \u2014 \uBBF8\uC9C0\uC6D0");
24291
25356
  }
@@ -24295,7 +25360,7 @@ function applyCellEdit(table, scanTable, gridR, gridC, newLines, ctx, before, af
24295
25360
  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");
24296
25361
  if (nonEmpty.length === 0) {
24297
25362
  if (newLines.length === 0) return 0;
24298
- const target = cell.paragraphs[0];
25363
+ const target = cell2.paragraphs[0];
24299
25364
  if (!target) return skip("\uBE48 \uC140\uC5D0 \uBB38\uB2E8\uC774 \uC5C6\uC5B4 \uD14D\uC2A4\uD2B8 \uC0BD\uC785 \uBD88\uAC00");
24300
25365
  const sp = buildParagraphSplices(target, newLines.join(" "), ctx.scans[target.sectionIndex]?.xml);
24301
25366
  if (sp === null) return skip("\uC140 \uBB38\uB2E8\uC5D0 \uD14D\uC2A4\uD2B8 \uB178\uB4DC\uB97C \uB9CC\uB4E4 \uC218 \uC5C6\uC74C");
@@ -24380,16 +25445,16 @@ function buildTableParagraphXml(rows, opts) {
24380
25445
  const trElements = rows.map((row, rowIdx) => {
24381
25446
  const cells = row.length < colCnt ? [...row, ...Array(colCnt - row.length).fill("")] : row;
24382
25447
  const isHeaderRow = rowIdx === 0;
24383
- const tdElements = cells.map((cell, colIdx) => {
24384
- const text = escapeXmlText(cellPlainText(cell));
25448
+ const tdElements = cells.map((cell2, colIdx) => {
25449
+ const text = escapeXmlText(cellPlainText(cell2));
24385
25450
  const cellP = `<hp:p paraPrIDRef="${cellParaPrId}" styleIDRef="0"><hp:run charPrIDRef="${cellCharPrId}"><hp:t>${text}</hp:t></hp:run></hp:p>`;
24386
25451
  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>`;
24387
25452
  }).join("");
24388
25453
  return `<hp:tr>${tdElements}</hp:tr>`;
24389
25454
  }).join("");
24390
25455
  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;
24391
- 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>`;
24392
- return `<hp:p paraPrIDRef="${outerParaPrId}" styleIDRef="0"><hp:run charPrIDRef="${cellCharPrId}">${tbl}</hp:run></hp:p>`;
25456
+ 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>`;
25457
+ return `<hp:p paraPrIDRef="${outerParaPrId}" styleIDRef="0"><hp:run charPrIDRef="${cellCharPrId}">${tbl2}</hp:run></hp:p>`;
24393
25458
  }
24394
25459
 
24395
25460
  // src/roundtrip/hwpx-entries.ts
@@ -24561,12 +25626,12 @@ function buildTableOrdinals(blocks) {
24561
25626
  function resolveParagraphMappings(blocks, scans) {
24562
25627
  const buckets = /* @__PURE__ */ new Map();
24563
25628
  for (const scan of scans) {
24564
- for (const para of scan.bodyParagraphs) {
24565
- const key = normForMatch(para.text);
25629
+ for (const para2 of scan.bodyParagraphs) {
25630
+ const key = normForMatch(para2.text);
24566
25631
  if (!key) continue;
24567
25632
  let list = buckets.get(key);
24568
25633
  if (!list) buckets.set(key, list = []);
24569
- list.push(para);
25634
+ list.push(para2);
24570
25635
  }
24571
25636
  }
24572
25637
  const headerNorms = new Set(scans.flatMap((s) => s.headerTexts.map(normForMatch)).filter(Boolean));
@@ -24652,11 +25717,11 @@ function convertParagraphToTable(block, orig, edited, ctx, skip) {
24652
25717
  if (!ti) return skip("\uBB38\uB2E8\u2192\uD45C \uBCC0\uD658 \uBD88\uAC00 \u2014 header \uC5D4\uD2B8\uB9AC(borderFills) \uD574\uC11D \uC2E4\uD328");
24653
25718
  const mapping = ctx.paraMap.get(orig.blockIdx);
24654
25719
  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");
24655
- const para = mapping.para;
24656
- 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");
24657
- const scan = ctx.scans[para.sectionIndex];
25720
+ const para2 = mapping.para;
25721
+ 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");
25722
+ const scan = ctx.scans[para2.sectionIndex];
24658
25723
  if (!scan) return skip("\uC139\uC158 \uB9E4\uD551 \uC2E4\uD328");
24659
- const pEnd = findElementEnd(scan.xml, para.start);
25724
+ const pEnd = findElementEnd(scan.xml, para2.start);
24660
25725
  if (pEnd < 0) return skip("\uBB38\uB2E8 \uB05D \uC704\uCE58 \uD0D0\uC0C9 \uC2E4\uD328");
24661
25726
  const rows = parseGfmTable(edited.lines);
24662
25727
  if (rows.length === 0 || rows.every((r) => r.length === 0)) return skip("\uD45C \uB0B4\uC6A9\uC774 \uBE44\uC5B4 \uC788\uC74C");
@@ -24666,7 +25731,7 @@ function convertParagraphToTable(block, orig, edited, ctx, skip) {
24666
25731
  ti.borderFillId = inj.borderFillId;
24667
25732
  ti.headerSplices.push(...inj.headerSplices);
24668
25733
  }
24669
- const outerParaPrId = extractParaPrIdRef(scan.xml, para.start) ?? 0;
25734
+ const outerParaPrId = extractParaPrIdRef(scan.xml, para2.start) ?? 0;
24670
25735
  const tableXml = buildTableParagraphXml(rows, {
24671
25736
  borderFillId: ti.borderFillId,
24672
25737
  outerParaPrId,
@@ -24674,7 +25739,7 @@ function convertParagraphToTable(block, orig, edited, ctx, skip) {
24674
25739
  cellCharPrId: 0,
24675
25740
  tableId: ti.nextId++
24676
25741
  });
24677
- ctx.sectionSplices[para.sectionIndex].push({ start: para.start, end: pEnd, replacement: tableXml });
25742
+ ctx.sectionSplices[para2.sectionIndex].push({ start: para2.start, end: pEnd, replacement: tableXml });
24678
25743
  return 1;
24679
25744
  }
24680
25745
  function patchParagraphUnit(block, orig, edited, ctx, skip) {
@@ -25155,7 +26220,7 @@ function scanSection(stream, sectionIndex, compressed) {
25155
26220
  }
25156
26221
  }
25157
26222
  const kind = !ctrlSeen || !nonGso ? "body" : "other";
25158
- const para = {
26223
+ const para2 = {
25159
26224
  sectionIndex,
25160
26225
  headerIdx: i,
25161
26226
  kind,
@@ -25167,8 +26232,8 @@ function scanSection(stream, sectionIndex, compressed) {
25167
26232
  nCharsRaw: rec.data.readUInt32LE(0),
25168
26233
  rawText: state.text
25169
26234
  };
25170
- paras.push(para);
25171
- parasByHeader.set(i, para);
26235
+ paras.push(para2);
26236
+ parasByHeader.set(i, para2);
25172
26237
  }
25173
26238
  const tables = [];
25174
26239
  for (let i = 0; i < records.length; i++) {
@@ -25321,13 +26386,13 @@ function msg(err) {
25321
26386
  function resolveParaMappings(blocks, scans) {
25322
26387
  const buckets = /* @__PURE__ */ new Map();
25323
26388
  for (const scan of scans) {
25324
- for (const para of scan.paras) {
25325
- if (para.kind === "other") continue;
25326
- const key = normForMatch(para.rawText);
26389
+ for (const para2 of scan.paras) {
26390
+ if (para2.kind === "other") continue;
26391
+ const key = normForMatch(para2.rawText);
25327
26392
  if (!key) continue;
25328
26393
  let list = buckets.get(key);
25329
26394
  if (!list) buckets.set(key, list = []);
25330
- list.push(para);
26395
+ list.push(para2);
25331
26396
  }
25332
26397
  }
25333
26398
  const usable = (list) => list.length === 1 || list.every((p) => p.kind === "body");
@@ -25363,18 +26428,18 @@ function resolveTableMappings(blocks, scanTables) {
25363
26428
  const result = /* @__PURE__ */ new Map();
25364
26429
  let si = 0;
25365
26430
  for (let i = 0; i < blocks.length; i++) {
25366
- const table = blocks[i].table;
25367
- if (blocks[i].type !== "table" || !table) continue;
26431
+ const table2 = blocks[i].table;
26432
+ if (blocks[i].type !== "table" || !table2) continue;
25368
26433
  const cands = [];
25369
26434
  for (let k = si; k < scanTables.length; k++) {
25370
- if (scanTables[k].rows === table.rows && scanTables[k].cols === table.cols) cands.push(k);
26435
+ if (scanTables[k].rows === table2.rows && scanTables[k].cols === table2.cols) cands.push(k);
25371
26436
  }
25372
26437
  if (cands.length === 0) continue;
25373
26438
  let pick2 = cands[0];
25374
26439
  if (cands.length > 1) {
25375
- let best = tableContentScore(table, scanTables[cands[0]]);
26440
+ let best = tableContentScore(table2, scanTables[cands[0]]);
25376
26441
  for (let ci = 1; ci < cands.length; ci++) {
25377
- const sc = tableContentScore(table, scanTables[cands[ci]]);
26442
+ const sc = tableContentScore(table2, scanTables[cands[ci]]);
25378
26443
  if (sc > best) {
25379
26444
  best = sc;
25380
26445
  pick2 = cands[ci];
@@ -25475,14 +26540,14 @@ function patchGfmCells(scanTable, orig, edited, ctx, skip) {
25475
26540
  ctx.skipped.push({ reason, before: summarize(origRows[r][c]), after: summarize(editedRows[r][c]) });
25476
26541
  return 0;
25477
26542
  };
25478
- const cell = scanTable.cells.get(`${r},${c}`);
25479
- if (!cell) {
26543
+ const cell2 = scanTable.cells.get(`${r},${c}`);
26544
+ if (!cell2) {
25480
26545
  cellSkip("\uBCD1\uD569 \uC601\uC5ED \uC140 \u2014 \uC575\uCEE4 \uC140\uC774 \uC544\uB2C8\uBBC0\uB85C \uBBF8\uC9C0\uC6D0");
25481
26546
  continue;
25482
26547
  }
25483
26548
  const beforeParts = origRows[r][c].split(/<br\s*\/?>/i);
25484
26549
  const afterParts = editedRows[r][c].split(/<br\s*\/?>/i);
25485
- if (cell.paras.length === 1) {
26550
+ if (cell2.paras.length === 1) {
25486
26551
  const beforeEach = beforeParts.map(gfmCellToPlain);
25487
26552
  const afterEach = afterParts.map(gfmCellToPlain);
25488
26553
  if (beforeEach.some((p) => p === null) || afterEach.some((p) => p === null)) {
@@ -25492,8 +26557,8 @@ function patchGfmCells(scanTable, orig, edited, ctx, skip) {
25492
26557
  const before = beforeEach.join("\n");
25493
26558
  const after = afterEach.join("\n");
25494
26559
  if (before === after) continue;
25495
- const para = cell.paras[0];
25496
- if (normForMatch(para.rawText) !== normForMatch(before)) {
26560
+ const para2 = cell2.paras[0];
26561
+ if (normForMatch(para2.rawText) !== normForMatch(before)) {
25497
26562
  cellSkip("\uC140 \uD14D\uC2A4\uD2B8 \uBD88\uC77C\uCE58 \u2014 \uC18C\uC2A4\uB9F5 \uC2E0\uB8B0 \uBD88\uAC00");
25498
26563
  continue;
25499
26564
  }
@@ -25501,14 +26566,14 @@ function patchGfmCells(scanTable, orig, edited, ctx, skip) {
25501
26566
  cellSkip("\uACF5\uBC31 \uC815\uADDC\uD654 \uBD88\uC548\uC815 \uD14D\uC2A4\uD2B8 \u2014 \uBBF8\uC9C0\uC6D0");
25502
26567
  continue;
25503
26568
  }
25504
- applied += stageParaPatch(ctx.scans[para.sectionIndex], para, after, cellSkip);
26569
+ applied += stageParaPatch(ctx.scans[para2.sectionIndex], para2, after, cellSkip);
25505
26570
  continue;
25506
26571
  }
25507
- if (beforeParts.length !== cell.paras.length || afterParts.length !== cell.paras.length) {
26572
+ if (beforeParts.length !== cell2.paras.length || afterParts.length !== cell2.paras.length) {
25508
26573
  cellSkip("\uC140 \uBB38\uB2E8 \uC218 \uBCC0\uACBD \u2014 \uBBF8\uC9C0\uC6D0 (\uBB38\uB2E8 \uCD94\uAC00/\uC0AD\uC81C)");
25509
26574
  continue;
25510
26575
  }
25511
- for (let k = 0; k < cell.paras.length; k++) {
26576
+ for (let k = 0; k < cell2.paras.length; k++) {
25512
26577
  const before = gfmCellToPlain(beforeParts[k]);
25513
26578
  const after = gfmCellToPlain(afterParts[k]);
25514
26579
  if (before === null || after === null) {
@@ -25520,8 +26585,8 @@ function patchGfmCells(scanTable, orig, edited, ctx, skip) {
25520
26585
  cellSkip("\uC140 \uB0B4 \uC904\uBC14\uAFC8 \uCD94\uAC00\uB294 \uBBF8\uC9C0\uC6D0 (v1)");
25521
26586
  break;
25522
26587
  }
25523
- const para = cell.paras[k];
25524
- if (normForMatch(para.rawText) !== normForMatch(before)) {
26588
+ const para2 = cell2.paras[k];
26589
+ if (normForMatch(para2.rawText) !== normForMatch(before)) {
25525
26590
  cellSkip("\uC140 \uD14D\uC2A4\uD2B8 \uBD88\uC77C\uCE58 \u2014 \uC18C\uC2A4\uB9F5 \uC2E0\uB8B0 \uBD88\uAC00");
25526
26591
  break;
25527
26592
  }
@@ -25529,15 +26594,15 @@ function patchGfmCells(scanTable, orig, edited, ctx, skip) {
25529
26594
  cellSkip("\uACF5\uBC31 \uC815\uADDC\uD654 \uBD88\uC548\uC815 \uD14D\uC2A4\uD2B8 \u2014 \uBBF8\uC9C0\uC6D0");
25530
26595
  break;
25531
26596
  }
25532
- applied += stageParaPatch(ctx.scans[para.sectionIndex], para, after, cellSkip);
26597
+ applied += stageParaPatch(ctx.scans[para2.sectionIndex], para2, after, cellSkip);
25533
26598
  }
25534
26599
  }
25535
26600
  }
25536
26601
  return applied;
25537
26602
  }
25538
- function patchHtmlCells5(table, scanTable, orig, edited, ctx, skip) {
25539
- if (replicateTableToHtml(table) !== orig.raw) return skip("\uD45C \uC88C\uD45C \uC7AC\uD604 \uBD88\uC77C\uCE58 \u2014 \uB9E4\uD551 \uC2E0\uB8B0 \uBD88\uAC00");
25540
- const replica = replicateHtmlTable(table);
26603
+ function patchHtmlCells5(table2, scanTable, orig, edited, ctx, skip) {
26604
+ if (replicateTableToHtml(table2) !== orig.raw) return skip("\uD45C \uC88C\uD45C \uC7AC\uD604 \uBD88\uC77C\uCE58 \u2014 \uB9E4\uD551 \uC2E0\uB8B0 \uBD88\uAC00");
26605
+ const replica = replicateHtmlTable(table2);
25541
26606
  const origRows = parseHtmlTable(orig.raw);
25542
26607
  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))) {
25543
26608
  return skip("\uC140 \uACBD\uACC4 \uBAA8\uD638 (\uB9AC\uD130\uB7F4 \uD0DC\uADF8 \uC758\uC2EC) \u2014 \uB9E4\uD551 \uC2E0\uB8B0 \uBD88\uAC00");
@@ -25573,15 +26638,15 @@ function patchHtmlCells5(table, scanTable, orig, edited, ctx, skip) {
25573
26638
  }
25574
26639
  if (origContent.lines.join("\n") !== editedContent.lines.join("\n")) {
25575
26640
  const newLines = editedContent.lines.map((l) => unescapeGfm(l));
25576
- applied += applyCellEdit5(table, scanTable, oc.gridR, oc.gridC, newLines, ctx, oc.inner, ec.inner, origContent.lines.length);
26641
+ applied += applyCellEdit5(table2, scanTable, oc.gridR, oc.gridC, newLines, ctx, oc.inner, ec.inner, origContent.lines.length);
25577
26642
  }
25578
26643
  }
25579
26644
  }
25580
26645
  return applied;
25581
26646
  }
25582
- function patchTextChunk5(table, scanTable, orig, edited, ctx, skip) {
25583
- if (table.rows === 1 && table.cols === 1) {
25584
- const content = sanitizeText(table.cells[0][0].text);
26647
+ function patchTextChunk5(table2, scanTable, orig, edited, ctx, skip) {
26648
+ if (table2.rows === 1 && table2.cols === 1) {
26649
+ const content = sanitizeText(table2.cells[0][0].text);
25585
26650
  const replicaLines = content.split(/\n/).map((line) => {
25586
26651
  const t = line.trim();
25587
26652
  if (!t) return "";
@@ -25595,12 +26660,12 @@ function patchTextChunk5(table, scanTable, orig, edited, ctx, skip) {
25595
26660
  const unwrap = m && /^\d+\.\s/.test(unescapeGfm(m[1]));
25596
26661
  return stripCellTokens(unescapeGfm(unwrap ? m[1] : l)).trim();
25597
26662
  }).filter(Boolean);
25598
- return applyCellEdit5(table, scanTable, 0, 0, newLines, ctx, orig.raw, edited.raw, orig.lines.length);
26663
+ return applyCellEdit5(table2, scanTable, 0, 0, newLines, ctx, orig.raw, edited.raw, orig.lines.length);
25599
26664
  }
25600
- if (table.cols === 1 && table.rows >= 2) {
26665
+ if (table2.cols === 1 && table2.rows >= 2) {
25601
26666
  const replica = [];
25602
- for (let r = 0; r < table.rows; r++) {
25603
- const line = escapeGfm(sanitizeText(table.cells[r][0].text)).replace(/\n/g, " ");
26667
+ for (let r = 0; r < table2.rows; r++) {
26668
+ const line = escapeGfm(sanitizeText(table2.cells[r][0].text)).replace(/\n/g, " ");
25604
26669
  if (line) replica.push({ line, gridR: r });
25605
26670
  }
25606
26671
  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");
@@ -25613,21 +26678,21 @@ function patchTextChunk5(table, scanTable, orig, edited, ctx, skip) {
25613
26678
  continue;
25614
26679
  }
25615
26680
  const newLines = [stripCellTokens(unescapeGfm(edited.lines[i])).trim()].filter(Boolean);
25616
- applied += applyCellEdit5(table, scanTable, replica[i].gridR, 0, newLines, ctx, replica[i].line, edited.lines[i], 1);
26681
+ applied += applyCellEdit5(table2, scanTable, replica[i].gridR, 0, newLines, ctx, replica[i].line, edited.lines[i], 1);
25617
26682
  }
25618
26683
  return applied;
25619
26684
  }
25620
26685
  return skip("\uD45C \uB80C\uB354 \uACBD\uB85C \uC2DD\uBCC4 \uC2E4\uD328");
25621
26686
  }
25622
- function applyCellEdit5(table, scanTable, gridR, gridC, newLines, ctx, before, after, origLineCount) {
26687
+ function applyCellEdit5(table2, scanTable, gridR, gridC, newLines, ctx, before, after, origLineCount) {
25623
26688
  const skip = (reason) => {
25624
26689
  ctx.skipped.push({ reason, before: summarize(before), after: summarize(after) });
25625
26690
  return 0;
25626
26691
  };
25627
- const cell = scanTable.cells.get(`${gridR},${gridC}`);
25628
- 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)");
25629
- const irCell = table.cells[gridR]?.[gridC];
25630
- const scanJoined = cell.paras.map((p) => p.rawText).filter((t) => normForMatch(t)).join("\n");
26692
+ const cell2 = scanTable.cells.get(`${gridR},${gridC}`);
26693
+ 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)");
26694
+ const irCell = table2.cells[gridR]?.[gridC];
26695
+ const scanJoined = cell2.paras.map((p) => p.rawText).filter((t) => normForMatch(t)).join("\n");
25631
26696
  if (irCell && normForMatch(scanJoined) !== normForMatch(stripCellTokens(irCell.text))) {
25632
26697
  if (normForMatch(irCell.text) !== "" || normForMatch(scanJoined) !== "") {
25633
26698
  const flatBlocks = (irCell.blocks ?? []).filter((b) => b.type === "paragraph" || b.type === "heading");
@@ -25637,13 +26702,13 @@ function applyCellEdit5(table, scanTable, gridR, gridC, newLines, ctx, before, a
25637
26702
  }
25638
26703
  }
25639
26704
  }
25640
- const nonEmpty = cell.paras.filter((p) => normForMatch(p.rawText) !== "");
26705
+ const nonEmpty = cell2.paras.filter((p) => normForMatch(p.rawText) !== "");
25641
26706
  if (origLineCount !== void 0 && nonEmpty.length > 0 && origLineCount !== nonEmpty.length) {
25642
26707
  return skip("\uC140 \uC904 \uACBD\uACC4 \uB9E4\uD551 \uBAA8\uD638 (\uBB38\uB2E8 \uB0B4 \uC904\uBC14\uAFC8) \u2014 \uBBF8\uC9C0\uC6D0");
25643
26708
  }
25644
26709
  const unstable = newLines.find((l) => sanitizeText(l) !== l);
25645
26710
  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");
25646
- const targets = nonEmpty.length > 0 ? nonEmpty : cell.paras;
26711
+ const targets = nonEmpty.length > 0 ? nonEmpty : cell2.paras;
25647
26712
  if (targets.length === 0) return skip("\uC140\uC5D0 \uBB38\uB2E8\uC774 \uC5C6\uC74C \u2014 \uBBF8\uC9C0\uC6D0");
25648
26713
  const assigned = [];
25649
26714
  for (let i = 0; i < targets.length; i++) {
@@ -25793,67 +26858,67 @@ function synthesizeLineSegs(lineSegData, newRaw, startUnits) {
25793
26858
  }
25794
26859
  return { buf: Buffer.concat(segs), count: lines.length };
25795
26860
  }
25796
- function stageParaPatch(scan, para, newPlain, skip) {
26861
+ function stageParaPatch(scan, para2, newPlain, skip) {
25797
26862
  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");
25798
- if (para.textIdx === -2) return skip("\uBCF5\uC218 PARA_TEXT \uB808\uCF54\uB4DC \uBB38\uB2E8 \u2014 \uBBF8\uC9C0\uC6D0 (v1)");
25799
- if (para.rangeTagCount > 0) return skip("\uBC94\uC704 \uD0DC\uADF8(\uD615\uAD11\uD39C/\uAD50\uC815\uBD80\uD638) \uBB38\uB2E8 \u2014 \uBBF8\uC9C0\uC6D0 (v1)");
25800
- if (para.charShapeIdx < 0 || para.lineSegIdx < 0) return skip("\uBB38\uB2E8 \uB808\uCF54\uB4DC \uAD6C\uC131 \uBE44\uC815\uD615 \u2014 \uBBF8\uC9C0\uC6D0");
25801
- if (scan.repl.has(para.headerIdx)) return skip("\uB3D9\uC77C \uBB38\uB2E8 \uC911\uBCF5 \uC218\uC815 \u2014 \uCCAB \uC218\uC815\uB9CC \uC801\uC6A9");
26863
+ if (para2.textIdx === -2) return skip("\uBCF5\uC218 PARA_TEXT \uB808\uCF54\uB4DC \uBB38\uB2E8 \u2014 \uBBF8\uC9C0\uC6D0 (v1)");
26864
+ if (para2.rangeTagCount > 0) return skip("\uBC94\uC704 \uD0DC\uADF8(\uD615\uAD11\uD39C/\uAD50\uC815\uBD80\uD638) \uBB38\uB2E8 \u2014 \uBBF8\uC9C0\uC6D0 (v1)");
26865
+ if (para2.charShapeIdx < 0 || para2.lineSegIdx < 0) return skip("\uBB38\uB2E8 \uB808\uCF54\uB4DC \uAD6C\uC131 \uBE44\uC815\uD615 \u2014 \uBBF8\uC9C0\uC6D0");
26866
+ if (scan.repl.has(para2.headerIdx)) return skip("\uB3D9\uC77C \uBB38\uB2E8 \uC911\uBCF5 \uC218\uC815 \u2014 \uCCAB \uC218\uC815\uB9CC \uC801\uC6A9");
25802
26867
  if (/[\u0000-\u0009\u000b-\u001f]/.test(newPlain)) return skip("\uC0C8 \uD14D\uC2A4\uD2B8\uC5D0 \uC81C\uC5B4\uBB38\uC790 \uD3EC\uD568 \u2014 \uBBF8\uC9C0\uC6D0");
25803
26868
  const records = scan.records;
25804
- const headerRec = records[para.headerIdx];
25805
- const charShapeRec = records[para.charShapeIdx];
26869
+ const headerRec = records[para2.headerIdx];
26870
+ const charShapeRec = records[para2.charShapeIdx];
25806
26871
  if (charShapeRec.data.length < 8) {
25807
26872
  return skip("CHAR_SHAPE \uB808\uCF54\uB4DC \uBE44\uC815\uD615 \u2014 \uBBF8\uC9C0\uC6D0");
25808
26873
  }
25809
- if (para.textIdx === -1) {
25810
- const nCharsLow = para.nCharsRaw & 2147483647;
26874
+ if (para2.textIdx === -1) {
26875
+ const nCharsLow = para2.nCharsRaw & 2147483647;
25811
26876
  if (nCharsLow > 1) return skip("PARA_TEXT \uC5C6\uB294 \uBB38\uB2E8\uC758 nChars \uBE44\uC815\uD615 \u2014 \uBBF8\uC9C0\uC6D0");
25812
26877
  const paraEnd = nCharsLow === 1 ? Buffer.from([13, 0]) : Buffer.alloc(0);
25813
- const at = para.headerIdx + 1;
26878
+ const at = para2.headerIdx + 1;
25814
26879
  const list = scan.inserts.get(at) ?? [];
25815
26880
  list.push({ tagId: TAG_PARA_TEXT, level: headerRec.level + 1, data: Buffer.concat([Buffer.from(newPlain, "utf16le"), paraEnd]) });
25816
26881
  scan.inserts.set(at, list);
25817
26882
  const newHeader2 = Buffer.from(headerRec.data);
25818
- newHeader2.writeUInt32LE((para.nCharsRaw & 2147483648 | newPlain.length + nCharsLow) >>> 0, 0);
26883
+ newHeader2.writeUInt32LE((para2.nCharsRaw & 2147483648 | newPlain.length + nCharsLow) >>> 0, 0);
25819
26884
  const cs2 = rebuildCharShape(charShapeRec.data, 0);
25820
- scan.repl.set(para.charShapeIdx, cs2.buf);
26885
+ scan.repl.set(para2.charShapeIdx, cs2.buf);
25821
26886
  newHeader2.writeUInt16LE(cs2.count, 12);
25822
26887
  if (newPlain.includes("\n")) {
25823
- const synth = synthesizeLineSegs(records[para.lineSegIdx].data, newPlain, 0);
26888
+ const synth = synthesizeLineSegs(records[para2.lineSegIdx].data, newPlain, 0);
25824
26889
  if (synth) {
25825
- scan.repl.set(para.lineSegIdx, synth.buf);
26890
+ scan.repl.set(para2.lineSegIdx, synth.buf);
25826
26891
  newHeader2.writeUInt16LE(synth.count, 16);
25827
26892
  }
25828
26893
  }
25829
- scan.repl.set(para.headerIdx, newHeader2);
26894
+ scan.repl.set(para2.headerIdx, newHeader2);
25830
26895
  return 1;
25831
26896
  }
25832
- const textRec = records[para.textIdx];
26897
+ const textRec = records[para2.textIdx];
25833
26898
  const seg = splitParaText(textRec.data);
25834
26899
  if (!seg) {
25835
- 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");
26900
+ 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");
25836
26901
  }
25837
- 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");
25838
- const lead = para.rawText.match(/^\s*/)[0];
25839
- const trail = para.rawText.match(/\s*$/)[0];
25840
- const newRaw = para.rawText.trim() === para.rawText ? newPlain : lead + newPlain + trail;
26902
+ 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");
26903
+ const lead = para2.rawText.match(/^\s*/)[0];
26904
+ const trail = para2.rawText.match(/\s*$/)[0];
26905
+ const newRaw = para2.rawText.trim() === para2.rawText ? newPlain : lead + newPlain + trail;
25841
26906
  const newText = Buffer.concat([seg.prefix, Buffer.from(newRaw, "utf16le"), seg.suffix]);
25842
- scan.repl.set(para.textIdx, newText);
26907
+ scan.repl.set(para2.textIdx, newText);
25843
26908
  const newHeader = Buffer.from(headerRec.data);
25844
26909
  const nChars = seg.prefixUnits + newRaw.length + seg.suffixUnits;
25845
- newHeader.writeUInt32LE((para.nCharsRaw & 2147483648 | nChars) >>> 0, 0);
26910
+ newHeader.writeUInt32LE((para2.nCharsRaw & 2147483648 | nChars) >>> 0, 0);
25846
26911
  const cs = rebuildCharShape(charShapeRec.data, seg.prefixUnits);
25847
- scan.repl.set(para.charShapeIdx, cs.buf);
26912
+ scan.repl.set(para2.charShapeIdx, cs.buf);
25848
26913
  newHeader.writeUInt16LE(cs.count, 12);
25849
26914
  if (newRaw.includes("\n")) {
25850
- const synth = synthesizeLineSegs(records[para.lineSegIdx].data, newRaw, seg.prefixUnits);
26915
+ const synth = synthesizeLineSegs(records[para2.lineSegIdx].data, newRaw, seg.prefixUnits);
25851
26916
  if (synth) {
25852
- scan.repl.set(para.lineSegIdx, synth.buf);
26917
+ scan.repl.set(para2.lineSegIdx, synth.buf);
25853
26918
  newHeader.writeUInt16LE(synth.count, 16);
25854
26919
  }
25855
26920
  }
25856
- scan.repl.set(para.headerIdx, newHeader);
26921
+ scan.repl.set(para2.headerIdx, newHeader);
25857
26922
  return 1;
25858
26923
  }
25859
26924
 
@@ -26018,9 +27083,9 @@ var HwpxSession = class _HwpxSession {
26018
27083
  const block = st.blocks[blockIndex];
26019
27084
  if (!block) return void 0;
26020
27085
  if (block.type === "paragraph" || block.type === "heading") {
26021
- const para = st.paraMap.get(blockIndex)?.para;
26022
- if (!para) return void 0;
26023
- return { kind: "paragraph", sectionIndex: para.sectionIndex, xmlStart: para.start };
27086
+ const para2 = st.paraMap.get(blockIndex)?.para;
27087
+ if (!para2) return void 0;
27088
+ return { kind: "paragraph", sectionIndex: para2.sectionIndex, xmlStart: para2.start };
26024
27089
  }
26025
27090
  if (block.type === "table" && block.table) {
26026
27091
  if (st.tableOrdinals.size !== st.scanTables.length) return void 0;
@@ -26057,13 +27122,13 @@ var HwpxSession = class _HwpxSession {
26057
27122
  if (!scanTable) {
26058
27123
  return { capability: "locked", reason: "\uD45C \uC18C\uC2A4\uB9F5 \uB9E4\uD551 \uC2E4\uD328" };
26059
27124
  }
26060
- const table = block.table;
27125
+ const table2 = block.table;
26061
27126
  const cells = [];
26062
27127
  let anyEditable = false;
26063
- for (let r = 0; r < table.rows; r++) {
27128
+ for (let r = 0; r < table2.rows; r++) {
26064
27129
  const row = [];
26065
- for (let c = 0; c < table.cols; c++) {
26066
- const info = cellStaticCheck(table, scanTable, r, c);
27130
+ for (let c = 0; c < table2.cols; c++) {
27131
+ const info = cellStaticCheck(table2, scanTable, r, c);
26067
27132
  if (info.editable) anyEditable = true;
26068
27133
  row.push(info);
26069
27134
  }
@@ -26252,12 +27317,12 @@ var HwpxSession = class _HwpxSession {
26252
27317
  return 1;
26253
27318
  }
26254
27319
  };
26255
- function cellStaticCheck(table, scanTable, r, c) {
26256
- const irCell = table.cells[r]?.[c];
27320
+ function cellStaticCheck(table2, scanTable, r, c) {
27321
+ const irCell = table2.cells[r]?.[c];
26257
27322
  if (!irCell) return { editable: false, reason: "\uC140 \uC88C\uD45C \uBC94\uC704 \uBC16" };
26258
- const cell = scanTable.cellByAnchor.get(`${r},${c}`);
26259
- if (!cell) return { editable: false, reason: "\uBCD1\uD569 \uC601\uC5ED\uC758 \uBE48 \uCE78\uC774\uAC70\uB098 \uC88C\uD45C \uBD88\uC77C\uCE58" };
26260
- const scanJoined = cell.paragraphs.map((p) => p.text).filter((t) => normForMatch(t)).join("\n");
27323
+ const cell2 = scanTable.cellByAnchor.get(`${r},${c}`);
27324
+ if (!cell2) return { editable: false, reason: "\uBCD1\uD569 \uC601\uC5ED\uC758 \uBE48 \uCE78\uC774\uAC70\uB098 \uC88C\uD45C \uBD88\uC77C\uCE58" };
27325
+ const scanJoined = cell2.paragraphs.map((p) => p.text).filter((t) => normForMatch(t)).join("\n");
26261
27326
  if (normForMatch(scanJoined) !== normForMatch(stripCellTokens(irCell.text))) {
26262
27327
  if (normForMatch(irCell.text) !== "" || normForMatch(scanJoined) !== "") {
26263
27328
  const flatBlocks = (irCell.blocks ?? []).filter((b) => b.type === "paragraph" || b.type === "heading");
@@ -26267,9 +27332,9 @@ function cellStaticCheck(table, scanTable, r, c) {
26267
27332
  }
26268
27333
  }
26269
27334
  }
26270
- const nonEmpty = cell.paragraphs.filter((p) => normForMatch(p.text) !== "");
27335
+ const nonEmpty = cell2.paragraphs.filter((p) => normForMatch(p.text) !== "");
26271
27336
  if (nonEmpty.length === 0) {
26272
- if (cell.paragraphs.length === 0) {
27337
+ if (cell2.paragraphs.length === 0) {
26273
27338
  return { editable: false, reason: "\uBE48 \uC140\uC5D0 \uBB38\uB2E8\uC774 \uC5C6\uC5B4 \uD14D\uC2A4\uD2B8 \uC0BD\uC785 \uBD88\uAC00" };
26274
27339
  }
26275
27340
  return { editable: true };
@@ -26587,7 +27652,8 @@ function reflowPara(p, doc, styles, areaW, startV, mode) {
26587
27652
  const firstWidth = avail;
26588
27653
  const contWidth = Math.max(500, avail + Math.min(0, geom.marginIntent));
26589
27654
  const contHorz = marginL - Math.min(0, geom.marginIntent);
26590
- const wrap = text.length === 0 ? { lines: 1, starts: [0], lastLineWidth: 0 } : simulateWrap(text, firstWidth, contWidth, height, ratio, mode, { spacingPct });
27655
+ const paraMode = geom.wrapMode ?? mode;
27656
+ const wrap = text.length === 0 ? { lines: 1, starts: [0], lastLineWidth: 0 } : simulateWrap(text, firstWidth, contWidth, height, ratio, paraMode, { spacingPct });
26591
27657
  const pitch = pitchFor(height, geom);
26592
27658
  const baseline = Math.round(height * BASELINE_RATIO);
26593
27659
  const spacing = Math.max(0, pitch - height);
@@ -26625,15 +27691,15 @@ function reflowTablesIn(p, doc, styles, mode, counter) {
26625
27691
  if (ln(obj) !== "tbl") continue;
26626
27692
  for (const tr of elements(obj)) {
26627
27693
  if (ln(tr) !== "tr") continue;
26628
- for (const tc of elements(tr)) {
26629
- if (ln(tc) !== "tc") continue;
26630
- const csz = findChildByLocalName(tc, "cellSz");
26631
- const cm = findChildByLocalName(tc, "cellMargin");
27694
+ for (const tc2 of elements(tr)) {
27695
+ if (ln(tc2) !== "tc") continue;
27696
+ const csz = findChildByLocalName(tc2, "cellSz");
27697
+ const cm = findChildByLocalName(tc2, "cellMargin");
26632
27698
  const cellW = num2(csz, "width");
26633
27699
  const mL = cm ? num2(cm, "left", 141) : 141;
26634
27700
  const mR = cm ? num2(cm, "right", 141) : 141;
26635
27701
  const areaW = Math.max(500, cellW - mL - mR);
26636
- const sub = findChildByLocalName(tc, "subList");
27702
+ const sub = findChildByLocalName(tc2, "subList");
26637
27703
  if (sub) reflowBlockFlow(sub, doc, styles, areaW, mode, counter, 0);
26638
27704
  }
26639
27705
  }
@@ -27041,10 +28107,10 @@ function drawShape(o, x, y, ctx, depth) {
27041
28107
  for (const p of elements2(sub)) if (ln2(p) === "p") drawPara(p, x, y, w, ctx, depth + 1);
27042
28108
  }
27043
28109
  }
27044
- function cellContentExtent(cell) {
27045
- if (!cell.sub) return 0;
28110
+ function cellContentExtent(cell2) {
28111
+ if (!cell2.sub) return 0;
27046
28112
  let ext = 0;
27047
- for (const p of elements2(cell.sub)) {
28113
+ for (const p of elements2(cell2.sub)) {
27048
28114
  if (ln2(p) !== "p") continue;
27049
28115
  const m = buildPara(p);
27050
28116
  for (const s of m.segs) ext = Math.max(ext, s.vertpos + s.textheight);
@@ -27069,30 +28135,30 @@ function edgeLine(x1, y1, x2, y2, e) {
27069
28135
  const dash = /DASH|DOT/.test(e.type) ? ` stroke-dasharray="${e.type.includes("DOT") ? "1,1.5" : "3,1.5"}"` : "";
27070
28136
  return `<line x1="${pt(x1)}" y1="${pt(y1)}" x2="${pt(x2)}" y2="${pt(y2)}" stroke="${escapeXml3(e.color)}" stroke-width="${e.widthPt.toFixed(2)}"${dash}/>`;
27071
28137
  }
27072
- function collectCells(tbl) {
27073
- const inMargin = findChildByLocalName(tbl, "inMargin");
28138
+ function collectCells(tbl2) {
28139
+ const inMargin = findChildByLocalName(tbl2, "inMargin");
27074
28140
  const defL = num3(inMargin, "left", 141), defR = num3(inMargin, "right", 141);
27075
28141
  const defT = num3(inMargin, "top", 141), defB = num3(inMargin, "bottom", 141);
27076
28142
  const cells = [];
27077
- for (const tr of elements2(tbl)) {
28143
+ for (const tr of elements2(tbl2)) {
27078
28144
  if (ln2(tr) !== "tr") continue;
27079
- for (const tc of elements2(tr)) {
27080
- if (ln2(tc) !== "tc") continue;
27081
- const addr = findChildByLocalName(tc, "cellAddr");
27082
- const span = findChildByLocalName(tc, "cellSpan");
27083
- const csz = findChildByLocalName(tc, "cellSz");
27084
- const cm = findChildByLocalName(tc, "cellMargin");
28145
+ for (const tc2 of elements2(tr)) {
28146
+ if (ln2(tc2) !== "tc") continue;
28147
+ const addr = findChildByLocalName(tc2, "cellAddr");
28148
+ const span = findChildByLocalName(tc2, "cellSpan");
28149
+ const csz = findChildByLocalName(tc2, "cellSz");
28150
+ const cm = findChildByLocalName(tc2, "cellMargin");
27085
28151
  if (!addr || !csz) continue;
27086
28152
  cells.push({
27087
- el: tc,
28153
+ el: tc2,
27088
28154
  ca: num3(addr, "colAddr"),
27089
28155
  ra: num3(addr, "rowAddr"),
27090
28156
  cs: Math.max(1, num3(span, "colSpan", 1)),
27091
28157
  rs: Math.max(1, num3(span, "rowSpan", 1)),
27092
28158
  w: num3(csz, "width"),
27093
28159
  h: num3(csz, "height"),
27094
- bfId: tc.getAttribute("borderFillIDRef"),
27095
- sub: findChildByLocalName(tc, "subList"),
28160
+ bfId: tc2.getAttribute("borderFillIDRef"),
28161
+ sub: findChildByLocalName(tc2, "subList"),
27096
28162
  marginL: cm ? num3(cm, "left", defL) : defL,
27097
28163
  marginR: cm ? num3(cm, "right", defR) : defR,
27098
28164
  marginT: cm ? num3(cm, "top", defT) : defT,
@@ -27102,8 +28168,8 @@ function collectCells(tbl) {
27102
28168
  }
27103
28169
  return cells;
27104
28170
  }
27105
- function measureTableHeight(tbl) {
27106
- const cells = collectCells(tbl);
28171
+ function measureTableHeight(tbl2) {
28172
+ const cells = collectCells(tbl2);
27107
28173
  if (cells.length === 0 || cells.length > 4096) return 0;
27108
28174
  const nRows = Math.max(...cells.map((c) => c.ra + c.rs));
27109
28175
  const rowH = solveRowHeights(
@@ -27114,14 +28180,14 @@ function measureTableHeight(tbl) {
27114
28180
  for (const h of rowH) sum += h;
27115
28181
  return sum;
27116
28182
  }
27117
- function drawTable(tbl, tx, ty, ctx, depth) {
28183
+ function drawTable(tbl2, tx, ty, ctx, depth) {
27118
28184
  if (depth > 16) {
27119
28185
  warnOnce(ctx, "depth", "\uC911\uCCA9 \uAE4A\uC774 16 \uCD08\uACFC \u2014 \uC774\uD558 \uC0DD\uB7B5");
27120
28186
  return;
27121
28187
  }
27122
28188
  ctx.stats.tables++;
27123
- const tblSz = findChildByLocalName(tbl, "sz");
27124
- const cells = collectCells(tbl);
28189
+ const tblSz = findChildByLocalName(tbl2, "sz");
28190
+ const cells = collectCells(tbl2);
27125
28191
  if (cells.length === 0 || cells.length > 4096) return;
27126
28192
  const nCols = Math.max(...cells.map((c) => c.ca + c.cs));
27127
28193
  const nRows = Math.max(...cells.map((c) => c.ra + c.rs));
@@ -27485,7 +28551,7 @@ async function parseHwp(buffer, options) {
27485
28551
  async function parsePdf(buffer, options) {
27486
28552
  let parsePdfDocument;
27487
28553
  try {
27488
- const mod = await import("./parser-JBBA5A5E.js");
28554
+ const mod = await import("./parser-G433UZMX.js");
27489
28555
  parsePdfDocument = mod.parsePdfDocument;
27490
28556
  } catch {
27491
28557
  return {
@@ -27600,13 +28666,16 @@ export {
27600
28666
  fillWithUniqueGuard,
27601
28667
  fitRatioForFewerLines,
27602
28668
  formatFillValue,
28669
+ gongmunLintWarnings,
27603
28670
  hwpxToProfile,
27604
28671
  inferFieldType,
27605
28672
  isHwpxFile,
28673
+ isKnownFont,
27606
28674
  isLabelCell,
27607
28675
  isOldHwpFile,
27608
28676
  isPdfFile,
27609
28677
  isZipFile,
28678
+ lintGongmunText,
27610
28679
  markdownToHwpx,
27611
28680
  markdownToPdf,
27612
28681
  measureTextWidth,
@@ -27630,6 +28699,7 @@ export {
27630
28699
  scanSectionXml,
27631
28700
  simulateWrap,
27632
28701
  simulateWrapKeepWord,
28702
+ unknownFontWarnings,
27633
28703
  validateHwpx
27634
28704
  };
27635
28705
  //# sourceMappingURL=index.js.map