kordoc 3.13.0 → 3.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +34 -1
  2. package/dist/{-MRPDPE2X.js → -H7N62NZU.js} +24 -13
  3. package/dist/{chunk-33CIKNL4.js → chunk-5RHRQ7HK.js} +479 -258
  4. package/dist/chunk-5RHRQ7HK.js.map +1 -0
  5. package/dist/{chunk-MEXUFQVC.cjs → chunk-BIP4JAVG.cjs} +5 -5
  6. package/dist/chunk-BIP4JAVG.cjs.map +1 -0
  7. package/dist/chunk-DCZVOIEO.cjs.map +1 -1
  8. package/dist/chunk-FGL7BH4P.js +1019 -0
  9. package/dist/chunk-FGL7BH4P.js.map +1 -0
  10. package/dist/chunk-GS7T56RP.cjs.map +1 -1
  11. package/dist/{chunk-Q6UXVJXI.js → chunk-IC56KHBL.js} +2 -2
  12. package/dist/chunk-JFNWJFKP.js +185 -0
  13. package/dist/chunk-JFNWJFKP.js.map +1 -0
  14. package/dist/{chunk-YXOT7P5B.js → chunk-LYL4IL3E.js} +5 -5
  15. package/dist/{chunk-YXOT7P5B.js.map → chunk-LYL4IL3E.js.map} +1 -1
  16. package/dist/{chunk-O4WFPOFN.js → chunk-Q7EGGW3H.js} +5 -5
  17. package/dist/{chunk-O4WFPOFN.js.map → chunk-Q7EGGW3H.js.map} +1 -1
  18. package/dist/{chunk-TWACKS3K.js → chunk-WD5NUUU6.js} +571 -729
  19. package/dist/chunk-WD5NUUU6.js.map +1 -0
  20. package/dist/cli.js +125 -12
  21. package/dist/cli.js.map +1 -1
  22. package/dist/formula-5NKVS2LR.cjs.map +1 -1
  23. package/dist/index.cjs +1668 -449
  24. package/dist/index.cjs.map +1 -1
  25. package/dist/index.d.cts +144 -6
  26. package/dist/index.d.ts +144 -6
  27. package/dist/index.js +1502 -283
  28. package/dist/index.js.map +1 -1
  29. package/dist/mcp.js +93 -12
  30. package/dist/mcp.js.map +1 -1
  31. package/dist/page-range-P7SDW6LR.cjs.map +1 -1
  32. package/dist/{parser-Z3IL2ESY.js → parser-5G247XYD.js} +54 -6
  33. package/dist/parser-5G247XYD.js.map +1 -0
  34. package/dist/{parser-DZBI3EA2.cjs → parser-6V7F3GET.cjs} +66 -18
  35. package/dist/parser-6V7F3GET.cjs.map +1 -0
  36. package/dist/{parser-XUNGOH76.js → parser-HBHCD7TE.js} +55 -7
  37. package/dist/parser-HBHCD7TE.js.map +1 -0
  38. package/dist/provider-G4C2V2PD.cjs.map +1 -1
  39. package/dist/render-VA4NHROW.js +10 -0
  40. package/dist/seal-UVDRGHEF.js +10 -0
  41. package/dist/seal-UVDRGHEF.js.map +1 -0
  42. package/dist/{watch-G5NFIT5L.js → watch-HIYNOSFD.js} +7 -5
  43. package/dist/{watch-G5NFIT5L.js.map → watch-HIYNOSFD.js.map} +1 -1
  44. package/package.json +4 -3
  45. package/dist/chunk-33CIKNL4.js.map +0 -1
  46. package/dist/chunk-MEXUFQVC.cjs.map +0 -1
  47. package/dist/chunk-TWACKS3K.js.map +0 -1
  48. package/dist/parser-DZBI3EA2.cjs.map +0 -1
  49. package/dist/parser-XUNGOH76.js.map +0 -1
  50. package/dist/parser-Z3IL2ESY.js.map +0 -1
  51. package/dist/render-VZ4OGHZU.js +0 -9
  52. /package/dist/{-MRPDPE2X.js.map → -H7N62NZU.js.map} +0 -0
  53. /package/dist/{chunk-Q6UXVJXI.js.map → chunk-IC56KHBL.js.map} +0 -0
  54. /package/dist/{render-VZ4OGHZU.js.map → render-VA4NHROW.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-LYL4IL3E.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-FGL7BH4P.js";
35
+ import {
36
+ SPACE_EM_FIXED,
37
+ charWidthEm1000,
38
+ fitRatioForFewerLines
39
+ } from "./chunk-5RHRQ7HK.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-33CIKNL4.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-YXOT7P5B.js";
34
- import {
35
- parsePageRange
36
- } from "./chunk-MOL7MDBG.js";
49
+ findChildByLocalName
50
+ } from "./chunk-JFNWJFKP.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-Q6UXVJXI.js";
61
+ } from "./chunk-IC56KHBL.js";
48
62
 
49
63
  // src/index.ts
50
64
  import { readFile } from "fs/promises";
@@ -640,10 +654,22 @@ function findEnclosingBrackets(eqString, startIdx) {
640
654
  }
641
655
  return null;
642
656
  }
