kordoc 3.15.0 → 3.16.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 (51) hide show
  1. package/README.md +20 -0
  2. package/dist/{-EYPKRLMN.js → -YVONYEEN.js} +17 -12
  3. package/dist/chunk-7WUTJXKP.js +1048 -0
  4. package/dist/chunk-7WUTJXKP.js.map +1 -0
  5. package/dist/{chunk-734GJLXH.js → chunk-CDFCA37S.js} +15 -177
  6. package/dist/chunk-CDFCA37S.js.map +1 -0
  7. package/dist/{chunk-Q5ZPWQID.js → chunk-F62GOZFB.js} +13 -6
  8. package/dist/chunk-F62GOZFB.js.map +1 -0
  9. package/dist/{chunk-Q3IHI3E6.js → chunk-I6T3DKYK.js} +371 -756
  10. package/dist/chunk-I6T3DKYK.js.map +1 -0
  11. package/dist/chunk-IY3NX4FT.js +185 -0
  12. package/dist/chunk-IY3NX4FT.js.map +1 -0
  13. package/dist/{chunk-SCFFABCT.js → chunk-K4L563FA.js} +2 -2
  14. package/dist/{chunk-ZRNYYEE6.js → chunk-QOPY6URE.js} +13 -6
  15. package/dist/chunk-QOPY6URE.js.map +1 -0
  16. package/dist/{chunk-DMBTOJK4.cjs → chunk-VNIQK4AL.cjs} +13 -6
  17. package/dist/chunk-VNIQK4AL.cjs.map +1 -0
  18. package/dist/cli.js +105 -14
  19. package/dist/cli.js.map +1 -1
  20. package/dist/index.cjs +1020 -384
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.cts +76 -4
  23. package/dist/index.d.ts +76 -4
  24. package/dist/index.js +817 -181
  25. package/dist/index.js.map +1 -1
  26. package/dist/mcp.js +80 -13
  27. package/dist/mcp.js.map +1 -1
  28. package/dist/{parser-O2SD4DFR.cjs → parser-3O2UF6VO.cjs} +35 -22
  29. package/dist/parser-3O2UF6VO.cjs.map +1 -0
  30. package/dist/{parser-76JSTEP3.js → parser-B4O7CW5Q.js} +24 -11
  31. package/dist/parser-B4O7CW5Q.js.map +1 -0
  32. package/dist/{parser-SNBQZO5E.js → parser-BNEAMKUF.js} +23 -10
  33. package/dist/parser-BNEAMKUF.js.map +1 -0
  34. package/dist/render-QCNMRR7L.js +10 -0
  35. package/dist/seal-REDSMUI5.js +10 -0
  36. package/dist/seal-REDSMUI5.js.map +1 -0
  37. package/dist/{watch-LEK5U5P6.js → watch-RLF5F3TN.js} +7 -5
  38. package/dist/{watch-LEK5U5P6.js.map → watch-RLF5F3TN.js.map} +1 -1
  39. package/package.json +2 -5
  40. package/dist/chunk-734GJLXH.js.map +0 -1
  41. package/dist/chunk-DMBTOJK4.cjs.map +0 -1
  42. package/dist/chunk-Q3IHI3E6.js.map +0 -1
  43. package/dist/chunk-Q5ZPWQID.js.map +0 -1
  44. package/dist/chunk-ZRNYYEE6.js.map +0 -1
  45. package/dist/parser-76JSTEP3.js.map +0 -1
  46. package/dist/parser-O2SD4DFR.cjs.map +0 -1
  47. package/dist/parser-SNBQZO5E.js.map +0 -1
  48. package/dist/render-LDI3LO2P.js +0 -9
  49. /package/dist/{-EYPKRLMN.js.map → -YVONYEEN.js.map} +0 -0
  50. /package/dist/{chunk-SCFFABCT.js.map → chunk-K4L563FA.js.map} +0 -0
  51. /package/dist/{render-LDI3LO2P.js.map → render-QCNMRR7L.js.map} +0 -0
@@ -1,39 +1,53 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ HEADING_RATIO_H1,
4
+ HEADING_RATIO_H2,
5
+ HEADING_RATIO_H3,
6
+ MAX_COLS,
7
+ MAX_ROWS,
8
+ blocksToMarkdown,
9
+ buildTable,
10
+ convertTableToText,
11
+ flattenLayoutTables,
12
+ mapPuaText
13
+ } from "./chunk-F62GOZFB.js";
2
14
  import {
3
15
  detectFormat,
4
16
  detectOle2Format,
5
17
  detectZipFormat,
6
18
  parseLenientCfb
7
19
  } from "./chunk-MEPHGCPQ.js";
20
+ import {
21
+ parsePageRange
22
+ } from "./chunk-MOL7MDBG.js";
23
+ import {
24
+ allLinesegRemovalSplices,
25
+ applySplices,
26
+ buildParagraphSplices,
27
+ buildRangeSplices,
28
+ escapeXmlText,
29
+ findElementEnd,
30
+ paraTText,
31
+ paraTextPureT,
32
+ patchZipEntries,
33
+ scanSectionXml
34
+ } from "./chunk-7WUTJXKP.js";
35
+ import {
36
+ SPACE_EM_FIXED,
37
+ charWidthEm1000,
38
+ fitRatioForFewerLines
39
+ } from "./chunk-CDFCA37S.js";
8
40
  import {
9
41
  MAX_DECOMPRESS_SIZE,
10
42
  MAX_XML_DEPTH,
11
43
  MAX_ZIP_ENTRIES,
12
- SPACE_EM_FIXED,
13
44
  applyPageText,
14
- charWidthEm1000,
15
45
  clampSpan,
16
46
  createSectionShared,
17
47
  createXmlParser,
18
48
  extractTextFromNode,
19
- findChildByLocalName,
20
- fitRatioForFewerLines
21
- } from "./chunk-734GJLXH.js";
22
- import {
23
- HEADING_RATIO_H1,
24
- HEADING_RATIO_H2,
25
- HEADING_RATIO_H3,
26
- MAX_COLS,
27
- MAX_ROWS,
28
- blocksToMarkdown,
29
- buildTable,
30
- convertTableToText,
31
- flattenLayoutTables,
32
- mapPuaText
33
- } from "./chunk-Q5ZPWQID.js";
34
- import {
35
- parsePageRange
36
- } from "./chunk-MOL7MDBG.js";
49
+ findChildByLocalName
50
+ } from "./chunk-IY3NX4FT.js";
37
51
  import {
38
52
  KordocError,
39
53
  classifyError,
@@ -44,7 +58,7 @@ import {
44
58
  sanitizeHref,
45
59
  stripDtd,
46
60
  toArrayBuffer
47
- } from "./chunk-SCFFABCT.js";
61
+ } from "./chunk-K4L563FA.js";
48
62
 
49
63
  // src/index.ts
50
64
  import { readFile } from "fs/promises";
