kordoc 3.16.0 → 3.16.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +1 -1
  2. package/dist/{-H7N62NZU.js → -C4FVXHIP.js} +7 -7
  3. package/dist/{chunk-IC56KHBL.js → chunk-4WI7QXEG.js} +2 -2
  4. package/dist/{chunk-BIP4JAVG.cjs → chunk-72LLOLFX.cjs} +13 -6
  5. package/dist/chunk-72LLOLFX.cjs.map +1 -0
  6. package/dist/{chunk-5RHRQ7HK.js → chunk-E4Y73XRH.js} +8 -4
  7. package/dist/chunk-E4Y73XRH.js.map +1 -0
  8. package/dist/{chunk-Q7EGGW3H.js → chunk-EJ2ZIYTO.js} +13 -6
  9. package/dist/chunk-EJ2ZIYTO.js.map +1 -0
  10. package/dist/{chunk-WD5NUUU6.js → chunk-EUEKDZ7O.js} +315 -262
  11. package/dist/chunk-EUEKDZ7O.js.map +1 -0
  12. package/dist/{chunk-JFNWJFKP.js → chunk-HECUYZZK.js} +2 -2
  13. package/dist/{chunk-LYL4IL3E.js → chunk-IS3IK7UT.js} +13 -6
  14. package/dist/chunk-IS3IK7UT.js.map +1 -0
  15. package/dist/{chunk-FGL7BH4P.js → chunk-WR5LHRXO.js} +49 -20
  16. package/dist/chunk-WR5LHRXO.js.map +1 -0
  17. package/dist/cli.js +56 -17
  18. package/dist/cli.js.map +1 -1
  19. package/dist/index.cjs +586 -502
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.cts +11 -3
  22. package/dist/index.d.ts +11 -3
  23. package/dist/index.js +358 -274
  24. package/dist/index.js.map +1 -1
  25. package/dist/mcp.js +25 -16
  26. package/dist/mcp.js.map +1 -1
  27. package/dist/{parser-HBHCD7TE.js → parser-CMPNM6ZL.js} +25 -12
  28. package/dist/parser-CMPNM6ZL.js.map +1 -0
  29. package/dist/{parser-5G247XYD.js → parser-GWL72XYS.js} +24 -11
  30. package/dist/parser-GWL72XYS.js.map +1 -0
  31. package/dist/{parser-6V7F3GET.cjs → parser-YVRTKGKO.cjs} +36 -23
  32. package/dist/parser-YVRTKGKO.cjs.map +1 -0
  33. package/dist/render-A2LFMJCP.js +10 -0
  34. package/dist/seal-KA4VAV2Z.js +10 -0
  35. package/dist/{watch-HIYNOSFD.js → watch-WLI6K3IR.js} +7 -7
  36. package/package.json +2 -5
  37. package/dist/chunk-5RHRQ7HK.js.map +0 -1
  38. package/dist/chunk-BIP4JAVG.cjs.map +0 -1
  39. package/dist/chunk-FGL7BH4P.js.map +0 -1
  40. package/dist/chunk-LYL4IL3E.js.map +0 -1
  41. package/dist/chunk-Q7EGGW3H.js.map +0 -1
  42. package/dist/chunk-WD5NUUU6.js.map +0 -1
  43. package/dist/parser-5G247XYD.js.map +0 -1
  44. package/dist/parser-6V7F3GET.cjs.map +0 -1
  45. package/dist/parser-HBHCD7TE.js.map +0 -1
  46. package/dist/render-VA4NHROW.js +0 -10
  47. package/dist/seal-UVDRGHEF.js +0 -10
  48. /package/dist/{-H7N62NZU.js.map → -C4FVXHIP.js.map} +0 -0
  49. /package/dist/{chunk-IC56KHBL.js.map → chunk-4WI7QXEG.js.map} +0 -0
  50. /package/dist/{chunk-JFNWJFKP.js.map → chunk-HECUYZZK.js.map} +0 -0
  51. /package/dist/{render-VA4NHROW.js.map → render-A2LFMJCP.js.map} +0 -0
  52. /package/dist/{seal-UVDRGHEF.js.map → seal-KA4VAV2Z.js.map} +0 -0
  53. /package/dist/{watch-HIYNOSFD.js.map → watch-WLI6K3IR.js.map} +0 -0
package/dist/index.js CHANGED
@@ -19,7 +19,7 @@ import {
19
19
  sanitizeHref,
20
20
  stripDtd,
21
21
  toArrayBuffer
22
- } from "./chunk-Q7EGGW3H.js";
22
+ } from "./chunk-EJ2ZIYTO.js";
23
23
  import {
24
24
  parsePageRange
25
25
  } from "./chunk-GE43BE46.js";