657
+ function maskLiteralSpans(eqString) {
658
+ return eqString.replace(/"[^"]*"/g, (m) => "\uFFFF".repeat(m.length)).replace(/\\text\{[^}]*\}/g, (m) => "\uFFFF".repeat(m.length));
659
+ }
660
+ function findKeywordToken(eqString, word, from = 0) {
661
+ const masked = maskLiteralSpans(eqString);
662
+ for (let i = masked.indexOf(word, from); i !== -1; i = masked.indexOf(word, i + 1)) {
663
+ const okL = i === 0 || masked[i - 1] === " ";
664
+ const okR = i + word.length === masked.length || masked[i + word.length] === " ";
665
+ if (okL && okR) return i;
666
+ }
667
+ return -1;
668
+ }
643
669
  function replaceFrac(eqString) {
644
670
  const hmlFrac = "over";
645
671
  while (true) {
646
- const cursor = eqString.indexOf(hmlFrac);
672
+ const cursor = findKeywordToken(eqString, hmlFrac);
647
673
  if (cursor === -1) break;
648
674
  try {
649
675
  const [numStart, numEnd] = findBrackets(eqString, cursor, 0);
@@ -659,12 +685,12 @@ function replaceFrac(eqString) {
659
685
  }
660
686
  function replaceRootOf(eqString) {
661
687
  while (true) {
662
- const rootCursor = eqString.indexOf("root");
688
+ const rootCursor = findKeywordToken(eqString, "root");
663
689
  if (rootCursor === -1) break;
664
690
  try {
665
- const ofCursor = eqString.indexOf("of");
666
- if (ofCursor === -1) return eqString;
667
691
  const elem1 = findBrackets(eqString, rootCursor, 1);
692
+ const ofCursor = findKeywordToken(eqString, "of", elem1[1]);
693
+ if (ofCursor === -1) return eqString;
668
694
  const elem2 = findBrackets(eqString, ofCursor, 1);
669
695
  const e1 = eqString.slice(elem1[0] + 1, elem1[1] - 1);
670
696
  const e2 = eqString.slice(elem2[0] + 1, elem2[1] - 1);
@@ -2082,7 +2108,6 @@ function appendParaText(state, data, resolveControl) {
2082
2108
  break;
2083
2109
  }
2084
2110
  result += "\n";
2085
- if (i + 14 <= data.length) i += 14;
2086
2111
  break;
2087
2112
  }
2088
2113
  case CHAR_PARA:
@@ -17955,6 +17980,7 @@ function collectOmmlRoots(p) {
17955
17980
  const tag = el.localName || el.tagName?.replace(/^[^:]+:/, "") || "";
17956
17981
  if (tag === "oMath" || tag === "oMathPara") {
17957
17982
  out.push(el);
17983
+ } else if (tag === "txbxContent" || tag === "Fallback") {
17958
17984
  } else {
17959
17985
  walk(el);
17960
17986
  }
@@ -18079,6 +18105,13 @@ function parseTable(tbl, styles, numbering, footnotes, rels) {
18079
18105
  for (const tr of trElements) {
18080
18106
  const row = [];
18081
18107
  let col = 0;
18108
+ const trPrEls = getChildElements(tr, "trPr");
18109
+ if (trPrEls.length > 0) {
18110
+ const gridBeforeEls = getChildElements(trPrEls[0], "gridBefore");
18111
+ if (gridBeforeEls.length > 0) {
18112
+ col = parseInt(getAttr(gridBeforeEls[0], "val") ?? "0", 10) || 0;
18113
+ }
18114
+ }
18082
18115
  for (const tc of getChildElements(tr, "tc")) {
18083
18116
  let colSpan = 1;
18084
18117
  let vMerge = null;
@@ -18093,12 +18126,28 @@ function parseTable(tbl, styles, numbering, footnotes, rels) {
18093
18126
  vMerge = getAttr(vMergeEls[0], "val") === "restart" ? "restart" : "continue";
18094
18127
  }
18095
18128
  }
18096
- const text = vMerge === "continue" ? "" : collectCellText(tc, styles, numbering, footnotes, rels, 0).join("\n");
18129
+ const text = collectCellText(tc, styles, numbering, footnotes, rels, 0).join("\n");
18097
18130
  row.push({ col, colSpan, vMerge, text });
18098
18131
  col += colSpan;
18099
18132
  }
18100
18133
  rawRows.push(row);
18101
18134
  }
18135
+ for (let r = 0; r < rawRows.length; r++) {
18136
+ for (const cell of rawRows[r]) {
18137
+ if (cell.vMerge !== "continue" || !cell.text) continue;
18138
+ let start;
18139
+ for (let pr = r - 1; pr >= 0 && !start; pr--) {
18140
+ start = rawRows[pr].find((pc) => pc.col === cell.col && pc.vMerge !== "continue");
18141
+ }
18142
+ if (start) {
18143
+ start.text = start.text ? `${start.text}
18144
+ ${cell.text}` : cell.text;
18145
+ cell.text = "";
18146
+ } else {
18147
+ cell.vMerge = null;
18148
+ }
18149
+ }
18150
+ }
18102
18151
  const cellRows = rawRows.map(
18103
18152
  (row, r) => row.filter((cell) => cell.vMerge !== "continue").map((cell) => {
18104
18153
  let rowSpan = 1;
@@ -18588,6 +18637,81 @@ function countSections(body) {
18588
18637
  }
18589
18638
 
18590
18639
  // src/form/match.ts
18640
+ function parseYMD(v) {
18641
+ const d = v.replace(/\D/g, "");
18642
+ let y, m, day;
18643
+ if (d.length >= 8) {
18644
+ y = d.slice(0, 4);
18645
+ m = d.slice(4, 6);
18646
+ day = d.slice(6, 8);
18647
+ } else if (d.length === 6) {
18648
+ const yy = +d.slice(0, 2);
18649
+ y = String(yy <= 29 ? 2e3 + yy : 1900 + yy);
18650
+ m = d.slice(2, 4);
18651
+ day = d.slice(4, 6);
18652
+ } else return null;
18653
+ return { y, yy: y.slice(2), m, d: day };
18654
+ }
18655
+ function fmtDate(v, style) {
18656
+ const p = parseYMD(v);
18657
+ if (!p) return v;
18658
+ 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));
18659
+ }
18660
+ function maskDigits(v, pattern) {
18661
+ const ds = v.replace(/\D/g, "");
18662
+ let i = 0;
18663
+ return pattern.replace(/#/g, () => ds[i++] ?? "");
18664
+ }
18665
+ function fmtPhone(v, style) {
18666
+ const d = v.replace(/\D/g, "");
18667
+ if (d.length < 9) return v;
18668
+ const a = d.slice(0, 3), b = d.slice(3, -4), c = d.slice(-4);
18669
+ switch (style) {
18670
+ case "digits":
18671
+ return d;
18672
+ case "dot":
18673
+ return `${a}.${b}.${c}`;
18674
+ case "space":
18675
+ return `${a} ${b} ${c}`;
18676
+ case "intl":
18677
+ return `+82-${d.slice(1, 3)}-${b}-${c}`;
18678
+ case "intl-paren":
18679
+ return `82)${d.slice(1, 3)}-${b}-${c}`;
18680
+ default:
18681
+ return `${a}-${b}-${c}`;
18682
+ }
18683
+ }
18684
+ function fmtRRN(v, style) {
18685
+ const d = v.replace(/\D/g, "");
18686
+ if (d.length !== 13) return v;
18687
+ switch (style) {
18688
+ case "digits":
18689
+ return d;
18690
+ case "front":
18691
+ return d.slice(0, 6);
18692
+ case "masked":
18693
+ return `${d.slice(0, 6)}-${d[6]}******`;
18694
+ default:
18695
+ return `${d.slice(0, 6)}-${d.slice(6)}`;
18696
+ }
18697
+ }
18698
+ function formatFillValue(value, format) {
18699
+ if (!format) return value;
18700
+ const ci = format.indexOf(":");
18701
+ const kind = ci >= 0 ? format.slice(0, ci) : format;
18702
+ const style = ci >= 0 ? format.slice(ci + 1) : "";
18703
+ if (kind === "date") return fmtDate(value, style);
18704
+ if (kind === "phone") return fmtPhone(value, style);
18705
+ if (kind === "rrn") return fmtRRN(value, style);
18706
+ if (kind === "mask") return maskDigits(value, style);
18707
+ if (kind === "digits") return value.replace(/\D/g, "");
18708
+ if (kind === "upper") return value.toUpperCase();
18709
+ if (kind === "lower") return value.toLowerCase();
18710
+ if (kind === "nospace") return value.replace(/\s+/g, "");
18711
+ if (format.includes("#")) return maskDigits(value, format);
18712
+ if (/(yyyy|yy|mm|dd)/.test(format)) return fmtDate(value, format);
18713
+ return value;
18714
+ }
18591
18715
  var ValueCursor = class {
18592
18716
  constructor(values) {
18593
18717
  this.values = values;
@@ -18739,11 +18863,32 @@ function padInsertion(text, pos, value) {
18739
18863
  }
18740
18864
  function normalizeValues(values) {
18741
18865
  const map = /* @__PURE__ */ new Map();
18742
- for (const [label, value] of Object.entries(values)) {
18743
- map.set(normalizeLabel(label), value);
18866
+ for (const [label, raw] of Object.entries(values)) {
18867
+ const { value, format } = typeof raw === "object" && !Array.isArray(raw) ? raw : { value: raw, format: void 0 };
18868
+ map.set(normalizeLabel(label), Array.isArray(value) ? value.map((v) => formatFillValue(v, format)) : formatFillValue(value, format));
18744
18869
  }
18745
18870
  return map;
18746
18871
  }
18872
+ async function fillWithUniqueGuard(values, run) {
18873
+ const first = await run(values);
18874
+ const counts = /* @__PURE__ */ new Map();
18875
+ for (const f of first.filled) {
18876
+ if (f.key) counts.set(f.key, (counts.get(f.key) ?? 0) + 1);
18877
+ }
18878
+ const isArrayValue = (normKey) => {
18879
+ for (const [label, raw] of Object.entries(values)) {
18880
+ if (normalizeLabel(label) !== normKey) continue;
18881
+ return Array.isArray(typeof raw === "object" && !Array.isArray(raw) ? raw.value : raw);
18882
+ }
18883
+ return false;
18884
+ };
18885
+ const dup = new Set([...counts].filter(([k, n]) => n >= 2 && !isArrayValue(k)).map(([k]) => k));
18886
+ if (dup.size === 0) return { ...first, rejected: [] };
18887
+ const filtered = Object.fromEntries(Object.entries(values).filter(([label]) => !dup.has(normalizeLabel(label))));
18888
+ const second = await run(filtered);
18889
+ const rejected = Object.keys(values).filter((label) => dup.has(normalizeLabel(label)));
18890
+ return { ...second, rejected };
18891
+ }
18747
18892
  function resolveUnmatched(normalizedValues, matchedLabels, originalValues) {
18748
18893
  return [...normalizedValues.keys()].filter((k) => !matchedLabels.has(k)).map((k) => {
18749
18894
  for (const orig of Object.keys(originalValues)) {
@@ -19013,7 +19158,7 @@ function fillFormFields(blocks, values) {
19013
19158
  cell.text = result.text;
19014
19159
  patternFilledCells.add(cell);
19015
19160
  for (const m of result.matches) {
19016
- filled.push({ label: m.label, value: m.value, row: r, col: c });
19161
+ filled.push({ label: m.label, value: m.value, row: r, col: c, key: m.key });
19017
19162
  }
19018
19163
  }
19019
19164
  }
@@ -19093,7 +19238,8 @@ function fillTable(table, values, filled, matchedLabels, patternFilledCells) {
19093
19238
  label: labelCell.text.trim().replace(/[::]\s*$/, ""),
19094
19239
  value: newValue,
19095
19240
  row: r,
19096
- col: c
19241
+ col: c,
19242
+ key: matchKey
19097
19243
  });
19098
19244
  }
19099
19245
  }
@@ -19122,7 +19268,8 @@ function fillTable(table, values, filled, matchedLabels, patternFilledCells) {
19122
19268
  label: headerCell.text.trim(),
19123
19269
  value: newValue,
19124
19270
  row: r,
19125
- col: c
19271
+ col: c,
19272
+ key: matchKey
19126
19273
  });
19127
19274
  }
19128
19275
  }
@@ -19139,7 +19286,7 @@ function fillInlineFields(text, values, filled, matchedLabels) {
19139
19286
  const newValue = values.consume(matchKey);
19140
19287
  if (newValue === void 0) continue;
19141
19288
  matchedLabels.add(matchKey);
19142
- filled.push({ label: seg.label.trim(), value: newValue, row: -1, col: -1 });
19289
+ filled.push({ label: seg.label.trim(), value: newValue, row: -1, col: -1, key: matchKey });
19143
19290
  out += text.slice(pos, seg.valueStart);
19144
19291
  out += seg.valueStart === seg.valueEnd ? padInsertion(text, seg.valueStart, newValue) : newValue;
19145
19292
  pos = seg.valueEnd;
@@ -19150,677 +19297,6 @@ function fillInlineFields(text, values, filled, matchedLabels) {
19150
19297
 
19151
19298
  // src/form/filler-hwpx.ts
19152
19299
  import JSZip5 from "jszip";
19153
-
19154
- // src/roundtrip/source-map.ts
19155
- function escapeXmlText(text) {
19156
- return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
19157
- }
19158
- function decodeXmlEntities(text) {
19159
- return text.replace(/&(lt|gt|amp|quot|apos|#x?[0-9a-fA-F]+);/g, (m, ent) => {
19160
- switch (ent) {
19161
- case "lt":
19162
- return "<";
19163
- case "gt":
19164
- return ">";
19165
- case "amp":
19166
- return "&";
19167
- case "quot":
19168
- return '"';
19169
- case "apos":
19170
- return "'";
19171
- }
19172
- try {
19173
- const code = ent[1] === "x" || ent[1] === "X" ? parseInt(ent.slice(2), 16) : parseInt(ent.slice(1), 10);
19174
- if (!isNaN(code) && code >= 0 && code <= 1114111) return String.fromCodePoint(code);
19175
- } catch {
19176
- }
19177
- return m;
19178
- });
19179
- }
19180
- function tContentToText(raw) {
19181
- return decodeXmlEntities(
19182
- raw.replace(/<\/?(?:[A-Za-z0-9_]+:)?(?:tab|fwSpace|hwSpace|br|lineBreak)(?:\s[^>]*)?\/?>/g, " ").replace(/<[^>]*>/g, "")
19183
- );
19184
- }
19185
- var TAG_RE = /<!--[\s\S]*?-->|<!\[CDATA\[[\s\S]*?\]\]>|<\?[\s\S]*?\?>|<!(?:"[^"]*"|'[^']*'|[^>"'])*>|<\/([^\s>]+)\s*>|<([^\s/>!?]+)((?:"[^"]*"|'[^']*'|[^>"'])*?)(\/?)>/g;
19186
- var T_BARRIER = /* @__PURE__ */ new Set([
19187
- "tbl",
19188
- "ctrl",
19189
- "caption",
19190
- "pic",
19191
- "shape",
19192
- "drawingObject",
19193
- "drawText",
19194
- "shapeComment",
19195
- "memogroup",
19196
- "memo",
19197
- "hiddenComment",
19198
- "equation",
19199
- "parameters",
19200
- "subList",
19201
- "p"
19202
- ]);
19203
- var PARA_CONTAINER = /* @__PURE__ */ new Set([
19204
- "tc",
19205
- "ctrl",
19206
- "caption",
19207
- "drawText",
19208
- "pic",
19209
- "shape",
19210
- "drawingObject",
19211
- "memogroup",
19212
- "memo",
19213
- "hiddenComment",
19214
- "footNote",
19215
- "endNote",
19216
- "fn",
19217
- "en"
19218
- // 각주/미주 — 파서는 호스트 블록 footnoteText로만 흡수
19219
- ]);
19220
- var TABLE_BARRIER = /* @__PURE__ */ new Set([
19221
- "tbl",
19222
- "ctrl",
19223
- "caption",
19224
- "memogroup",
19225
- "memo",
19226
- "hiddenComment"
19227
- ]);
19228
- function localOf(qname) {
19229
- const i = qname.indexOf(":");
19230
- return i >= 0 ? qname.slice(i + 1) : qname;
19231
- }
19232
- function prefixOf(qname) {
19233
- const i = qname.indexOf(":");
19234
- return i >= 0 ? qname.slice(0, i) : "";
19235
- }
19236
- function scanSectionXml(xml, sectionIndex) {
19237
- const stack = [];
19238
- const bodyParagraphs = [];
19239
- const tables = [];
19240
- const headerTexts = [];
19241
- const footerTexts = [];
19242
- const excludedParagraphs = [];
19243
- const orphanTables = [];
19244
- const paraStack = [];
19245
- const tableStack = [];
19246
- const rowStack = [];
19247
- const trStartStack = [];
19248
- const cellStack = [];
19249
- let pendingT = null;
19250
- const ctrlSubStack = [];
19251
- const classifyPara = () => {
19252
- let sawDrawText = false;
19253
- for (let i = stack.length - 1; i >= 0; i--) {
19254
- const l = stack[i].local;
19255
- if (l === "tc") return { kind: "cell", inTextbox: sawDrawText };
19256
- if (l === "drawText") {
19257
- sawDrawText = true;
19258
- continue;
19259
- }
19260
- if (PARA_CONTAINER.has(l)) return { kind: "excluded", inTextbox: sawDrawText };
19261
- }
19262
- return sawDrawText ? { kind: "draw", inTextbox: true } : { kind: "body", inTextbox: false };
19263
- };
19264
- const owningPara = () => {
19265
- if (paraStack.length === 0) return null;
19266
- for (let i = stack.length - 1; i >= 0; i--) {
19267
- const l = stack[i].local;
19268
- if (l === "p") return paraStack[paraStack.length - 1];
19269
- if (T_BARRIER.has(l)) return null;
19270
- }
19271
- return null;
19272
- };
19273
- const isTableTopLevel = () => {
19274
- for (let i = stack.length - 1; i >= 0; i--) {
19275
- if (TABLE_BARRIER.has(stack[i].local)) return false;
19276
- }
19277
- return true;
19278
- };
19279
- const currentCtrlSub = () => ctrlSubStack.length > 0 ? ctrlSubStack[ctrlSubStack.length - 1] : null;
19280
- TAG_RE.lastIndex = 0;
19281
- let m;
19282
- while ((m = TAG_RE.exec(xml)) !== null) {
19283
- const [full, closeName, openName, , selfClose] = m;
19284
- if (closeName === void 0 && openName === void 0) continue;
19285
- if (closeName !== void 0) {
19286
- const local2 = localOf(closeName);
19287
- if (local2 === "t" && pendingT) {
19288
- const { para, contentStart: contentStart2 } = pendingT;
19289
- para.tRanges.push({ contentStart: contentStart2, contentEnd: m.index });
19290
- para.text += tContentToText(xml.slice(contentStart2, m.index));
19291
- pendingT = null;
19292
- }
19293
- for (let i = stack.length - 1; i >= 0; i--) {
19294
- if (stack[i].local === local2) {
19295
- stack.length = i;
19296
- break;
19297
- }
19298
- }
19299
- if (local2 === "p") {
19300
- const para = paraStack.pop();
19301
- if (para && para.kind === "excluded") {
19302
- const sub = currentCtrlSub();
19303
- if (sub && para.text.trim()) sub.texts.push(para.text);
19304
- }
19305
- } else if (local2 === "tc") {
19306
- const cell = cellStack.pop();
19307
- const row = rowStack[rowStack.length - 1];
19308
- if (cell && row) row.push(cell);
19309
- } else if (local2 === "tr") {
19310
- const row = rowStack[rowStack.length - 1];
19311
- const table = tableStack[tableStack.length - 1];
19312
- if (row && table && row.length > 0) {
19313
- table.rows.push(row);
19314
- const trStart = trStartStack[trStartStack.length - 1];
19315
- if (trStart >= 0) table.rowRanges.push({ start: trStart, end: m.index + full.length });
19316
- }
19317
- if (rowStack.length > 0) rowStack[rowStack.length - 1] = [];
19318
- if (trStartStack.length > 0) trStartStack[trStartStack.length - 1] = -1;
19319
- } else if (local2 === "tbl") {
19320
- const table = tableStack.pop();
19321
- rowStack.pop();
19322
- trStartStack.pop();
19323
- if (table) {
19324
- finalizeTable(table);
19325
- if (!table.topLevel) {
19326
- const cell = cellStack[cellStack.length - 1];
19327
- if (cell) cell.tables.push(table);
19328
- else orphanTables.push(table);
19329
- }
19330
- }
19331
- } else if (local2 === "header" || local2 === "footer") {
19332
- const sub = ctrlSubStack[ctrlSubStack.length - 1];
19333
- if (sub) {
19334
- ctrlSubStack.pop();
19335
- const joined = sub.texts.join("\n").trim();
19336
- if (joined) (sub.kind === "header" ? headerTexts : footerTexts).push(joined);
19337
- }
19338
- }
19339
- continue;
19340
- }
19341
- const qname = openName;
19342
- const local = localOf(qname);
19343
- const attrsRaw = m[3] || "";
19344
- const isSelfClose = selfClose === "/";
19345
- const contentStart = m.index + full.length;
19346
- if (isSelfClose) {
19347
- if (local === "t") {
19348
- const para = owningPara();
19349
- if (para) para.tRanges.push({ contentStart: m.index, contentEnd: m.index + full.length, selfClosing: true, prefix: prefixOf(qname) });
19350
- } else if (local === "tab" || local === "fwSpace" || local === "hwSpace" || local === "br" || local === "lineBreak") {
19351
- if (!pendingT) {
19352
- const para = owningPara();
19353
- if (para) para.text += " ";
19354
- }
19355
- } else if (local === "run" || local === "r") {
19356
- const para = owningPara();
19357
- if (para && !para.selfCloseRun) para.selfCloseRun = { start: m.index, end: m.index + full.length };
19358
- } else if (local === "cellAddr") {
19359
- const cell = cellStack[cellStack.length - 1];
19360
- if (cell && insideCurrentTable(stack, tableStack)) {
19361
- const ca = parseInt(getAttr2(attrsRaw, "colAddr") || "", 10);
19362
- const ra = parseInt(getAttr2(attrsRaw, "rowAddr") || "", 10);
19363
- if (!isNaN(ca)) cell.colAddr = ca;
19364
- if (!isNaN(ra)) cell.rowAddr = ra;
19365
- cell.addrTagRange = { start: m.index, end: m.index + full.length };
19366
- }
19367
- } else if (local === "cellSpan") {
19368
- const cell = cellStack[cellStack.length - 1];
19369
- if (cell && insideCurrentTable(stack, tableStack)) {
19370
- const cs = parseInt(getAttr2(attrsRaw, "colSpan") || "1", 10);
19371
- const rs = parseInt(getAttr2(attrsRaw, "rowSpan") || "1", 10);
19372
- cell.colSpan = isNaN(cs) || cs < 1 ? 1 : cs;
19373
- cell.rowSpan = isNaN(rs) || rs < 1 ? 1 : rs;
19374
- }
19375
- }
19376
- continue;
19377
- }
19378
- if (local === "t") {
19379
- const para = owningPara();
19380
- if (para) pendingT = { para, contentStart };
19381
- stack.push({ local, qname, contentStart });
19382
- continue;
19383
- }
19384
- stack.push({ local, qname, contentStart });
19385
- if (local === "p") {
19386
- const para = {
19387
- sectionIndex,
19388
- kind: "excluded",
19389
- // 분류는 push 직후 스택 기준 (자기 자신 제외)
19390
- start: m.index,
19391
- tRanges: [],
19392
- text: ""
19393
- };
19394
- stack.pop();
19395
- const cls = classifyPara();
19396
- para.kind = cls.kind;
19397
- if (cls.inTextbox) para.inTextbox = true;
19398
- stack.push({ local, qname, contentStart });
19399
- paraStack.push(para);
19400
- if (para.kind === "body" || para.kind === "draw") bodyParagraphs.push(para);
19401
- else if (para.kind === "cell") {
19402
- const cell = cellStack[cellStack.length - 1];
19403
- if (cell) cell.paragraphs.push(para);
19404
- } else if (para.kind === "excluded") {
19405
- excludedParagraphs.push(para);
19406
- }
19407
- } else if (local === "run" || local === "r") {
19408
- const para = owningPara();
19409
- if (para && para.runPrefix === void 0) para.runPrefix = prefixOf(qname);
19410
- } else if (local === "tbl") {
19411
- const table = {
19412
- sectionIndex,
19413
- start: m.index,
19414
- topLevel: false,
19415
- rows: [],
19416
- rowRanges: [],
19417
- cellByAnchor: /* @__PURE__ */ new Map()
19418
- };
19419
- stack.pop();
19420
- table.topLevel = isTableTopLevel();
19421
- stack.push({ local, qname, contentStart });
19422
- tableStack.push(table);
19423
- rowStack.push([]);
19424
- trStartStack.push(-1);
19425
- if (table.topLevel) tables.push(table);
19426
- } else if (local === "tr") {
19427
- if (rowStack.length > 0) rowStack[rowStack.length - 1] = [];
19428
- if (trStartStack.length > 0) trStartStack[trStartStack.length - 1] = m.index;
19429
- } else if (local === "tc") {
19430
- cellStack.push({ colSpan: 1, rowSpan: 1, paragraphs: [], tables: [] });
19431
- } else if (local === "cellAddr" || local === "cellSpan") {
19432
- const cell = cellStack[cellStack.length - 1];
19433
- if (cell && insideCurrentTable(stack, tableStack)) {
19434
- if (local === "cellAddr") {
19435
- const ca = parseInt(getAttr2(attrsRaw, "colAddr") || "", 10);
19436
- const ra = parseInt(getAttr2(attrsRaw, "rowAddr") || "", 10);
19437
- if (!isNaN(ca)) cell.colAddr = ca;
19438
- if (!isNaN(ra)) cell.rowAddr = ra;
19439
- cell.addrTagRange = { start: m.index, end: contentStart };
19440
- } else {
19441
- const cs = parseInt(getAttr2(attrsRaw, "colSpan") || "1", 10);
19442
- const rs = parseInt(getAttr2(attrsRaw, "rowSpan") || "1", 10);
19443
- cell.colSpan = isNaN(cs) || cs < 1 ? 1 : cs;
19444
- cell.rowSpan = isNaN(rs) || rs < 1 ? 1 : rs;
19445
- }
19446
- }
19447
- } else if (local === "header" || local === "footer") {
19448
- if (stack.some((f) => f.local === "ctrl")) {
19449
- ctrlSubStack.push({ kind: local, texts: [] });
19450
- }
19451
- } else if (local === "tab" || local === "fwSpace" || local === "hwSpace" || local === "br" || local === "lineBreak") {
19452
- const para = owningPara();
19453
- if (para) para.text += " ";
19454
- }
19455
- }
19456
- for (const para of bodyParagraphs) fillRunInsertPos(para, xml);
19457
- for (const para of excludedParagraphs) fillRunInsertPos(para, xml);
19458
- const fillTableInsertPos = (table, depth = 0) => {
19459
- if (depth > 16) return;
19460
- for (const row of table.rows) {
19461
- for (const cell of row) {
19462
- for (const para of cell.paragraphs) fillRunInsertPos(para, xml);
19463
- for (const nested of cell.tables) fillTableInsertPos(nested, depth + 1);
19464
- }
19465
- }
19466
- };
19467
- for (const table of tables) fillTableInsertPos(table);
19468
- for (const table of orphanTables) fillTableInsertPos(table);
19469
- return { sectionIndex, xml, bodyParagraphs, tables, headerTexts, footerTexts, excludedParagraphs, orphanTables };
19470
- }
19471
- function getAttr2(attrsRaw, name) {
19472
- const re = new RegExp(`(?:^|\\s)${name}\\s*=\\s*(?:"([^"]*)"|'([^']*)')`);
19473
- const m = attrsRaw.match(re);
19474
- return m ? m[1] ?? m[2] : void 0;
19475
- }
19476
- function insideCurrentTable(stack, tableStack) {
19477
- if (tableStack.length === 0) return false;
19478
- for (let i = stack.length - 1; i >= 0; i--) {
19479
- const l = stack[i].local;
19480
- if (l === "tc") return true;
19481
- if (l === "tbl") return false;
19482
- }
19483
- return false;
19484
- }
19485
- function fillRunInsertPos(para, xml) {
19486
- if (para.tRanges.length > 0) return;
19487
- const pEnd = findElementEnd(xml, para.start);
19488
- if (pEnd < 0) return;
19489
- const slice = xml.slice(para.start, pEnd);
19490
- const runOpen = slice.match(/<((?:[A-Za-z0-9_]+:)?run)(?:\s(?:"[^"]*"|'[^']*'|[^>"'])*?)?(\/?)>/);
19491
- if (!runOpen || runOpen.index === void 0) return;
19492
- if (runOpen[2] === "/") return;
19493
- const qname = runOpen[1];
19494
- const closeIdx = slice.indexOf(`</${qname}>`, runOpen.index);
19495
- if (closeIdx < 0) return;
19496
- para.runInsertPos = para.start + closeIdx;
19497
- para.runPrefix = prefixOf(qname);
19498
- }
19499
- function findElementEnd(xml, start) {
19500
- const open = xml.slice(start).match(/^<([^\s/>!?]+)/);
19501
- if (!open) return -1;
19502
- const qname = open[1];
19503
- const re = new RegExp(`<${qname}(?=[\\s/>])(?:"[^"]*"|'[^']*'|[^>"'])*?(/?)>|</${qname}\\s*>`, "g");
19504
- re.lastIndex = start;
19505
- let depth = 0;
19506
- let mm;
19507
- while ((mm = re.exec(xml)) !== null) {
19508
- if (mm[0].startsWith("</")) {
19509
- depth--;
19510
- if (depth === 0) return mm.index + mm[0].length;
19511
- } else if (mm[1] !== "/") {
19512
- depth++;
19513
- }
19514
- }
19515
- return -1;
19516
- }
19517
- function finalizeTable(table) {
19518
- const hasAddr = table.rows.some((row) => row.some((c) => c.colAddr !== void 0 && c.rowAddr !== void 0));
19519
- if (hasAddr) {
19520
- for (const row of table.rows) {
19521
- for (const cell of row) {
19522
- if (cell.rowAddr !== void 0 && cell.colAddr !== void 0) {
19523
- table.cellByAnchor.set(`${cell.rowAddr},${cell.colAddr}`, cell);
19524
- }
19525
- }
19526
- }
19527
- return;
19528
- }
19529
- const numRows = table.rows.length;
19530
- const occupied = Array.from({ length: numRows }, () => []);
19531
- for (let rowIdx = 0; rowIdx < numRows; rowIdx++) {
19532
- let colIdx = 0;
19533
- for (const cell of table.rows[rowIdx]) {
19534
- while (occupied[rowIdx][colIdx]) colIdx++;
19535
- cell.rowAddr = rowIdx;
19536
- cell.colAddr = colIdx;
19537
- table.cellByAnchor.set(`${rowIdx},${colIdx}`, cell);
19538
- for (let r = rowIdx; r < Math.min(rowIdx + cell.rowSpan, numRows); r++) {
19539
- for (let c = colIdx; c < colIdx + cell.colSpan; c++) {
19540
- occupied[r][c] = true;
19541
- }
19542
- }
19543
- colIdx += cell.colSpan;
19544
- }
19545
- }
19546
- }
19547
- function buildParagraphSplices(para, newText, xml) {
19548
- if (newText && xml) {
19549
- const orig = paraTText(para, xml);
19550
- if (orig && orig.trim() !== "") {
19551
- const lead = orig.match(/^\s*/)[0];
19552
- const trail = orig.match(/\s*$/)[0];
19553
- if ((lead || trail) && newText.trim() !== "") {
19554
- newText = lead + newText.replace(/^\s+|\s+$/g, "") + trail;
19555
- }
19556
- }
19557
- }
19558
- const escaped = escapeXmlText(newText);
19559
- if (para.tRanges.length > 0) {
19560
- const splices = [];
19561
- const first = para.tRanges[0];
19562
- if (first.selfClosing) {
19563
- const prefix = first.prefix ? first.prefix + ":" : "";
19564
- splices.push({ start: first.contentStart, end: first.contentEnd, replacement: `<${prefix}t>${escaped}</${prefix}t>` });
19565
- } else {
19566
- splices.push({ start: first.contentStart, end: first.contentEnd, replacement: escaped });
19567
- }
19568
- for (let i = 1; i < para.tRanges.length; i++) {
19569
- const r = para.tRanges[i];
19570
- if (!r.selfClosing && r.contentStart < r.contentEnd) {
19571
- splices.push({ start: r.contentStart, end: r.contentEnd, replacement: "" });
19572
- }
19573
- }
19574
- return splices;
19575
- }
19576
- if (para.runInsertPos !== void 0) {
19577
- if (!newText) return [];
19578
- const prefix = para.runPrefix ? para.runPrefix + ":" : "";
19579
- return [{ start: para.runInsertPos, end: para.runInsertPos, replacement: `<${prefix}t>${escaped}</${prefix}t>` }];
19580
- }
19581
- if (para.selfCloseRun && xml) {
19582
- if (!newText) return [];
19583
- const { start, end } = para.selfCloseRun;
19584
- const tag = xml.slice(start, end);
19585
- const qm = tag.match(/^<([^\s/>]+)/);
19586
- if (!qm || !tag.endsWith("/>")) return null;
19587
- const qname = qm[1];
19588
- const colon = qname.indexOf(":");
19589
- const prefix = colon >= 0 ? qname.slice(0, colon) + ":" : "";
19590
- const opened = tag.slice(0, tag.length - 2).trimEnd() + ">";
19591
- return [{ start, end, replacement: `${opened}<${prefix}t>${escaped}</${prefix}t></${qname}>` }];
19592
- }
19593
- return newText ? null : [];
19594
- }
19595
- function paraTText(para, xml) {
19596
- let text = "";
19597
- for (const t of para.tRanges) {
19598
- if (t.selfClosing) continue;
19599
- const raw = xml.slice(t.contentStart, t.contentEnd);
19600
- if (/[<&]/.test(raw)) return null;
19601
- text += raw;
19602
- }
19603
- return text;
19604
- }
19605
- function paraTextPureT(para, xml) {
19606
- let len = 0;
19607
- for (const t of para.tRanges) {
19608
- if (t.selfClosing) continue;
19609
- len += tContentToText(xml.slice(t.contentStart, t.contentEnd)).length;
19610
- }
19611
- return len === para.text.length;
19612
- }
19613
- function buildRangeSplices(para, xml, start, end, replacement) {
19614
- if (start < 0 || end < start) return null;
19615
- const segs = [];
19616
- let offset = 0;
19617
- for (const t of para.tRanges) {
19618
- if (t.selfClosing) continue;
19619
- const raw = xml.slice(t.contentStart, t.contentEnd);
19620
- if (/[<&]/.test(raw)) return null;
19621
- segs.push({ contentStart: t.contentStart, from: offset, to: offset + raw.length });
19622
- offset += raw.length;
19623
- }
19624
- if (segs.length === 0 || end > offset) return null;
19625
- const escaped = escapeXmlText(replacement);
19626
- if (start === end) {
19627
- for (const seg of segs) {
19628
- if (start >= seg.from && start <= seg.to) {
19629
- const at = seg.contentStart + (start - seg.from);
19630
- return [{ start: at, end: at, replacement: escaped }];
19631
- }
19632
- }
19633
- return null;
19634
- }
19635
- const splices = [];
19636
- let placed = false;
19637
- for (const seg of segs) {
19638
- if (seg.to <= start || seg.from >= end) continue;
19639
- const localStart = Math.max(seg.from, start) - seg.from;
19640
- const localEnd = Math.min(seg.to, end) - seg.from;
19641
- splices.push({
19642
- start: seg.contentStart + localStart,
19643
- end: seg.contentStart + localEnd,
19644
- replacement: placed ? "" : escaped
19645
- });
19646
- placed = true;
19647
- }
19648
- return placed ? splices : null;
19649
- }
19650
- function allLinesegRemovalSplices(xml) {
19651
- const segRe = /<(\w+:)?linesegarray\b[^>]*?(?:\/>|>[\s\S]*?<\/\1linesegarray>)/g;
19652
- const splices = [];
19653
- let m;
19654
- while ((m = segRe.exec(xml)) !== null) {
19655
- splices.push({ start: m.index, end: m.index + m[0].length, replacement: "" });
19656
- }
19657
- return splices;
19658
- }
19659
- function applySplices(xml, splices) {
19660
- const sorted = [...splices].sort((a, b) => a.start - b.start);
19661
- for (let i = 1; i < sorted.length; i++) {
19662
- if (sorted[i].start < sorted[i - 1].end) {
19663
- throw new Error("\uC18C\uC2A4\uB9F5 splice \uBC94\uC704 \uACB9\uCE68 \u2014 \uB0B4\uBD80 \uC624\uB958");
19664
- }
19665
- }
19666
- let result = xml;
19667
- for (let i = sorted.length - 1; i >= 0; i--) {
19668
- const s = sorted[i];
19669
- result = result.slice(0, s.start) + s.replacement + result.slice(s.end);
19670
- }
19671
- return result;
19672
- }
19673
-
19674
- // src/roundtrip/zip-patch.ts
19675
- import { deflateRawSync } from "zlib";
19676
- var EOCD_SIG = 101010256;
19677
- var CD_SIG = 33639248;
19678
- var LOCAL_SIG = 67324752;
19679
- var ZIP64_EOCD_LOC_SIG = 117853008;
19680
- function copyBytes(buf, start, end) {
19681
- return new Uint8Array(buf.subarray(start, end));
19682
- }
19683
- function parseCentralDirectory(buf) {
19684
- const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
19685
- const minEocd = Math.max(0, buf.length - 22 - 65535);
19686
- let eocdOffset = -1;
19687
- for (let i = buf.length - 22; i >= minEocd; i--) {
19688
- if (view.getUint32(i, true) === EOCD_SIG && i + 22 + view.getUint16(i + 20, true) === buf.length) {
19689
- eocdOffset = i;
19690
- break;
19691
- }
19692
- }
19693
- if (eocdOffset < 0) {
19694
- for (let i = buf.length - 22; i >= minEocd; i--) {
19695
- if (view.getUint32(i, true) !== EOCD_SIG) continue;
19696
- if (i + 22 + view.getUint16(i + 20, true) > buf.length) continue;
19697
- const cand = view.getUint32(i + 16, true);
19698
- if (cand < buf.length - 4 && view.getUint32(cand, true) === CD_SIG) {
19699
- eocdOffset = i;
19700
- break;
19701
- }
19702
- }
19703
- }
19704
- if (eocdOffset < 0) throw new KordocError("ZIP EOCD\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
19705
- const totalEntries = view.getUint16(eocdOffset + 10, true);
19706
- const cdSize = view.getUint32(eocdOffset + 12, true);
19707
- const cdOffset = view.getUint32(eocdOffset + 16, true);
19708
- if (cdOffset === 4294967295 || totalEntries === 65535) throw new KordocError("ZIP64\uB294 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
19709
- if (eocdOffset >= 20 && view.getUint32(eocdOffset - 20, true) === ZIP64_EOCD_LOC_SIG) {
19710
- throw new KordocError("ZIP64\uB294 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
19711
- }
19712
- const decoder = new TextDecoder("utf-8");
19713
- const entries = [];
19714
- let pos = cdOffset;
19715
- for (let i = 0; i < totalEntries; i++) {
19716
- if (view.getUint32(pos, true) !== CD_SIG) throw new KordocError("ZIP Central Directory \uC190\uC0C1");
19717
- const flags = view.getUint16(pos + 8, true);
19718
- const method = view.getUint16(pos + 10, true);
19719
- const crc = view.getUint32(pos + 16, true);
19720
- const compSize = view.getUint32(pos + 20, true);
19721
- const uncompSize = view.getUint32(pos + 24, true);
19722
- const nameLen = view.getUint16(pos + 28, true);
19723
- const extraLen = view.getUint16(pos + 30, true);
19724
- const commentLen = view.getUint16(pos + 32, true);
19725
- const localOffset = view.getUint32(pos + 42, true);
19726
- if (compSize === 4294967295 || uncompSize === 4294967295 || localOffset === 4294967295) {
19727
- throw new KordocError("ZIP64\uB294 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
19728
- }
19729
- const name = decoder.decode(buf.subarray(pos + 46, pos + 46 + nameLen));
19730
- const cdEnd = pos + 46 + nameLen + extraLen + commentLen;
19731
- entries.push({ cdStart: pos, cdEnd, name, flags, method, crc, compSize, uncompSize, localOffset });
19732
- pos = cdEnd;
19733
- }
19734
- return { entries, cdOffset, cdSize, eocdOffset };
19735
- }
19736
- var CRC_TABLE = (() => {
19737
- const table = new Uint32Array(256);
19738
- for (let n = 0; n < 256; n++) {
19739
- let c = n;
19740
- for (let k = 0; k < 8; k++) c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
19741
- table[n] = c >>> 0;
19742
- }
19743
- return table;
19744
- })();
19745
- function crc32(data) {
19746
- let crc = 4294967295;
19747
- for (let i = 0; i < data.length; i++) {
19748
- crc = CRC_TABLE[(crc ^ data[i]) & 255] ^ crc >>> 8;
19749
- }
19750
- return (crc ^ 4294967295) >>> 0;
19751
- }
19752
- function patchZipEntries(original, replacements) {
19753
- const { entries, cdOffset, eocdOffset } = parseCentralDirectory(original);
19754
- const view = new DataView(original.buffer, original.byteOffset, original.byteLength);
19755
- for (const name of replacements.keys()) {
19756
- if (!entries.some((e) => e.name === name)) throw new KordocError(`ZIP\uC5D0 \uC5C6\uB294 \uC5D4\uD2B8\uB9AC: ${name}`);
19757
- }
19758
- const byLocal = [...entries].sort((a, b) => a.localOffset - b.localOffset);
19759
- const segments = [];
19760
- const newLocalOffset = /* @__PURE__ */ new Map();
19761
- const newMeta = /* @__PURE__ */ new Map();
19762
- let offset = 0;
19763
- for (let i = 0; i < byLocal.length; i++) {
19764
- const e = byLocal[i];
19765
- const segEnd = i + 1 < byLocal.length ? byLocal[i + 1].localOffset : cdOffset;
19766
- newLocalOffset.set(e, offset);
19767
- const newData = replacements.get(e.name);
19768
- if (newData === void 0) {
19769
- const seg = original.subarray(e.localOffset, segEnd);
19770
- segments.push(seg);
19771
- offset += seg.length;
19772
- continue;
19773
- }
19774
- if (view.getUint32(e.localOffset, true) !== LOCAL_SIG) throw new KordocError("ZIP \uB85C\uCEEC \uD5E4\uB354 \uC2DC\uADF8\uB2C8\uCC98 \uBD88\uC77C\uCE58");
19775
- const nameLen = view.getUint16(e.localOffset + 26, true);
19776
- const extraLen = view.getUint16(e.localOffset + 28, true);
19777
- const headerLen = 30 + nameLen + extraLen;
19778
- const header = copyBytes(original, e.localOffset, e.localOffset + headerLen);
19779
- const hview = new DataView(header.buffer, header.byteOffset, header.byteLength);
19780
- const method = e.method;
19781
- const compData = method === 0 ? newData : new Uint8Array(deflateRawSync(newData));
19782
- const crc = crc32(newData);
19783
- const flags = e.flags & ~8;
19784
- hview.setUint16(6, flags, true);
19785
- hview.setUint32(14, crc, true);
19786
- hview.setUint32(18, compData.length, true);
19787
- hview.setUint32(22, newData.length, true);
19788
- segments.push(header, compData);
19789
- offset += headerLen + compData.length;
19790
- newMeta.set(e, { crc, compSize: compData.length, uncompSize: newData.length, flags });
19791
- }
19792
- const newCdOffset = offset;
19793
- for (const e of entries) {
19794
- const cd = copyBytes(original, e.cdStart, e.cdEnd);
19795
- const cview = new DataView(cd.buffer, cd.byteOffset, cd.byteLength);
19796
- cview.setUint32(42, newLocalOffset.get(e), true);
19797
- const meta = newMeta.get(e);
19798
- if (meta) {
19799
- cview.setUint16(8, meta.flags, true);
19800
- cview.setUint32(16, meta.crc, true);
19801
- cview.setUint32(20, meta.compSize, true);
19802
- cview.setUint32(24, meta.uncompSize, true);
19803
- }
19804
- segments.push(cd);
19805
- offset += cd.length;
19806
- }
19807
- const newCdSize = offset - newCdOffset;
19808
- const eocd = copyBytes(original, eocdOffset);
19809
- const eview = new DataView(eocd.buffer, eocd.byteOffset, eocd.byteLength);
19810
- eview.setUint32(12, newCdSize, true);
19811
- eview.setUint32(16, newCdOffset, true);
19812
- segments.push(eocd);
19813
- offset += eocd.length;
19814
- const result = new Uint8Array(offset);
19815
- let pos = 0;
19816
- for (const seg of segments) {
19817
- result.set(seg, pos);
19818
- pos += seg.length;
19819
- }
19820
- return result;
19821
- }
19822
-
19823
- // src/form/filler-hwpx.ts
19824
19300
  async function fillHwpx(hwpxBuffer, values) {
19825
19301
  const u8 = new Uint8Array(hwpxBuffer);
19826
19302
  const zip = await JSZip5.loadAsync(hwpxBuffer);
@@ -19976,7 +19452,8 @@ async function fillHwpx(hwpxBuffer, values) {
19976
19452
  label: cellLabelText(headerCells[colIdx]).trim(),
19977
19453
  value: newValue,
19978
19454
  row: rowIdx,
19979
- col: colIdx
19455
+ col: colIdx,
19456
+ key: matchKey
19980
19457
  });
19981
19458
  }
19982
19459
  }
@@ -20513,12 +19990,14 @@ function generateContainerXml() {
20513
19990
  </ocf:rootfiles>
20514
19991
  </ocf:container>`;
20515
19992
  }
20516
- function generateManifest() {
19993
+ function generateManifest(chartParts = []) {
19994
+ const chartItems = chartParts.map((p, i) => `
19995
+ <opf:item id="chart${i + 1}" href="${p.name}" media-type="application/xml"/>`).join("");
20517
19996
  return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
20518
19997
  <opf:package xmlns:opf="${NS_OPF}" xmlns:hpf="${NS_HPF}" xmlns:hh="${NS_HEAD}">
20519
19998
  <opf:manifest>
20520
19999
  <opf:item id="header" href="Contents/header.xml" media-type="application/xml"/>
20521
- <opf:item id="section0" href="Contents/section0.xml" media-type="application/xml"/>
20000
+ <opf:item id="section0" href="Contents/section0.xml" media-type="application/xml"/>${chartItems}
20522
20001
  </opf:manifest>
20523
20002
  <opf:spine>
20524
20003
  <opf:itemref idref="header" linear="no"/>
@@ -21487,6 +20966,9 @@ function readCommand(input, idx, depth) {
21487
20966
  const body = readGroupOrToken(input, name.next, depth);
21488
20967
  return { value: `${ACCENT_COMMANDS[command]}{${body.value}}`, next: body.next };
21489
20968
  }
20969
+ if (command === ",") return { value: "`", next: name.next };
20970
+ if (command === ";" || command === ":") return { value: "~", next: name.next };
20971
+ if (command === "!") return { value: "", next: name.next };
21490
20972
  if (command === "mathrm" || command === "text") {
21491
20973
  const start = skipSpaces(input, name.next);
21492
20974
  if (input[start] === "{") {
@@ -21562,6 +21044,210 @@ function generateEquationParagraph(input, zOrder = 0) {
21562
21044
  return `<hp:p paraPrIDRef="${PARA_NORMAL}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_NORMAL}">${generateEquationXml(script, zOrder)}</hp:run></hp:p>`;
21563
21045
  }
21564
21046
 
21047
+ // src/hwpx/chart-gen.ts
21048
+ var XML_ESC = { "&": "&amp;", "<": "&lt;", ">": "&gt;" };
21049
+ var xmlEscape = (s) => s.replace(/[&<>]/g, (c) => XML_ESC[c]);
21050
+ var CHART_TYPES = {
21051
+ 0: { el: "barChart", dir: "col", grp: "clustered" },
21052
+ 1: { el: "barChart", dir: "col", grp: "stacked", overlap: 100 },
21053
+ 2: { el: "lineChart", grp: "standard", marker: true },
21054
+ 3: { el: "barChart", dir: "bar", grp: "clustered" },
21055
+ 4: { el: "barChart", dir: "bar", grp: "stacked", overlap: 100 },
21056
+ 5: { el: "scatterChart", scatter: true },
21057
+ 6: { el: "pieChart", pie: true },
21058
+ 7: { el: "pieChart", pie: true, explode: true },
21059
+ 8: { el: "doughnutChart", pie: true, hole: 50 },
21060
+ 9: { el: "areaChart", grp: "standard" },
21061
+ 10: { el: "areaChart", grp: "stacked" },
21062
+ 11: { el: "radarChart", radar: true },
21063
+ 12: { el: "bar3DChart", dir: "col", grp: "clustered" },
21064
+ 13: { el: "bar3DChart", dir: "col", grp: "stacked", overlap: 100 },
21065
+ 14: { el: "bar3DChart", dir: "bar", grp: "clustered" },
21066
+ 15: { el: "bar3DChart", dir: "bar", grp: "stacked", overlap: 100 },
21067
+ 16: { el: "pie3DChart", pie: true },
21068
+ 17: { el: "pie3DChart", pie: true, explode: true },
21069
+ 18: { el: "area3DChart", grp: "standard" },
21070
+ 19: { el: "area3DChart", grp: "stacked" }
21071
+ };
21072
+ var CHART_ALIAS = {
21073
+ column: 0,
21074
+ col: 0,
21075
+ \uC138\uB85C\uB9C9\uB300: 0,
21076
+ \uB9C9\uB300: 0,
21077
+ column_stacked: 1,
21078
+ \uC138\uB85C\uB9C9\uB300_\uB204\uC801: 1,
21079
+ line: 2,
21080
+ \uC120: 2,
21081
+ \uAEBE\uC740\uC120: 2,
21082
+ bar: 3,
21083
+ \uAC00\uB85C\uB9C9\uB300: 3,
21084
+ bar_stacked: 4,
21085
+ scatter: 5,
21086
+ \uBD84\uC0B0: 5,
21087
+ pie: 6,
21088
+ \uC6D0: 6,
21089
+ \uD30C\uC774: 6,
21090
+ pie_explode: 7,
21091
+ doughnut: 8,
21092
+ donut: 8,
21093
+ \uB3C4\uB11B: 8,
21094
+ area: 9,
21095
+ \uC601\uC5ED: 9,
21096
+ area_stacked: 10,
21097
+ radar: 11,
21098
+ \uBC29\uC0AC\uD615: 11,
21099
+ bar3d: 12,
21100
+ column3d: 12,
21101
+ pie3d: 16
21102
+ };
21103
+ function chartSpec(t) {
21104
+ if (!t) return CHART_TYPES[0];
21105
+ const key = CHART_ALIAS[t.toLowerCase()] ?? Number(t);
21106
+ return CHART_TYPES[key] ?? CHART_TYPES[0];
21107
+ }
21108
+ var HU_PER_MM = 7200 / 25.4;
21109
+ var RESERVED_KEYS = /* @__PURE__ */ new Set(["type", "cat", "size", "colors", "point_colors", "title"]);
21110
+ function parseChartFence(text) {
21111
+ let type;
21112
+ let cat = null;
21113
+ let widthMm = 32250 / HU_PER_MM;
21114
+ let heightMm = 18750 / HU_PER_MM;
21115
+ let colors = null;
21116
+ let pointColors = null;
21117
+ const series = [];
21118
+ for (const rawLine of text.split("\n")) {
21119
+ const line = rawLine.trim();
21120
+ if (!line || line.startsWith("#")) continue;
21121
+ const colon = line.search(/[::]/);
21122
+ if (colon <= 0) continue;
21123
+ const key = line.slice(0, colon).trim();
21124
+ const value = line.slice(colon + 1).trim();
21125
+ const keyLower = key.toLowerCase();
21126
+ if (keyLower === "type") {
21127
+ type = value;
21128
+ } else if (keyLower === "cat") {
21129
+ cat = value.split(",").map((s) => s.trim()).filter(Boolean);
21130
+ } else if (keyLower === "size") {
21131
+ const m = value.match(/^(\d+(?:\.\d+)?)\s*[x×]\s*(\d+(?:\.\d+)?)$/i);
21132
+ if (m) {
21133
+ widthMm = Number(m[1]);
21134
+ heightMm = Number(m[2]);
21135
+ }
21136
+ } else if (keyLower === "colors") {
21137
+ colors = value.split(",").map((s) => s.trim()).filter(Boolean);
21138
+ } else if (keyLower === "point_colors") {
21139
+ pointColors = value.split(",").map((s) => s.trim()).filter(Boolean);
21140
+ } else if (keyLower === "title") {
21141
+ } else if (!RESERVED_KEYS.has(keyLower)) {
21142
+ const nums = value.split(",").map((s) => Number(s.trim()));
21143
+ if (nums.length > 0 && nums.every((n) => Number.isFinite(n))) {
21144
+ series.push({ name: key, values: nums });
21145
+ }
21146
+ }
21147
+ }
21148
+ if (series.length === 0) return null;
21149
+ const spec = chartSpec(type);
21150
+ const catFinal = cat ?? series[0].values.map((_, i) => `\uD56D\uBAA9 ${i + 1}`);
21151
+ let finalSeries = spec.pie ? [series[0]] : series;
21152
+ finalSeries = finalSeries.map((s) => ({ ...s }));
21153
+ if (spec.pie) {
21154
+ const slice = colors ?? pointColors;
21155
+ if (slice) finalSeries[0].pointColors = slice;
21156
+ } else {
21157
+ if (colors) finalSeries.forEach((s, i) => {
21158
+ s.color = colors[i % colors.length];
21159
+ });
21160
+ if (pointColors && finalSeries[0]) finalSeries[0].pointColors = pointColors;
21161
+ }
21162
+ return {
21163
+ spec,
21164
+ cat: catFinal,
21165
+ series: finalSeries,
21166
+ widthHu: Math.round(widthMm * HU_PER_MM),
21167
+ heightHu: Math.round(heightMm * HU_PER_MM)
21168
+ };
21169
+ }
21170
+ var colLetter = (i) => String.fromCharCode(66 + i);
21171
+ function strCachePts(vals) {
21172
+ return `<c:ptCount val="${vals.length}"/>` + vals.map((v, i) => `<c:pt idx="${i}"><c:v>${xmlEscape(v)}</c:v></c:pt>`).join("");
21173
+ }
21174
+ function numCachePts(vals) {
21175
+ 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("");
21176
+ }
21177
+ function chartColorFill(color) {
21178
+ if (color == null) return null;
21179
+ const c = color.trim();
21180
+ if (/^accent[1-6]$/i.test(c)) return `<a:solidFill><a:schemeClr val="${c.toLowerCase()}"/></a:solidFill>`;
21181
+ const hex = c.replace(/^#/, "").toUpperCase();
21182
+ if (/^[0-9A-F]{6}$/.test(hex)) return `<a:solidFill><a:srgbClr val="${hex}"/></a:solidFill>`;
21183
+ return null;
21184
+ }
21185
+ function serSpPr(color, stroke) {
21186
+ const f = chartColorFill(color);
21187
+ if (!f) return "<c:spPr/>";
21188
+ 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>`;
21189
+ }
21190
+ function dPtXml(pointColors, pie) {
21191
+ if (!pointColors?.length) return "";
21192
+ return pointColors.map((col, i) => {
21193
+ const f = chartColorFill(col);
21194
+ if (!f) return "";
21195
+ const mid = pie ? '<c:invertIfNegative val="0"/><c:bubble3D val="0"/><c:explosion val="0"/>' : '<c:bubble3D val="0"/>';
21196
+ return `<c:dPt><c:idx val="${i}"/>${mid}<c:spPr>${f}</c:spPr></c:dPt>`;
21197
+ }).join("");
21198
+ }
21199
+ function stdSer(idx, name, cat, values, explode, color, pointColors, stroke, pie) {
21200
+ const cl = colLetter(idx);
21201
+ 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>`;
21202
+ }
21203
+ function scatterSer(idx, name, xvals, yvals) {
21204
+ const cl = colLetter(idx);
21205
+ 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>`;
21206
+ }
21207
+ function catAxXml(id, pos, cross) {
21208
+ 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>`;
21209
+ }
21210
+ function valAxXml(id, pos, cross) {
21211
+ 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>`;
21212
+ }
21213
+ function buildChartSpaceXml(fence) {
21214
+ const { spec, cat, series } = fence;
21215
+ 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"';
21216
+ const ax1 = "111111111";
21217
+ const ax2 = "222222222";
21218
+ let plot;
21219
+ if (spec.scatter) {
21220
+ const n = Math.max(0, ...series.map((s) => s.values.length));
21221
+ const xs = Array.from({ length: n }, (_, i) => {
21222
+ const c = cat[i];
21223
+ const v = Number(c);
21224
+ return c !== void 0 && c !== "" && Number.isFinite(v) ? v : i + 1;
21225
+ });
21226
+ const sers = series.map((s, i) => scatterSer(i, s.name, xs, s.values)).join("");
21227
+ 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);
21228
+ } else if (spec.pie) {
21229
+ const s0 = series[0];
21230
+ 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}>`;
21231
+ } else {
21232
+ const stroke = spec.el === "lineChart" || spec.el === "radarChart" || !!spec.radar;
21233
+ const sers = series.map((s, i) => stdSer(i, s.name, cat, s.values, false, s.color, s.pointColors, stroke, false)).join("");
21234
+ const horiz = spec.dir === "bar";
21235
+ let inner = "";
21236
+ if (spec.dir) inner += `<c:barDir val="${spec.dir}"/>`;
21237
+ if (spec.grp) inner += `<c:grouping val="${spec.grp}"/>`;
21238
+ if (spec.radar) inner += `<c:radarStyle val="standard"/>`;
21239
+ inner += `<c:varyColors val="0"/>${sers}`;
21240
+ if (spec.marker) inner += `<c:marker val="1"/>`;
21241
+ if (spec.el.startsWith("bar")) inner += `<c:gapWidth val="150"/><c:overlap val="${spec.overlap ?? 0}"/>`;
21242
+ inner += `<c:axId val="${ax1}"/><c:axId val="${ax2}"/>`;
21243
+ plot = `<c:${spec.el}>${inner}</c:${spec.el}>` + catAxXml(ax1, horiz ? "l" : "b", ax2) + valAxXml(ax2, horiz ? "b" : "l", ax1);
21244
+ }
21245
+ 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>`;
21246
+ }
21247
+ function buildChartElementXml(partName, widthHu, heightHu, id) {
21248
+ 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>`;
21249
+ }
21250
+
21565
21251
  // src/hwpx/gen-section.ts
21566
21252
  function generateSecPr(gongmun) {
21567
21253
  const m = gongmun ? {
@@ -21574,7 +21260,7 @@ function generateSecPr(gongmun) {
21574
21260
  } : { top: 8504, bottom: 4252, left: 5670, right: 4252, header: 2835, footer: 2835 };
21575
21261
  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>`;
21576
21262
  }
21577
- function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null, fit = null) {
21263
+ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null, fit = null, chartParts = null) {
21578
21264
  const paraXmls = [];
21579
21265
  let isFirst = true;
21580
21266
  const orderedCounters = {};
@@ -21605,6 +21291,21 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
21605
21291
  break;
21606
21292
  }
21607
21293
  case "code_block": {
21294
+ if (chartParts !== null && (block.lang || "").toLowerCase() === "chart") {
21295
+ const fence = parseChartFence(block.text || "");
21296
+ if (fence) {
21297
+ const partName = `Chart/chart${chartParts.length + 1}.xml`;
21298
+ chartParts.push({ name: partName, xml: buildChartSpaceXml(fence) });
21299
+ const chartEl = buildChartElementXml(partName, fence.widthHu, fence.heightHu, 91e5 + blockIdx);
21300
+ if (isFirst) {
21301
+ const secRun = `<hp:run charPrIDRef="0">${generateSecPr(gongmun)}<hp:t></hp:t></hp:run>`;
21302
+ paraXmls.push(`<hp:p paraPrIDRef="0" styleIDRef="0">${secRun}</hp:p>`);
21303
+ isFirst = false;
21304
+ }
21305
+ xml = `<hp:p paraPrIDRef="${PARA_NORMAL}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_NORMAL}">${chartEl}</hp:run></hp:p>`;
21306
+ break;
21307
+ }
21308
+ }
21608
21309
  const codeLines = (block.text || "").split("\n");
21609
21310
  xml = codeLines.map((line) => generateParagraph(line || " ", PARA_CODE)).join("\n ");
21610
21311
  break;
@@ -21714,13 +21415,15 @@ async function markdownToHwpx(markdown, options) {
21714
21415
  const blocks = parseMarkdownToBlocks(markdown);
21715
21416
  const gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null;
21716
21417
  const fit = gongmun && gongmunList ? computeGongmunFitPlan(blocks, gongmun, gongmunList) : null;
21717
- const sectionXml = blocksToSectionXml(blocks, theme, gongmun, gongmunList, fit);
21418
+ const chartParts = [];
21419
+ const sectionXml = blocksToSectionXml(blocks, theme, gongmun, gongmunList, fit, chartParts);
21718
21420
  const zip = new JSZip6();
21719
21421
  zip.file("mimetype", "application/hwp+zip", { compression: "STORE" });
21720
21422
  zip.file("META-INF/container.xml", generateContainerXml());
21721
- zip.file("Contents/content.hpf", generateManifest());
21423
+ zip.file("Contents/content.hpf", generateManifest(chartParts));
21722
21424
  zip.file("Contents/header.xml", generateHeaderXml(theme, gongmun, fit?.variants ?? []));
21723
21425
  zip.file("Contents/section0.xml", sectionXml);
21426
+ for (const part of chartParts) zip.file(part.name, part.xml);
21724
21427
  zip.file("Preview/PrvText.txt", buildPrvText(blocks));
21725
21428
  return await zip.generateAsync({ type: "arraybuffer" });
21726
21429
  }
@@ -22839,7 +22542,7 @@ async function resolveHeaderEntryName(zip) {
22839
22542
  }
22840
22543
 
22841
22544
  // src/roundtrip/hwp5-patch.ts
22842
- import { deflateRawSync as deflateRawSync2 } from "zlib";
22545
+ import { deflateRawSync } from "zlib";
22843
22546
  import { createRequire as createRequire2 } from "module";
22844
22547
 
22845
22548
  // src/roundtrip/ole-surgeon.ts
@@ -23354,7 +23057,7 @@ async function patchHwp(original, editedMarkdown, options) {
23354
23057
  for (let i = 0; i < scans.length; i++) {
23355
23058
  if (scans[i].repl.size === 0 && scans[i].inserts.size === 0) continue;
23356
23059
  const newStream = serializeRecords(scans[i].records, scans[i].repl, scans[i].inserts);
23357
- const content = compressed ? deflateRawSync2(newStream) : newStream;
23060
+ const content = compressed ? deflateRawSync(newStream) : newStream;
23358
23061
  out = replaceOleStream(out, sectionPaths[i], content);
23359
23062
  }
23360
23063
  data = new Uint8Array(out);
@@ -23489,10 +23192,11 @@ function handleModified(orig, edited, ctx) {
23489
23192
  function patchParagraph(block, orig, edited, ctx, skip) {
23490
23193
  const mapping = ctx.paraMap.get(orig.blockIdx);
23491
23194
  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)");
23492
- if (block.text && block.text.includes("\n")) {
23493
- return skip("\uBB38\uB2E8 \uB0B4 \uAC15\uC81C \uC904\uBC14\uAFC8 \uD3EC\uD568 \u2014 \uC218\uC815 \uC2DC \uC904\uBC14\uAFC8 \uBCF4\uC874 \uBD88\uAC00\uB85C \uBBF8\uC9C0\uC6D0 (v1)");
23195
+ const restoreBr = (s) => s.replace(/\s*<br\s*\/?\s*>\s*/gi, "\n");
23196
+ let newPlain = restoreBr(textUnitToPlain(edited.raw, block));
23197
+ if (block.text && block.text.includes("\n") && !newPlain.includes("\n")) {
23198
+ 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)");
23494
23199
  }
23495
- let newPlain = textUnitToPlain(edited.raw, block);
23496
23200
  if (block.footnoteText) {
23497
23201
  const noteMatch = newPlain.match(/\s*\(주: ([\s\S]*)\)$/);
23498
23202
  if (noteMatch) {
@@ -23514,7 +23218,7 @@ function patchParagraph(block, orig, edited, ctx, skip) {
23514
23218
  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) });
23515
23219
  }
23516
23220
  }
23517
- const origPlain = textUnitToPlain(orig.raw, block);
23221
+ const origPlain = restoreBr(textUnitToPlain(orig.raw, block));
23518
23222
  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");
23519
23223
  if (sanitizeText(newPlain) !== newPlain) {
23520
23224
  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");
@@ -23542,6 +23246,28 @@ function patchGfmCells(scanTable, orig, edited, ctx, skip) {
23542
23246
  }
23543
23247
  const beforeParts = origRows[r][c].split(/<br\s*\/?>/i);
23544
23248
  const afterParts = editedRows[r][c].split(/<br\s*\/?>/i);
23249
+ if (cell.paras.length === 1) {
23250
+ const beforeEach = beforeParts.map(gfmCellToPlain);
23251
+ const afterEach = afterParts.map(gfmCellToPlain);
23252
+ if (beforeEach.some((p) => p === null) || afterEach.some((p) => p === null)) {
23253
+ cellSkip("\uC11C\uC2DD/\uB9C1\uD06C/\uC774\uBBF8\uC9C0 \uD3EC\uD568 \uC140 \uC218\uC815\uC740 \uBBF8\uC9C0\uC6D0 (v1)");
23254
+ continue;
23255
+ }
23256
+ const before = beforeEach.join("\n");
23257
+ const after = afterEach.join("\n");
23258
+ if (before === after) continue;
23259
+ const para = cell.paras[0];
23260
+ if (normForMatch(para.rawText) !== normForMatch(before)) {
23261
+ cellSkip("\uC140 \uD14D\uC2A4\uD2B8 \uBD88\uC77C\uCE58 \u2014 \uC18C\uC2A4\uB9F5 \uC2E0\uB8B0 \uBD88\uAC00");
23262
+ continue;
23263
+ }
23264
+ if (afterEach.some((l) => sanitizeText(l) !== l)) {
23265
+ cellSkip("\uACF5\uBC31 \uC815\uADDC\uD654 \uBD88\uC548\uC815 \uD14D\uC2A4\uD2B8 \u2014 \uBBF8\uC9C0\uC6D0");
23266
+ continue;
23267
+ }
23268
+ applied += stageParaPatch(ctx.scans[para.sectionIndex], para, after, cellSkip);
23269
+ continue;
23270
+ }
23545
23271
  if (beforeParts.length !== cell.paras.length || afterParts.length !== cell.paras.length) {
23546
23272
  cellSkip("\uC140 \uBB38\uB2E8 \uC218 \uBCC0\uACBD \u2014 \uBBF8\uC9C0\uC6D0 (\uBB38\uB2E8 \uCD94\uAC00/\uC0AD\uC81C)");
23547
23273
  continue;
@@ -23686,13 +23412,13 @@ function applyCellEdit5(table, scanTable, gridR, gridC, newLines, ctx, before, a
23686
23412
  const assigned = [];
23687
23413
  for (let i = 0; i < targets.length; i++) {
23688
23414
  if (i < newLines.length) {
23689
- assigned.push(i === targets.length - 1 && newLines.length > targets.length ? newLines.slice(i).join(" ") : newLines[i]);
23415
+ assigned.push(i === targets.length - 1 && newLines.length > targets.length ? newLines.slice(i).join("\n") : newLines[i]);
23690
23416
  } else {
23691
23417
  assigned.push("");
23692
23418
  }
23693
23419
  }
23694
23420
  if (newLines.length > targets.length) {
23695
- ctx.skipped.push({ reason: "\uC140 \uB0B4 \uC904 \uCD94\uAC00\uB294 \uBB38\uB2E8 \uC0DD\uC131 \uBBF8\uC9C0\uC6D0 \u2014 \uB9C8\uC9C0\uB9C9 \uBB38\uB2E8\uC5D0 \uBCD1\uD569 \uC801\uC6A9", after: summarize(after), partial: true });
23421
+ ctx.skipped.push({ reason: "\uC140 \uB0B4 \uCD94\uAC00 \uC904\uC744 \uB9C8\uC9C0\uB9C9 \uBB38\uB2E8\uC5D0 \uAC15\uC81C \uC904\uBC14\uAFC8\uC73C\uB85C \uBCD1\uD569(\uBB38\uB2E8 \uC0DD\uC131 \uB300\uC2E0)", after: summarize(after), partial: true });
23696
23422
  } else if (newLines.length < nonEmpty.length && nonEmpty.length > 1) {
23697
23423
  ctx.skipped.push({ reason: "\uC140 \uB0B4 \uC904 \uC0AD\uC81C\uB294 \uBB38\uB2E8 \uC81C\uAC70 \uBBF8\uC9C0\uC6D0 \u2014 \uBE48 \uBB38\uB2E8 \uC794\uC874(\uBDF0\uC5B4\uC5D0 \uBE48 \uC904 \uD45C\uC2DC \uAC00\uB2A5)", before: summarize(before), after: summarize(after), partial: true });
23698
23424
  }
@@ -23750,8 +23476,7 @@ function splitParaText(data) {
23750
23476
  i += 16;
23751
23477
  toks.push({ start, end: i, units: 1, plain: false, visible: false });
23752
23478
  } else {
23753
- if (i + 14 <= data.length) i += 14;
23754
- toks.push({ start, end: i, units: 1, plain: false, visible: true });
23479
+ toks.push({ start, end: i, units: 1, plain: true, visible: true });
23755
23480
  }
23756
23481
  break;
23757
23482
  default: {
@@ -23814,13 +23539,31 @@ function rebuildCharShape(csData, coreStartUnit) {
23814
23539
  });
23815
23540
  return { buf, count: kept.length };
23816
23541
  }
23542
+ function synthesizeLineSegs(lineSegData, newRaw, startUnits) {
23543
+ if (lineSegData.length < 36) return null;
23544
+ const seg0 = lineSegData.subarray(0, 36);
23545
+ const vPos0 = seg0.readInt32LE(4);
23546
+ const pitch = seg0.readInt32LE(8) + seg0.readInt32LE(20);
23547
+ if (pitch <= 0) return null;
23548
+ const lines = newRaw.split("\n");
23549
+ const segs = [];
23550
+ let pos = startUnits;
23551
+ for (let k = 0; k < lines.length; k++) {
23552
+ const s = Buffer.from(seg0);
23553
+ s.writeUInt32LE((k === 0 ? 0 : pos) >>> 0, 0);
23554
+ s.writeInt32LE(vPos0 + k * pitch, 4);
23555
+ segs.push(s);
23556
+ pos += lines[k].length + 1;
23557
+ }
23558
+ return { buf: Buffer.concat(segs), count: lines.length };
23559
+ }
23817
23560
  function stageParaPatch(scan, para, newPlain, skip) {
23818
23561
  if (!scan.safe) return skip("\uC139\uC158 \uB808\uCF54\uB4DC \uC7AC\uC9C1\uB82C\uD654 \uBD88\uC77C\uCE58 \u2014 \uC548\uC804\uC744 \uC704\uD574 \uC774 \uC139\uC158\uC740 \uBBF8\uC9C0\uC6D0");
23819
23562
  if (para.textIdx === -2) return skip("\uBCF5\uC218 PARA_TEXT \uB808\uCF54\uB4DC \uBB38\uB2E8 \u2014 \uBBF8\uC9C0\uC6D0 (v1)");
23820
23563
  if (para.rangeTagCount > 0) return skip("\uBC94\uC704 \uD0DC\uADF8(\uD615\uAD11\uD39C/\uAD50\uC815\uBD80\uD638) \uBB38\uB2E8 \u2014 \uBBF8\uC9C0\uC6D0 (v1)");
23821
23564
  if (para.charShapeIdx < 0 || para.lineSegIdx < 0) return skip("\uBB38\uB2E8 \uB808\uCF54\uB4DC \uAD6C\uC131 \uBE44\uC815\uD615 \u2014 \uBBF8\uC9C0\uC6D0");
23822
23565
  if (scan.repl.has(para.headerIdx)) return skip("\uB3D9\uC77C \uBB38\uB2E8 \uC911\uBCF5 \uC218\uC815 \u2014 \uCCAB \uC218\uC815\uB9CC \uC801\uC6A9");
23823
- if (/[\u0000-\u001f]/.test(newPlain)) return skip("\uC0C8 \uD14D\uC2A4\uD2B8\uC5D0 \uC81C\uC5B4\uBB38\uC790 \uD3EC\uD568 \u2014 \uBBF8\uC9C0\uC6D0");
23566
+ if (/[\u0000-\u0009\u000b-\u001f]/.test(newPlain)) return skip("\uC0C8 \uD14D\uC2A4\uD2B8\uC5D0 \uC81C\uC5B4\uBB38\uC790 \uD3EC\uD568 \u2014 \uBBF8\uC9C0\uC6D0");
23824
23567
  const records = scan.records;
23825
23568
  const headerRec = records[para.headerIdx];
23826
23569
  const charShapeRec = records[para.charShapeIdx];
@@ -23840,6 +23583,13 @@ function stageParaPatch(scan, para, newPlain, skip) {
23840
23583
  const cs2 = rebuildCharShape(charShapeRec.data, 0);
23841
23584
  scan.repl.set(para.charShapeIdx, cs2.buf);
23842
23585
  newHeader2.writeUInt16LE(cs2.count, 12);
23586
+ if (newPlain.includes("\n")) {
23587
+ const synth = synthesizeLineSegs(records[para.lineSegIdx].data, newPlain, 0);
23588
+ if (synth) {
23589
+ scan.repl.set(para.lineSegIdx, synth.buf);
23590
+ newHeader2.writeUInt16LE(synth.count, 16);
23591
+ }
23592
+ }
23843
23593
  scan.repl.set(para.headerIdx, newHeader2);
23844
23594
  return 1;
23845
23595
  }
@@ -23860,15 +23610,108 @@ function stageParaPatch(scan, para, newPlain, skip) {
23860
23610
  const cs = rebuildCharShape(charShapeRec.data, seg.prefixUnits);
23861
23611
  scan.repl.set(para.charShapeIdx, cs.buf);
23862
23612
  newHeader.writeUInt16LE(cs.count, 12);
23613
+ if (newRaw.includes("\n")) {
23614
+ const synth = synthesizeLineSegs(records[para.lineSegIdx].data, newRaw, seg.prefixUnits);
23615
+ if (synth) {
23616
+ scan.repl.set(para.lineSegIdx, synth.buf);
23617
+ newHeader.writeUInt16LE(synth.count, 16);
23618
+ }
23619
+ }
23863
23620
  scan.repl.set(para.headerIdx, newHeader);
23864
23621
  return 1;
23865
23622
  }
23866
23623
 
23867
- // src/roundtrip/session.ts
23624
+ // src/validate.ts
23868
23625
  import JSZip8 from "jszip";
23626
+ import { DOMParser as DOMParser4 } from "@xmldom/xmldom";
23627
+ var REQUIRED_FILES = [
23628
+ "mimetype",
23629
+ "META-INF/container.xml",
23630
+ "Contents/content.hpf",
23631
+ "Contents/header.xml",
23632
+ "Contents/section0.xml"
23633
+ ];
23634
+ var EXPECTED_MIMETYPE = "application/hwp+zip";
23635
+ var XML_SUFFIXES = [".xml", ".hpf", ".rdf"];
23636
+ var SECTION_FILE_RE = /^Contents\/section\d+\.xml$/;
23637
+ var SECCNT_RE = /<(?:\w+:)?head\b[^>]*?\bsecCnt="(\d+)"/;
23638
+ var OPF_HREF_RE = /<opf:item\b[^>]*?\bhref="([^"]*)"/g;
23639
+ async function validateHwpx(buffer) {
23640
+ const issues = [];
23641
+ let zip;
23642
+ try {
23643
+ zip = await JSZip8.loadAsync(buffer);
23644
+ } catch (err) {
23645
+ return {
23646
+ ok: false,
23647
+ issues: [{ message: `\uC720\uD6A8\uD55C ZIP\uC774 \uC544\uB2D8: ${err instanceof Error ? err.message : String(err)}` }],
23648
+ entryCount: 0
23649
+ };
23650
+ }
23651
+ const rawNames = Object.keys(zip.files);
23652
+ const names = rawNames.filter((n) => !zip.files[n].dir);
23653
+ if (names.length === 0) return { ok: false, issues: [{ message: "\uBE48 ZIP" }], entryCount: 0 };
23654
+ if (rawNames[0] !== "mimetype") {
23655
+ issues.push({ message: `\uCCAB zip \uC5D4\uD2B8\uB9AC\uAC00 '${rawNames[0]}' \u2014 'mimetype'\uC774\uC5B4\uC57C \uD568` });
23656
+ }
23657
+ const nameset = new Set(names);
23658
+ if (nameset.has("mimetype")) {
23659
+ const mt = (await zip.files["mimetype"].async("string")).trim();
23660
+ if (mt !== EXPECTED_MIMETYPE) {
23661
+ issues.push({ path: "mimetype", message: `\uB0B4\uC6A9\uC774 '${mt}' \u2014 '${EXPECTED_MIMETYPE}'\uC774\uC5B4\uC57C \uD568` });
23662
+ }
23663
+ }
23664
+ for (const req of REQUIRED_FILES) {
23665
+ if (!nameset.has(req)) issues.push({ message: `\uD544\uC218 \uD30C\uC77C \uB204\uB77D: ${req}` });
23666
+ }
23667
+ for (const name of names) {
23668
+ if (!XML_SUFFIXES.some((s) => name.endsWith(s))) continue;
23669
+ const text = await zip.files[name].async("string");
23670
+ let firstError = null;
23671
+ try {
23672
+ new DOMParser4({
23673
+ onError(level, msg2) {
23674
+ if (level !== "warning" && firstError === null) firstError = String(msg2);
23675
+ }
23676
+ }).parseFromString(text, "text/xml");
23677
+ } catch (err) {
23678
+ firstError ??= err instanceof Error ? err.message : String(err);
23679
+ }
23680
+ if (firstError !== null) {
23681
+ issues.push({ path: name, message: `XML \uC6F0\uD3FC\uB4DC \uC704\uBC18: ${firstError.split("\n")[0]}` });
23682
+ }
23683
+ }
23684
+ if (nameset.has("Contents/header.xml")) {
23685
+ const header = await zip.files["Contents/header.xml"].async("string");
23686
+ const m = SECCNT_RE.exec(header);
23687
+ if (m) {
23688
+ const declared = Number(m[1]);
23689
+ const actual = names.filter((n) => SECTION_FILE_RE.test(n)).length;
23690
+ if (declared !== actual) {
23691
+ issues.push({
23692
+ path: "Contents/header.xml",
23693
+ message: `secCnt=${declared}\uC778\uB370 \uC2E4\uC81C sectionN.xml\uC740 ${actual}\uAC1C \u2014 \uD55C\uCEF4\uB3C5\uC2A4\uAC00 \uC5F4\uAE30\uB97C \uAC70\uBD80\uD568`
23694
+ });
23695
+ }
23696
+ }
23697
+ }
23698
+ if (nameset.has("Contents/content.hpf")) {
23699
+ const hpf = await zip.files["Contents/content.hpf"].async("string");
23700
+ for (const m of hpf.matchAll(OPF_HREF_RE)) {
23701
+ const href = m[1];
23702
+ if (!nameset.has(href) && !nameset.has(`Contents/${href}`)) {
23703
+ issues.push({ path: "Contents/content.hpf", message: `manifest\uAC00 \uC5C6\uB294 \uD30C\uC77C\uC744 \uCC38\uC870: ${href}` });
23704
+ }
23705
+ }
23706
+ }
23707
+ return { ok: issues.length === 0, issues, entryCount: names.length };
23708
+ }
23709
+
23710
+ // src/roundtrip/session.ts
23711
+ import JSZip9 from "jszip";
23869
23712
  async function buildState(bytes) {
23870
23713
  const parsed = await parseHwpxDocument(u8ToArrayBuffer2(bytes));
23871
- const zip = await JSZip8.loadAsync(bytes);
23714
+ const zip = await JSZip9.loadAsync(bytes);
23872
23715
  const sectionPaths = await resolveSectionEntryNames(zip);
23873
23716
  if (sectionPaths.length === 0) {
23874
23717
  throw new Error("HWPX \uC139\uC158 \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
@@ -24449,7 +24292,7 @@ async function parseHwp(buffer, options) {
24449
24292
  async function parsePdf(buffer, options) {
24450
24293
  let parsePdfDocument;
24451
24294
  try {
24452
- const mod = await import("./parser-XUNGOH76.js");
24295
+ const mod = await import("./parser-HBHCD7TE.js");
24453
24296
  parsePdfDocument = mod.parsePdfDocument;
24454
24297
  } catch {
24455
24298
  return {
@@ -24542,16 +24385,14 @@ async function fillForm(input, values, outputFormat = "markdown") {
24542
24385
  export {
24543
24386
  extractHwpxMetadataOnly,
24544
24387
  extractHwp5MetadataOnly,
24388
+ formatFillValue,
24545
24389
  ValueCursor,
24390
+ fillWithUniqueGuard,
24546
24391
  isLabelCell,
24547
24392
  extractFormFields,
24548
24393
  inferFieldType,
24549
24394
  extractFormSchema,
24550
24395
  fillFormFields,
24551
- scanSectionXml,
24552
- buildParagraphSplices,
24553
- buildRangeSplices,
24554
- applySplices,
24555
24396
  fillHwpx,
24556
24397
  PRESET_ALIAS,
24557
24398
  normalizeGongmunPreset,
@@ -24560,6 +24401,7 @@ export {
24560
24401
  diffBlocks,
24561
24402
  patchHwpx,
24562
24403
  patchHwp,
24404
+ validateHwpx,
24563
24405
  HwpxSession,
24564
24406
  openHwpxDocument,
24565
24407
  patchHwpxBlocks,
@@ -24577,4 +24419,4 @@ export {
24577
24419
  parseHwpml,
24578
24420
  fillForm
24579
24421
  };
24580
- //# sourceMappingURL=chunk-TWACKS3K.js.map
24422
+ //# sourceMappingURL=chunk-WD5NUUU6.js.map