@@ -646,8 +660,8 @@ function maskLiteralSpans(eqString) {
646
660
  function findKeywordToken(eqString, word, from = 0) {
647
661
  const masked = maskLiteralSpans(eqString);
648
662
  for (let i = masked.indexOf(word, from); i !== -1; i = masked.indexOf(word, i + 1)) {
649
- const okL = i === 0 || masked[i - 1] === " ";
650
- const okR = i + word.length === masked.length || masked[i + word.length] === " ";
663
+ const okL = i === 0 || /\s/.test(masked[i - 1]);
664
+ const okR = i + word.length === masked.length || /\s/.test(masked[i + word.length]);
651
665
  if (okL && okR) return i;
652
666
  }
653
667
  return -1;
@@ -658,11 +672,22 @@ function replaceFrac(eqString) {
658
672
  const cursor = findKeywordToken(eqString, hmlFrac);
659
673
  if (cursor === -1) break;
660
674
  try {
661
- const [numStart, numEnd] = findBrackets(eqString, cursor, 0);
662
- const numerator = eqString.slice(numStart, numEnd);
675
+ let end = cursor;
676
+ while (end > 0 && /\s/.test(eqString[end - 1])) end--;
677
+ let numStart, numEnd, wrapped;
678
+ if (end > 0 && eqString[end - 1] === "}") {
679
+ [numStart, numEnd] = findBrackets(eqString, end - 1, 0);
680
+ wrapped = eqString.slice(numStart, numEnd);
681
+ } else {
682
+ numEnd = end;
683
+ numStart = end;
684
+ while (numStart > 0 && !/\s/.test(eqString[numStart - 1])) numStart--;
685
+ if (numStart === numEnd) throw new Error("empty numerator");
686
+ wrapped = "{" + eqString.slice(numStart, numEnd) + "}";
687
+ }
663
688
  const beforeFrac = eqString.slice(0, numStart);
664
689
  const afterFrac = eqString.slice(cursor + hmlFrac.length);
665
- eqString = beforeFrac + "\\frac" + numerator + afterFrac;
690
+ eqString = beforeFrac + "\\frac" + wrapped + afterFrac;
666
691
  } catch {
667
692
  return eqString;
668
693
  }
@@ -18095,7 +18120,7 @@ function parseTable(tbl, styles, numbering, footnotes, rels) {
18095
18120
  if (trPrEls.length > 0) {
18096
18121
  const gridBeforeEls = getChildElements(trPrEls[0], "gridBefore");
18097
18122
  if (gridBeforeEls.length > 0) {
18098
- col = parseInt(getAttr(gridBeforeEls[0], "val") ?? "0", 10) || 0;
18123
+ col = Math.max(0, parseInt(getAttr(gridBeforeEls[0], "val") ?? "0", 10) || 0);
18099
18124
  }
18100
18125
  }
18101
18126
  for (const tc of getChildElements(tr, "tc")) {
@@ -18624,34 +18649,47 @@ function countSections(body) {
18624
18649
 
18625
18650
  // src/form/match.ts
18626
18651
  function parseYMD(v) {
18627
- const d = v.replace(/\D/g, "");
18628
18652
  let y, m, day;
18629
- if (d.length >= 8) {
18630
- y = d.slice(0, 4);
18631
- m = d.slice(4, 6);
18632
- day = d.slice(6, 8);
18633
- } else if (d.length === 6) {
18634
- const yy = +d.slice(0, 2);
18635
- y = String(yy <= 29 ? 2e3 + yy : 1900 + yy);
18636
- m = d.slice(2, 4);
18637
- day = d.slice(4, 6);
18638
- } else return null;
18653
+ const parts = v.split(/[^0-9]+/).filter(Boolean);
18654
+ if (parts.length === 3) {
18655
+ const [yp, mp, dp] = parts;
18656
+ const yn = +yp;
18657
+ y = yp.length >= 3 ? yp : String(yn <= 29 ? 2e3 + yn : 1900 + yn);
18658
+ m = mp.padStart(2, "0");
18659
+ day = dp.padStart(2, "0");
18660
+ } else {
18661
+ const d = v.replace(/\D/g, "");
18662
+ if (d.length >= 8) {
18663
+ y = d.slice(0, 4);
18664
+ m = d.slice(4, 6);
18665
+ day = d.slice(6, 8);
18666
+ } else if (d.length === 6) {
18667
+ const yy = +d.slice(0, 2);
18668
+ y = String(yy <= 29 ? 2e3 + yy : 1900 + yy);
18669
+ m = d.slice(2, 4);
18670
+ day = d.slice(4, 6);
18671
+ } else return null;
18672
+ }
18673
+ if (+m < 1 || +m > 12 || +day < 1 || +day > 31) return null;
18639
18674
  return { y, yy: y.slice(2), m, d: day };
18640
18675
  }
18641
18676
  function fmtDate(v, style) {
18642
18677
  const p = parseYMD(v);
18643
18678
  if (!p) return v;
18644
- 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));
18679
+ 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));
18645
18680
  }
18646
18681
  function maskDigits(v, pattern) {
18647
18682
  const ds = v.replace(/\D/g, "");
18683
+ const need = (pattern.match(/#/g) ?? []).length;
18684
+ if (need === 0 || ds.length !== need) return v;
18648
18685
  let i = 0;
18649
- return pattern.replace(/#/g, () => ds[i++] ?? "");
18686
+ return pattern.replace(/#/g, () => ds[i++]);
18650
18687
  }
18651
18688
  function fmtPhone(v, style) {
18652
18689
  const d = v.replace(/\D/g, "");
18653
18690
  if (d.length < 9) return v;
18654
- const a = d.slice(0, 3), b = d.slice(3, -4), c = d.slice(-4);
18691
+ const areaLen = d.startsWith("02") ? 2 : 3;
18692
+ const a = d.slice(0, areaLen), b = d.slice(areaLen, -4), c = d.slice(-4);
18655
18693
  switch (style) {
18656
18694
  case "digits":
18657
18695
  return d;
@@ -18660,9 +18698,9 @@ function fmtPhone(v, style) {
18660
18698
  case "space":
18661
18699
  return `${a} ${b} ${c}`;
18662
18700
  case "intl":
18663
- return `+82-${d.slice(1, 3)}-${b}-${c}`;
18701
+ return `+82-${d.slice(1, areaLen)}-${b}-${c}`;
18664
18702
  case "intl-paren":
18665
- return `82)${d.slice(1, 3)}-${b}-${c}`;
18703
+ return `82)${d.slice(1, areaLen)}-${b}-${c}`;
18666
18704
  default:
18667
18705
  return `${a}-${b}-${c}`;
18668
18706
  }
@@ -18690,7 +18728,10 @@ function formatFillValue(value, format) {
18690
18728
  if (kind === "phone") return fmtPhone(value, style);
18691
18729
  if (kind === "rrn") return fmtRRN(value, style);
18692
18730
  if (kind === "mask") return maskDigits(value, style);
18693
- if (kind === "digits") return value.replace(/\D/g, "");
18731
+ if (kind === "digits") {
18732
+ const only = value.replace(/\D/g, "");
18733
+ return only || value;
18734
+ }
18694
18735
  if (kind === "upper") return value.toUpperCase();
18695
18736
  if (kind === "lower") return value.toLowerCase();
18696
18737
  if (kind === "nospace") return value.replace(/\s+/g, "");
@@ -18767,7 +18808,7 @@ function isKeywordLabel(text) {
18767
18808
  }
18768
18809
  return false;
18769
18810
  }
18770
- function fillInCellPatterns(cellText, values, matchedLabels) {
18811
+ function fillInCellPatterns(cellText, values, matchedLabels, blockedLabels) {
18771
18812
  let text = cellText;
18772
18813
  const matches = [];
18773
18814
  text = text.replace(
@@ -18775,6 +18816,7 @@ function fillInCellPatterns(cellText, values, matchedLabels) {
18775
18816
  (match, prefix, suffix) => {
18776
18817
  const label = prefix + suffix;
18777
18818
  const normalizedLabel = normalizeLabel(label);
18819
+ if (blockedLabels?.has(normalizedLabel)) return match;
18778
18820
  const matchKey = values.available(normalizedLabel) ? normalizedLabel : values.available(normalizeLabel(prefix)) ? normalizeLabel(prefix) : void 0;
18779
18821
  if (matchKey === void 0) return match;
18780
18822
  const newValue = values.consume(matchKey);
@@ -18870,8 +18912,12 @@ async function fillWithUniqueGuard(values, run) {
18870
18912
  };
18871
18913
  const dup = new Set([...counts].filter(([k, n]) => n >= 2 && !isArrayValue(k)).map(([k]) => k));
18872
18914
  if (dup.size === 0) return { ...first, rejected: [] };
18915
+ const blockedLabels = /* @__PURE__ */ new Set();
18916
+ for (const f of first.filled) {
18917
+ if (f.key && dup.has(f.key)) blockedLabels.add(normalizeLabel(f.label));
18918
+ }
18873
18919
  const filtered = Object.fromEntries(Object.entries(values).filter(([label]) => !dup.has(normalizeLabel(label))));
18874
- const second = await run(filtered);
18920
+ const second = await run(filtered, blockedLabels);
18875
18921
  const rejected = Object.keys(values).filter((label) => dup.has(normalizeLabel(label)));
18876
18922
  return { ...second, rejected };
18877
18923
  }
@@ -19126,7 +19172,7 @@ function extractFormSchema(blocks) {
19126
19172
  }
19127
19173
 
19128
19174
  // src/form/filler.ts
19129
- function fillFormFields(blocks, values) {
19175
+ function fillFormFields(blocks, values, blockedLabels) {
19130
19176
  const cloned = structuredClone(blocks);
19131
19177
  const filled = [];
19132
19178
  const matchedLabels = /* @__PURE__ */ new Set();
@@ -19139,7 +19185,7 @@ function fillFormFields(blocks, values) {
19139
19185
  for (let c = 0; c < table.cols; c++) {
19140
19186
  const cell = table.cells[r]?.[c];
19141
19187
  if (!cell) continue;
19142
- const result = fillInCellPatterns(cell.text, cursor, matchedLabels);
19188
+ const result = fillInCellPatterns(cell.text, cursor, matchedLabels, blockedLabels);
19143
19189
  if (result) {
19144
19190
  cell.text = result.text;
19145
19191
  patternFilledCells.add(cell);
@@ -19151,11 +19197,11 @@ function fillFormFields(blocks, values) {
19151
19197
  }
19152
19198
  }
19153
19199
  for (const table of allTables) {
19154
- fillTable(table, cursor, filled, matchedLabels, patternFilledCells);
19200
+ fillTable(table, cursor, filled, matchedLabels, patternFilledCells, blockedLabels);
19155
19201
  }
19156
19202
  for (const block of cloned) {
19157
19203
  if (block.type !== "paragraph" || !block.text) continue;
19158
- const newText = fillInlineFields(block.text, cursor, filled, matchedLabels);
19204
+ const newText = fillInlineFields(block.text, cursor, filled, matchedLabels, blockedLabels);
19159
19205
  if (newText !== block.text) block.text = newText;
19160
19206
  }
19161
19207
  const unmatched = resolveUnmatched(normalizedValues, matchedLabels, values);
@@ -19193,7 +19239,7 @@ function coveredPositions(table) {
19193
19239
  }
19194
19240
  return covered;
19195
19241
  }
19196
- function fillTable(table, values, filled, matchedLabels, patternFilledCells) {
19242
+ function fillTable(table, values, filled, matchedLabels, patternFilledCells, blockedLabels) {
19197
19243
  if (table.cols < 2) return;
19198
19244
  const covered = coveredPositions(table);
19199
19245
  for (let r = 0; r < table.rows; r++) {
@@ -19210,6 +19256,7 @@ function fillTable(table, values, filled, matchedLabels, patternFilledCells) {
19210
19256
  if (isKeywordLabel(valueCell.text)) continue;
19211
19257
  const normalizedCellLabel = normalizeLabel(labelCell.text);
19212
19258
  if (!normalizedCellLabel) continue;
19259
+ if (blockedLabels?.has(normalizedCellLabel)) continue;
19213
19260
  const matchKey = findMatchingKey(normalizedCellLabel, values);
19214
19261
  if (matchKey === void 0) continue;
19215
19262
  const newValue = values.consume(matchKey);
@@ -19243,6 +19290,7 @@ function fillTable(table, values, filled, matchedLabels, patternFilledCells) {
19243
19290
  const valueCell = table.cells[r]?.[c];
19244
19291
  if (!headerCell || !valueCell) continue;
19245
19292
  const headerLabel = normalizeLabel(headerCell.text);
19293
+ if (blockedLabels?.has(headerLabel)) continue;
19246
19294
  const matchKey = findMatchingKey(headerLabel, values);
19247
19295
  if (matchKey === void 0) continue;
19248
19296
  if (!values.isArray(matchKey) && matchedLabels.has(matchKey)) continue;
@@ -19261,13 +19309,15 @@ function fillTable(table, values, filled, matchedLabels, patternFilledCells) {
19261
19309
  }
19262
19310
  }
19263
19311
  }
19264
- function fillInlineFields(text, values, filled, matchedLabels) {
19312
+ function fillInlineFields(text, values, filled, matchedLabels, blockedLabels) {
19265
19313
  const segments = scanInlineSegments(text);
19266
19314
  if (segments.length === 0) return text;
19267
19315
  let out = "";
19268
19316
  let pos = 0;
19269
19317
  for (const seg of segments) {
19270
- const matchKey = findMatchingKey(normalizeLabel(seg.label), values);
19318
+ const nlabel = normalizeLabel(seg.label);
19319
+ if (blockedLabels?.has(nlabel)) continue;
19320
+ const matchKey = findMatchingKey(nlabel, values);
19271
19321
  if (matchKey === void 0) continue;
19272
19322
  const newValue = values.consume(matchKey);
19273
19323
  if (newValue === void 0) continue;
@@ -19283,678 +19333,7 @@ function fillInlineFields(text, values, filled, matchedLabels) {
19283
19333
 
19284
19334
  // src/form/filler-hwpx.ts
19285
19335
  import JSZip5 from "jszip";
19286
-
19287
- // src/roundtrip/source-map.ts
19288
- function escapeXmlText(text) {
19289
- return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
19290
- }
19291
- function decodeXmlEntities(text) {
19292
- return text.replace(/&(lt|gt|amp|quot|apos|#x?[0-9a-fA-F]+);/g, (m, ent) => {
19293
- switch (ent) {
19294
- case "lt":
19295
- return "<";
19296
- case "gt":
19297
- return ">";
19298
- case "amp":
19299
- return "&";
19300
- case "quot":
19301
- return '"';
19302
- case "apos":
19303
- return "'";
19304
- }
19305
- try {
19306
- const code = ent[1] === "x" || ent[1] === "X" ? parseInt(ent.slice(2), 16) : parseInt(ent.slice(1), 10);
19307
- if (!isNaN(code) && code >= 0 && code <= 1114111) return String.fromCodePoint(code);
19308
- } catch {
19309
- }
19310
- return m;
19311
- });
19312
- }
19313
- function tContentToText(raw) {
19314
- return decodeXmlEntities(
19315
- raw.replace(/<\/?(?:[A-Za-z0-9_]+:)?(?:tab|fwSpace|hwSpace|br|lineBreak)(?:\s[^>]*)?\/?>/g, " ").replace(/<[^>]*>/g, "")
19316
- );
19317
- }
19318
- var TAG_RE = /<!--[\s\S]*?-->|<!\[CDATA\[[\s\S]*?\]\]>|<\?[\s\S]*?\?>|<!(?:"[^"]*"|'[^']*'|[^>"'])*>|<\/([^\s>]+)\s*>|<([^\s/>!?]+)((?:"[^"]*"|'[^']*'|[^>"'])*?)(\/?)>/g;
19319
- var T_BARRIER = /* @__PURE__ */ new Set([
19320
- "tbl",
19321
- "ctrl",
19322
- "caption",
19323
- "pic",
19324
- "shape",
19325
- "drawingObject",
19326
- "drawText",
19327
- "shapeComment",
19328
- "memogroup",
19329
- "memo",
19330
- "hiddenComment",
19331
- "equation",
19332
- "parameters",
19333
- "subList",
19334
- "p"
19335
- ]);
19336
- var PARA_CONTAINER = /* @__PURE__ */ new Set([
19337
- "tc",
19338
- "ctrl",
19339
- "caption",
19340
- "drawText",
19341
- "pic",
19342
- "shape",
19343
- "drawingObject",
19344
- "memogroup",
19345
- "memo",
19346
- "hiddenComment",
19347
- "footNote",
19348
- "endNote",
19349
- "fn",
19350
- "en"
19351
- // 각주/미주 — 파서는 호스트 블록 footnoteText로만 흡수
19352
- ]);
19353
- var TABLE_BARRIER = /* @__PURE__ */ new Set([
19354
- "tbl",
19355
- "ctrl",
19356
- "caption",
19357
- "memogroup",
19358
- "memo",
19359
- "hiddenComment"
19360
- ]);
19361
- function localOf(qname) {
19362
- const i = qname.indexOf(":");
19363
- return i >= 0 ? qname.slice(i + 1) : qname;
19364
- }
19365
- function prefixOf(qname) {
19366
- const i = qname.indexOf(":");
19367
- return i >= 0 ? qname.slice(0, i) : "";
19368
- }
19369
- function scanSectionXml(xml, sectionIndex) {
19370
- const stack = [];
19371
- const bodyParagraphs = [];
19372
- const tables = [];
19373
- const headerTexts = [];
19374
- const footerTexts = [];
19375
- const excludedParagraphs = [];
19376
- const orphanTables = [];
19377
- const paraStack = [];
19378
- const tableStack = [];
19379
- const rowStack = [];
19380
- const trStartStack = [];
19381
- const cellStack = [];
19382
- let pendingT = null;
19383
- const ctrlSubStack = [];
19384
- const classifyPara = () => {
19385
- let sawDrawText = false;
19386
- for (let i = stack.length - 1; i >= 0; i--) {
19387
- const l = stack[i].local;
19388
- if (l === "tc") return { kind: "cell", inTextbox: sawDrawText };
19389
- if (l === "drawText") {
19390
- sawDrawText = true;
19391
- continue;
19392
- }
19393
- if (PARA_CONTAINER.has(l)) return { kind: "excluded", inTextbox: sawDrawText };
19394
- }
19395
- return sawDrawText ? { kind: "draw", inTextbox: true } : { kind: "body", inTextbox: false };
19396
- };
19397
- const owningPara = () => {
19398
- if (paraStack.length === 0) return null;
19399
- for (let i = stack.length - 1; i >= 0; i--) {
19400
- const l = stack[i].local;
19401
- if (l === "p") return paraStack[paraStack.length - 1];
19402
- if (T_BARRIER.has(l)) return null;
19403
- }
19404
- return null;
19405
- };
19406
- const isTableTopLevel = () => {
19407
- for (let i = stack.length - 1; i >= 0; i--) {
19408
- if (TABLE_BARRIER.has(stack[i].local)) return false;
19409
- }
19410
- return true;
19411
- };
19412
- const currentCtrlSub = () => ctrlSubStack.length > 0 ? ctrlSubStack[ctrlSubStack.length - 1] : null;
19413
- TAG_RE.lastIndex = 0;
19414
- let m;
19415
- while ((m = TAG_RE.exec(xml)) !== null) {
19416
- const [full, closeName, openName, , selfClose] = m;
19417
- if (closeName === void 0 && openName === void 0) continue;
19418
- if (closeName !== void 0) {
19419
- const local2 = localOf(closeName);
19420
- if (local2 === "t" && pendingT) {
19421
- const { para, contentStart: contentStart2 } = pendingT;
19422
- para.tRanges.push({ contentStart: contentStart2, contentEnd: m.index });
19423
- para.text += tContentToText(xml.slice(contentStart2, m.index));
19424
- pendingT = null;
19425
- }
19426
- for (let i = stack.length - 1; i >= 0; i--) {
19427
- if (stack[i].local === local2) {
19428
- stack.length = i;
19429
- break;
19430
- }
19431
- }
19432
- if (local2 === "p") {
19433
- const para = paraStack.pop();
19434
- if (para && para.kind === "excluded") {
19435
- const sub = currentCtrlSub();
19436
- if (sub && para.text.trim()) sub.texts.push(para.text);
19437
- }
19438
- } else if (local2 === "tc") {
19439
- const cell = cellStack.pop();
19440
- const row = rowStack[rowStack.length - 1];
19441
- if (cell && row) row.push(cell);
19442
- } else if (local2 === "tr") {
19443
- const row = rowStack[rowStack.length - 1];
19444
- const table = tableStack[tableStack.length - 1];
19445
- if (row && table && row.length > 0) {
19446
- table.rows.push(row);
19447
- const trStart = trStartStack[trStartStack.length - 1];
19448
- if (trStart >= 0) table.rowRanges.push({ start: trStart, end: m.index + full.length });
19449
- }
19450
- if (rowStack.length > 0) rowStack[rowStack.length - 1] = [];
19451
- if (trStartStack.length > 0) trStartStack[trStartStack.length - 1] = -1;
19452
- } else if (local2 === "tbl") {
19453
- const table = tableStack.pop();
19454
- rowStack.pop();
19455
- trStartStack.pop();
19456
- if (table) {
19457
- finalizeTable(table);
19458
- if (!table.topLevel) {
19459
- const cell = cellStack[cellStack.length - 1];
19460
- if (cell) cell.tables.push(table);
19461
- else orphanTables.push(table);
19462
- }
19463
- }
19464
- } else if (local2 === "header" || local2 === "footer") {
19465
- const sub = ctrlSubStack[ctrlSubStack.length - 1];
19466
- if (sub) {
19467
- ctrlSubStack.pop();
19468
- const joined = sub.texts.join("\n").trim();
19469
- if (joined) (sub.kind === "header" ? headerTexts : footerTexts).push(joined);
19470
- }
19471
- }
19472
- continue;
19473
- }
19474
- const qname = openName;
19475
- const local = localOf(qname);
19476
- const attrsRaw = m[3] || "";
19477
- const isSelfClose = selfClose === "/";
19478
- const contentStart = m.index + full.length;
19479
- if (isSelfClose) {
19480
- if (local === "t") {
19481
- const para = owningPara();
19482
- if (para) para.tRanges.push({ contentStart: m.index, contentEnd: m.index + full.length, selfClosing: true, prefix: prefixOf(qname) });
19483
- } else if (local === "tab" || local === "fwSpace" || local === "hwSpace" || local === "br" || local === "lineBreak") {
19484
- if (!pendingT) {
19485
- const para = owningPara();
19486
- if (para) para.text += " ";
19487
- }
19488
- } else if (local === "run" || local === "r") {
19489
- const para = owningPara();
19490
- if (para && !para.selfCloseRun) para.selfCloseRun = { start: m.index, end: m.index + full.length };
19491
- } else if (local === "cellAddr") {
19492
- const cell = cellStack[cellStack.length - 1];
19493
- if (cell && insideCurrentTable(stack, tableStack)) {
19494
- const ca = parseInt(getAttr2(attrsRaw, "colAddr") || "", 10);
19495
- const ra = parseInt(getAttr2(attrsRaw, "rowAddr") || "", 10);
19496
- if (!isNaN(ca)) cell.colAddr = ca;
19497
- if (!isNaN(ra)) cell.rowAddr = ra;
19498
- cell.addrTagRange = { start: m.index, end: m.index + full.length };
19499
- }
19500
- } else if (local === "cellSpan") {
19501
- const cell = cellStack[cellStack.length - 1];
19502
- if (cell && insideCurrentTable(stack, tableStack)) {
19503
- const cs = parseInt(getAttr2(attrsRaw, "colSpan") || "1", 10);
19504
- const rs = parseInt(getAttr2(attrsRaw, "rowSpan") || "1", 10);
19505
- cell.colSpan = isNaN(cs) || cs < 1 ? 1 : cs;
19506
- cell.rowSpan = isNaN(rs) || rs < 1 ? 1 : rs;
19507
- }
19508
- }
19509
- continue;
19510
- }
19511
- if (local === "t") {
19512
- const para = owningPara();
19513
- if (para) pendingT = { para, contentStart };
19514
- stack.push({ local, qname, contentStart });
19515
- continue;
19516
- }
19517
- stack.push({ local, qname, contentStart });
19518
- if (local === "p") {
19519
- const para = {
19520
- sectionIndex,
19521
- kind: "excluded",
19522
- // 분류는 push 직후 스택 기준 (자기 자신 제외)
19523
- start: m.index,
19524
- tRanges: [],
19525
- text: ""
19526
- };
19527
- stack.pop();
19528
- const cls = classifyPara();
19529
- para.kind = cls.kind;
19530
- if (cls.inTextbox) para.inTextbox = true;
19531
- stack.push({ local, qname, contentStart });
19532
- paraStack.push(para);
19533
- if (para.kind === "body" || para.kind === "draw") bodyParagraphs.push(para);
19534
- else if (para.kind === "cell") {
19535
- const cell = cellStack[cellStack.length - 1];
19536
- if (cell) cell.paragraphs.push(para);
19537
- } else if (para.kind === "excluded") {
19538
- excludedParagraphs.push(para);
19539
- }
19540
- } else if (local === "run" || local === "r") {
19541
- const para = owningPara();
19542
- if (para && para.runPrefix === void 0) para.runPrefix = prefixOf(qname);
19543
- } else if (local === "tbl") {
19544
- const table = {
19545
- sectionIndex,
19546
- start: m.index,
19547
- topLevel: false,
19548
- rows: [],
19549
- rowRanges: [],
19550
- cellByAnchor: /* @__PURE__ */ new Map()
19551
- };
19552
- stack.pop();
19553
- table.topLevel = isTableTopLevel();
19554
- stack.push({ local, qname, contentStart });
19555
- tableStack.push(table);
19556
- rowStack.push([]);
19557
- trStartStack.push(-1);
19558
- if (table.topLevel) tables.push(table);
19559
- } else if (local === "tr") {
19560
- if (rowStack.length > 0) rowStack[rowStack.length - 1] = [];
19561
- if (trStartStack.length > 0) trStartStack[trStartStack.length - 1] = m.index;
19562
- } else if (local === "tc") {
19563
- cellStack.push({ colSpan: 1, rowSpan: 1, paragraphs: [], tables: [] });
19564
- } else if (local === "cellAddr" || local === "cellSpan") {
19565
- const cell = cellStack[cellStack.length - 1];
19566
- if (cell && insideCurrentTable(stack, tableStack)) {
19567
- if (local === "cellAddr") {
19568
- const ca = parseInt(getAttr2(attrsRaw, "colAddr") || "", 10);
19569
- const ra = parseInt(getAttr2(attrsRaw, "rowAddr") || "", 10);
19570
- if (!isNaN(ca)) cell.colAddr = ca;
19571
- if (!isNaN(ra)) cell.rowAddr = ra;
19572
- cell.addrTagRange = { start: m.index, end: contentStart };
19573
- } else {
19574
- const cs = parseInt(getAttr2(attrsRaw, "colSpan") || "1", 10);
19575
- const rs = parseInt(getAttr2(attrsRaw, "rowSpan") || "1", 10);
19576
- cell.colSpan = isNaN(cs) || cs < 1 ? 1 : cs;
19577
- cell.rowSpan = isNaN(rs) || rs < 1 ? 1 : rs;
19578
- }
19579
- }
19580
- } else if (local === "header" || local === "footer") {
19581
- if (stack.some((f) => f.local === "ctrl")) {
19582
- ctrlSubStack.push({ kind: local, texts: [] });
19583
- }
19584
- } else if (local === "tab" || local === "fwSpace" || local === "hwSpace" || local === "br" || local === "lineBreak") {
19585
- const para = owningPara();
19586
- if (para) para.text += " ";
19587
- }
19588
- }
19589
- for (const para of bodyParagraphs) fillRunInsertPos(para, xml);
19590
- for (const para of excludedParagraphs) fillRunInsertPos(para, xml);
19591
- const fillTableInsertPos = (table, depth = 0) => {
19592
- if (depth > 16) return;
19593
- for (const row of table.rows) {
19594
- for (const cell of row) {
19595
- for (const para of cell.paragraphs) fillRunInsertPos(para, xml);
19596
- for (const nested of cell.tables) fillTableInsertPos(nested, depth + 1);
19597
- }
19598
- }
19599
- };
19600
- for (const table of tables) fillTableInsertPos(table);
19601
- for (const table of orphanTables) fillTableInsertPos(table);
19602
- return { sectionIndex, xml, bodyParagraphs, tables, headerTexts, footerTexts, excludedParagraphs, orphanTables };
19603
- }
19604
- function getAttr2(attrsRaw, name) {
19605
- const re = new RegExp(`(?:^|\\s)${name}\\s*=\\s*(?:"([^"]*)"|'([^']*)')`);
19606
- const m = attrsRaw.match(re);
19607
- return m ? m[1] ?? m[2] : void 0;
19608
- }
19609
- function insideCurrentTable(stack, tableStack) {
19610
- if (tableStack.length === 0) return false;
19611
- for (let i = stack.length - 1; i >= 0; i--) {
19612
- const l = stack[i].local;
19613
- if (l === "tc") return true;
19614
- if (l === "tbl") return false;
19615
- }
19616
- return false;
19617
- }
19618
- function fillRunInsertPos(para, xml) {
19619
- if (para.tRanges.length > 0) return;
19620
- const pEnd = findElementEnd(xml, para.start);
19621
- if (pEnd < 0) return;
19622
- const slice = xml.slice(para.start, pEnd);
19623
- const runOpen = slice.match(/<((?:[A-Za-z0-9_]+:)?run)(?:\s(?:"[^"]*"|'[^']*'|[^>"'])*?)?(\/?)>/);
19624
- if (!runOpen || runOpen.index === void 0) return;
19625
- if (runOpen[2] === "/") return;
19626
- const qname = runOpen[1];
19627
- const closeIdx = slice.indexOf(`</${qname}>`, runOpen.index);
19628
- if (closeIdx < 0) return;
19629
- para.runInsertPos = para.start + closeIdx;
19630
- para.runPrefix = prefixOf(qname);
19631
- }
19632
- function findElementEnd(xml, start) {
19633
- const open = xml.slice(start).match(/^<([^\s/>!?]+)/);
19634
- if (!open) return -1;
19635
- const qname = open[1];
19636
- const re = new RegExp(`<${qname}(?=[\\s/>])(?:"[^"]*"|'[^']*'|[^>"'])*?(/?)>|</${qname}\\s*>`, "g");
19637
- re.lastIndex = start;
19638
- let depth = 0;
19639
- let mm;
19640
- while ((mm = re.exec(xml)) !== null) {
19641
- if (mm[0].startsWith("</")) {
19642
- depth--;
19643
- if (depth === 0) return mm.index + mm[0].length;
19644
- } else if (mm[1] !== "/") {
19645
- depth++;
19646
- }
19647
- }
19648
- return -1;
19649
- }
19650
- function finalizeTable(table) {
19651
- const hasAddr = table.rows.some((row) => row.some((c) => c.colAddr !== void 0 && c.rowAddr !== void 0));
19652
- if (hasAddr) {
19653
- for (const row of table.rows) {
19654
- for (const cell of row) {
19655
- if (cell.rowAddr !== void 0 && cell.colAddr !== void 0) {
19656
- table.cellByAnchor.set(`${cell.rowAddr},${cell.colAddr}`, cell);
19657
- }
19658
- }
19659
- }
19660
- return;
19661
- }
19662
- const numRows = table.rows.length;
19663
- const occupied = Array.from({ length: numRows }, () => []);
19664
- for (let rowIdx = 0; rowIdx < numRows; rowIdx++) {
19665
- let colIdx = 0;
19666
- for (const cell of table.rows[rowIdx]) {
19667
- while (occupied[rowIdx][colIdx]) colIdx++;
19668
- cell.rowAddr = rowIdx;
19669
- cell.colAddr = colIdx;
19670
- table.cellByAnchor.set(`${rowIdx},${colIdx}`, cell);
19671
- for (let r = rowIdx; r < Math.min(rowIdx + cell.rowSpan, numRows); r++) {
19672
- for (let c = colIdx; c < colIdx + cell.colSpan; c++) {
19673
- occupied[r][c] = true;
19674
- }
19675
- }
19676
- colIdx += cell.colSpan;
19677
- }
19678
- }
19679
- }
19680
- function buildParagraphSplices(para, newText, xml) {
19681
- if (newText && xml) {
19682
- const orig = paraTText(para, xml);
19683
- if (orig && orig.trim() !== "") {
19684
- const lead = orig.match(/^\s*/)[0];
19685
- const trail = orig.match(/\s*$/)[0];
19686
- if ((lead || trail) && newText.trim() !== "") {
19687
- newText = lead + newText.replace(/^\s+|\s+$/g, "") + trail;
19688
- }
19689
- }
19690
- }
19691
- const escaped = escapeXmlText(newText);
19692
- if (para.tRanges.length > 0) {
19693
- const splices = [];
19694
- const first = para.tRanges[0];
19695
- if (first.selfClosing) {
19696
- const prefix = first.prefix ? first.prefix + ":" : "";
19697
- splices.push({ start: first.contentStart, end: first.contentEnd, replacement: `<${prefix}t>${escaped}</${prefix}t>` });
19698
- } else {
19699
- splices.push({ start: first.contentStart, end: first.contentEnd, replacement: escaped });
19700
- }
19701
- for (let i = 1; i < para.tRanges.length; i++) {
19702
- const r = para.tRanges[i];
19703
- if (!r.selfClosing && r.contentStart < r.contentEnd) {
19704
- splices.push({ start: r.contentStart, end: r.contentEnd, replacement: "" });
19705
- }
19706
- }
19707
- return splices;
19708
- }
19709
- if (para.runInsertPos !== void 0) {
19710
- if (!newText) return [];
19711
- const prefix = para.runPrefix ? para.runPrefix + ":" : "";
19712
- return [{ start: para.runInsertPos, end: para.runInsertPos, replacement: `<${prefix}t>${escaped}</${prefix}t>` }];
19713
- }
19714
- if (para.selfCloseRun && xml) {
19715
- if (!newText) return [];
19716
- const { start, end } = para.selfCloseRun;
19717
- const tag = xml.slice(start, end);
19718
- const qm = tag.match(/^<([^\s/>]+)/);
19719
- if (!qm || !tag.endsWith("/>")) return null;
19720
- const qname = qm[1];
19721
- const colon = qname.indexOf(":");
19722
- const prefix = colon >= 0 ? qname.slice(0, colon) + ":" : "";
19723
- const opened = tag.slice(0, tag.length - 2).trimEnd() + ">";
19724
- return [{ start, end, replacement: `${opened}<${prefix}t>${escaped}</${prefix}t></${qname}>` }];
19725
- }
19726
- return newText ? null : [];
19727
- }
19728
- function paraTText(para, xml) {
19729
- let text = "";
19730
- for (const t of para.tRanges) {
19731
- if (t.selfClosing) continue;
19732
- const raw = xml.slice(t.contentStart, t.contentEnd);
19733
- if (/[<&]/.test(raw)) return null;
19734
- text += raw;
19735
- }
19736
- return text;
19737
- }
19738
- function paraTextPureT(para, xml) {
19739
- let len = 0;
19740
- for (const t of para.tRanges) {
19741
- if (t.selfClosing) continue;
19742
- len += tContentToText(xml.slice(t.contentStart, t.contentEnd)).length;
19743
- }
19744
- return len === para.text.length;
19745
- }
19746
- function buildRangeSplices(para, xml, start, end, replacement) {
19747
- if (start < 0 || end < start) return null;
19748
- const segs = [];
19749
- let offset = 0;
19750
- for (const t of para.tRanges) {
19751
- if (t.selfClosing) continue;
19752
- const raw = xml.slice(t.contentStart, t.contentEnd);
19753
- if (/[<&]/.test(raw)) return null;
19754
- segs.push({ contentStart: t.contentStart, from: offset, to: offset + raw.length });
19755
- offset += raw.length;
19756
- }
19757
- if (segs.length === 0 || end > offset) return null;
19758
- const escaped = escapeXmlText(replacement);
19759
- if (start === end) {
19760
- for (const seg of segs) {
19761
- if (start >= seg.from && start <= seg.to) {
19762
- const at = seg.contentStart + (start - seg.from);
19763
- return [{ start: at, end: at, replacement: escaped }];
19764
- }
19765
- }
19766
- return null;
19767
- }
19768
- const splices = [];
19769
- let placed = false;
19770
- for (const seg of segs) {
19771
- if (seg.to <= start || seg.from >= end) continue;
19772
- const localStart = Math.max(seg.from, start) - seg.from;
19773
- const localEnd = Math.min(seg.to, end) - seg.from;
19774
- splices.push({
19775
- start: seg.contentStart + localStart,
19776
- end: seg.contentStart + localEnd,
19777
- replacement: placed ? "" : escaped
19778
- });
19779
- placed = true;
19780
- }
19781
- return placed ? splices : null;
19782
- }
19783
- function allLinesegRemovalSplices(xml) {
19784
- const segRe = /<(\w+:)?linesegarray\b[^>]*?(?:\/>|>[\s\S]*?<\/\1linesegarray>)/g;
19785
- const splices = [];
19786
- let m;
19787
- while ((m = segRe.exec(xml)) !== null) {
19788
- splices.push({ start: m.index, end: m.index + m[0].length, replacement: "" });
19789
- }
19790
- return splices;
19791
- }
19792
- function applySplices(xml, splices) {
19793
- const sorted = [...splices].sort((a, b) => a.start - b.start);
19794
- for (let i = 1; i < sorted.length; i++) {
19795
- if (sorted[i].start < sorted[i - 1].end) {
19796
- throw new Error("\uC18C\uC2A4\uB9F5 splice \uBC94\uC704 \uACB9\uCE68 \u2014 \uB0B4\uBD80 \uC624\uB958");
19797
- }
19798
- }
19799
- let result = xml;
19800
- for (let i = sorted.length - 1; i >= 0; i--) {
19801
- const s = sorted[i];
19802
- result = result.slice(0, s.start) + s.replacement + result.slice(s.end);
19803
- }
19804
- return result;
19805
- }
19806
-
19807
- // src/roundtrip/zip-patch.ts
19808
- import { deflateRawSync } from "zlib";
19809
- var EOCD_SIG = 101010256;
19810
- var CD_SIG = 33639248;
19811
- var LOCAL_SIG = 67324752;
19812
- var ZIP64_EOCD_LOC_SIG = 117853008;
19813
- function copyBytes(buf, start, end) {
19814
- return new Uint8Array(buf.subarray(start, end));
19815
- }
19816
- function parseCentralDirectory(buf) {
19817
- const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
19818
- const minEocd = Math.max(0, buf.length - 22 - 65535);
19819
- let eocdOffset = -1;
19820
- for (let i = buf.length - 22; i >= minEocd; i--) {
19821
- if (view.getUint32(i, true) === EOCD_SIG && i + 22 + view.getUint16(i + 20, true) === buf.length) {
19822
- eocdOffset = i;
19823
- break;
19824
- }
19825
- }
19826
- if (eocdOffset < 0) {
19827
- for (let i = buf.length - 22; i >= minEocd; i--) {
19828
- if (view.getUint32(i, true) !== EOCD_SIG) continue;
19829
- if (i + 22 + view.getUint16(i + 20, true) > buf.length) continue;
19830
- const cand = view.getUint32(i + 16, true);
19831
- if (cand < buf.length - 4 && view.getUint32(cand, true) === CD_SIG) {
19832
- eocdOffset = i;
19833
- break;
19834
- }
19835
- }
19836
- }
19837
- if (eocdOffset < 0) throw new KordocError("ZIP EOCD\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
19838
- const totalEntries = view.getUint16(eocdOffset + 10, true);
19839
- const cdSize = view.getUint32(eocdOffset + 12, true);
19840
- const cdOffset = view.getUint32(eocdOffset + 16, true);
19841
- if (cdOffset === 4294967295 || totalEntries === 65535) throw new KordocError("ZIP64\uB294 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
19842
- if (eocdOffset >= 20 && view.getUint32(eocdOffset - 20, true) === ZIP64_EOCD_LOC_SIG) {
19843
- throw new KordocError("ZIP64\uB294 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
19844
- }
19845
- const decoder = new TextDecoder("utf-8");
19846
- const entries = [];
19847
- let pos = cdOffset;
19848
- for (let i = 0; i < totalEntries; i++) {
19849
- if (view.getUint32(pos, true) !== CD_SIG) throw new KordocError("ZIP Central Directory \uC190\uC0C1");
19850
- const flags = view.getUint16(pos + 8, true);
19851
- const method = view.getUint16(pos + 10, true);
19852
- const crc = view.getUint32(pos + 16, true);
19853
- const compSize = view.getUint32(pos + 20, true);
19854
- const uncompSize = view.getUint32(pos + 24, true);
19855
- const nameLen = view.getUint16(pos + 28, true);
19856
- const extraLen = view.getUint16(pos + 30, true);
19857
- const commentLen = view.getUint16(pos + 32, true);
19858
- const localOffset = view.getUint32(pos + 42, true);
19859
- if (compSize === 4294967295 || uncompSize === 4294967295 || localOffset === 4294967295) {
19860
- throw new KordocError("ZIP64\uB294 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
19861
- }
19862
- const name = decoder.decode(buf.subarray(pos + 46, pos + 46 + nameLen));
19863
- const cdEnd = pos + 46 + nameLen + extraLen + commentLen;
19864
- entries.push({ cdStart: pos, cdEnd, name, flags, method, crc, compSize, uncompSize, localOffset });
19865
- pos = cdEnd;
19866
- }
19867
- return { entries, cdOffset, cdSize, eocdOffset };
19868
- }
19869
- var CRC_TABLE = (() => {
19870
- const table = new Uint32Array(256);
19871
- for (let n = 0; n < 256; n++) {
19872
- let c = n;
19873
- for (let k = 0; k < 8; k++) c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
19874
- table[n] = c >>> 0;
19875
- }
19876
- return table;
19877
- })();
19878
- function crc32(data) {
19879
- let crc = 4294967295;
19880
- for (let i = 0; i < data.length; i++) {
19881
- crc = CRC_TABLE[(crc ^ data[i]) & 255] ^ crc >>> 8;
19882
- }
19883
- return (crc ^ 4294967295) >>> 0;
19884
- }
19885
- function patchZipEntries(original, replacements) {
19886
- const { entries, cdOffset, eocdOffset } = parseCentralDirectory(original);
19887
- const view = new DataView(original.buffer, original.byteOffset, original.byteLength);
19888
- for (const name of replacements.keys()) {
19889
- if (!entries.some((e) => e.name === name)) throw new KordocError(`ZIP\uC5D0 \uC5C6\uB294 \uC5D4\uD2B8\uB9AC: ${name}`);
19890
- }
19891
- const byLocal = [...entries].sort((a, b) => a.localOffset - b.localOffset);
19892
- const segments = [];
19893
- const newLocalOffset = /* @__PURE__ */ new Map();
19894
- const newMeta = /* @__PURE__ */ new Map();
19895
- let offset = 0;
19896
- for (let i = 0; i < byLocal.length; i++) {
19897
- const e = byLocal[i];
19898
- const segEnd = i + 1 < byLocal.length ? byLocal[i + 1].localOffset : cdOffset;
19899
- newLocalOffset.set(e, offset);
19900
- const newData = replacements.get(e.name);
19901
- if (newData === void 0) {
19902
- const seg = original.subarray(e.localOffset, segEnd);
19903
- segments.push(seg);
19904
- offset += seg.length;
19905
- continue;
19906
- }
19907
- if (view.getUint32(e.localOffset, true) !== LOCAL_SIG) throw new KordocError("ZIP \uB85C\uCEEC \uD5E4\uB354 \uC2DC\uADF8\uB2C8\uCC98 \uBD88\uC77C\uCE58");
19908
- const nameLen = view.getUint16(e.localOffset + 26, true);
19909
- const extraLen = view.getUint16(e.localOffset + 28, true);
19910
- const headerLen = 30 + nameLen + extraLen;
19911
- const header = copyBytes(original, e.localOffset, e.localOffset + headerLen);
19912
- const hview = new DataView(header.buffer, header.byteOffset, header.byteLength);
19913
- const method = e.method;
19914
- const compData = method === 0 ? newData : new Uint8Array(deflateRawSync(newData));
19915
- const crc = crc32(newData);
19916
- const flags = e.flags & ~8;
19917
- hview.setUint16(6, flags, true);
19918
- hview.setUint32(14, crc, true);
19919
- hview.setUint32(18, compData.length, true);
19920
- hview.setUint32(22, newData.length, true);
19921
- segments.push(header, compData);
19922
- offset += headerLen + compData.length;
19923
- newMeta.set(e, { crc, compSize: compData.length, uncompSize: newData.length, flags });
19924
- }
19925
- const newCdOffset = offset;
19926
- for (const e of entries) {
19927
- const cd = copyBytes(original, e.cdStart, e.cdEnd);
19928
- const cview = new DataView(cd.buffer, cd.byteOffset, cd.byteLength);
19929
- cview.setUint32(42, newLocalOffset.get(e), true);
19930
- const meta = newMeta.get(e);
19931
- if (meta) {
19932
- cview.setUint16(8, meta.flags, true);
19933
- cview.setUint32(16, meta.crc, true);
19934
- cview.setUint32(20, meta.compSize, true);
19935
- cview.setUint32(24, meta.uncompSize, true);
19936
- }
19937
- segments.push(cd);
19938
- offset += cd.length;
19939
- }
19940
- const newCdSize = offset - newCdOffset;
19941
- const eocd = copyBytes(original, eocdOffset);
19942
- const eview = new DataView(eocd.buffer, eocd.byteOffset, eocd.byteLength);
19943
- eview.setUint32(12, newCdSize, true);
19944
- eview.setUint32(16, newCdOffset, true);
19945
- segments.push(eocd);
19946
- offset += eocd.length;
19947
- const result = new Uint8Array(offset);
19948
- let pos = 0;
19949
- for (const seg of segments) {
19950
- result.set(seg, pos);
19951
- pos += seg.length;
19952
- }
19953
- return result;
19954
- }
19955
-
19956
- // src/form/filler-hwpx.ts
19957
- async function fillHwpx(hwpxBuffer, values) {
19336
+ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19958
19337
  const u8 = new Uint8Array(hwpxBuffer);
19959
19338
  const zip = await JSZip5.loadAsync(hwpxBuffer);
19960
19339
  const sectionPaths = Object.keys(zip.files).filter((name) => /[Ss]ection\d+\.xml$/i.test(name)).sort();
@@ -19998,7 +19377,7 @@ async function fillHwpx(hwpxBuffer, values) {
19998
19377
  for (const cell of row) {
19999
19378
  for (const para of cell.paragraphs) {
20000
19379
  const text = matchText(para);
20001
- const result = fillInCellPatterns(text, cursor, matchedLabels);
19380
+ const result = fillInCellPatterns(text, cursor, matchedLabels, blockedLabels);
20002
19381
  if (!result) continue;
20003
19382
  const l = led(para);
20004
19383
  if (l.fullText !== void 0) continue;
@@ -20016,7 +19395,7 @@ async function fillHwpx(hwpxBuffer, values) {
20016
19395
  for (const m of result.matches) {
20017
19396
  l.filledIdx.push(filled.length);
20018
19397
  l.matchKeys.push(m.key);
20019
- filled.push({ label: m.label, value: m.value, row: -1, col: -1 });
19398
+ filled.push({ label: m.label, value: m.value, row: -1, col: -1, key: m.key });
20020
19399
  }
20021
19400
  }
20022
19401
  }
@@ -20032,6 +19411,7 @@ async function fillHwpx(hwpxBuffer, values) {
20032
19411
  if (isKeywordLabel(cellLabelText(valueCell))) continue;
20033
19412
  const normalizedCellLabel = normalizeLabel(labelText);
20034
19413
  if (!normalizedCellLabel) continue;
19414
+ if (blockedLabels?.has(normalizedCellLabel)) continue;
20035
19415
  const matchKey = findMatchingKey(normalizedCellLabel, cursor);
20036
19416
  if (matchKey === void 0) continue;
20037
19417
  if (patternApplied.has(valueCell)) {
@@ -20049,7 +19429,8 @@ async function fillHwpx(hwpxBuffer, values) {
20049
19429
  label: labelText.trim().replace(/[::]\s*$/, ""),
20050
19430
  value: newValue,
20051
19431
  row: rowIdx,
20052
- col: colIdx
19432
+ col: colIdx,
19433
+ key: matchKey
20053
19434
  });
20054
19435
  } else {
20055
19436
  const paras = valueCell.paragraphs;
@@ -20071,7 +19452,8 @@ async function fillHwpx(hwpxBuffer, values) {
20071
19452
  label: labelText.trim().replace(/[::]\s*$/, ""),
20072
19453
  value: newValue,
20073
19454
  row: rowIdx,
20074
- col: colIdx
19455
+ col: colIdx,
19456
+ key: matchKey
20075
19457
  });
20076
19458
  }
20077
19459
  }
@@ -20087,6 +19469,7 @@ async function fillHwpx(hwpxBuffer, values) {
20087
19469
  const dataCells = table.rows[rowIdx];
20088
19470
  for (let colIdx = 0; colIdx < Math.min(headerCells.length, dataCells.length); colIdx++) {
20089
19471
  const headerLabel = normalizeLabel(cellLabelText(headerCells[colIdx]));
19472
+ if (blockedLabels?.has(headerLabel)) continue;
20090
19473
  const matchKey = findMatchingKey(headerLabel, cursor);
20091
19474
  if (matchKey === void 0) continue;
20092
19475
  if (!cursor.isArray(matchKey) && matchedLabels.has(matchKey)) continue;
@@ -20122,7 +19505,9 @@ async function fillHwpx(hwpxBuffer, values) {
20122
19505
  if (existing?.fullText !== void 0) continue;
20123
19506
  const text = matchText(para);
20124
19507
  for (const seg of scanInlineSegments(text)) {
20125
- const matchKey = findMatchingKey(normalizeLabel(seg.label), cursor);
19508
+ const nlabel = normalizeLabel(seg.label);
19509
+ if (blockedLabels?.has(nlabel)) continue;
19510
+ const matchKey = findMatchingKey(nlabel, cursor);
20126
19511
  if (matchKey === void 0) continue;
20127
19512
  const newValue = cursor.consume(matchKey);
20128
19513
  if (newValue === void 0) continue;
@@ -20132,7 +19517,7 @@ async function fillHwpx(hwpxBuffer, values) {
20132
19517
  matchedLabels.add(matchKey);
20133
19518
  l.filledIdx.push(filled.length);
20134
19519
  l.matchKeys.push(matchKey);
20135
- filled.push({ label: seg.label.trim(), value: newValue, row: -1, col: -1 });
19520
+ filled.push({ label: seg.label.trim(), value: newValue, row: -1, col: -1, key: matchKey });
20136
19521
  }
20137
19522
  }
20138
19523
  const splices = [];
@@ -20426,7 +19811,8 @@ function buildPrvText(blocks) {
20426
19811
  let bytes = 0;
20427
19812
  for (const b of blocks) {
20428
19813
  let text = b.text || (b.rows ? b.rows.map((r) => r.join(" ")).join("\n") : "");
20429
- if (b.type === "html_table") text = text.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
19814
+ if (b.type === "code_block" && (b.lang || "").toLowerCase() === "chart") text = "[\uCC28\uD2B8]";
19815
+ else if (b.type === "html_table") text = text.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
20430
19816
  if (!text) continue;
20431
19817
  lines.push(text);
20432
19818
  bytes += text.length * 3;
@@ -20445,7 +19831,7 @@ function findMathDelim(s, from) {
20445
19831
  return i;
20446
19832
  }
20447
19833
  function parseMarkdownToBlocks(md2) {
20448
- const lines = md2.split("\n");
19834
+ const lines = md2.replace(/\r\n?/g, "\n").split("\n");
20449
19835
  const blocks = [];
20450
19836
  let i = 0;
20451
19837
  while (i < lines.length) {
@@ -20493,13 +19879,13 @@ function parseMarkdownToBlocks(md2) {
20493
19879
  continue;
20494
19880
  }
20495
19881
  }
20496
- const fenceMatch = line.match(/^(`{3,}|~{3,})(.*)$/);
19882
+ const fenceMatch = line.match(/^ {0,3}(`{3,}|~{3,})(.*)$/);
20497
19883
  if (fenceMatch) {
20498
19884
  const fence = fenceMatch[1];
20499
19885
  const lang = fenceMatch[2].trim();
20500
19886
  const codeLines = [];
20501
19887
  i++;
20502
- while (i < lines.length && !lines[i].startsWith(fence)) {
19888
+ while (i < lines.length && !lines[i].replace(/^ {0,3}/, "").startsWith(fence)) {
20503
19889
  codeLines.push(lines[i]);
20504
19890
  i++;
20505
19891
  }
@@ -20647,12 +20033,14 @@ function generateContainerXml() {
20647
20033
  </ocf:rootfiles>
20648
20034
  </ocf:container>`;
20649
20035
  }
20650
- function generateManifest() {
20036
+ function generateManifest(chartParts = []) {
20037
+ const chartItems = chartParts.map((p, i) => `
20038
+ <opf:item id="chart${i + 1}" href="${p.name}" media-type="application/xml"/>`).join("");
20651
20039
  return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
20652
20040
  <opf:package xmlns:opf="${NS_OPF}" xmlns:hpf="${NS_HPF}" xmlns:hh="${NS_HEAD}">
20653
20041
  <opf:manifest>
20654
20042
  <opf:item id="header" href="Contents/header.xml" media-type="application/xml"/>
20655
- <opf:item id="section0" href="Contents/section0.xml" media-type="application/xml"/>
20043
+ <opf:item id="section0" href="Contents/section0.xml" media-type="application/xml"/>${chartItems}
20656
20044
  </opf:manifest>
20657
20045
  <opf:spine>
20658
20046
  <opf:itemref idref="header" linear="no"/>
@@ -20833,6 +20221,219 @@ function generateHeaderXml(theme, gongmun, ratioVariants = []) {
20833
20221
  </hh:head>`;
20834
20222
  }
20835
20223
 
20224
+ // src/hwpx/chart-gen.ts
20225
+ var XML_ESC = { "&": "&amp;", "<": "&lt;", ">": "&gt;" };
20226
+ var xmlEscape = (s) => s.replace(/[&<>]/g, (c) => XML_ESC[c]);
20227
+ var CHART_TYPES = {
20228
+ 0: { el: "barChart", dir: "col", grp: "clustered" },
20229
+ 1: { el: "barChart", dir: "col", grp: "stacked", overlap: 100 },
20230
+ 2: { el: "lineChart", grp: "standard", marker: true },
20231
+ 3: { el: "barChart", dir: "bar", grp: "clustered" },
20232
+ 4: { el: "barChart", dir: "bar", grp: "stacked", overlap: 100 },
20233
+ 5: { el: "scatterChart", scatter: true },
20234
+ 6: { el: "pieChart", pie: true },
20235
+ 7: { el: "pieChart", pie: true, explode: true },
20236
+ 8: { el: "doughnutChart", pie: true, hole: 50 },
20237
+ 9: { el: "areaChart", grp: "standard" },
20238
+ 10: { el: "areaChart", grp: "stacked" },
20239
+ 11: { el: "radarChart", radar: true },
20240
+ 12: { el: "bar3DChart", dir: "col", grp: "clustered" },
20241
+ 13: { el: "bar3DChart", dir: "col", grp: "stacked", overlap: 100 },
20242
+ 14: { el: "bar3DChart", dir: "bar", grp: "clustered" },
20243
+ 15: { el: "bar3DChart", dir: "bar", grp: "stacked", overlap: 100 },
20244
+ 16: { el: "pie3DChart", pie: true },
20245
+ 17: { el: "pie3DChart", pie: true, explode: true },
20246
+ 18: { el: "area3DChart", grp: "standard" },
20247
+ 19: { el: "area3DChart", grp: "stacked" }
20248
+ };
20249
+ var CHART_ALIAS = {
20250
+ column: 0,
20251
+ col: 0,
20252
+ \uC138\uB85C\uB9C9\uB300: 0,
20253
+ \uB9C9\uB300: 0,
20254
+ column_stacked: 1,
20255
+ \uC138\uB85C\uB9C9\uB300_\uB204\uC801: 1,
20256
+ line: 2,
20257
+ \uC120: 2,
20258
+ \uAEBE\uC740\uC120: 2,
20259
+ bar: 3,
20260
+ \uAC00\uB85C\uB9C9\uB300: 3,
20261
+ bar_stacked: 4,
20262
+ scatter: 5,
20263
+ \uBD84\uC0B0: 5,
20264
+ pie: 6,
20265
+ \uC6D0: 6,
20266
+ \uD30C\uC774: 6,
20267
+ pie_explode: 7,
20268
+ doughnut: 8,
20269
+ donut: 8,
20270
+ \uB3C4\uB11B: 8,
20271
+ area: 9,
20272
+ \uC601\uC5ED: 9,
20273
+ area_stacked: 10,
20274
+ radar: 11,
20275
+ \uBC29\uC0AC\uD615: 11,
20276
+ bar3d: 12,
20277
+ column3d: 12,
20278
+ pie3d: 16
20279
+ };
20280
+ function chartSpec(t) {
20281
+ if (!t) return CHART_TYPES[0];
20282
+ const key = CHART_ALIAS[t.toLowerCase()] ?? Number(t);
20283
+ return CHART_TYPES[key] ?? CHART_TYPES[0];
20284
+ }
20285
+ var HU_PER_MM = 7200 / 25.4;
20286
+ var RESERVED_KEYS = /* @__PURE__ */ new Set(["type", "cat", "size", "colors", "point_colors", "title"]);
20287
+ function parseChartFence(text) {
20288
+ let type;
20289
+ let cat = null;
20290
+ let widthMm = 32250 / HU_PER_MM;
20291
+ let heightMm = 18750 / HU_PER_MM;
20292
+ let colors = null;
20293
+ let pointColors = null;
20294
+ const series = [];
20295
+ for (const rawLine of text.split("\n")) {
20296
+ const line = rawLine.trim();
20297
+ if (!line || line.startsWith("#")) continue;
20298
+ const colon = line.search(/[::]/);
20299
+ if (colon <= 0) continue;
20300
+ const key = line.slice(0, colon).trim();
20301
+ const value = line.slice(colon + 1).trim();
20302
+ const keyLower = key.toLowerCase();
20303
+ if (keyLower === "type") {
20304
+ type = value;
20305
+ } else if (keyLower === "cat") {
20306
+ cat = value.split(",").map((s) => s.trim()).filter(Boolean);
20307
+ } else if (keyLower === "size") {
20308
+ const m = value.match(/^(\d+(?:\.\d+)?)\s*[x×]\s*(\d+(?:\.\d+)?)$/i);
20309
+ if (m) {
20310
+ const clamp = (n) => Math.min(500, Math.max(10, n));
20311
+ widthMm = clamp(Number(m[1]));
20312
+ heightMm = clamp(Number(m[2]));
20313
+ }
20314
+ } else if (keyLower === "colors") {
20315
+ colors = value.split(",").map((s) => s.trim()).filter(Boolean);
20316
+ } else if (keyLower === "point_colors") {
20317
+ pointColors = value.split(",").map((s) => s.trim()).filter(Boolean);
20318
+ } else if (keyLower === "title") {
20319
+ } else if (!RESERVED_KEYS.has(keyLower)) {
20320
+ const segs = value.replace(/(\d),(?=\d{3}(?:\D|$))/g, "$1").split(",").map((s) => s.trim()).filter(Boolean);
20321
+ if (segs.length === 0) continue;
20322
+ const nums = segs.map(Number);
20323
+ if (nums.every((n) => Number.isFinite(n))) {
20324
+ series.push({ name: key, values: nums });
20325
+ } else {
20326
+ return null;
20327
+ }
20328
+ }
20329
+ }
20330
+ if (series.length === 0) return null;
20331
+ const spec = chartSpec(type);
20332
+ let finalSeries = spec.pie ? [series[0]] : series;
20333
+ finalSeries = finalSeries.map((s) => ({ ...s }));
20334
+ const ptLen = Math.max(cat?.length ?? 0, ...finalSeries.map((s) => s.values.length));
20335
+ const catFinal = Array.from({ length: ptLen }, (_, i) => cat?.[i] ?? `\uD56D\uBAA9 ${i + 1}`);
20336
+ if (!spec.scatter) {
20337
+ finalSeries = finalSeries.map((s) => ({ ...s, values: catFinal.map((_, i) => s.values[i] ?? 0) }));
20338
+ }
20339
+ if (spec.pie) {
20340
+ const slice = colors ?? pointColors;
20341
+ if (slice) finalSeries[0].pointColors = slice;
20342
+ } else {
20343
+ if (colors) finalSeries.forEach((s, i) => {
20344
+ s.color = colors[i % colors.length];
20345
+ });
20346
+ if (pointColors && finalSeries[0]) finalSeries[0].pointColors = pointColors;
20347
+ }
20348
+ return {
20349
+ spec,
20350
+ cat: catFinal,
20351
+ series: finalSeries,
20352
+ widthHu: Math.round(widthMm * HU_PER_MM),
20353
+ heightHu: Math.round(heightMm * HU_PER_MM)
20354
+ };
20355
+ }
20356
+ var colLetter = (i) => String.fromCharCode(66 + i);
20357
+ function strCachePts(vals) {
20358
+ return `<c:ptCount val="${vals.length}"/>` + vals.map((v, i) => `<c:pt idx="${i}"><c:v>${xmlEscape(v)}</c:v></c:pt>`).join("");
20359
+ }
20360
+ function numCachePts(vals) {
20361
+ 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("");
20362
+ }
20363
+ function chartColorFill(color) {
20364
+ if (color == null) return null;
20365
+ const c = color.trim();
20366
+ if (/^accent[1-6]$/i.test(c)) return `<a:solidFill><a:schemeClr val="${c.toLowerCase()}"/></a:solidFill>`;
20367
+ const hex = c.replace(/^#/, "").toUpperCase();
20368
+ if (/^[0-9A-F]{6}$/.test(hex)) return `<a:solidFill><a:srgbClr val="${hex}"/></a:solidFill>`;
20369
+ return null;
20370
+ }
20371
+ function serSpPr(color, stroke) {
20372
+ const f = chartColorFill(color);
20373
+ if (!f) return "<c:spPr/>";
20374
+ 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>`;
20375
+ }
20376
+ function dPtXml(pointColors, pie) {
20377
+ if (!pointColors?.length) return "";
20378
+ return pointColors.map((col, i) => {
20379
+ const f = chartColorFill(col);
20380
+ if (!f) return "";
20381
+ const mid = pie ? '<c:invertIfNegative val="0"/><c:bubble3D val="0"/><c:explosion val="0"/>' : '<c:bubble3D val="0"/>';
20382
+ return `<c:dPt><c:idx val="${i}"/>${mid}<c:spPr>${f}</c:spPr></c:dPt>`;
20383
+ }).join("");
20384
+ }
20385
+ function stdSer(idx, name, cat, values, explode, color, pointColors, stroke, pie) {
20386
+ const cl = colLetter(idx);
20387
+ 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>`;
20388
+ }
20389
+ function scatterSer(idx, name, xvals, yvals) {
20390
+ const cl = colLetter(idx);
20391
+ 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>`;
20392
+ }
20393
+ function catAxXml(id, pos, cross) {
20394
+ 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>`;
20395
+ }
20396
+ function valAxXml(id, pos, cross) {
20397
+ 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>`;
20398
+ }
20399
+ function buildChartSpaceXml(fence) {
20400
+ const { spec, cat, series } = fence;
20401
+ 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"';
20402
+ const ax1 = "111111111";
20403
+ const ax2 = "222222222";
20404
+ let plot;
20405
+ if (spec.scatter) {
20406
+ const n = Math.max(0, ...series.map((s) => s.values.length));
20407
+ const xs = Array.from({ length: n }, (_, i) => {
20408
+ const c = cat[i];
20409
+ const v = Number(c);
20410
+ return c !== void 0 && c !== "" && Number.isFinite(v) ? v : i + 1;
20411
+ });
20412
+ const sers = series.map((s, i) => scatterSer(i, s.name, xs, s.values)).join("");
20413
+ 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);
20414
+ } else if (spec.pie) {
20415
+ const s0 = series[0];
20416
+ 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}>`;
20417
+ } else {
20418
+ const stroke = spec.el === "lineChart" || spec.el === "radarChart" || !!spec.radar;
20419
+ const sers = series.map((s, i) => stdSer(i, s.name, cat, s.values, false, s.color, s.pointColors, stroke, false)).join("");
20420
+ const horiz = spec.dir === "bar";
20421
+ let inner = "";
20422
+ if (spec.dir) inner += `<c:barDir val="${spec.dir}"/>`;
20423
+ if (spec.grp) inner += `<c:grouping val="${spec.grp}"/>`;
20424
+ if (spec.radar) inner += `<c:radarStyle val="standard"/>`;
20425
+ inner += `<c:varyColors val="0"/>${sers}`;
20426
+ if (spec.marker) inner += `<c:marker val="1"/>`;
20427
+ if (spec.el.startsWith("bar")) inner += `<c:gapWidth val="150"/><c:overlap val="${spec.overlap ?? 0}"/>`;
20428
+ inner += `<c:axId val="${ax1}"/><c:axId val="${ax2}"/>`;
20429
+ plot = `<c:${spec.el}>${inner}</c:${spec.el}>` + catAxXml(ax1, horiz ? "l" : "b", ax2) + valAxXml(ax2, horiz ? "b" : "l", ax1);
20430
+ }
20431
+ 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>`;
20432
+ }
20433
+ function buildChartElementXml(partName, widthHu, heightHu, id) {
20434
+ 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>`;
20435
+ }
20436
+
20836
20437
  // src/hwpx/gen-gongmun-fit.ts
20837
20438
  function plainRenderText(text) {
20838
20439
  return parseInlineMarkdown(text).map((s) => s.text).join("");
@@ -20885,18 +20486,18 @@ function precomputeGongmunList(blocks, gongmun) {
20885
20486
  i++;
20886
20487
  continue;
20887
20488
  }
20888
- const passThrough = (t) => t === "table" || t === "html_table" || t === "equation";
20489
+ 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;
20889
20490
  const run = [];
20890
20491
  while (i < blocks.length) {
20891
- const t = blocks[i].type;
20892
- if (t === "list_item") {
20492
+ const b = blocks[i];
20493
+ if (b.type === "list_item") {
20893
20494
  run.push(i);
20894
20495
  i++;
20895
20496
  continue;
20896
20497
  }
20897
- if (passThrough(t)) {
20498
+ if (passThrough(b)) {
20898
20499
  let j = i + 1;
20899
- while (j < blocks.length && passThrough(blocks[j].type)) j++;
20500
+ while (j < blocks.length && passThrough(blocks[j])) j++;
20900
20501
  if (j < blocks.length && blocks[j].type === "list_item") {
20901
20502
  i = j;
20902
20503
  continue;
@@ -21711,7 +21312,7 @@ function generateSecPr(gongmun) {
21711
21312
  } : { top: 8504, bottom: 4252, left: 5670, right: 4252, header: 2835, footer: 2835 };
21712
21313
  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>`;
21713
21314
  }
21714
- function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null, fit = null) {
21315
+ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null, fit = null, chartParts = null) {
21715
21316
  const paraXmls = [];
21716
21317
  let isFirst = true;
21717
21318
  const orderedCounters = {};
@@ -21742,6 +21343,21 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
21742
21343
  break;
21743
21344
  }
21744
21345
  case "code_block": {
21346
+ if (chartParts !== null && (block.lang || "").toLowerCase() === "chart") {
21347
+ const fence = parseChartFence(block.text || "");
21348
+ if (fence) {
21349
+ const partName = `Chart/chart${chartParts.length + 1}.xml`;
21350
+ chartParts.push({ name: partName, xml: buildChartSpaceXml(fence) });
21351
+ const chartEl = buildChartElementXml(partName, fence.widthHu, fence.heightHu, 91e5 + blockIdx);
21352
+ if (isFirst) {
21353
+ const secRun = `<hp:run charPrIDRef="0">${generateSecPr(gongmun)}<hp:t></hp:t></hp:run>`;
21354
+ paraXmls.push(`<hp:p paraPrIDRef="0" styleIDRef="0">${secRun}</hp:p>`);
21355
+ isFirst = false;
21356
+ }
21357
+ xml = `<hp:p paraPrIDRef="${PARA_NORMAL}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_NORMAL}">${chartEl}</hp:run></hp:p>`;
21358
+ break;
21359
+ }
21360
+ }
21745
21361
  const codeLines = (block.text || "").split("\n");
21746
21362
  xml = codeLines.map((line) => generateParagraph(line || " ", PARA_CODE)).join("\n ");
21747
21363
  break;
@@ -21851,13 +21467,15 @@ async function markdownToHwpx(markdown, options) {
21851
21467
  const blocks = parseMarkdownToBlocks(markdown);
21852
21468
  const gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null;
21853
21469
  const fit = gongmun && gongmunList ? computeGongmunFitPlan(blocks, gongmun, gongmunList) : null;
21854
- const sectionXml = blocksToSectionXml(blocks, theme, gongmun, gongmunList, fit);
21470
+ const chartParts = [];
21471
+ const sectionXml = blocksToSectionXml(blocks, theme, gongmun, gongmunList, fit, chartParts);
21855
21472
  const zip = new JSZip6();
21856
21473
  zip.file("mimetype", "application/hwp+zip", { compression: "STORE" });
21857
21474
  zip.file("META-INF/container.xml", generateContainerXml());
21858
- zip.file("Contents/content.hpf", generateManifest());
21475
+ zip.file("Contents/content.hpf", generateManifest(chartParts));
21859
21476
  zip.file("Contents/header.xml", generateHeaderXml(theme, gongmun, fit?.variants ?? []));
21860
21477
  zip.file("Contents/section0.xml", sectionXml);
21478
+ for (const part of chartParts) zip.file(part.name, part.xml);
21861
21479
  zip.file("Preview/PrvText.txt", buildPrvText(blocks));
21862
21480
  return await zip.generateAsync({ type: "arraybuffer" });
21863
21481
  }
@@ -22976,7 +22594,7 @@ async function resolveHeaderEntryName(zip) {
22976
22594
  }
22977
22595
 
22978
22596
  // src/roundtrip/hwp5-patch.ts
22979
- import { deflateRawSync as deflateRawSync2 } from "zlib";
22597
+ import { deflateRawSync } from "zlib";
22980
22598
  import { createRequire as createRequire2 } from "module";
22981
22599
 
22982
22600
  // src/roundtrip/ole-surgeon.ts
@@ -23491,7 +23109,7 @@ async function patchHwp(original, editedMarkdown, options) {
23491
23109
  for (let i = 0; i < scans.length; i++) {
23492
23110
  if (scans[i].repl.size === 0 && scans[i].inserts.size === 0) continue;
23493
23111
  const newStream = serializeRecords(scans[i].records, scans[i].repl, scans[i].inserts);
23494
- const content = compressed ? deflateRawSync2(newStream) : newStream;
23112
+ const content = compressed ? deflateRawSync(newStream) : newStream;
23495
23113
  out = replaceOleStream(out, sectionPaths[i], content);
23496
23114
  }
23497
23115
  data = new Uint8Array(out);
@@ -23503,7 +23121,8 @@ async function patchHwp(original, editedMarkdown, options) {
23503
23121
  if (options?.verify !== false) {
23504
23122
  try {
23505
23123
  const reparsed = parseHwp5Document(Buffer.from(data));
23506
- verification = diffUnitLists(splitMarkdownUnits(reparsed.markdown), editedUnits);
23124
+ const normBr = (u) => ({ ...u, raw: u.raw.replace(/<br\s*\/?\s*>/gi, "\n") });
23125
+ verification = diffUnitLists(splitMarkdownUnits(reparsed.markdown).map(normBr), editedUnits.map(normBr));
23507
23126
  } catch (err) {
23508
23127
  return { success: false, applied, skipped, error: `\uD328\uCE58\uBCF8 \uC7AC\uD30C\uC2F1 \uC2E4\uD328 \u2014 \uD328\uCE58 \uC911\uB2E8: ${msg(err)}` };
23509
23128
  }
@@ -23626,7 +23245,7 @@ function handleModified(orig, edited, ctx) {
23626
23245
  function patchParagraph(block, orig, edited, ctx, skip) {
23627
23246
  const mapping = ctx.paraMap.get(orig.blockIdx);
23628
23247
  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)");
23629
- const restoreBr = (s) => s.replace(/\s*<br\s*\/?\s*>\s*/gi, "\n");
23248
+ const restoreBr = (s) => s.replace(/(?:\s*<br\s*\/?\s*>\s*)+/gi, "\n");
23630
23249
  let newPlain = restoreBr(textUnitToPlain(edited.raw, block));
23631
23250
  if (block.text && block.text.includes("\n") && !newPlain.includes("\n")) {
23632
23251
  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)");
@@ -23652,7 +23271,7 @@ function patchParagraph(block, orig, edited, ctx, skip) {
23652
23271
  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) });
23653
23272
  }
23654
23273
  }
23655
- const origPlain = restoreBr(textUnitToPlain(orig.raw, block));
23274
+ const origPlain = block.text != null ? block.text : restoreBr(textUnitToPlain(orig.raw, block));
23656
23275
  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");
23657
23276
  if (sanitizeText(newPlain) !== newPlain) {
23658
23277
  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");
@@ -24726,7 +24345,7 @@ async function parseHwp(buffer, options) {
24726
24345
  async function parsePdf(buffer, options) {
24727
24346
  let parsePdfDocument;
24728
24347
  try {
24729
- const mod = await import("./parser-76JSTEP3.js");
24348
+ const mod = await import("./parser-B4O7CW5Q.js");
24730
24349
  parsePdfDocument = mod.parsePdfDocument;
24731
24350
  } catch {
24732
24351
  return {
@@ -24827,10 +24446,6 @@ export {
24827
24446
  inferFieldType,
24828
24447
  extractFormSchema,
24829
24448
  fillFormFields,
24830
- scanSectionXml,
24831
- buildParagraphSplices,
24832
- buildRangeSplices,
24833
- applySplices,
24834
24449
  fillHwpx,
24835
24450
  PRESET_ALIAS,
24836
24451
  normalizeGongmunPreset,
@@ -24857,4 +24472,4 @@ export {
24857
24472
  parseHwpml,
24858
24473
  fillForm
24859
24474
  };
24860
- //# sourceMappingURL=chunk-Q3IHI3E6.js.map
24475
+ //# sourceMappingURL=chunk-I6T3DKYK.js.map