@@ -926,8 +926,8 @@ function maskLiteralSpans(eqString) {
926
926
  function findKeywordToken(eqString, word, from = 0) {
927
927
  const masked = maskLiteralSpans(eqString);
928
928
  for (let i = masked.indexOf(word, from); i !== -1; i = masked.indexOf(word, i + 1)) {
929
- const okL = i === 0 || masked[i - 1] === " ";
930
- const okR = i + word.length === masked.length || masked[i + word.length] === " ";
929
+ const okL = i === 0 || /\s/.test(masked[i - 1]);
930
+ const okR = i + word.length === masked.length || /\s/.test(masked[i + word.length]);
931
931
  if (okL && okR) return i;
932
932
  }
933
933
  return -1;
@@ -938,11 +938,22 @@ function replaceFrac(eqString) {
938
938
  const cursor = findKeywordToken(eqString, hmlFrac);
939
939
  if (cursor === -1) break;
940
940
  try {
941
- const [numStart, numEnd] = findBrackets(eqString, cursor, 0);
942
- const numerator = eqString.slice(numStart, numEnd);
941
+ let end = cursor;
942
+ while (end > 0 && /\s/.test(eqString[end - 1])) end--;
943
+ let numStart, numEnd, wrapped;
944
+ if (end > 0 && eqString[end - 1] === "}") {
945
+ [numStart, numEnd] = findBrackets(eqString, end - 1, 0);
946
+ wrapped = eqString.slice(numStart, numEnd);
947
+ } else {
948
+ numEnd = end;
949
+ numStart = end;
950
+ while (numStart > 0 && !/\s/.test(eqString[numStart - 1])) numStart--;
951
+ if (numStart === numEnd) throw new Error("empty numerator");
952
+ wrapped = "{" + eqString.slice(numStart, numEnd) + "}";
953
+ }
943
954
  const beforeFrac = eqString.slice(0, numStart);
944
955
  const afterFrac = eqString.slice(cursor + hmlFrac.length);
945
- eqString = beforeFrac + "\\frac" + numerator + afterFrac;
956
+ eqString = beforeFrac + "\\frac" + wrapped + afterFrac;
946
957
  } catch {
947
958
  return eqString;
948
959
  }
@@ -18348,7 +18359,7 @@ function parseTable(tbl, styles, numbering, footnotes, rels) {
18348
18359
  if (trPrEls.length > 0) {
18349
18360
  const gridBeforeEls = getChildElements(trPrEls[0], "gridBefore");
18350
18361
  if (gridBeforeEls.length > 0) {
18351
- col = parseInt(getAttr(gridBeforeEls[0], "val") ?? "0", 10) || 0;
18362
+ col = Math.max(0, parseInt(getAttr(gridBeforeEls[0], "val") ?? "0", 10) || 0);
18352
18363
  }
18353
18364
  }
18354
18365
  for (const tc of getChildElements(tr, "tc")) {
@@ -18877,34 +18888,47 @@ function countSections(body) {
18877
18888
 
18878
18889
  // src/form/match.ts
18879
18890
  function parseYMD(v) {
18880
- const d = v.replace(/\D/g, "");
18881
18891
  let y, m, day;
18882
- if (d.length >= 8) {
18883
- y = d.slice(0, 4);
18884
- m = d.slice(4, 6);
18885
- day = d.slice(6, 8);
18886
- } else if (d.length === 6) {
18887
- const yy = +d.slice(0, 2);
18888
- y = String(yy <= 29 ? 2e3 + yy : 1900 + yy);
18889
- m = d.slice(2, 4);
18890
- day = d.slice(4, 6);
18891
- } else return null;
18892
+ const parts = v.split(/[^0-9]+/).filter(Boolean);
18893
+ if (parts.length === 3) {
18894
+ const [yp, mp, dp] = parts;
18895
+ const yn = +yp;
18896
+ y = yp.length >= 3 ? yp : String(yn <= 29 ? 2e3 + yn : 1900 + yn);
18897
+ m = mp.padStart(2, "0");
18898
+ day = dp.padStart(2, "0");
18899
+ } else {
18900
+ const d = v.replace(/\D/g, "");
18901
+ if (d.length >= 8) {
18902
+ y = d.slice(0, 4);
18903
+ m = d.slice(4, 6);
18904
+ day = d.slice(6, 8);
18905
+ } else if (d.length === 6) {
18906
+ const yy = +d.slice(0, 2);
18907
+ y = String(yy <= 29 ? 2e3 + yy : 1900 + yy);
18908
+ m = d.slice(2, 4);
18909
+ day = d.slice(4, 6);
18910
+ } else return null;
18911
+ }
18912
+ if (+m < 1 || +m > 12 || +day < 1 || +day > 31) return null;
18892
18913
  return { y, yy: y.slice(2), m, d: day };
18893
18914
  }
18894
18915
  function fmtDate(v, style) {
18895
18916
  const p = parseYMD(v);
18896
18917
  if (!p) return v;
18897
- return (style || "yyyy-mm-dd").replace(/yyyy/g, p.y).replace(/yy/g, p.yy).replace(/mm/g, p.m).replace(/dd/g, p.d).replace(/m/g, String(+p.m)).replace(/d/g, String(+p.d));
18918
+ return (style || "yyyy-mm-dd").replace(/yyyy/gi, p.y).replace(/yy/gi, p.yy).replace(/mm/gi, p.m).replace(/dd/gi, p.d).replace(/(?<![a-z])m(?![a-z])/gi, String(+p.m)).replace(/(?<![a-z])d(?![a-z])/gi, String(+p.d));
18898
18919
  }
18899
18920
  function maskDigits(v, pattern) {
18900
18921
  const ds = v.replace(/\D/g, "");
18922
+ const need = (pattern.match(/#/g) ?? []).length;
18923
+ if (need === 0 || ds.length !== need) return v;
18901
18924
  let i = 0;
18902
- return pattern.replace(/#/g, () => ds[i++] ?? "");
18925
+ return pattern.replace(/#/g, () => ds[i++]);
18903
18926
  }
18904
18927
  function fmtPhone(v, style) {
18905
18928
  const d = v.replace(/\D/g, "");
18906
18929
  if (d.length < 9) return v;
18907
- const a = d.slice(0, 3), b = d.slice(3, -4), c = d.slice(-4);
18930
+ const areaLen = d.startsWith("02") ? 2 : 3;
18931
+ const a = d.slice(0, areaLen), b = d.slice(areaLen, -4), c = d.slice(-4);
18908
18932
  switch (style) {
18909
18933
  case "digits":
18910
18934
  return d;
@@ -18913,9 +18937,9 @@ function fmtPhone(v, style) {
18913
18937
  case "space":
18914
18938
  return `${a} ${b} ${c}`;
18915
18939
  case "intl":
18916
- return `+82-${d.slice(1, 3)}-${b}-${c}`;
18940
+ return `+82-${d.slice(1, areaLen)}-${b}-${c}`;
18917
18941
  case "intl-paren":
18918
- return `82)${d.slice(1, 3)}-${b}-${c}`;
18942
+ return `82)${d.slice(1, areaLen)}-${b}-${c}`;
18919
18943
  default:
18920
18944
  return `${a}-${b}-${c}`;
18921
18945
  }
@@ -18943,7 +18967,10 @@ function formatFillValue(value, format) {
18943
18967
  if (kind === "phone") return fmtPhone(value, style);
18944
18968
  if (kind === "rrn") return fmtRRN(value, style);
18945
18969
  if (kind === "mask") return maskDigits(value, style);
18946
- if (kind === "digits") return value.replace(/\D/g, "");
18970
+ if (kind === "digits") {
18971
+ const only = value.replace(/\D/g, "");
18972
+ return only || value;
18973
+ }
18947
18974
  if (kind === "upper") return value.toUpperCase();
18948
18975
  if (kind === "lower") return value.toLowerCase();
18949
18976
  if (kind === "nospace") return value.replace(/\s+/g, "");
@@ -19020,7 +19047,7 @@ function isKeywordLabel(text) {
19020
19047
  }
19021
19048
  return false;
19022
19049
  }
19023
- function fillInCellPatterns(cellText, values, matchedLabels) {
19050
+ function fillInCellPatterns(cellText, values, matchedLabels, blockedLabels) {
19024
19051
  let text = cellText;
19025
19052
  const matches = [];
19026
19053
  text = text.replace(
@@ -19028,6 +19055,7 @@ function fillInCellPatterns(cellText, values, matchedLabels) {
19028
19055
  (match, prefix, suffix) => {
19029
19056
  const label = prefix + suffix;
19030
19057
  const normalizedLabel = normalizeLabel(label);
19058
+ if (blockedLabels?.has(normalizedLabel)) return match;
19031
19059
  const matchKey = values.available(normalizedLabel) ? normalizedLabel : values.available(normalizeLabel(prefix)) ? normalizeLabel(prefix) : void 0;
19032
19060
  if (matchKey === void 0) return match;
19033
19061
  const newValue = values.consume(matchKey);
@@ -19123,8 +19151,12 @@ async function fillWithUniqueGuard(values, run) {
19123
19151
  };
19124
19152
  const dup = new Set([...counts].filter(([k, n]) => n >= 2 && !isArrayValue(k)).map(([k]) => k));
19125
19153
  if (dup.size === 0) return { ...first, rejected: [] };
19154
+ const blockedLabels = /* @__PURE__ */ new Set();
19155
+ for (const f of first.filled) {
19156
+ if (f.key && dup.has(f.key)) blockedLabels.add(normalizeLabel(f.label));
19157
+ }
19126
19158
  const filtered = Object.fromEntries(Object.entries(values).filter(([label]) => !dup.has(normalizeLabel(label))));
19127
- const second = await run(filtered);
19159
+ const second = await run(filtered, blockedLabels);
19128
19160
  const rejected = Object.keys(values).filter((label) => dup.has(normalizeLabel(label)));
19129
19161
  return { ...second, rejected };
19130
19162
  }
@@ -19379,7 +19411,7 @@ function extractFormSchema(blocks) {
19379
19411
  }
19380
19412
 
19381
19413
  // src/form/filler.ts
19382
- function fillFormFields(blocks, values) {
19414
+ function fillFormFields(blocks, values, blockedLabels) {
19383
19415
  const cloned = structuredClone(blocks);
19384
19416
  const filled = [];
19385
19417
  const matchedLabels = /* @__PURE__ */ new Set();
@@ -19392,7 +19424,7 @@ function fillFormFields(blocks, values) {
19392
19424
  for (let c = 0; c < table.cols; c++) {
19393
19425
  const cell = table.cells[r]?.[c];
19394
19426
  if (!cell) continue;
19395
- const result = fillInCellPatterns(cell.text, cursor, matchedLabels);
19427
+ const result = fillInCellPatterns(cell.text, cursor, matchedLabels, blockedLabels);
19396
19428
  if (result) {
19397
19429
  cell.text = result.text;
19398
19430
  patternFilledCells.add(cell);
@@ -19404,11 +19436,11 @@ function fillFormFields(blocks, values) {
19404
19436
  }
19405
19437
  }
19406
19438
  for (const table of allTables) {
19407
- fillTable(table, cursor, filled, matchedLabels, patternFilledCells);
19439
+ fillTable(table, cursor, filled, matchedLabels, patternFilledCells, blockedLabels);
19408
19440
  }
19409
19441
  for (const block of cloned) {
19410
19442
  if (block.type !== "paragraph" || !block.text) continue;
19411
- const newText = fillInlineFields(block.text, cursor, filled, matchedLabels);
19443
+ const newText = fillInlineFields(block.text, cursor, filled, matchedLabels, blockedLabels);
19412
19444
  if (newText !== block.text) block.text = newText;
19413
19445
  }
19414
19446
  const unmatched = resolveUnmatched(normalizedValues, matchedLabels, values);
@@ -19446,7 +19478,7 @@ function coveredPositions(table) {
19446
19478
  }
19447
19479
  return covered;
19448
19480
  }
19449
- function fillTable(table, values, filled, matchedLabels, patternFilledCells) {
19481
+ function fillTable(table, values, filled, matchedLabels, patternFilledCells, blockedLabels) {
19450
19482
  if (table.cols < 2) return;
19451
19483
  const covered = coveredPositions(table);
19452
19484
  for (let r = 0; r < table.rows; r++) {
@@ -19463,6 +19495,7 @@ function fillTable(table, values, filled, matchedLabels, patternFilledCells) {
19463
19495
  if (isKeywordLabel(valueCell.text)) continue;
19464
19496
  const normalizedCellLabel = normalizeLabel(labelCell.text);
19465
19497
  if (!normalizedCellLabel) continue;
19498
+ if (blockedLabels?.has(normalizedCellLabel)) continue;
19466
19499
  const matchKey = findMatchingKey(normalizedCellLabel, values);
19467
19500
  if (matchKey === void 0) continue;
19468
19501
  const newValue = values.consume(matchKey);
@@ -19496,6 +19529,7 @@ function fillTable(table, values, filled, matchedLabels, patternFilledCells) {
19496
19529
  const valueCell = table.cells[r]?.[c];
19497
19530
  if (!headerCell || !valueCell) continue;
19498
19531
  const headerLabel = normalizeLabel(headerCell.text);
19532
+ if (blockedLabels?.has(headerLabel)) continue;
19499
19533
  const matchKey = findMatchingKey(headerLabel, values);
19500
19534
  if (matchKey === void 0) continue;
19501
19535
  if (!values.isArray(matchKey) && matchedLabels.has(matchKey)) continue;
@@ -19514,13 +19548,15 @@ function fillTable(table, values, filled, matchedLabels, patternFilledCells) {
19514
19548
  }
19515
19549
  }
19516
19550
  }
19517
- function fillInlineFields(text, values, filled, matchedLabels) {
19551
+ function fillInlineFields(text, values, filled, matchedLabels, blockedLabels) {
19518
19552
  const segments = scanInlineSegments(text);
19519
19553
  if (segments.length === 0) return text;
19520
19554
  let out = "";
19521
19555
  let pos = 0;
19522
19556
  for (const seg of segments) {
19523
- const matchKey = findMatchingKey(normalizeLabel(seg.label), values);
19557
+ const nlabel = normalizeLabel(seg.label);
19558
+ if (blockedLabels?.has(nlabel)) continue;
19559
+ const matchKey = findMatchingKey(nlabel, values);
19524
19560
  if (matchKey === void 0) continue;
19525
19561
  const newValue = values.consume(matchKey);
19526
19562
  if (newValue === void 0) continue;
@@ -20263,7 +20299,7 @@ function patchZipEntries(original, replacements, additions) {
20263
20299
  }
20264
20300
 
20265
20301
  // src/form/filler-hwpx.ts
20266
- async function fillHwpx(hwpxBuffer, values) {
20302
+ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
20267
20303
  const u8 = new Uint8Array(hwpxBuffer);
20268
20304
  const zip = await JSZip6.loadAsync(hwpxBuffer);
20269
20305
  const sectionPaths = Object.keys(zip.files).filter((name) => /[Ss]ection\d+\.xml$/i.test(name)).sort();
@@ -20307,7 +20343,7 @@ async function fillHwpx(hwpxBuffer, values) {
20307
20343
  for (const cell of row) {
20308
20344
  for (const para of cell.paragraphs) {
20309
20345
  const text = matchText(para);
20310
- const result = fillInCellPatterns(text, cursor, matchedLabels);
20346
+ const result = fillInCellPatterns(text, cursor, matchedLabels, blockedLabels);
20311
20347
  if (!result) continue;
20312
20348
  const l = led(para);
20313
20349
  if (l.fullText !== void 0) continue;
@@ -20325,7 +20361,7 @@ async function fillHwpx(hwpxBuffer, values) {
20325
20361
  for (const m of result.matches) {
20326
20362
  l.filledIdx.push(filled.length);
20327
20363
  l.matchKeys.push(m.key);
20328
- filled.push({ label: m.label, value: m.value, row: -1, col: -1 });
20364
+ filled.push({ label: m.label, value: m.value, row: -1, col: -1, key: m.key });
20329
20365
  }
20330
20366
  }
20331
20367
  }
@@ -20341,6 +20377,7 @@ async function fillHwpx(hwpxBuffer, values) {
20341
20377
  if (isKeywordLabel(cellLabelText(valueCell))) continue;
20342
20378
  const normalizedCellLabel = normalizeLabel(labelText);
20343
20379
  if (!normalizedCellLabel) continue;
20380
+ if (blockedLabels?.has(normalizedCellLabel)) continue;
20344
20381
  const matchKey = findMatchingKey(normalizedCellLabel, cursor);
20345
20382
  if (matchKey === void 0) continue;
20346
20383
  if (patternApplied.has(valueCell)) {
@@ -20358,7 +20395,8 @@ async function fillHwpx(hwpxBuffer, values) {
20358
20395
  label: labelText.trim().replace(/[::]\s*$/, ""),
20359
20396
  value: newValue,
20360
20397
  row: rowIdx,
20361
- col: colIdx
20398
+ col: colIdx,
20399
+ key: matchKey
20362
20400
  });
20363
20401
  } else {
20364
20402
  const paras = valueCell.paragraphs;
@@ -20380,7 +20418,8 @@ async function fillHwpx(hwpxBuffer, values) {
20380
20418
  label: labelText.trim().replace(/[::]\s*$/, ""),
20381
20419
  value: newValue,
20382
20420
  row: rowIdx,
20383
- col: colIdx
20421
+ col: colIdx,
20422
+ key: matchKey
20384
20423
  });
20385
20424
  }
20386
20425
  }
@@ -20396,6 +20435,7 @@ async function fillHwpx(hwpxBuffer, values) {
20396
20435
  const dataCells = table.rows[rowIdx];
20397
20436
  for (let colIdx = 0; colIdx < Math.min(headerCells.length, dataCells.length); colIdx++) {
20398
20437
  const headerLabel = normalizeLabel(cellLabelText(headerCells[colIdx]));
20438
+ if (blockedLabels?.has(headerLabel)) continue;
20399
20439
  const matchKey = findMatchingKey(headerLabel, cursor);
20400
20440
  if (matchKey === void 0) continue;
20401
20441
  if (!cursor.isArray(matchKey) && matchedLabels.has(matchKey)) continue;
@@ -20431,7 +20471,9 @@ async function fillHwpx(hwpxBuffer, values) {
20431
20471
  if (existing?.fullText !== void 0) continue;
20432
20472
  const text = matchText(para);
20433
20473
  for (const seg of scanInlineSegments(text)) {
20434
- const matchKey = findMatchingKey(normalizeLabel(seg.label), cursor);
20474
+ const nlabel = normalizeLabel(seg.label);
20475
+ if (blockedLabels?.has(nlabel)) continue;
20476
+ const matchKey = findMatchingKey(nlabel, cursor);
20435
20477
  if (matchKey === void 0) continue;
20436
20478
  const newValue = cursor.consume(matchKey);
20437
20479
  if (newValue === void 0) continue;
@@ -20441,7 +20483,7 @@ async function fillHwpx(hwpxBuffer, values) {
20441
20483
  matchedLabels.add(matchKey);
20442
20484
  l.filledIdx.push(filled.length);
20443
20485
  l.matchKeys.push(matchKey);
20444
- filled.push({ label: seg.label.trim(), value: newValue, row: -1, col: -1 });
20486
+ filled.push({ label: seg.label.trim(), value: newValue, row: -1, col: -1, key: matchKey });
20445
20487
  }
20446
20488
  }
20447
20489
  const splices = [];
@@ -20974,7 +21016,8 @@ function buildPrvText(blocks) {
20974
21016
  let bytes = 0;
20975
21017
  for (const b of blocks) {
20976
21018
  let text = b.text || (b.rows ? b.rows.map((r) => r.join(" ")).join("\n") : "");
20977
- if (b.type === "html_table") text = text.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
21019
+ if (b.type === "code_block" && (b.lang || "").toLowerCase() === "chart") text = "[\uCC28\uD2B8]";
21020
+ else if (b.type === "html_table") text = text.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
20978
21021
  if (!text) continue;
20979
21022
  lines.push(text);
20980
21023
  bytes += text.length * 3;
@@ -20993,7 +21036,7 @@ function findMathDelim(s, from) {
20993
21036
  return i;
20994
21037
  }
20995
21038
  function parseMarkdownToBlocks(md2) {
20996
- const lines = md2.split("\n");
21039
+ const lines = md2.replace(/\r\n?/g, "\n").split("\n");
20997
21040
  const blocks = [];
20998
21041
  let i = 0;
20999
21042
  while (i < lines.length) {
@@ -21041,13 +21084,13 @@ function parseMarkdownToBlocks(md2) {
21041
21084
  continue;
21042
21085
  }
21043
21086
  }
21044
- const fenceMatch = line.match(/^(`{3,}|~{3,})(.*)$/);
21087
+ const fenceMatch = line.match(/^ {0,3}(`{3,}|~{3,})(.*)$/);
21045
21088
  if (fenceMatch) {
21046
21089
  const fence = fenceMatch[1];
21047
21090
  const lang = fenceMatch[2].trim();
21048
21091
  const codeLines = [];
21049
21092
  i++;
21050
- while (i < lines.length && !lines[i].startsWith(fence)) {
21093
+ while (i < lines.length && !lines[i].replace(/^ {0,3}/, "").startsWith(fence)) {
21051
21094
  codeLines.push(lines[i]);
21052
21095
  i++;
21053
21096
  }
@@ -21383,6 +21426,219 @@ function generateHeaderXml(theme, gongmun, ratioVariants = []) {
21383
21426
  </hh:head>`;
21384
21427
  }
21385
21428
 
21429
+ // src/hwpx/chart-gen.ts
21430
+ var XML_ESC = { "&": "&amp;", "<": "&lt;", ">": "&gt;" };
21431
+ var xmlEscape = (s) => s.replace(/[&<>]/g, (c) => XML_ESC[c]);
21432
+ var CHART_TYPES = {
21433
+ 0: { el: "barChart", dir: "col", grp: "clustered" },
21434
+ 1: { el: "barChart", dir: "col", grp: "stacked", overlap: 100 },
21435
+ 2: { el: "lineChart", grp: "standard", marker: true },
21436
+ 3: { el: "barChart", dir: "bar", grp: "clustered" },
21437
+ 4: { el: "barChart", dir: "bar", grp: "stacked", overlap: 100 },
21438
+ 5: { el: "scatterChart", scatter: true },
21439
+ 6: { el: "pieChart", pie: true },
21440
+ 7: { el: "pieChart", pie: true, explode: true },
21441
+ 8: { el: "doughnutChart", pie: true, hole: 50 },
21442
+ 9: { el: "areaChart", grp: "standard" },
21443
+ 10: { el: "areaChart", grp: "stacked" },
21444
+ 11: { el: "radarChart", radar: true },
21445
+ 12: { el: "bar3DChart", dir: "col", grp: "clustered" },
21446
+ 13: { el: "bar3DChart", dir: "col", grp: "stacked", overlap: 100 },
21447
+ 14: { el: "bar3DChart", dir: "bar", grp: "clustered" },
21448
+ 15: { el: "bar3DChart", dir: "bar", grp: "stacked", overlap: 100 },
21449
+ 16: { el: "pie3DChart", pie: true },
21450
+ 17: { el: "pie3DChart", pie: true, explode: true },
21451
+ 18: { el: "area3DChart", grp: "standard" },
21452
+ 19: { el: "area3DChart", grp: "stacked" }
21453
+ };
21454
+ var CHART_ALIAS = {
21455
+ column: 0,
21456
+ col: 0,
21457
+ \uC138\uB85C\uB9C9\uB300: 0,
21458
+ \uB9C9\uB300: 0,
21459
+ column_stacked: 1,
21460
+ \uC138\uB85C\uB9C9\uB300_\uB204\uC801: 1,
21461
+ line: 2,
21462
+ \uC120: 2,
21463
+ \uAEBE\uC740\uC120: 2,
21464
+ bar: 3,
21465
+ \uAC00\uB85C\uB9C9\uB300: 3,
21466
+ bar_stacked: 4,
21467
+ scatter: 5,
21468
+ \uBD84\uC0B0: 5,
21469
+ pie: 6,
21470
+ \uC6D0: 6,
21471
+ \uD30C\uC774: 6,
21472
+ pie_explode: 7,
21473
+ doughnut: 8,
21474
+ donut: 8,
21475
+ \uB3C4\uB11B: 8,
21476
+ area: 9,
21477
+ \uC601\uC5ED: 9,
21478
+ area_stacked: 10,
21479
+ radar: 11,
21480
+ \uBC29\uC0AC\uD615: 11,
21481
+ bar3d: 12,
21482
+ column3d: 12,
21483
+ pie3d: 16
21484
+ };
21485
+ function chartSpec(t) {
21486
+ if (!t) return CHART_TYPES[0];
21487
+ const key = CHART_ALIAS[t.toLowerCase()] ?? Number(t);
21488
+ return CHART_TYPES[key] ?? CHART_TYPES[0];
21489
+ }
21490
+ var HU_PER_MM = 7200 / 25.4;
21491
+ var RESERVED_KEYS = /* @__PURE__ */ new Set(["type", "cat", "size", "colors", "point_colors", "title"]);
21492
+ function parseChartFence(text) {
21493
+ let type;
21494
+ let cat = null;
21495
+ let widthMm = 32250 / HU_PER_MM;
21496
+ let heightMm = 18750 / HU_PER_MM;
21497
+ let colors = null;
21498
+ let pointColors = null;
21499
+ const series = [];
21500
+ for (const rawLine of text.split("\n")) {
21501
+ const line = rawLine.trim();
21502
+ if (!line || line.startsWith("#")) continue;
21503
+ const colon = line.search(/[::]/);
21504
+ if (colon <= 0) continue;
21505
+ const key = line.slice(0, colon).trim();
21506
+ const value = line.slice(colon + 1).trim();
21507
+ const keyLower = key.toLowerCase();
21508
+ if (keyLower === "type") {
21509
+ type = value;
21510
+ } else if (keyLower === "cat") {
21511
+ cat = value.split(",").map((s) => s.trim()).filter(Boolean);
21512
+ } else if (keyLower === "size") {
21513
+ const m = value.match(/^(\d+(?:\.\d+)?)\s*[x×]\s*(\d+(?:\.\d+)?)$/i);
21514
+ if (m) {
21515
+ const clamp = (n) => Math.min(500, Math.max(10, n));
21516
+ widthMm = clamp(Number(m[1]));
21517
+ heightMm = clamp(Number(m[2]));
21518
+ }
21519
+ } else if (keyLower === "colors") {
21520
+ colors = value.split(",").map((s) => s.trim()).filter(Boolean);
21521
+ } else if (keyLower === "point_colors") {
21522
+ pointColors = value.split(",").map((s) => s.trim()).filter(Boolean);
21523
+ } else if (keyLower === "title") {
21524
+ } else if (!RESERVED_KEYS.has(keyLower)) {
21525
+ const segs = value.replace(/(\d),(?=\d{3}(?:\D|$))/g, "$1").split(",").map((s) => s.trim()).filter(Boolean);
21526
+ if (segs.length === 0) continue;
21527
+ const nums = segs.map(Number);
21528
+ if (nums.every((n) => Number.isFinite(n))) {
21529
+ series.push({ name: key, values: nums });
21530
+ } else {
21531
+ return null;
21532
+ }
21533
+ }
21534
+ }
21535
+ if (series.length === 0) return null;
21536
+ const spec = chartSpec(type);
21537
+ let finalSeries = spec.pie ? [series[0]] : series;
21538
+ finalSeries = finalSeries.map((s) => ({ ...s }));
21539
+ const ptLen = Math.max(cat?.length ?? 0, ...finalSeries.map((s) => s.values.length));
21540
+ const catFinal = Array.from({ length: ptLen }, (_, i) => cat?.[i] ?? `\uD56D\uBAA9 ${i + 1}`);
21541
+ if (!spec.scatter) {
21542
+ finalSeries = finalSeries.map((s) => ({ ...s, values: catFinal.map((_, i) => s.values[i] ?? 0) }));
21543
+ }
21544
+ if (spec.pie) {
21545
+ const slice = colors ?? pointColors;
21546
+ if (slice) finalSeries[0].pointColors = slice;
21547
+ } else {
21548
+ if (colors) finalSeries.forEach((s, i) => {
21549
+ s.color = colors[i % colors.length];
21550
+ });
21551
+ if (pointColors && finalSeries[0]) finalSeries[0].pointColors = pointColors;
21552
+ }
21553
+ return {
21554
+ spec,
21555
+ cat: catFinal,
21556
+ series: finalSeries,
21557
+ widthHu: Math.round(widthMm * HU_PER_MM),
21558
+ heightHu: Math.round(heightMm * HU_PER_MM)
21559
+ };
21560
+ }
21561
+ var colLetter = (i) => String.fromCharCode(66 + i);
21562
+ function strCachePts(vals) {
21563
+ return `<c:ptCount val="${vals.length}"/>` + vals.map((v, i) => `<c:pt idx="${i}"><c:v>${xmlEscape(v)}</c:v></c:pt>`).join("");
21564
+ }
21565
+ function numCachePts(vals) {
21566
+ return `<c:formatCode>General</c:formatCode><c:ptCount val="${vals.length}"/>` + vals.map((v, i) => `<c:pt idx="${i}"><c:v>${Number(v) || 0}</c:v></c:pt>`).join("");
21567
+ }
21568
+ function chartColorFill(color) {
21569
+ if (color == null) return null;
21570
+ const c = color.trim();
21571
+ if (/^accent[1-6]$/i.test(c)) return `<a:solidFill><a:schemeClr val="${c.toLowerCase()}"/></a:solidFill>`;
21572
+ const hex = c.replace(/^#/, "").toUpperCase();
21573
+ if (/^[0-9A-F]{6}$/.test(hex)) return `<a:solidFill><a:srgbClr val="${hex}"/></a:solidFill>`;
21574
+ return null;
21575
+ }
21576
+ function serSpPr(color, stroke) {
21577
+ const f = chartColorFill(color);
21578
+ if (!f) return "<c:spPr/>";
21579
+ return stroke ? `<c:spPr><a:ln w="28575" cap="flat" cmpd="sng" algn="ctr">${f}<a:prstDash val="solid"/><a:round/></a:ln></c:spPr>` : `<c:spPr>${f}</c:spPr>`;
21580
+ }
21581
+ function dPtXml(pointColors, pie) {
21582
+ if (!pointColors?.length) return "";
21583
+ return pointColors.map((col, i) => {
21584
+ const f = chartColorFill(col);
21585
+ if (!f) return "";
21586
+ const mid = pie ? '<c:invertIfNegative val="0"/><c:bubble3D val="0"/><c:explosion val="0"/>' : '<c:bubble3D val="0"/>';
21587
+ return `<c:dPt><c:idx val="${i}"/>${mid}<c:spPr>${f}</c:spPr></c:dPt>`;
21588
+ }).join("");
21589
+ }
21590
+ function stdSer(idx, name, cat, values, explode, color, pointColors, stroke, pie) {
21591
+ const cl = colLetter(idx);
21592
+ return `<c:ser><c:idx val="${idx}"/><c:order val="${idx}"/><c:tx><c:strRef><c:f>Sheet1!$${cl}$1</c:f><c:strCache><c:ptCount val="1"/><c:pt idx="0"><c:v>${xmlEscape(name)}</c:v></c:pt></c:strCache></c:strRef></c:tx>${serSpPr(color, stroke)}<c:invertIfNegative val="0"/>` + (explode ? `<c:explosion val="25"/>` : "") + dPtXml(pointColors, pie) + `<c:cat><c:strRef><c:f>Sheet1!$A$2:$A$${cat.length + 1}</c:f><c:strCache>${strCachePts(cat)}</c:strCache></c:strRef></c:cat><c:val><c:numRef><c:f>Sheet1!$${cl}$2:$${cl}$${values.length + 1}</c:f><c:numCache>${numCachePts(values)}</c:numCache></c:numRef></c:val></c:ser>`;
21593
+ }
21594
+ function scatterSer(idx, name, xvals, yvals) {
21595
+ const cl = colLetter(idx);
21596
+ return `<c:ser><c:idx val="${idx}"/><c:order val="${idx}"/><c:tx><c:strRef><c:f>Sheet1!$${cl}$1</c:f><c:strCache><c:ptCount val="1"/><c:pt idx="0"><c:v>${xmlEscape(name)}</c:v></c:pt></c:strCache></c:strRef></c:tx><c:spPr><a:ln w="28575"><a:noFill/></a:ln></c:spPr><c:marker><c:symbol val="circle"/><c:size val="7"/></c:marker><c:xVal><c:numRef><c:f>Sheet1!$A$2:$A$${xvals.length + 1}</c:f><c:numCache>${numCachePts(xvals)}</c:numCache></c:numRef></c:xVal><c:yVal><c:numRef><c:f>Sheet1!$${cl}$2:$${cl}$${yvals.length + 1}</c:f><c:numCache>${numCachePts(yvals)}</c:numCache></c:numRef></c:yVal></c:ser>`;
21597
+ }
21598
+ function catAxXml(id, pos, cross) {
21599
+ return `<c:catAx><c:axId val="${id}"/><c:scaling><c:orientation val="minMax"/></c:scaling><c:axPos val="${pos}"/><c:crossAx val="${cross}"/><c:delete val="0"/><c:majorTickMark val="out"/><c:minorTickMark val="none"/><c:tickLblPos val="nextTo"/><c:crosses val="autoZero"/><c:auto val="1"/><c:lblAlgn val="ctr"/><c:lblOffset val="100"/><c:noMultiLvlLbl val="0"/></c:catAx>`;
21600
+ }
21601
+ function valAxXml(id, pos, cross) {
21602
+ return `<c:valAx><c:axId val="${id}"/><c:scaling><c:orientation val="minMax"/></c:scaling><c:axPos val="${pos}"/><c:majorGridlines/><c:numFmt formatCode="General" sourceLinked="1"/><c:crossAx val="${cross}"/><c:delete val="0"/><c:majorTickMark val="out"/><c:minorTickMark val="none"/><c:tickLblPos val="nextTo"/><c:crosses val="autoZero"/><c:crossBetween val="between"/></c:valAx>`;
21603
+ }
21604
+ function buildChartSpaceXml(fence) {
21605
+ const { spec, cat, series } = fence;
21606
+ const NS = 'xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:c="http://schemas.openxmlformats.org/drawingml/2006/chart"';
21607
+ const ax1 = "111111111";
21608
+ const ax2 = "222222222";
21609
+ let plot;
21610
+ if (spec.scatter) {
21611
+ const n = Math.max(0, ...series.map((s) => s.values.length));
21612
+ const xs = Array.from({ length: n }, (_, i) => {
21613
+ const c = cat[i];
21614
+ const v = Number(c);
21615
+ return c !== void 0 && c !== "" && Number.isFinite(v) ? v : i + 1;
21616
+ });
21617
+ const sers = series.map((s, i) => scatterSer(i, s.name, xs, s.values)).join("");
21618
+ plot = `<c:scatterChart><c:scatterStyle val="lineMarker"/><c:varyColors val="0"/>${sers}<c:axId val="${ax1}"/><c:axId val="${ax2}"/></c:scatterChart>` + valAxXml(ax1, "b", ax2) + valAxXml(ax2, "l", ax1);
21619
+ } else if (spec.pie) {
21620
+ const s0 = series[0];
21621
+ plot = `<c:${spec.el}><c:varyColors val="1"/>${stdSer(0, s0.name, cat, s0.values, !!spec.explode, s0.color, s0.pointColors, false, true)}<c:firstSliceAng val="0"/>` + (spec.hole != null ? `<c:holeSize val="${spec.hole}"/>` : "") + `</c:${spec.el}>`;
21622
+ } else {
21623
+ const stroke = spec.el === "lineChart" || spec.el === "radarChart" || !!spec.radar;
21624
+ const sers = series.map((s, i) => stdSer(i, s.name, cat, s.values, false, s.color, s.pointColors, stroke, false)).join("");
21625
+ const horiz = spec.dir === "bar";
21626
+ let inner = "";
21627
+ if (spec.dir) inner += `<c:barDir val="${spec.dir}"/>`;
21628
+ if (spec.grp) inner += `<c:grouping val="${spec.grp}"/>`;
21629
+ if (spec.radar) inner += `<c:radarStyle val="standard"/>`;
21630
+ inner += `<c:varyColors val="0"/>${sers}`;
21631
+ if (spec.marker) inner += `<c:marker val="1"/>`;
21632
+ if (spec.el.startsWith("bar")) inner += `<c:gapWidth val="150"/><c:overlap val="${spec.overlap ?? 0}"/>`;
21633
+ inner += `<c:axId val="${ax1}"/><c:axId val="${ax2}"/>`;
21634
+ plot = `<c:${spec.el}>${inner}</c:${spec.el}>` + catAxXml(ax1, horiz ? "l" : "b", ax2) + valAxXml(ax2, horiz ? "b" : "l", ax1);
21635
+ }
21636
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><c:chartSpace ${NS}><c:date1904 val="0"/><c:roundedCorners val="0"/><c:chart><c:autoTitleDeleted val="0"/><c:plotArea><c:layout/>${plot}</c:plotArea><c:legend><c:legendPos val="r"/><c:overlay val="0"/></c:legend><c:plotVisOnly val="1"/><c:dispBlanksAs val="gap"/></c:chart></c:chartSpace>`;
21637
+ }
21638
+ function buildChartElementXml(partName, widthHu, heightHu, id) {
21639
+ return `<hp:chart id="${id}" zOrder="0" numberingType="PICTURE" textWrap="TOP_AND_BOTTOM" textFlow="BOTH_SIDES" lock="0" dropcapstyle="None" chartIDRef="${partName}"><hp:sz width="${widthHu}" widthRelTo="ABSOLUTE" height="${heightHu}" 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="709" right="709" top="709" bottom="709"/></hp:chart>`;
21640
+ }
21641
+
21386
21642
  // src/hwpx/gen-gongmun-fit.ts
21387
21643
  function plainRenderText(text) {
21388
21644
  return parseInlineMarkdown(text).map((s) => s.text).join("");
@@ -21435,18 +21691,18 @@ function precomputeGongmunList(blocks, gongmun) {
21435
21691
  i++;
21436
21692
  continue;
21437
21693
  }
21438
- const passThrough = (t) => t === "table" || t === "html_table" || t === "equation";
21694
+ const passThrough = (b) => b.type === "table" || b.type === "html_table" || b.type === "equation" || b.type === "code_block" && (b.lang || "").toLowerCase() === "chart" && parseChartFence(b.text || "") !== null;
21439
21695
  const run = [];
21440
21696
  while (i < blocks.length) {
21441
- const t = blocks[i].type;
21442
- if (t === "list_item") {
21697
+ const b = blocks[i];
21698
+ if (b.type === "list_item") {
21443
21699
  run.push(i);
21444
21700
  i++;
21445
21701
  continue;
21446
21702
  }
21447
- if (passThrough(t)) {
21703
+ if (passThrough(b)) {
21448
21704
  let j = i + 1;
21449
- while (j < blocks.length && passThrough(blocks[j].type)) j++;
21705
+ while (j < blocks.length && passThrough(blocks[j])) j++;
21450
21706
  if (j < blocks.length && blocks[j].type === "list_item") {
21451
21707
  i = j;
21452
21708
  continue;
@@ -22249,210 +22505,6 @@ function generateEquationParagraph(input, zOrder = 0) {
22249
22505
  return `<hp:p paraPrIDRef="${PARA_NORMAL}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_NORMAL}">${generateEquationXml(script, zOrder)}</hp:run></hp:p>`;
22250
22506
  }
22251
22507
 
22252
- // src/hwpx/chart-gen.ts
22253
- var XML_ESC = { "&": "&amp;", "<": "&lt;", ">": "&gt;" };
22254
- var xmlEscape = (s) => s.replace(/[&<>]/g, (c) => XML_ESC[c]);
22255
- var CHART_TYPES = {
22256
- 0: { el: "barChart", dir: "col", grp: "clustered" },
22257
- 1: { el: "barChart", dir: "col", grp: "stacked", overlap: 100 },
22258
- 2: { el: "lineChart", grp: "standard", marker: true },
22259
- 3: { el: "barChart", dir: "bar", grp: "clustered" },
22260
- 4: { el: "barChart", dir: "bar", grp: "stacked", overlap: 100 },
22261
- 5: { el: "scatterChart", scatter: true },
22262
- 6: { el: "pieChart", pie: true },
22263
- 7: { el: "pieChart", pie: true, explode: true },
22264
- 8: { el: "doughnutChart", pie: true, hole: 50 },
22265
- 9: { el: "areaChart", grp: "standard" },
22266
- 10: { el: "areaChart", grp: "stacked" },
22267
- 11: { el: "radarChart", radar: true },
22268
- 12: { el: "bar3DChart", dir: "col", grp: "clustered" },
22269
- 13: { el: "bar3DChart", dir: "col", grp: "stacked", overlap: 100 },
22270
- 14: { el: "bar3DChart", dir: "bar", grp: "clustered" },
22271
- 15: { el: "bar3DChart", dir: "bar", grp: "stacked", overlap: 100 },
22272
- 16: { el: "pie3DChart", pie: true },
22273
- 17: { el: "pie3DChart", pie: true, explode: true },
22274
- 18: { el: "area3DChart", grp: "standard" },
22275
- 19: { el: "area3DChart", grp: "stacked" }
22276
- };
22277
- var CHART_ALIAS = {
22278
- column: 0,
22279
- col: 0,
22280
- \uC138\uB85C\uB9C9\uB300: 0,
22281
- \uB9C9\uB300: 0,
22282
- column_stacked: 1,
22283
- \uC138\uB85C\uB9C9\uB300_\uB204\uC801: 1,
22284
- line: 2,
22285
- \uC120: 2,
22286
- \uAEBE\uC740\uC120: 2,
22287
- bar: 3,
22288
- \uAC00\uB85C\uB9C9\uB300: 3,
22289
- bar_stacked: 4,
22290
- scatter: 5,
22291
- \uBD84\uC0B0: 5,
22292
- pie: 6,
22293
- \uC6D0: 6,
22294
- \uD30C\uC774: 6,
22295
- pie_explode: 7,
22296
- doughnut: 8,
22297
- donut: 8,
22298
- \uB3C4\uB11B: 8,
22299
- area: 9,
22300
- \uC601\uC5ED: 9,
22301
- area_stacked: 10,
22302
- radar: 11,
22303
- \uBC29\uC0AC\uD615: 11,
22304
- bar3d: 12,
22305
- column3d: 12,
22306
- pie3d: 16
22307
- };
22308
- function chartSpec(t) {
22309
- if (!t) return CHART_TYPES[0];
22310
- const key = CHART_ALIAS[t.toLowerCase()] ?? Number(t);
22311
- return CHART_TYPES[key] ?? CHART_TYPES[0];
22312
- }
22313
- var HU_PER_MM = 7200 / 25.4;
22314
- var RESERVED_KEYS = /* @__PURE__ */ new Set(["type", "cat", "size", "colors", "point_colors", "title"]);
22315
- function parseChartFence(text) {
22316
- let type;
22317
- let cat = null;
22318
- let widthMm = 32250 / HU_PER_MM;
22319
- let heightMm = 18750 / HU_PER_MM;
22320
- let colors = null;
22321
- let pointColors = null;
22322
- const series = [];
22323
- for (const rawLine of text.split("\n")) {
22324
- const line = rawLine.trim();
22325
- if (!line || line.startsWith("#")) continue;
22326
- const colon = line.search(/[::]/);
22327
- if (colon <= 0) continue;
22328
- const key = line.slice(0, colon).trim();
22329
- const value = line.slice(colon + 1).trim();
22330
- const keyLower = key.toLowerCase();
22331
- if (keyLower === "type") {
22332
- type = value;
22333
- } else if (keyLower === "cat") {
22334
- cat = value.split(",").map((s) => s.trim()).filter(Boolean);
22335
- } else if (keyLower === "size") {
22336
- const m = value.match(/^(\d+(?:\.\d+)?)\s*[x×]\s*(\d+(?:\.\d+)?)$/i);
22337
- if (m) {
22338
- widthMm = Number(m[1]);
22339
- heightMm = Number(m[2]);
22340
- }
22341
- } else if (keyLower === "colors") {
22342
- colors = value.split(",").map((s) => s.trim()).filter(Boolean);
22343
- } else if (keyLower === "point_colors") {
22344
- pointColors = value.split(",").map((s) => s.trim()).filter(Boolean);
22345
- } else if (keyLower === "title") {
22346
- } else if (!RESERVED_KEYS.has(keyLower)) {
22347
- const nums = value.split(",").map((s) => Number(s.trim()));
22348
- if (nums.length > 0 && nums.every((n) => Number.isFinite(n))) {
22349
- series.push({ name: key, values: nums });
22350
- }
22351
- }
22352
- }
22353
- if (series.length === 0) return null;
22354
- const spec = chartSpec(type);
22355
- const catFinal = cat ?? series[0].values.map((_, i) => `\uD56D\uBAA9 ${i + 1}`);
22356
- let finalSeries = spec.pie ? [series[0]] : series;
22357
- finalSeries = finalSeries.map((s) => ({ ...s }));
22358
- if (spec.pie) {
22359
- const slice = colors ?? pointColors;
22360
- if (slice) finalSeries[0].pointColors = slice;
22361
- } else {
22362
- if (colors) finalSeries.forEach((s, i) => {
22363
- s.color = colors[i % colors.length];
22364
- });
22365
- if (pointColors && finalSeries[0]) finalSeries[0].pointColors = pointColors;
22366
- }
22367
- return {
22368
- spec,
22369
- cat: catFinal,
22370
- series: finalSeries,
22371
- widthHu: Math.round(widthMm * HU_PER_MM),
22372
- heightHu: Math.round(heightMm * HU_PER_MM)
22373
- };
22374
- }
22375
- var colLetter = (i) => String.fromCharCode(66 + i);
22376
- function strCachePts(vals) {
22377
- return `<c:ptCount val="${vals.length}"/>` + vals.map((v, i) => `<c:pt idx="${i}"><c:v>${xmlEscape(v)}</c:v></c:pt>`).join("");
22378
- }
22379
- function numCachePts(vals) {
22380
- return `<c:formatCode>General</c:formatCode><c:ptCount val="${vals.length}"/>` + vals.map((v, i) => `<c:pt idx="${i}"><c:v>${Number(v) || 0}</c:v></c:pt>`).join("");
22381
- }
22382
- function chartColorFill(color) {
22383
- if (color == null) return null;
22384
- const c = color.trim();
22385
- if (/^accent[1-6]$/i.test(c)) return `<a:solidFill><a:schemeClr val="${c.toLowerCase()}"/></a:solidFill>`;
22386
- const hex = c.replace(/^#/, "").toUpperCase();
22387
- if (/^[0-9A-F]{6}$/.test(hex)) return `<a:solidFill><a:srgbClr val="${hex}"/></a:solidFill>`;
22388
- return null;
22389
- }
22390
- function serSpPr(color, stroke) {
22391
- const f = chartColorFill(color);
22392
- if (!f) return "<c:spPr/>";
22393
- return stroke ? `<c:spPr><a:ln w="28575" cap="flat" cmpd="sng" algn="ctr">${f}<a:prstDash val="solid"/><a:round/></a:ln></c:spPr>` : `<c:spPr>${f}</c:spPr>`;
22394
- }
22395
- function dPtXml(pointColors, pie) {
22396
- if (!pointColors?.length) return "";
22397
- return pointColors.map((col, i) => {
22398
- const f = chartColorFill(col);
22399
- if (!f) return "";
22400
- const mid = pie ? '<c:invertIfNegative val="0"/><c:bubble3D val="0"/><c:explosion val="0"/>' : '<c:bubble3D val="0"/>';
22401
- return `<c:dPt><c:idx val="${i}"/>${mid}<c:spPr>${f}</c:spPr></c:dPt>`;
22402
- }).join("");
22403
- }
22404
- function stdSer(idx, name, cat, values, explode, color, pointColors, stroke, pie) {
22405
- const cl = colLetter(idx);
22406
- return `<c:ser><c:idx val="${idx}"/><c:order val="${idx}"/><c:tx><c:strRef><c:f>Sheet1!$${cl}$1</c:f><c:strCache><c:ptCount val="1"/><c:pt idx="0"><c:v>${xmlEscape(name)}</c:v></c:pt></c:strCache></c:strRef></c:tx>${serSpPr(color, stroke)}<c:invertIfNegative val="0"/>` + (explode ? `<c:explosion val="25"/>` : "") + dPtXml(pointColors, pie) + `<c:cat><c:strRef><c:f>Sheet1!$A$2:$A$${cat.length + 1}</c:f><c:strCache>${strCachePts(cat)}</c:strCache></c:strRef></c:cat><c:val><c:numRef><c:f>Sheet1!$${cl}$2:$${cl}$${values.length + 1}</c:f><c:numCache>${numCachePts(values)}</c:numCache></c:numRef></c:val></c:ser>`;
22407
- }
22408
- function scatterSer(idx, name, xvals, yvals) {
22409
- const cl = colLetter(idx);
22410
- return `<c:ser><c:idx val="${idx}"/><c:order val="${idx}"/><c:tx><c:strRef><c:f>Sheet1!$${cl}$1</c:f><c:strCache><c:ptCount val="1"/><c:pt idx="0"><c:v>${xmlEscape(name)}</c:v></c:pt></c:strCache></c:strRef></c:tx><c:spPr><a:ln w="28575"><a:noFill/></a:ln></c:spPr><c:marker><c:symbol val="circle"/><c:size val="7"/></c:marker><c:xVal><c:numRef><c:f>Sheet1!$A$2:$A$${xvals.length + 1}</c:f><c:numCache>${numCachePts(xvals)}</c:numCache></c:numRef></c:xVal><c:yVal><c:numRef><c:f>Sheet1!$${cl}$2:$${cl}$${yvals.length + 1}</c:f><c:numCache>${numCachePts(yvals)}</c:numCache></c:numRef></c:yVal></c:ser>`;
22411
- }
22412
- function catAxXml(id, pos, cross) {
22413
- return `<c:catAx><c:axId val="${id}"/><c:scaling><c:orientation val="minMax"/></c:scaling><c:axPos val="${pos}"/><c:crossAx val="${cross}"/><c:delete val="0"/><c:majorTickMark val="out"/><c:minorTickMark val="none"/><c:tickLblPos val="nextTo"/><c:crosses val="autoZero"/><c:auto val="1"/><c:lblAlgn val="ctr"/><c:lblOffset val="100"/><c:noMultiLvlLbl val="0"/></c:catAx>`;
22414
- }
22415
- function valAxXml(id, pos, cross) {
22416
- return `<c:valAx><c:axId val="${id}"/><c:scaling><c:orientation val="minMax"/></c:scaling><c:axPos val="${pos}"/><c:majorGridlines/><c:numFmt formatCode="General" sourceLinked="1"/><c:crossAx val="${cross}"/><c:delete val="0"/><c:majorTickMark val="out"/><c:minorTickMark val="none"/><c:tickLblPos val="nextTo"/><c:crosses val="autoZero"/><c:crossBetween val="between"/></c:valAx>`;
22417
- }
22418
- function buildChartSpaceXml(fence) {
22419
- const { spec, cat, series } = fence;
22420
- const NS = 'xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:c="http://schemas.openxmlformats.org/drawingml/2006/chart"';
22421
- const ax1 = "111111111";
22422
- const ax2 = "222222222";
22423
- let plot;
22424
- if (spec.scatter) {
22425
- const n = Math.max(0, ...series.map((s) => s.values.length));
22426
- const xs = Array.from({ length: n }, (_, i) => {
22427
- const c = cat[i];
22428
- const v = Number(c);
22429
- return c !== void 0 && c !== "" && Number.isFinite(v) ? v : i + 1;
22430
- });
22431
- const sers = series.map((s, i) => scatterSer(i, s.name, xs, s.values)).join("");
22432
- plot = `<c:scatterChart><c:scatterStyle val="lineMarker"/><c:varyColors val="0"/>${sers}<c:axId val="${ax1}"/><c:axId val="${ax2}"/></c:scatterChart>` + valAxXml(ax1, "b", ax2) + valAxXml(ax2, "l", ax1);
22433
- } else if (spec.pie) {
22434
- const s0 = series[0];
22435
- plot = `<c:${spec.el}><c:varyColors val="1"/>${stdSer(0, s0.name, cat, s0.values, !!spec.explode, s0.color, s0.pointColors, false, true)}<c:firstSliceAng val="0"/>` + (spec.hole != null ? `<c:holeSize val="${spec.hole}"/>` : "") + `</c:${spec.el}>`;
22436
- } else {
22437
- const stroke = spec.el === "lineChart" || spec.el === "radarChart" || !!spec.radar;
22438
- const sers = series.map((s, i) => stdSer(i, s.name, cat, s.values, false, s.color, s.pointColors, stroke, false)).join("");
22439
- const horiz = spec.dir === "bar";
22440
- let inner = "";
22441
- if (spec.dir) inner += `<c:barDir val="${spec.dir}"/>`;
22442
- if (spec.grp) inner += `<c:grouping val="${spec.grp}"/>`;
22443
- if (spec.radar) inner += `<c:radarStyle val="standard"/>`;
22444
- inner += `<c:varyColors val="0"/>${sers}`;
22445
- if (spec.marker) inner += `<c:marker val="1"/>`;
22446
- if (spec.el.startsWith("bar")) inner += `<c:gapWidth val="150"/><c:overlap val="${spec.overlap ?? 0}"/>`;
22447
- inner += `<c:axId val="${ax1}"/><c:axId val="${ax2}"/>`;
22448
- plot = `<c:${spec.el}>${inner}</c:${spec.el}>` + catAxXml(ax1, horiz ? "l" : "b", ax2) + valAxXml(ax2, horiz ? "b" : "l", ax1);
22449
- }
22450
- return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><c:chartSpace ${NS}><c:date1904 val="0"/><c:roundedCorners val="0"/><c:chart><c:autoTitleDeleted val="0"/><c:plotArea><c:layout/>${plot}</c:plotArea><c:legend><c:legendPos val="r"/><c:overlay val="0"/></c:legend><c:plotVisOnly val="1"/><c:dispBlanksAs val="gap"/></c:chart></c:chartSpace>`;
22451
- }
22452
- function buildChartElementXml(partName, widthHu, heightHu, id) {
22453
- return `<hp:chart id="${id}" zOrder="0" numberingType="PICTURE" textWrap="TOP_AND_BOTTOM" textFlow="BOTH_SIDES" lock="0" dropcapstyle="None" chartIDRef="${partName}"><hp:sz width="${widthHu}" widthRelTo="ABSOLUTE" height="${heightHu}" 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="709" right="709" top="709" bottom="709"/></hp:chart>`;
22454
- }
22455
-
22456
22508
  // src/hwpx/gen-section.ts
22457
22509
  function generateSecPr(gongmun) {
22458
22510
  const m = gongmun ? {
@@ -22894,6 +22946,21 @@ var MIME = {
22894
22946
  bmp: "image/bmp",
22895
22947
  gif: "image/gif"
22896
22948
  };
22949
+ function imageMagicMatches(buf, ext) {
22950
+ switch (ext) {
22951
+ case "png":
22952
+ return buf.length >= 8 && buf[0] === 137 && buf[1] === 80 && buf[2] === 78 && buf[3] === 71;
22953
+ case "jpg":
22954
+ case "jpeg":
22955
+ return buf.length >= 3 && buf[0] === 255 && buf[1] === 216 && buf[2] === 255;
22956
+ case "bmp":
22957
+ return buf.length >= 2 && buf[0] === 66 && buf[1] === 77;
22958
+ case "gif":
22959
+ return buf.length >= 6 && buf[0] === 71 && buf[1] === 73 && buf[2] === 70;
22960
+ default:
22961
+ return false;
22962
+ }
22963
+ }
22897
22964
  function glyphEm(code) {
22898
22965
  if (code < 32) return 0;
22899
22966
  if (code <= 126) return 0.5;
@@ -22908,19 +22975,19 @@ function measureMm(text, emMm) {
22908
22975
  function collectSites(scan) {
22909
22976
  const sites = [];
22910
22977
  for (const p of scan.bodyParagraphs) sites.push({ para: p });
22911
- const walkTables = (tables, depth) => {
22978
+ const walkTables = (tables, depth, outer) => {
22912
22979
  if (depth > 16) return;
22913
22980
  for (const t of tables) {
22914
22981
  for (const row of t.rows) {
22915
22982
  for (const cell of row) {
22916
- for (const p of cell.paragraphs) sites.push({ para: p, cell, table: t });
22917
- walkTables(cell.tables, depth + 1);
22983
+ for (const p of cell.paragraphs) sites.push({ para: p, cell, table: t, nested: depth > 0, outer: outer.length ? outer : void 0 });
22984
+ walkTables(cell.tables, depth + 1, [...outer, { cell, table: t }]);
22918
22985
  }
22919
22986
  }
22920
22987
  }
22921
22988
  };
22922
- walkTables(scan.tables, 0);
22923
- walkTables(scan.orphanTables, 0);
22989
+ walkTables(scan.tables, 0, []);
22990
+ walkTables(scan.orphanTables, 0, []);
22924
22991
  sites.sort((a, b) => a.para.start - b.para.start);
22925
22992
  return sites;
22926
22993
  }
@@ -22934,7 +23001,10 @@ function paraOpenTag(xml, para) {
22934
23001
  }
22935
23002
  function anchorRunInfo(xml, para, anchor) {
22936
23003
  let tr = para.tRanges.find((r) => !r.selfClosing && xml.slice(r.contentStart, r.contentEnd).includes(anchor));
22937
- if (!tr) tr = para.tRanges[para.tRanges.length - 1];
23004
+ if (!tr) {
23005
+ const head = anchor[0];
23006
+ tr = para.tRanges.find((r) => !r.selfClosing && xml.slice(r.contentStart, r.contentEnd).includes(head)) ?? para.tRanges[para.tRanges.length - 1];
23007
+ }
22938
23008
  if (!tr) return null;
22939
23009
  const before = xml.slice(Math.max(0, para.start), tr.contentStart);
22940
23010
  const runOpen = [...before.matchAll(/<([A-Za-z0-9]+):run\b[^>]*>/g)].pop();
@@ -22973,14 +23043,17 @@ function cellContentWidthMm(xml, cell) {
22973
23043
  }
22974
23044
  function cellLeftOffsetMm(xml, table, cell) {
22975
23045
  if (cell.colAddr === void 0) return 0;
22976
- const row = table.rows.find((r) => r.includes(cell));
22977
- if (!row) return 0;
22978
- let sum = 0;
22979
- for (const c of row) {
22980
- if (c === cell || c.colAddr === void 0 || c.colAddr >= cell.colAddr) continue;
22981
- const w = cellSzWidthHu(xml, c);
22982
- if (w) sum += w;
23046
+ const colW = /* @__PURE__ */ new Map();
23047
+ for (const row of table.rows) {
23048
+ for (const c of row) {
23049
+ if (c.colAddr === void 0 || colW.has(c.colAddr)) continue;
23050
+ if (c.colSpan > 1) continue;
23051
+ const w = cellSzWidthHu(xml, c);
23052
+ if (w) colW.set(c.colAddr, w);
23053
+ }
22983
23054
  }
23055
+ let sum = 0;
23056
+ for (let col = 0; col < cell.colAddr; col++) sum += colW.get(col) ?? 0;
22984
23057
  return sum / HU_PER_MM2;
22985
23058
  }
22986
23059
  function bodyColumnWidthMm(xml) {
@@ -22999,7 +23072,7 @@ async function placeSealHwpx(hwpxBuffer, ops) {
22999
23072
  if (ops.length === 0) throw new KordocError("place_seal: \uBC30\uCE58\uD560 \uB3C4\uC7A5\uC774 \uC5C6\uC2B5\uB2C8\uB2E4");
23000
23073
  const u8 = new Uint8Array(hwpxBuffer);
23001
23074
  const zip = await JSZip8.loadAsync(hwpxBuffer);
23002
- const sectionPaths = Object.keys(zip.files).filter((name) => /[Ss]ection\d+\.xml$/i.test(name)).sort();
23075
+ const sectionPaths = Object.keys(zip.files).filter((name) => /[Ss]ection\d+\.xml$/i.test(name)).sort((a, b) => Number(a.match(/(\d+)\.xml$/i)?.[1] ?? 0) - Number(b.match(/(\d+)\.xml$/i)?.[1] ?? 0));
23003
23076
  if (sectionPaths.length === 0) throw new KordocError("HWPX\uC5D0\uC11C \uC139\uC158 \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
23004
23077
  const manifestPath = Object.keys(zip.files).find((name) => /\.hpf$/i.test(name));
23005
23078
  const headerPath = Object.keys(zip.files).find((name) => /(^|\/)header\.xml$/i.test(name));
@@ -23045,6 +23118,7 @@ async function placeSealHwpx(hwpxBuffer, ops) {
23045
23118
  if (!op.image || op.image.length === 0) throw new KordocError("place_seal: \uB3C4\uC7A5 \uC774\uBBF8\uC9C0\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4");
23046
23119
  const ext = (op.ext ?? "png").toLowerCase();
23047
23120
  if (!MIME[ext]) throw new KordocError(`place_seal: \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uC774\uBBF8\uC9C0 \uD655\uC7A5\uC790 .${ext} (png/jpg/bmp/gif)`);
23121
+ if (!imageMagicMatches(op.image, ext)) throw new KordocError(`place_seal: \uC774\uBBF8\uC9C0 \uB0B4\uC6A9\uC774 .${ext} \uD615\uC2DD\uC774 \uC544\uB2D9\uB2C8\uB2E4 (\uB9E4\uC9C1\uBC14\uC774\uD2B8 \uBD88\uC77C\uCE58)`);
23048
23122
  const wantOcc = op.occurrence ?? 0;
23049
23123
  let found = null;
23050
23124
  let total = 0;
@@ -23093,7 +23167,7 @@ async function placeSealHwpx(hwpxBuffer, ops) {
23093
23167
  const lineHMm = emMm;
23094
23168
  const startXMm = measureMm(site.para.text.slice(0, idxInText), emMm);
23095
23169
  const anchorWMm = measureMm(op.anchor, emMm);
23096
- const sizeMm = op.sizeMm ?? Math.max(7, Math.min(18, lineHMm * 1.6));
23170
+ const sizeMm = op.sizeMm != null && Number.isFinite(op.sizeMm) && op.sizeMm > 0 ? op.sizeMm : Math.max(7, Math.min(18, lineHMm * 1.6));
23097
23171
  const availMm = (site.cell ? cellContentWidthMm(xml, site.cell) : null) ?? bodyColumnWidthMm(xml);
23098
23172
  const paraPrId = attrOf(paraOpenTag(xml, site.para), "paraPrIDRef") ?? "0";
23099
23173
  const align = styles?.paraAlign.get(paraPrId);
@@ -23107,7 +23181,7 @@ async function placeSealHwpx(hwpxBuffer, ops) {
23107
23181
  if (mode === "auto") {
23108
23182
  mode = availMm - (alignShiftMm + startXMm + anchorWMm) >= sizeMm + 2 ? "right" : "overlap";
23109
23183
  }
23110
- const cellShiftMm = site.cell && site.table ? cellLeftOffsetMm(xml, site.table, site.cell) : 0;
23184
+ const cellShiftMm = site.cell && site.table ? cellLeftOffsetMm(xml, site.table, site.cell) + (site.outer ?? []).reduce((s, o) => s + cellLeftOffsetMm(xml, o.table, o.cell), 0) : 0;
23111
23185
  const posXMm = (mode === "right" ? startXMm + anchorWMm + 2 : startXMm + anchorWMm / 2 - sizeMm / 2) + alignShiftMm + cellShiftMm + (op.dxMm ?? 0);
23112
23186
  const posYMm = -(sizeMm - lineHMm) / 2 + (op.dyMm ?? 0);
23113
23187
  const n = nextImageNum();
@@ -23125,6 +23199,12 @@ async function placeSealHwpx(hwpxBuffer, ops) {
23125
23199
  end: run.insertAt,
23126
23200
  replacement: `<${run.prefix}:run charPrIDRef="${run.charPr}">${pic}</${run.prefix}:run>`
23127
23201
  });
23202
+ const warnings = [];
23203
+ const paraSeg = xml.slice(site.para.start, run.insertAt);
23204
+ if (/<[A-Za-z0-9]+:tab\b/.test(paraSeg)) warnings.push("\uD0ED\uC774 \uB4E0 \uBB38\uB2E8 \u2014 \uB3C4\uC7A5 \uAC00\uB85C \uC704\uCE58\uAC00 \uADFC\uC0AC\uAC12\uC785\uB2C8\uB2E4 (dx \uB85C \uBCF4\uC815)");
23205
+ if (/<[A-Za-z0-9]+:(lineBreak|br)\b/.test(paraSeg)) warnings.push("\uC904\uBC14\uAFC8\uC774 \uB4E0 \uBB38\uB2E8 \u2014 \uC575\uCEE4\uAC00 2\uBC88\uC9F8 \uC904 \uC774\uD558\uBA74 \uC138\uB85C \uC704\uCE58\uAC00 \uC5B4\uAE0B\uB0A0 \uC218 \uC788\uC2B5\uB2C8\uB2E4 (dy \uB85C \uBCF4\uC815)");
23206
+ if (site.nested) warnings.push("\uC911\uCCA9\uD45C(\uD45C \uC548 \uD45C) \uC140 \uC575\uCEE4 \u2014 \uBC14\uAE65 \uC140 \uC624\uD504\uC14B\uC744 \uCCB4\uC778\uC73C\uB85C \uAC00\uC0B0\uD558\uB098 \uC140 \uC5EC\uBC31\xB7\uC815\uB82C\uC740 \uADFC\uC0AC\uC785\uB2C8\uB2E4 (\uD544\uC694 \uC2DC dx \uB85C \uBCF4\uC815)");
23207
+ if (site.para.inTextbox) warnings.push("\uAE00\uC0C1\uC790 \uC575\uCEE4 \u2014 \uAE00\uC0C1\uC790 \uAE30\uD558\uB97C \uBC18\uC601\uD558\uC9C0 \uC54A\uC544 \uC815\uB82C \uBCF4\uC815\uC774 \uADFC\uC0AC\uC785\uB2C8\uB2E4 (dx/dy \uB85C \uBCF4\uC815)");
23128
23208
  placed.push({
23129
23209
  anchor: op.anchor,
23130
23210
  occurrence: wantOcc,
@@ -23133,7 +23213,8 @@ async function placeSealHwpx(hwpxBuffer, ops) {
23133
23213
  posXMm: Math.round(posXMm * 100) / 100,
23134
23214
  posYMm: Math.round(posYMm * 100) / 100,
23135
23215
  sizeMm: Math.round(sizeMm * 100) / 100,
23136
- entry
23216
+ entry,
23217
+ ...warnings.length > 0 ? { warnings } : {}
23137
23218
  });
23138
23219
  }
23139
23220
  const encoder = new TextEncoder();
@@ -24660,7 +24741,8 @@ async function patchHwp(original, editedMarkdown, options) {
24660
24741
  if (options?.verify !== false) {
24661
24742
  try {
24662
24743
  const reparsed = parseHwp5Document(Buffer.from(data));
24663
- verification = diffUnitLists(splitMarkdownUnits(reparsed.markdown), editedUnits);
24744
+ const normBr = (u) => ({ ...u, raw: u.raw.replace(/<br\s*\/?\s*>/gi, "\n") });
24745
+ verification = diffUnitLists(splitMarkdownUnits(reparsed.markdown).map(normBr), editedUnits.map(normBr));
24664
24746
  } catch (err) {
24665
24747
  return { success: false, applied, skipped, error: `\uD328\uCE58\uBCF8 \uC7AC\uD30C\uC2F1 \uC2E4\uD328 \u2014 \uD328\uCE58 \uC911\uB2E8: ${msg(err)}` };
24666
24748
  }
@@ -24783,7 +24865,7 @@ function handleModified(orig, edited, ctx) {
24783
24865
  function patchParagraph(block, orig, edited, ctx, skip) {
24784
24866
  const mapping = ctx.paraMap.get(orig.blockIdx);
24785
24867
  if (!mapping?.para) return skip("\uBB38\uB2E8 \uC18C\uC2A4\uB9F5 \uB9E4\uD551 \uC2E4\uD328 (\uBA38\uB9AC\uB9D0/\uAE00\uC0C1\uC790/\uCEA1\uC158 \uC601\uC5ED\uC774\uAC70\uB098 \uD14D\uC2A4\uD2B8 \uBD88\uC77C\uCE58)");
24786
- const restoreBr = (s) => s.replace(/\s*<br\s*\/?\s*>\s*/gi, "\n");
24868
+ const restoreBr = (s) => s.replace(/(?:\s*<br\s*\/?\s*>\s*)+/gi, "\n");
24787
24869
  let newPlain = restoreBr(textUnitToPlain(edited.raw, block));
24788
24870
  if (block.text && block.text.includes("\n") && !newPlain.includes("\n")) {
24789
24871
  return skip("\uB2E4\uC911\uC904 \uBB38\uB2E8 \uC218\uC815\uC5D0 <br> \uC5C6\uC74C \u2014 \uC904\uBC14\uAFC8 \uC704\uCE58 \uBCF4\uC874 \uBD88\uAC00\uB85C \uBBF8\uC9C0\uC6D0 (\uC904\uBC14\uAFC8\uC740 <br>\uB85C \uD45C\uAE30)");
@@ -24809,7 +24891,7 @@ function patchParagraph(block, orig, edited, ctx, skip) {
24809
24891
  ctx.skipped.push({ reason: "\uC790\uB3D9\uBC88\uD638 \uC811\uB450 \uC2DD\uBCC4 \uC2E4\uD328 \u2014 \uBC88\uD638 \uD3EC\uD568 \uD14D\uC2A4\uD2B8\uB85C \uC801\uC6A9 (\uBDF0\uC5B4\uC5D0\uC11C \uC911\uBCF5 \uD45C\uC2DC \uAC00\uB2A5)", after: summarize(newPlain) });
24810
24892
  }
24811
24893
  }
24812
- const origPlain = restoreBr(textUnitToPlain(orig.raw, block));
24894
+ const origPlain = block.text != null ? block.text : restoreBr(textUnitToPlain(orig.raw, block));
24813
24895
  if (newPlain === origPlain) return skip("\uD14D\uC2A4\uD2B8 \uC678 \uBCC0\uACBD(\uD5E4\uB529 \uB808\uBCA8/\uC11C\uC2DD)\uB9CC \uAC10\uC9C0 \u2014 \uC2A4\uD0C0\uC77C \uBCC0\uACBD\uC740 \uBBF8\uC9C0\uC6D0");
24814
24896
  if (sanitizeText(newPlain) !== newPlain) {
24815
24897
  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");
@@ -26567,6 +26649,8 @@ function sniffMime(name, bytes) {
26567
26649
  }
26568
26650
  async function renderHwpxToSvg(input, options) {
26569
26651
  const maxImg = options?.maxImageBytes ?? 40 * 1024 * 1024;
26652
+ const ab = input instanceof Uint8Array ? input.buffer.slice(input.byteOffset, input.byteOffset + input.byteLength) : input;
26653
+ precheckZipSize(ab, MAX_DECOMPRESS_SIZE, MAX_ZIP_ENTRIES);
26570
26654
  let zip;
26571
26655
  try {
26572
26656
  zip = await JSZip12.loadAsync(input);
@@ -26779,7 +26863,7 @@ async function parseHwp(buffer, options) {
26779
26863
  async function parsePdf(buffer, options) {
26780
26864
  let parsePdfDocument;
26781
26865
  try {
26782
- const mod = await import("./parser-5G247XYD.js");
26866
+ const mod = await import("./parser-GWL72XYS.js");
26783
26867
  parsePdfDocument = mod.parsePdfDocument;
26784
26868
  } catch {
26785
26869
  return {