kordoc 4.21.19 → 4.21.21

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 (129) hide show
  1. package/README.md +7 -5
  2. package/dist/{-FLYHAUQ6.js → -ZYF6HX4M.js} +11 -11
  3. package/dist/{chunk-TC6DQLYN.js → chunk-2ZGP7A5T.js} +2 -2
  4. package/dist/{chunk-4VM6BT4W.js → chunk-3TCF5HPP.js} +2 -2
  5. package/dist/{chunk-2DNJW2HO.cjs → chunk-57VNFMMS.cjs} +3 -3
  6. package/dist/{chunk-2DNJW2HO.cjs.map → chunk-57VNFMMS.cjs.map} +1 -1
  7. package/dist/{chunk-OON4IJU2.js → chunk-5HTFWUJE.js} +2 -2
  8. package/dist/{chunk-AQ5GIBBH.js → chunk-7YAJCXCD.js} +2 -2
  9. package/dist/{chunk-3O4YC67B.js → chunk-BC54LBST.js} +3 -3
  10. package/dist/{chunk-GK4QLKNT.js → chunk-BG6LUCQL.js} +2 -2
  11. package/dist/{chunk-SM42XSI3.js → chunk-CY4QM2KQ.js} +2 -2
  12. package/dist/{chunk-KLKV47XO.cjs → chunk-DTZIZ5PP.cjs} +13 -13
  13. package/dist/{chunk-KLKV47XO.cjs.map → chunk-DTZIZ5PP.cjs.map} +1 -1
  14. package/dist/{chunk-INZGI6PI.js → chunk-FBJVDBMO.js} +2 -2
  15. package/dist/{chunk-Z2OOYQ4I.js → chunk-FZMGF6XU.js} +2 -2
  16. package/dist/{chunk-JGGYLUGD.cjs → chunk-H2MS4VG3.cjs} +3 -3
  17. package/dist/{chunk-JGGYLUGD.cjs.map → chunk-H2MS4VG3.cjs.map} +1 -1
  18. package/dist/{chunk-3PCAJWGK.js → chunk-HWIW3WK2.js} +42 -3
  19. package/dist/{chunk-3PCAJWGK.js.map → chunk-HWIW3WK2.js.map} +1 -1
  20. package/dist/{chunk-F6N7CDB7.js → chunk-J5PBI3ZC.js} +3 -3
  21. package/dist/{chunk-DQ2YGTRS.js → chunk-KBV4WFZ6.js} +145 -123
  22. package/dist/chunk-KBV4WFZ6.js.map +1 -0
  23. package/dist/{chunk-YDIVY65W.js → chunk-KTLHADU4.js} +2 -2
  24. package/dist/{chunk-3KW2Q655.cjs → chunk-MCUX2Y2C.cjs} +2 -2
  25. package/dist/{chunk-3KW2Q655.cjs.map → chunk-MCUX2Y2C.cjs.map} +1 -1
  26. package/dist/{chunk-X6WXU4LA.js → chunk-PTF4NCFM.js} +2 -2
  27. package/dist/{chunk-46PYORID.js → chunk-QHNVH4TC.js} +6 -6
  28. package/dist/{chunk-RYRUQ73F.js → chunk-RBRHO7WL.js} +2 -2
  29. package/dist/{chunk-CLAIAXMX.js → chunk-T3DTTK23.js} +2 -2
  30. package/dist/{chunk-DZVZVZAD.cjs → chunk-T7PN5D4D.cjs} +6 -6
  31. package/dist/{chunk-DZVZVZAD.cjs.map → chunk-T7PN5D4D.cjs.map} +1 -1
  32. package/dist/{chunk-EYLEVRHT.cjs → chunk-TMUUDMDH.cjs} +274 -172
  33. package/dist/chunk-TMUUDMDH.cjs.map +1 -0
  34. package/dist/{chunk-VIFY6DJZ.js → chunk-TRO4CQHJ.js} +4 -4
  35. package/dist/{chunk-OWLDTF5Q.js → chunk-WGMYVRSA.js} +2 -2
  36. package/dist/{chunk-AMXIYV73.js → chunk-YHPJTLCA.js} +2 -2
  37. package/dist/{chunk-QWOZRYUA.js → chunk-YM3K3LCD.js} +450 -110
  38. package/dist/chunk-YM3K3LCD.js.map +1 -0
  39. package/dist/{chunk-Y5OSPKBU.js → chunk-YQZOPT3A.js} +225 -43
  40. package/dist/chunk-YQZOPT3A.js.map +1 -0
  41. package/dist/{chunk-UDODNSDU.js → chunk-ZZIQWSGC.js} +2 -2
  42. package/dist/chunks-MDMJRCJ7.js +10 -0
  43. package/dist/cli.js +30 -30
  44. package/dist/{formula-2YYGN7UE.js → formula-6XNIXZ5L.js} +3 -3
  45. package/dist/{formula-EKXCURKO.cjs → formula-A3I5VAP7.cjs} +9 -9
  46. package/dist/{formula-EKXCURKO.cjs.map → formula-A3I5VAP7.cjs.map} +1 -1
  47. package/dist/{formula-Z5UPXBQM.js → formula-P7M7IH2L.js} +4 -4
  48. package/dist/{image-ocr-23R7RVHP.js → image-ocr-3C6W3KZO.js} +6 -6
  49. package/dist/{image-ocr-IMLFZ2JC.js → image-ocr-ITNY454I.js} +9 -9
  50. package/dist/{image-ocr-TE76KKNV.cjs → image-ocr-UJRSQ2T3.cjs} +15 -15
  51. package/dist/{image-ocr-TE76KKNV.cjs.map → image-ocr-UJRSQ2T3.cjs.map} +1 -1
  52. package/dist/index.cjs +1064 -687
  53. package/dist/index.cjs.map +1 -1
  54. package/dist/index.d.cts +1 -1
  55. package/dist/index.d.ts +1 -1
  56. package/dist/index.js +482 -105
  57. package/dist/index.js.map +1 -1
  58. package/dist/mcp.js +22 -22
  59. package/dist/{model-bundle-GTSRH2DY.js → model-bundle-LAWQH75O.js} +5 -5
  60. package/dist/{models-2J3NS7G2.js → models-6QTD2CFM.js} +5 -5
  61. package/dist/{parse-worker-v2-VO5UY3MP.js → parse-worker-v2-FEPJG3ER.js} +12 -12
  62. package/dist/{parser-FXGAKPUI.js → parser-56I364YM.js} +16 -8
  63. package/dist/{parser-JVUZ7EEV.js.map → parser-56I364YM.js.map} +1 -1
  64. package/dist/{parser-JVUZ7EEV.js → parser-KFCY3NIN.js} +19 -11
  65. package/dist/{parser-FXGAKPUI.js.map → parser-KFCY3NIN.js.map} +1 -1
  66. package/dist/{parser-D5VMCDLG.cjs → parser-VKWUMUML.cjs} +142 -134
  67. package/dist/parser-VKWUMUML.cjs.map +1 -0
  68. package/dist/pdf-ocr-MME37BL4.js +18 -0
  69. package/dist/pdf-ocr-OKAHNEJA.cjs +19 -0
  70. package/dist/{pdf-ocr-YFNUYBYJ.cjs.map → pdf-ocr-OKAHNEJA.cjs.map} +1 -1
  71. package/dist/pdf-ocr-ZZ6AJL6Z.js +22 -0
  72. package/dist/{profile-io-ULK73H2G.js → profile-io-OCITHUQF.js} +3 -3
  73. package/dist/{rasterize-FG3NX3GA.js → rasterize-SFCG4YOI.js} +3 -3
  74. package/dist/{redact-doc-NMKTKG24.js → redact-doc-5SMPXIGG.js} +11 -11
  75. package/dist/{render-GQUUGPOJ.js → render-FGPG5A2N.js} +7 -7
  76. package/dist/seal-GA7NZDTG.js +10 -0
  77. package/dist/{setup-PRBHD7JI.js → setup-JQVYZO7I.js} +3 -3
  78. package/dist/visual-YMG644YW.js +20 -0
  79. package/dist/{watch-LFSXNO2B.js → watch-C77BUSP7.js} +12 -12
  80. package/package.json +1 -1
  81. package/dist/chunk-DQ2YGTRS.js.map +0 -1
  82. package/dist/chunk-EYLEVRHT.cjs.map +0 -1
  83. package/dist/chunk-QWOZRYUA.js.map +0 -1
  84. package/dist/chunk-Y5OSPKBU.js.map +0 -1
  85. package/dist/chunks-J46DCTUC.js +0 -10
  86. package/dist/parser-D5VMCDLG.cjs.map +0 -1
  87. package/dist/pdf-ocr-364WQ5TY.js +0 -18
  88. package/dist/pdf-ocr-4MZELYCR.js +0 -22
  89. package/dist/pdf-ocr-YFNUYBYJ.cjs +0 -19
  90. package/dist/seal-EVHTG5GH.js +0 -10
  91. package/dist/visual-TCIR6MOG.js +0 -20
  92. /package/dist/{-FLYHAUQ6.js.map → -ZYF6HX4M.js.map} +0 -0
  93. /package/dist/{chunk-TC6DQLYN.js.map → chunk-2ZGP7A5T.js.map} +0 -0
  94. /package/dist/{chunk-4VM6BT4W.js.map → chunk-3TCF5HPP.js.map} +0 -0
  95. /package/dist/{chunk-OON4IJU2.js.map → chunk-5HTFWUJE.js.map} +0 -0
  96. /package/dist/{chunk-AQ5GIBBH.js.map → chunk-7YAJCXCD.js.map} +0 -0
  97. /package/dist/{chunk-3O4YC67B.js.map → chunk-BC54LBST.js.map} +0 -0
  98. /package/dist/{chunk-GK4QLKNT.js.map → chunk-BG6LUCQL.js.map} +0 -0
  99. /package/dist/{chunk-SM42XSI3.js.map → chunk-CY4QM2KQ.js.map} +0 -0
  100. /package/dist/{chunk-INZGI6PI.js.map → chunk-FBJVDBMO.js.map} +0 -0
  101. /package/dist/{chunk-Z2OOYQ4I.js.map → chunk-FZMGF6XU.js.map} +0 -0
  102. /package/dist/{chunk-F6N7CDB7.js.map → chunk-J5PBI3ZC.js.map} +0 -0
  103. /package/dist/{chunk-YDIVY65W.js.map → chunk-KTLHADU4.js.map} +0 -0
  104. /package/dist/{chunk-X6WXU4LA.js.map → chunk-PTF4NCFM.js.map} +0 -0
  105. /package/dist/{chunk-46PYORID.js.map → chunk-QHNVH4TC.js.map} +0 -0
  106. /package/dist/{chunk-RYRUQ73F.js.map → chunk-RBRHO7WL.js.map} +0 -0
  107. /package/dist/{chunk-CLAIAXMX.js.map → chunk-T3DTTK23.js.map} +0 -0
  108. /package/dist/{chunk-VIFY6DJZ.js.map → chunk-TRO4CQHJ.js.map} +0 -0
  109. /package/dist/{chunk-OWLDTF5Q.js.map → chunk-WGMYVRSA.js.map} +0 -0
  110. /package/dist/{chunk-AMXIYV73.js.map → chunk-YHPJTLCA.js.map} +0 -0
  111. /package/dist/{chunk-UDODNSDU.js.map → chunk-ZZIQWSGC.js.map} +0 -0
  112. /package/dist/{chunks-J46DCTUC.js.map → chunks-MDMJRCJ7.js.map} +0 -0
  113. /package/dist/{formula-2YYGN7UE.js.map → formula-6XNIXZ5L.js.map} +0 -0
  114. /package/dist/{formula-Z5UPXBQM.js.map → formula-P7M7IH2L.js.map} +0 -0
  115. /package/dist/{image-ocr-23R7RVHP.js.map → image-ocr-3C6W3KZO.js.map} +0 -0
  116. /package/dist/{image-ocr-IMLFZ2JC.js.map → image-ocr-ITNY454I.js.map} +0 -0
  117. /package/dist/{model-bundle-GTSRH2DY.js.map → model-bundle-LAWQH75O.js.map} +0 -0
  118. /package/dist/{models-2J3NS7G2.js.map → models-6QTD2CFM.js.map} +0 -0
  119. /package/dist/{parse-worker-v2-VO5UY3MP.js.map → parse-worker-v2-FEPJG3ER.js.map} +0 -0
  120. /package/dist/{pdf-ocr-364WQ5TY.js.map → pdf-ocr-MME37BL4.js.map} +0 -0
  121. /package/dist/{pdf-ocr-4MZELYCR.js.map → pdf-ocr-ZZ6AJL6Z.js.map} +0 -0
  122. /package/dist/{profile-io-ULK73H2G.js.map → profile-io-OCITHUQF.js.map} +0 -0
  123. /package/dist/{rasterize-FG3NX3GA.js.map → rasterize-SFCG4YOI.js.map} +0 -0
  124. /package/dist/{redact-doc-NMKTKG24.js.map → redact-doc-5SMPXIGG.js.map} +0 -0
  125. /package/dist/{render-GQUUGPOJ.js.map → render-FGPG5A2N.js.map} +0 -0
  126. /package/dist/{seal-EVHTG5GH.js.map → seal-GA7NZDTG.js.map} +0 -0
  127. /package/dist/{setup-PRBHD7JI.js.map → setup-JQVYZO7I.js.map} +0 -0
  128. /package/dist/{visual-TCIR6MOG.js.map → visual-YMG644YW.js.map} +0 -0
  129. /package/dist/{watch-LFSXNO2B.js.map → watch-C77BUSP7.js.map} +0 -0
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  blocksToPages,
3
3
  inlineImagesIntoMarkdown
4
- } from "./chunk-CLAIAXMX.js";
4
+ } from "./chunk-T3DTTK23.js";
5
5
  import {
6
6
  parsePageRange
7
7
  } from "./chunk-V4BH5SRQ.js";
@@ -32,7 +32,7 @@ import {
32
32
  tidyScriptTags,
33
33
  unframeLayoutTables,
34
34
  wrapScript
35
- } from "./chunk-YDIVY65W.js";
35
+ } from "./chunk-KTLHADU4.js";
36
36
  import {
37
37
  KordocError,
38
38
  OPTIONAL_DEP_INSTALL_HINT,
@@ -50,7 +50,7 @@ import {
50
50
  toArrayBuffer,
51
51
  unescapeHtml,
52
52
  unzipLimitBytes
53
- } from "./chunk-UDODNSDU.js";
53
+ } from "./chunk-ZZIQWSGC.js";
54
54
 
55
55
  // src/plain-markdown.ts
56
56
  function toPlainMarkdown(md2) {
@@ -22501,7 +22501,7 @@ function isKeywordLabel(text) {
22501
22501
  }
22502
22502
  return false;
22503
22503
  }
22504
- function fillInCellPatterns(cellText, values, matchedLabels, blockedLabels) {
22504
+ function fillInCellPatterns(cellText, values, matchedLabels, blockedLabels, annotationSkip) {
22505
22505
  let text = cellText;
22506
22506
  const matches = [];
22507
22507
  text = text.replace(
@@ -22538,7 +22538,7 @@ function fillInCellPatterns(cellText, values, matchedLabels, blockedLabels) {
22538
22538
  (match, keyword) => {
22539
22539
  const normalizedKw = normalizeLabel(keyword);
22540
22540
  const matchKey = values.available(normalizedKw) ? normalizedKw : void 0;
22541
- if (matchKey === void 0) return match;
22541
+ if (matchKey === void 0 || annotationSkip?.has(matchKey)) return match;
22542
22542
  const newValue = values.consume(matchKey);
22543
22543
  matchedLabels.add(matchKey);
22544
22544
  matches.push({ key: matchKey, label: keyword, value: newValue });
@@ -22763,6 +22763,17 @@ function isLabelCell(text) {
22763
22763
  }
22764
22764
  return false;
22765
22765
  }
22766
+ function isBlankValue(text) {
22767
+ return /^[\s_()()\-\u2014\u2013~.·,]*$/.test(text);
22768
+ }
22769
+ function isColumnHeaderRow(heads, below) {
22770
+ if (heads.length < 2 || below.some((b) => b === void 0)) return false;
22771
+ const hs = heads.map((h) => h.trim());
22772
+ if (hs.some((h) => !h || h.length > 40 || SENTENCE_ENDING_RE.test(h))) return false;
22773
+ const blanks = below.filter((b) => isBlankValue(b)).length;
22774
+ if (blanks === below.length) return true;
22775
+ return hs.length >= 3 && blanks >= hs.length - 1 && hs.every((h) => h.length <= 20 && isLabelCell(h));
22776
+ }
22766
22777
  function extractFormFields(blocks) {
22767
22778
  const fields = [];
22768
22779
  let totalTables = 0;
@@ -22795,10 +22806,47 @@ function collectTables(blocks, out = [], depth = 0) {
22795
22806
  }
22796
22807
  return out;
22797
22808
  }
22809
+ function coveredGrid(table2) {
22810
+ const covered = Array.from({ length: table2.rows }, () => new Array(table2.cols).fill(false));
22811
+ for (let r = 0; r < table2.rows; r++) {
22812
+ for (let c = 0; c < table2.cols; c++) {
22813
+ const cell2 = table2.cells[r]?.[c];
22814
+ if (!cell2 || covered[r][c]) continue;
22815
+ for (let rr = r; rr < Math.min(r + cell2.rowSpan, table2.rows); rr++) {
22816
+ for (let cc = c; cc < Math.min(c + cell2.colSpan, table2.cols); cc++) if (rr !== r || cc !== c) covered[rr][cc] = true;
22817
+ }
22818
+ }
22819
+ }
22820
+ return covered;
22821
+ }
22822
+ function columnHeaderRows(table2) {
22823
+ const covered = coveredGrid(table2);
22824
+ const rows = /* @__PURE__ */ new Set();
22825
+ for (let r = 0; r + 1 < table2.rows; r++) {
22826
+ const heads = [];
22827
+ for (let c = 0; c < table2.cols; c++) {
22828
+ const cell2 = table2.cells[r]?.[c];
22829
+ if (cell2 && !covered[r][c] && cell2.rowSpan <= 1) heads.push(c);
22830
+ }
22831
+ const below = heads.map((c) => covered[r + 1][c] ? void 0 : table2.cells[r + 1]?.[c]?.text);
22832
+ if (isColumnHeaderRow(heads.map((c) => table2.cells[r][c].text), below)) rows.add(r);
22833
+ }
22834
+ return rows;
22835
+ }
22798
22836
  function extractFromTable(table2) {
22799
22837
  const fields = [];
22838
+ const headerRows = table2.cols >= 2 ? columnHeaderRows(table2) : /* @__PURE__ */ new Set();
22839
+ const covered = headerRows.size > 0 ? coveredGrid(table2) : [];
22800
22840
  if (table2.cols >= 2) {
22801
22841
  for (let r = 0; r < table2.rows; r++) {
22842
+ if (headerRows.has(r)) {
22843
+ for (let c = 0; c < table2.cols; c++) {
22844
+ const cell2 = table2.cells[r]?.[c];
22845
+ if (!cell2 || covered[r][c] || cell2.rowSpan > 1 || !cell2.text.trim()) continue;
22846
+ fields.push({ label: cell2.text.trim().replace(/[::]\s*$/, ""), value: (table2.cells[r + 1]?.[c]?.text ?? "").trim(), row: r + 1, col: c });
22847
+ }
22848
+ continue;
22849
+ }
22802
22850
  for (let c = 0; c < table2.cols - 1; c++) {
22803
22851
  const labelCell = table2.cells[r]?.[c];
22804
22852
  const valueCell = table2.cells[r]?.[c + 1];
@@ -23608,6 +23656,44 @@ function allLinesegRemovalSplices(xml) {
23608
23656
  }
23609
23657
  return splices;
23610
23658
  }
23659
+ function changedLinesegRemovalSplices(xml, edits) {
23660
+ if (edits.length === 0) return [];
23661
+ const points = edits.map((e) => e.start).sort((a, b) => a - b);
23662
+ const tagRe = /<(\/?)((?:[A-Za-z0-9_]+:)?(?:p|linesegarray))(?=[\s/>])(?:"[^"]*"|'[^']*'|[^>"'])*?(\/?)>/g;
23663
+ const stack = [];
23664
+ const out = [];
23665
+ let pi = 0;
23666
+ let m;
23667
+ while ((m = tagRe.exec(xml)) !== null) {
23668
+ while (pi < points.length && points[pi] <= m.index) {
23669
+ if (stack.length) stack[stack.length - 1].dirty = true;
23670
+ pi++;
23671
+ }
23672
+ const [full, close, qname, selfClose] = m;
23673
+ const isSeg = qname.endsWith("linesegarray");
23674
+ if (isSeg) {
23675
+ if (close) continue;
23676
+ let end = m.index + full.length;
23677
+ if (!selfClose) {
23678
+ const ci = xml.indexOf(`</${qname}>`, end);
23679
+ if (ci < 0) continue;
23680
+ end = ci + qname.length + 3;
23681
+ tagRe.lastIndex = end;
23682
+ }
23683
+ const top = stack[stack.length - 1];
23684
+ if (top && !top.seg) top.seg = { start: m.index, end };
23685
+ continue;
23686
+ }
23687
+ if (close) {
23688
+ const p = stack.pop();
23689
+ if (p?.dirty && p.seg) out.push({ start: p.seg.start, end: p.seg.end, replacement: "" });
23690
+ } else if (!selfClose) {
23691
+ stack.push({ dirty: false });
23692
+ }
23693
+ }
23694
+ const claimed = edits.filter((e) => e.end > e.start);
23695
+ return out.filter((ls) => !claimed.some((c) => ls.start >= c.start && ls.end <= c.end));
23696
+ }
23611
23697
  function applySplices(xml, splices) {
23612
23698
  const sorted = [...splices].sort((a, b) => a.start - b.start);
23613
23699
  const parts = [];
@@ -23729,10 +23815,17 @@ function fillClickHereInXml(xml, cursor, blockedLabels) {
23729
23815
  if (current === replacement) continue;
23730
23816
  splices.push({ start: region.start, end: region.end, replacement });
23731
23817
  }
23818
+ const changedAt = [];
23819
+ let delta = 0;
23820
+ for (const s of [...splices].sort((a, b) => a.start - b.start)) {
23821
+ changedAt.push(s.start + delta);
23822
+ delta += s.replacement.length - (s.end - s.start);
23823
+ }
23732
23824
  return {
23733
23825
  xml: splices.length > 0 ? applySplices(xml, splices) : null,
23734
23826
  filled,
23735
- matchedKeys
23827
+ matchedKeys,
23828
+ changedAt
23736
23829
  };
23737
23830
  }
23738
23831
  async function extractClickHereFields(hwpxBuffer) {
@@ -23981,6 +24074,7 @@ function patchZipEntries(original, replacements, additions) {
23981
24074
  }
23982
24075
 
23983
24076
  // src/form/filler-hwpx.ts
24077
+ var ANNOTATION_BLANK_RE = /[((][^))]*[::]\s*[))]/;
23984
24078
  async function fillHwpx(hwpxBuffer, values, blockedLabels) {
23985
24079
  const u8 = new Uint8Array(hwpxBuffer);
23986
24080
  precheckZipSize(hwpxBuffer);
@@ -23999,13 +24093,13 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
23999
24093
  const replacements = /* @__PURE__ */ new Map();
24000
24094
  const encoder = new TextEncoder();
24001
24095
  const sectionXmls = /* @__PURE__ */ new Map();
24002
- const fieldModified = /* @__PURE__ */ new Set();
24096
+ const fieldModified = /* @__PURE__ */ new Map();
24003
24097
  const fieldMatchedKeys = /* @__PURE__ */ new Set();
24004
24098
  for (const p of sectionPaths) {
24005
24099
  const xml = await zip.file(p).async("text");
24006
24100
  const outcome = fillClickHereInXml(xml, cursor, blockedLabels);
24007
24101
  sectionXmls.set(p, outcome.xml ?? xml);
24008
- if (outcome.xml !== null) fieldModified.add(p);
24102
+ if (outcome.xml !== null) fieldModified.set(p, outcome.changedAt);
24009
24103
  for (const f of outcome.filled) filled.push(f);
24010
24104
  for (const k of outcome.matchedKeys) fieldMatchedKeys.add(k);
24011
24105
  }
@@ -24013,9 +24107,31 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
24013
24107
  matchedLabels.add(k);
24014
24108
  normalizedValues.delete(k);
24015
24109
  }
24110
+ const scans = sectionPaths.map((p, si) => scanSectionXml(sectionXmls.get(p), si));
24111
+ const annotationSkip = /* @__PURE__ */ new Set();
24112
+ for (let si = 0; si < scans.length; si++) {
24113
+ const xml = sectionXmls.get(sectionPaths[si]);
24114
+ for (const table2 of collectAllTables(scans[si])) {
24115
+ for (const row of table2.rows) {
24116
+ for (const cell2 of row) {
24117
+ const t = cell2.paragraphs.filter((p) => !p.inTextbox).map((p) => paraTText(p, xml) ?? p.text).join("");
24118
+ if (!isLabelCell(t) || ANNOTATION_BLANK_RE.test(t)) continue;
24119
+ const key = findMatchingKey(normalizeLabel(t), cursor);
24120
+ if (key !== void 0 && !cursor.isArray(key)) annotationSkip.add(key);
24121
+ }
24122
+ }
24123
+ }
24124
+ for (const para2 of scans[si].bodyParagraphs) {
24125
+ for (const seg of scanInlineSegments(paraTText(para2, xml) ?? para2.text)) {
24126
+ const key = matchInlineSegment(seg, cursor, blockedLabels)?.key;
24127
+ if (key !== void 0 && !cursor.isArray(key)) annotationSkip.add(key);
24128
+ }
24129
+ }
24130
+ }
24131
+ const firstTarget = /* @__PURE__ */ new Map();
24016
24132
  for (let si = 0; si < sectionPaths.length; si++) {
24017
24133
  const xml = sectionXmls.get(sectionPaths[si]);
24018
- const scan = scanSectionXml(xml, si);
24134
+ const scan = scans[si];
24019
24135
  const ledger = /* @__PURE__ */ new Map();
24020
24136
  const led = (p) => {
24021
24137
  let l = ledger.get(p);
@@ -24024,25 +24140,14 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
24024
24140
  };
24025
24141
  const matchText = (p) => paraTText(p, xml) ?? p.text;
24026
24142
  const cellLabelText = (cell2) => cell2.paragraphs.filter((p) => !p.inTextbox).map((p) => matchText(p)).join("");
24027
- const allTables = [];
24028
- const collectTables2 = (tables, depth) => {
24029
- if (depth > 16) return;
24030
- for (const t of tables) {
24031
- allTables.push(t);
24032
- for (const row of t.rows) {
24033
- for (const cell2 of row) collectTables2(cell2.tables, depth + 1);
24034
- }
24035
- }
24036
- };
24037
- collectTables2(scan.tables, 0);
24038
- collectTables2(scan.orphanTables, 0);
24143
+ const allTables = collectAllTables(scan);
24039
24144
  const patternApplied = /* @__PURE__ */ new Set();
24040
24145
  for (const table2 of allTables) {
24041
24146
  for (const row of table2.rows) {
24042
24147
  for (const cell2 of row) {
24043
24148
  for (const para2 of cell2.paragraphs) {
24044
24149
  const text = matchText(para2);
24045
- const result = fillInCellPatterns(text, cursor, matchedLabels, blockedLabels);
24150
+ const result = fillInCellPatterns(text, cursor, matchedLabels, blockedLabels, annotationSkip);
24046
24151
  if (!result) continue;
24047
24152
  const l = led(para2);
24048
24153
  if (l.fullText !== void 0) continue;
@@ -24066,29 +24171,69 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
24066
24171
  }
24067
24172
  }
24068
24173
  }
24174
+ const isForeignLabel = (text) => {
24175
+ if (isKeywordLabel(text)) return true;
24176
+ const t = text.trim();
24177
+ if (/^[①-⑳]/.test(t) && t.length <= 20) return true;
24178
+ if (ANNOTATION_BLANK_RE.test(t)) return false;
24179
+ const n = normalizeLabel(t);
24180
+ return !!n && cursor.has(n);
24181
+ };
24182
+ const laterOk = (key, current) => cursor.isArray(key) || !firstTarget.has(key) || isBlankValue(current) || current.trim() === firstTarget.get(key);
24183
+ const markFirst = (key, current) => {
24184
+ if (!cursor.isArray(key) && !firstTarget.has(key)) firstTarget.set(key, current.trim());
24185
+ };
24186
+ const fillInLabelCell = (cell2, labelText, key, rowIdx, colIdx) => {
24187
+ if (cell2.colSpan < 2) return;
24188
+ if (!cursor.isArray(key) && matchedLabels.has(key)) return;
24189
+ const paras = cell2.paragraphs.filter((p) => !p.inTextbox && matchText(p).trim());
24190
+ if (paras.length !== 1 || cell2.tables.length > 0) return;
24191
+ const l = led(paras[0]);
24192
+ if (l.fullText !== void 0 || l.ranges.length > 0) return;
24193
+ const value = cursor.consume(key);
24194
+ if (value === void 0) return;
24195
+ const text = matchText(paras[0]);
24196
+ l.ranges.push({ start: text.trimEnd().length, end: text.length, replacement: " " + value });
24197
+ l.filledIdx.push(filled.length);
24198
+ l.matchKeys.push(key);
24199
+ matchedLabels.add(key);
24200
+ markFirst(key, labelText);
24201
+ filled.push({ label: labelText.trim().replace(/[::]\s*$/, ""), value, row: rowIdx, col: colIdx, key });
24202
+ };
24069
24203
  for (const table2 of allTables) {
24070
- const skipHeaderRow = table2.rows.length >= 2 && (() => {
24071
- const first = table2.rows[0];
24072
- const allLabels = first.length > 0 && first.every((cell2) => {
24073
- const t = cellLabelText(cell2).trim();
24074
- return t.length > 0 && t.length <= 20 && isLabelCell(t);
24075
- });
24076
- if (!allLabels) return false;
24204
+ const firstRowAllLabels = table2.rows.length >= 2 && table2.rows[0].length > 0 && table2.rows[0].every((cell2) => {
24205
+ const t = cellLabelText(cell2).trim();
24206
+ return t.length > 0 && t.length <= 20 && isLabelCell(t);
24207
+ });
24208
+ const headerRows = /* @__PURE__ */ new Set();
24209
+ for (let r = 0; r + 1 < table2.rows.length; r++) {
24210
+ const heads = table2.rows[r].filter((c) => c.rowSpan <= 1);
24211
+ const below = heads.map((h) => table2.rows[r + 1].find((c) => c.colAddr === h.colAddr));
24212
+ if (isColumnHeaderRow(heads.map(cellLabelText), below.map((b) => b ? cellLabelText(b) : void 0))) headerRows.add(r);
24213
+ }
24214
+ const skipRows = new Set(headerRows);
24215
+ if (firstRowAllLabels) {
24077
24216
  const d0 = table2.rows[1][0];
24078
- return d0 === void 0 || !isLabelCell(cellLabelText(d0));
24079
- })();
24080
- for (let rowIdx = skipHeaderRow ? 1 : 0; rowIdx < table2.rows.length; rowIdx++) {
24217
+ if (d0 === void 0 || !isLabelCell(cellLabelText(d0))) skipRows.add(0);
24218
+ }
24219
+ for (let rowIdx = 0; rowIdx < table2.rows.length; rowIdx++) {
24220
+ if (skipRows.has(rowIdx)) continue;
24081
24221
  const cells = table2.rows[rowIdx];
24082
- for (let colIdx = 0; colIdx < cells.length - 1; colIdx++) {
24222
+ for (let colIdx = 0; colIdx < cells.length; colIdx++) {
24083
24223
  const labelText = cellLabelText(cells[colIdx]);
24084
24224
  if (!isLabelCell(labelText)) continue;
24085
- const valueCell = cells[colIdx + 1];
24086
- if (isKeywordLabel(cellLabelText(valueCell))) continue;
24087
24225
  const normalizedCellLabel = normalizeLabel(labelText);
24088
24226
  if (!normalizedCellLabel) continue;
24089
24227
  if (blockedLabels?.has(normalizedCellLabel)) continue;
24090
24228
  const matchKey = findMatchingKey(normalizedCellLabel, cursor);
24091
24229
  if (matchKey === void 0) continue;
24230
+ const valueCell = cells[colIdx + 1];
24231
+ const valueText = valueCell ? cellLabelText(valueCell) : "";
24232
+ if (!valueCell || isForeignLabel(valueText)) {
24233
+ fillInLabelCell(cells[colIdx], labelText, matchKey, rowIdx, colIdx);
24234
+ continue;
24235
+ }
24236
+ if (!laterOk(matchKey, valueText)) continue;
24092
24237
  if (patternApplied.has(valueCell)) {
24093
24238
  const target = valueCell.paragraphs.find((p) => p.tRanges.length > 0) ?? valueCell.paragraphs[0];
24094
24239
  if (!target) continue;
@@ -24100,6 +24245,7 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
24100
24245
  l.filledIdx.push(filled.length);
24101
24246
  l.matchKeys.push(matchKey);
24102
24247
  matchedLabels.add(matchKey);
24248
+ markFirst(matchKey, valueText);
24103
24249
  filled.push({
24104
24250
  label: labelText.trim().replace(/[::]\s*$/, ""),
24105
24251
  value: newValue,
@@ -24123,6 +24269,7 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
24123
24269
  lk.ranges = [];
24124
24270
  }
24125
24271
  matchedLabels.add(matchKey);
24272
+ markFirst(matchKey, valueText);
24126
24273
  filled.push({
24127
24274
  label: labelText.trim().replace(/[::]\s*$/, ""),
24128
24275
  value: newValue,
@@ -24133,65 +24280,67 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
24133
24280
  }
24134
24281
  }
24135
24282
  }
24136
- if (table2.rows.length >= 2) {
24137
- const headerCells = table2.rows[0];
24138
- const allLabels = headerCells.length > 0 && headerCells.every((cell2) => {
24139
- const t = cellLabelText(cell2).trim();
24140
- return t.length > 0 && t.length <= 20 && isLabelCell(t);
24141
- });
24142
- if (allLabels) {
24143
- for (let rowIdx = 1; rowIdx < table2.rows.length; rowIdx++) {
24144
- const dataCells = table2.rows[rowIdx];
24145
- for (let colIdx = 0; colIdx < Math.min(headerCells.length, dataCells.length); colIdx++) {
24146
- const headerLabel = normalizeLabel(cellLabelText(headerCells[colIdx]));
24147
- if (blockedLabels?.has(headerLabel)) continue;
24148
- const matchKey = findMatchingKey(headerLabel, cursor);
24149
- if (matchKey === void 0) continue;
24150
- if (!cursor.isArray(matchKey) && matchedLabels.has(matchKey)) continue;
24151
- const dataCell = dataCells[colIdx];
24152
- if (patternApplied.has(dataCell)) {
24153
- const target = dataCell.paragraphs.find((p) => p.tRanges.length > 0) ?? dataCell.paragraphs[0];
24154
- if (!target) continue;
24155
- const l = led(target);
24156
- if (l.fullText !== void 0) continue;
24157
- const newValue2 = cursor.consume(matchKey);
24158
- if (newValue2 === void 0) continue;
24159
- l.ranges.push({ start: 0, end: 0, replacement: newValue2 + " " });
24160
- l.filledIdx.push(filled.length);
24161
- l.matchKeys.push(matchKey);
24162
- matchedLabels.add(matchKey);
24163
- filled.push({
24164
- label: cellLabelText(headerCells[colIdx]).trim(),
24165
- value: newValue2,
24166
- row: rowIdx,
24167
- col: colIdx,
24168
- key: matchKey
24169
- });
24170
- continue;
24171
- }
24172
- const newValue = cursor.consume(matchKey);
24173
- if (newValue === void 0) continue;
24174
- const paras = dataCell.paragraphs;
24175
- if (paras.length === 0) continue;
24176
- const l0 = led(paras[0]);
24177
- l0.fullText = newValue;
24178
- l0.ranges = [];
24179
- l0.filledIdx.push(filled.length);
24180
- l0.matchKeys.push(matchKey);
24181
- for (let k = 1; k < paras.length; k++) {
24182
- const lk = led(paras[k]);
24183
- lk.fullText = "";
24184
- lk.ranges = [];
24185
- }
24283
+ const verticalRows = new Set(headerRows);
24284
+ if (firstRowAllLabels) verticalRows.add(0);
24285
+ for (const h of [...verticalRows].sort((a, b) => a - b)) {
24286
+ const headerCells = table2.rows[h];
24287
+ const scalarSeen = /* @__PURE__ */ new Set();
24288
+ for (let rowIdx = h + 1; rowIdx < table2.rows.length && !verticalRows.has(rowIdx); rowIdx++) {
24289
+ const dataCells = table2.rows[rowIdx];
24290
+ for (let colIdx = 0; colIdx < headerCells.length; colIdx++) {
24291
+ const dataCell = dataCells.find((c) => c.colAddr === headerCells[colIdx].colAddr);
24292
+ if (!dataCell) continue;
24293
+ const headerLabel = normalizeLabel(cellLabelText(headerCells[colIdx]));
24294
+ if (!headerLabel || blockedLabels?.has(headerLabel)) continue;
24295
+ const matchKey = findMatchingKey(headerLabel, cursor);
24296
+ if (matchKey === void 0) continue;
24297
+ if (!cursor.isArray(matchKey) && (matchedLabels.has(matchKey) || scalarSeen.has(colIdx))) continue;
24298
+ if (!cursor.isArray(matchKey)) scalarSeen.add(colIdx);
24299
+ if (isForeignLabel(cellLabelText(dataCell))) continue;
24300
+ if (patternApplied.has(dataCell)) {
24301
+ const target = dataCell.paragraphs.find((p) => p.tRanges.length > 0) ?? dataCell.paragraphs[0];
24302
+ if (!target) continue;
24303
+ const l = led(target);
24304
+ if (l.fullText !== void 0) continue;
24305
+ const newValue2 = cursor.consume(matchKey);
24306
+ if (newValue2 === void 0) continue;
24307
+ l.ranges.push({ start: 0, end: 0, replacement: newValue2 + " " });
24308
+ l.filledIdx.push(filled.length);
24309
+ l.matchKeys.push(matchKey);
24186
24310
  matchedLabels.add(matchKey);
24311
+ markFirst(matchKey, cellLabelText(dataCell));
24187
24312
  filled.push({
24188
24313
  label: cellLabelText(headerCells[colIdx]).trim(),
24189
- value: newValue,
24314
+ value: newValue2,
24190
24315
  row: rowIdx,
24191
24316
  col: colIdx,
24192
24317
  key: matchKey
24193
24318
  });
24319
+ continue;
24194
24320
  }
24321
+ const newValue = cursor.consume(matchKey);
24322
+ if (newValue === void 0) continue;
24323
+ const paras = dataCell.paragraphs;
24324
+ if (paras.length === 0) continue;
24325
+ const l0 = led(paras[0]);
24326
+ l0.fullText = newValue;
24327
+ l0.ranges = [];
24328
+ l0.filledIdx.push(filled.length);
24329
+ l0.matchKeys.push(matchKey);
24330
+ for (let k = 1; k < paras.length; k++) {
24331
+ const lk = led(paras[k]);
24332
+ lk.fullText = "";
24333
+ lk.ranges = [];
24334
+ }
24335
+ matchedLabels.add(matchKey);
24336
+ markFirst(matchKey, cellLabelText(dataCell));
24337
+ filled.push({
24338
+ label: cellLabelText(headerCells[colIdx]).trim(),
24339
+ value: newValue,
24340
+ row: rowIdx,
24341
+ col: colIdx,
24342
+ key: matchKey
24343
+ });
24195
24344
  }
24196
24345
  }
24197
24346
  }
@@ -24207,9 +24356,11 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
24207
24356
  const matched = matches[i];
24208
24357
  if (matched === void 0) continue;
24209
24358
  const matchKey = matched.key;
24359
+ const ve = clampSegmentEnd(text, seg, segments[i + 1], matches[i + 1]?.viaExt ?? false);
24360
+ if (!laterOk(matchKey, text.slice(seg.valueStart, ve))) continue;
24210
24361
  const newValue = cursor.consume(matchKey);
24211
24362
  if (newValue === void 0) continue;
24212
- const ve = clampSegmentEnd(text, seg, segments[i + 1], matches[i + 1]?.viaExt ?? false);
24363
+ markFirst(matchKey, text.slice(seg.valueStart, ve));
24213
24364
  const replacement = seg.valueStart === ve ? padInsertion(text, seg.valueStart, newValue) : newValue;
24214
24365
  const l = led(para2);
24215
24366
  l.ranges.push({ start: seg.valueStart, end: ve, replacement });
@@ -24263,8 +24414,10 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
24263
24414
  for (const k of l.matchKeys) succeededKeys.add(k);
24264
24415
  splices.push(...paraSplices);
24265
24416
  }
24266
- if (splices.length > 0 || fieldModified.has(sectionPaths[si])) {
24267
- splices.push(...allLinesegRemovalSplices(xml));
24417
+ const fieldAt = fieldModified.get(sectionPaths[si]);
24418
+ if (splices.length > 0 || fieldAt) {
24419
+ const marks = (fieldAt ?? []).map((at) => ({ start: at, end: at, replacement: "" }));
24420
+ splices.push(...changedLinesegRemovalSplices(xml, [...splices, ...marks]));
24268
24421
  replacements.set(sectionPaths[si], encoder.encode(applySplices(xml, splices)));
24269
24422
  }
24270
24423
  }
@@ -24281,6 +24434,21 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
24281
24434
  ...warnings.length > 0 ? { warnings } : {}
24282
24435
  };
24283
24436
  }
24437
+ function collectAllTables(scan) {
24438
+ const out = [];
24439
+ const walk = (tables, depth) => {
24440
+ if (depth > 16) return;
24441
+ for (const t of tables) {
24442
+ out.push(t);
24443
+ for (const row of t.rows) {
24444
+ for (const cell2 of row) walk(cell2.tables, depth + 1);
24445
+ }
24446
+ }
24447
+ };
24448
+ walk(scan.tables, 0);
24449
+ walk(scan.orphanTables, 0);
24450
+ return out;
24451
+ }
24284
24452
 
24285
24453
  // src/table/classifier.ts
24286
24454
  var DIAGRAM_KEYWORDS = /조직도|비상\s*연락망|연락망|체계도|업무\s*체계도|기구표|배치도|흐름도|추진\s*체계/u;
@@ -33368,7 +33536,7 @@ function parseCharPrs(headerDoc, hangulFonts) {
33368
33536
  if (color) def.textColor = color;
33369
33537
  if (cp.getAttribute("bold") === "1") def.bold = true;
33370
33538
  if (cp.getAttribute("italic") === "1") def.italic = true;
33371
- if (findChildByLocalName(cp, "underline")) def.underline = true;
33539
+ if (findChildByLocalName(cp, "underline")?.getAttribute("type") === "BOTTOM") def.underline = true;
33372
33540
  const fontRef = findChildByLocalName(cp, "fontRef");
33373
33541
  const hangul = fontRef?.getAttribute("hangul");
33374
33542
  if (hangul) {
@@ -34698,6 +34866,163 @@ function buildEmbeddedLineSplices(para2, xml, newLines) {
34698
34866
  return splices;
34699
34867
  }
34700
34868
 
34869
+ // src/roundtrip/inline-edit.ts
34870
+ var ESCAPABLE = /* @__PURE__ */ new Set(["~", "*", "_", "`", "|", "#", "<", "$", "\\"]);
34871
+ var isWs = (c) => c !== void 0 && /\s/.test(c);
34872
+ function parseEmphasis(text) {
34873
+ const toks = [];
34874
+ const pushText = (s, code = false) => {
34875
+ const last = toks[toks.length - 1];
34876
+ if (last && last.kind === "text" && !!last.code === code) last.text += s;
34877
+ else toks.push({ kind: "text", text: s, code });
34878
+ };
34879
+ for (let i = 0; i < text.length; ) {
34880
+ const c = text[i];
34881
+ if (c === "\\" && ESCAPABLE.has(text[i + 1])) {
34882
+ pushText(text[i + 1]);
34883
+ i += 2;
34884
+ continue;
34885
+ }
34886
+ if (c === "`") {
34887
+ const close = text.indexOf("`", i + 1);
34888
+ if (close > i + 1) {
34889
+ pushText(text.slice(i + 1, close), true);
34890
+ i = close + 1;
34891
+ continue;
34892
+ }
34893
+ }
34894
+ if (text.startsWith("<u>", i)) {
34895
+ toks.push({ kind: "u-open", text: "<u>" });
34896
+ i += 3;
34897
+ continue;
34898
+ }
34899
+ if (text.startsWith("</u>", i)) {
34900
+ toks.push({ kind: "u-close", text: "</u>" });
34901
+ i += 4;
34902
+ continue;
34903
+ }
34904
+ if (text.startsWith("~~", i)) {
34905
+ toks.push({ kind: "strike", text: "~~" });
34906
+ i += 2;
34907
+ continue;
34908
+ }
34909
+ if (c === "*") {
34910
+ let j = i;
34911
+ while (text[j] === "*") j++;
34912
+ toks.push({ kind: "star", text: text.slice(i, j), n: j - i });
34913
+ i = j;
34914
+ continue;
34915
+ }
34916
+ pushText(c);
34917
+ i++;
34918
+ }
34919
+ const charBefore = (k) => {
34920
+ const t = toks[k - 1];
34921
+ return t?.kind === "text" ? t.text[t.text.length - 1] : t ? "x" : void 0;
34922
+ };
34923
+ const charAfter = (k) => {
34924
+ const t = toks[k + 1];
34925
+ return t?.kind === "text" ? t.text[0] : t ? "x" : void 0;
34926
+ };
34927
+ const stack = [];
34928
+ for (let k = 0; k < toks.length; k++) {
34929
+ const t = toks[k];
34930
+ if (t.kind === "text") continue;
34931
+ const top = stack.length ? toks[stack[stack.length - 1]] : void 0;
34932
+ const canClose = t.kind === "u-close" || (t.kind === "star" || t.kind === "strike") && charBefore(k) !== void 0 && !isWs(charBefore(k));
34933
+ const matches = top && (t.kind === "u-close" && top.kind === "u-open" || t.kind === "strike" && top.kind === "strike" || t.kind === "star" && top.kind === "star" && top.n === t.n);
34934
+ if (canClose && matches) {
34935
+ top.paired = true;
34936
+ t.paired = true;
34937
+ stack.pop();
34938
+ continue;
34939
+ }
34940
+ const canOpen = t.kind === "u-open" || (t.kind === "star" || t.kind === "strike") && charAfter(k) !== void 0 && !isWs(charAfter(k));
34941
+ if (canOpen) stack.push(k);
34942
+ }
34943
+ const segs = [];
34944
+ let cur = "";
34945
+ const cut = () => {
34946
+ if (cur) segs.push(cur);
34947
+ cur = "";
34948
+ };
34949
+ for (const t of toks) {
34950
+ if (t.kind !== "text" && t.paired) {
34951
+ cut();
34952
+ continue;
34953
+ }
34954
+ if (t.code) {
34955
+ cut();
34956
+ segs.push(t.text);
34957
+ continue;
34958
+ }
34959
+ cur += t.text;
34960
+ }
34961
+ cut();
34962
+ return { plain: segs.join(""), segs };
34963
+ }
34964
+ function alignToRaw(raw, norm2) {
34965
+ const pos = new Array(norm2.length);
34966
+ let j = 0;
34967
+ for (let i = 0; i < norm2.length; i++) {
34968
+ for (; ; ) {
34969
+ if (j >= raw.length) return null;
34970
+ const a = norm2[i], b = raw[j];
34971
+ if (a === b || isWs(a) && isWs(b)) break;
34972
+ if (isWs(b)) {
34973
+ j++;
34974
+ continue;
34975
+ }
34976
+ return null;
34977
+ }
34978
+ pos[i] = j++;
34979
+ }
34980
+ if (raw.slice(j).trim() !== "") return null;
34981
+ return pos;
34982
+ }
34983
+ function commonEnds(a, b) {
34984
+ let p = 0;
34985
+ while (p < a.length && p < b.length && a[p] === b[p]) p++;
34986
+ let s = 0;
34987
+ while (s < a.length - p && s < b.length - p && a[a.length - 1 - s] === b[b.length - 1 - s]) s++;
34988
+ return { p, s };
34989
+ }
34990
+ function alignedTextEdits(raw, origNorm, newNorm, origSegs, newSegs) {
34991
+ if (!origNorm) return null;
34992
+ const pos = alignToRaw(raw, origNorm);
34993
+ if (!pos) return null;
34994
+ const ranges = [];
34995
+ const diffInto = (o, n, base) => {
34996
+ if (o === n) return;
34997
+ const { p, s } = commonEnds(o, n);
34998
+ ranges.push({ a: base + p, b: base + o.length - s, text: n.slice(p, n.length - s) });
34999
+ };
35000
+ if (origSegs && newSegs && origSegs.length === newSegs.length && origSegs.length > 1 && origSegs.join("") === origNorm && newSegs.join("") === newNorm) {
35001
+ let base = 0;
35002
+ for (let k = 0; k < origSegs.length; k++) {
35003
+ diffInto(origSegs[k], newSegs[k], base);
35004
+ base += origSegs[k].length;
35005
+ }
35006
+ } else {
35007
+ diffInto(origNorm, newNorm, 0);
35008
+ }
35009
+ const at = (a) => a < pos.length ? pos[a] : pos[pos.length - 1] + 1;
35010
+ return ranges.map((r) => ({ start: at(r.a), end: r.b > r.a ? pos[r.b - 1] + 1 : at(r.a), text: r.text }));
35011
+ }
35012
+ function minimalTextSplices(para2, xml, origPlain, newPlain, origSegs, newSegs) {
35013
+ const raw = paraTText(para2, xml);
35014
+ if (raw === null) return null;
35015
+ const edits = alignedTextEdits(raw, origPlain, newPlain, origSegs, newSegs);
35016
+ if (!edits || edits.length === 0) return null;
35017
+ const out = [];
35018
+ for (const e of edits) {
35019
+ const sp = buildRangeSplices(para2, xml, e.start, e.end, e.text);
35020
+ if (!sp) return null;
35021
+ out.push(...sp);
35022
+ }
35023
+ return out;
35024
+ }
35025
+
34701
35026
  // src/roundtrip/table-patch.ts
34702
35027
  function patchGfmTable(table2, scanTable, orig, edited, ctx, skip) {
34703
35028
  const replica = replicateGfmTable(table2);
@@ -35014,7 +35339,8 @@ function applyCellEdit(table2, scanTable, gridR, gridC, newLines, ctx, before2,
35014
35339
  }
35015
35340
  for (let i = 0; i < nonEmpty.length; i++) {
35016
35341
  if (assigned[i] === nonEmpty[i].text || normForMatch(assigned[i]) === normForMatch(nonEmpty[i].text)) continue;
35017
- const sp = buildParagraphSplices(nonEmpty[i], assigned[i], ctx.scans[nonEmpty[i].sectionIndex]?.xml);
35342
+ const xml = ctx.scans[nonEmpty[i].sectionIndex]?.xml;
35343
+ const sp = (xml ? minimalTextSplices(nonEmpty[i], xml, normForMatch(nonEmpty[i].text), assigned[i]) : null) ?? buildParagraphSplices(nonEmpty[i], assigned[i], xml);
35018
35344
  if (sp === null) return skip("\uC140 \uBB38\uB2E8\uC5D0 \uD14D\uC2A4\uD2B8 \uB178\uB4DC\uB97C \uB9CC\uB4E4 \uC218 \uC5C6\uC74C");
35019
35345
  splices.push(...sp);
35020
35346
  sectionIndex = nonEmpty[i].sectionIndex;
@@ -35881,7 +36207,13 @@ function patchParagraph(block, orig, edited, ctx, skip) {
35881
36207
  if (sanitizeText(newPlain) !== newPlain) {
35882
36208
  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");
35883
36209
  }
35884
- return stageParaPatch(ctx.scans[mapping.para.sectionIndex], mapping.para, newPlain, skip);
36210
+ let origMd = restoreBr(textUnitToPlain(orig.raw, block));
36211
+ if (block.footnoteText) origMd = origMd.replace(/\s*\(주: [\s\S]*\)$/, "");
36212
+ if (mapping.prefixStripped) {
36213
+ const origPrefix = block.text.split(" ", 1)[0];
36214
+ if (origMd.startsWith(origPrefix + " ")) origMd = origMd.slice(origPrefix.length + 1);
36215
+ }
36216
+ return stageParaPatch(ctx.scans[mapping.para.sectionIndex], mapping.para, newPlain, skip, origMd);
35885
36217
  }
35886
36218
  function patchGfmCells(scanTable, orig, edited, ctx, skip) {
35887
36219
  const origRows = parseGfmTable(orig.lines);
@@ -36197,6 +36529,39 @@ function rebuildCharShape(csData, coreStartUnit) {
36197
36529
  });
36198
36530
  return { buf, count: kept.length };
36199
36531
  }
36532
+ function shiftCharShape(csData, start, end, newLen) {
36533
+ const pairs = [];
36534
+ for (let o = 0; o + 8 <= csData.length; o += 8) pairs.push([csData.readUInt32LE(o), csData.readUInt32LE(o + 4)]);
36535
+ if (pairs.length === 0) return { buf: Buffer.from(csData.subarray(0, 8)), count: 1 };
36536
+ const delta = newLen - (end - start);
36537
+ const out = [];
36538
+ let inRange;
36539
+ for (const [p, id] of pairs) {
36540
+ if (p <= start) out.push([p, id]);
36541
+ else if (p <= end) inRange = id;
36542
+ else {
36543
+ if (inRange !== void 0) {
36544
+ out.push([start + newLen, inRange]);
36545
+ inRange = void 0;
36546
+ }
36547
+ out.push([p + delta, id]);
36548
+ }
36549
+ }
36550
+ if (inRange !== void 0) out.push([start + newLen, inRange]);
36551
+ const kept = [];
36552
+ for (const [p, id] of out) {
36553
+ const last = kept[kept.length - 1];
36554
+ if (last && last[0] === p) last[1] = id;
36555
+ else if (last && last[1] === id) continue;
36556
+ else kept.push([p, id]);
36557
+ }
36558
+ const buf = Buffer.alloc(kept.length * 8);
36559
+ kept.forEach(([p, id], k) => {
36560
+ buf.writeUInt32LE(p >>> 0, k * 8);
36561
+ buf.writeUInt32LE(id >>> 0, k * 8 + 4);
36562
+ });
36563
+ return { buf, count: kept.length };
36564
+ }
36200
36565
  var CRC_TABLE2 = (() => {
36201
36566
  const t = new Uint32Array(256);
36202
36567
  for (let n = 0; n < 256; n++) {
@@ -36235,7 +36600,7 @@ function synthesizeLineSegs(lineSegData, newRaw, startUnits) {
36235
36600
  }
36236
36601
  return { buf: Buffer.concat(segs), count: lines.length };
36237
36602
  }
36238
- function stageParaPatch(scan, para2, newPlain, skip) {
36603
+ function stageParaPatch(scan, para2, newPlain, skip, origPlain) {
36239
36604
  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");
36240
36605
  if (para2.textIdx === -2) return skip("\uBCF5\uC218 PARA_TEXT \uB808\uCF54\uB4DC \uBB38\uB2E8 \u2014 \uBBF8\uC9C0\uC6D0 (v1)");
36241
36606
  if (para2.rangeTagCount > 0) return skip("\uBC94\uC704 \uD0DC\uADF8(\uD615\uAD11\uD39C/\uAD50\uC815\uBD80\uD638) \uBB38\uB2E8 \u2014 \uBBF8\uC9C0\uC6D0 (v1)");
@@ -36277,15 +36642,16 @@ function stageParaPatch(scan, para2, newPlain, skip) {
36277
36642
  return skip(para2.ctrlMask !== 0 ? "\uCEE8\uD2B8\uB864 \uBB38\uC790(\uD0ED/\uD544\uB4DC/\uD2B9\uC218\uACF5\uBC31 \uB4F1 \uD14D\uC2A4\uD2B8 \uC911\uAC04) \uD3EC\uD568 \uBB38\uB2E8 \u2014 \uBBF8\uC9C0\uC6D0 (v1)" : "PARA_TEXT \uC7AC\uAD6C\uC131 \uBD88\uC77C\uCE58 \u2014 \uC6D0\uBB38 \uBCF4\uC874 \uBD88\uAC00\uB85C \uBBF8\uC9C0\uC6D0");
36278
36643
  }
36279
36644
  if (seg.core !== para2.rawText) return skip("PARA_TEXT \uC7AC\uAD6C\uC131 \uBD88\uC77C\uCE58 \u2014 \uC6D0\uBB38 \uBCF4\uC874 \uBD88\uAC00\uB85C \uBBF8\uC9C0\uC6D0");
36645
+ const edit = origPlain !== void 0 && !origPlain.includes("\n") && !newPlain.includes("\n") ? alignedTextEdits(para2.rawText, origPlain, newPlain)?.[0] : void 0;
36280
36646
  const lead = para2.rawText.match(/^\s*/)[0];
36281
36647
  const trail = para2.rawText.match(/\s*$/)[0];
36282
- const newRaw = para2.rawText.trim() === para2.rawText ? newPlain : lead + newPlain + trail;
36648
+ const newRaw = edit ? para2.rawText.slice(0, edit.start) + edit.text + para2.rawText.slice(edit.end) : para2.rawText.trim() === para2.rawText ? newPlain : lead + newPlain + trail;
36283
36649
  const newText = Buffer.concat([seg.prefix, Buffer.from(newRaw, "utf16le"), seg.suffix]);
36284
36650
  scan.repl.set(para2.textIdx, newText);
36285
36651
  const newHeader = Buffer.from(headerRec.data);
36286
36652
  const nChars = seg.prefixUnits + newRaw.length + seg.suffixUnits;
36287
36653
  newHeader.writeUInt32LE((para2.nCharsRaw & 2147483648 | nChars) >>> 0, 0);
36288
- const cs = rebuildCharShape(charShapeRec.data, seg.prefixUnits);
36654
+ const cs = edit ? shiftCharShape(charShapeRec.data, seg.prefixUnits + edit.start, seg.prefixUnits + edit.end, edit.text.length) : rebuildCharShape(charShapeRec.data, seg.prefixUnits);
36289
36655
  scan.repl.set(para2.charShapeIdx, cs.buf);
36290
36656
  newHeader.writeUInt16LE(cs.count, 12);
36291
36657
  if (newRaw.includes("\n")) {
@@ -36387,8 +36753,7 @@ async function patchHwpx(original, editedMarkdown, options) {
36387
36753
  for (let i = 0; i < scans.length; i++) {
36388
36754
  if (sectionSplices[i].length === 0) continue;
36389
36755
  edited.push({ name: sectionPaths[i], xml: scans[i].xml, splices: [...sectionSplices[i]] });
36390
- const claimed = sectionSplices[i].filter((s) => s.end > s.start);
36391
- sectionSplices[i].push(...allLinesegRemovalSplices(scans[i].xml).filter((ls) => !claimed.some((c) => ls.start >= c.start && ls.end <= c.end)));
36756
+ sectionSplices[i].push(...changedLinesegRemovalSplices(scans[i].xml, sectionSplices[i]));
36392
36757
  const newXml = applySplices(scans[i].xml, sectionSplices[i]);
36393
36758
  replacements.set(sectionPaths[i], encoder.encode(newXml));
36394
36759
  }
@@ -36681,9 +37046,13 @@ function patchParagraphUnit(block, orig, edited, ctx, skip) {
36681
37046
  if (block.text && block.text.includes("\n")) {
36682
37047
  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)");
36683
37048
  }
36684
- const origPlain = textUnitToPlain(orig.raw, block);
36685
- let newPlain = textUnitToPlain(edited.raw, block);
37049
+ const origInline = parseEmphasis(textUnitInline(orig.raw, block));
37050
+ const newInline = parseEmphasis(textUnitInline(edited.raw, block));
37051
+ let origPlain = origInline.plain;
37052
+ let newPlain = newInline.plain;
37053
+ const segsUsable = !block.footnoteText && !mapping.noteMarks?.length && !mapping.prefixStripped;
36686
37054
  if (block.footnoteText) {
37055
+ origPlain = origPlain.replace(/\s*\(주: [\s\S]*\)$/, "");
36687
37056
  const noteMatch = newPlain.match(/\s*\(주: ([\s\S]*)\)$/);
36688
37057
  if (noteMatch) {
36689
37058
  newPlain = newPlain.slice(0, noteMatch.index).trimEnd();
@@ -36695,12 +37064,14 @@ function patchParagraphUnit(block, orig, edited, ctx, skip) {
36695
37064
  }
36696
37065
  }
36697
37066
  if (mapping.noteMarks?.length) {
37067
+ origPlain = removeNoteMarks(origPlain, mapping.noteMarks).text;
36698
37068
  const r = removeNoteMarks(newPlain, mapping.noteMarks);
36699
37069
  newPlain = r.text;
36700
37070
  if (r.missing.length) ctx.skipped.push({ reason: "\uAC01\uC8FC \uCC38\uC870 \uBD80\uD638 \uC0AD\uC81C\uB294 \uBBF8\uC9C0\uC6D0 \u2014 \uAC01\uC8FC \uC720\uC9C0, \uBCF8\uBB38\uB9CC \uC801\uC6A9", before: r.missing.join(" ") });
36701
37071
  }
36702
37072
  if (mapping.prefixStripped) {
36703
37073
  const origPrefix = block.text.split(" ", 1)[0];
37074
+ if (origPlain.startsWith(origPrefix + " ")) origPlain = origPlain.slice(origPrefix.length + 1);
36704
37075
  const sp = newPlain.indexOf(" ");
36705
37076
  const newFirst = sp > 0 ? newPlain.slice(0, sp) : newPlain;
36706
37077
  if (newFirst === origPrefix || AUTONUM_PREFIX_RE.test(newFirst)) {
@@ -36710,16 +37081,22 @@ function patchParagraphUnit(block, orig, edited, ctx, skip) {
36710
37081
  }
36711
37082
  }
36712
37083
  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");
36713
- if (sanitizeText(newPlain) !== newPlain) {
37084
+ if (sanitizeText(newPlain) !== newPlain && sanitizeText(origPlain) === origPlain) {
36714
37085
  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");
36715
37086
  }
36716
37087
  const xml = ctx.scans[mapping.para.sectionIndex]?.xml;
36717
- const splices = (xml ? markerRunSplices(mapping.para, xml, newPlain) : null) ?? buildParagraphSplices(mapping.para, newPlain, xml);
37088
+ const splices = (xml ? minimalTextSplices(mapping.para, xml, origPlain, newPlain, segsUsable ? origInline.segs : void 0, segsUsable ? newInline.segs : void 0) : null) ?? (xml ? markerRunSplices(mapping.para, xml, newPlain) : null) ?? buildParagraphSplices(mapping.para, newPlain, xml);
36718
37089
  if (splices === null) return skip("\uBB38\uB2E8\uC5D0 \uD14D\uC2A4\uD2B8 \uB178\uB4DC\uB97C \uB9CC\uB4E4 \uC218 \uC5C6\uC74C");
36719
37090
  ctx.sectionSplices[mapping.para.sectionIndex].push(...splices);
37091
+ if (segsUsable && origInline.segs.length !== newInline.segs.length) {
37092
+ ctx.skipped.push({ reason: "\uAC15\uC870(\uAD75\uAC8C\xB7\uBC11\uC904 \uB4F1) \uCD94\uAC00\xB7\uC0AD\uC81C\uB294 \uBBF8\uC9C0\uC6D0: \uAE00\uB9CC \uC801\uC6A9, \uC6D0\uBB38 \uAE00\uC790 \uBAA8\uC591 \uC720\uC9C0", before: summarize(orig.raw), after: summarize(edited.raw), partial: true });
37093
+ }
36720
37094
  return 1;
36721
37095
  }
36722
37096
  function textUnitToPlain(raw, block) {
37097
+ return parseEmphasis(textUnitInline(raw, block)).plain;
37098
+ }
37099
+ function textUnitInline(raw, block) {
36723
37100
  let text = raw.split("\n").map((l) => l.trim()).filter(Boolean).join(" ");
36724
37101
  if (block.type === "heading" || block.text && /^\[별표\s*\d+/.test(sanitizeText(block.text))) {
36725
37102
  text = text.replace(/^#{1,6}\s+/, "");
@@ -36731,7 +37108,7 @@ function textUnitToPlain(raw, block) {
36731
37108
  if (/^\*[^*][\s\S]*\*$/.test(text) && block.text && /^\([^)]*조[^)]*관련\)$/.test(sanitizeText(block.text))) {
36732
37109
  text = text.slice(1, -1);
36733
37110
  }
36734
- return unescapeGfm(text);
37111
+ return text;
36735
37112
  }
36736
37113
  function diffUnitLists(a, b) {
36737
37114
  const pairs = alignUnits(a.map((u) => u.raw), b.map((u) => u.raw));
@@ -39572,7 +39949,7 @@ var HwpxSession = class _HwpxSession {
39572
39949
  try {
39573
39950
  for (let s = 0; s < st.scans.length; s++) {
39574
39951
  if (sectionSplices[s].length === 0) continue;
39575
- sectionSplices[s].push(...allLinesegRemovalSplices(st.scans[s].xml));
39952
+ sectionSplices[s].push(...changedLinesegRemovalSplices(st.scans[s].xml, sectionSplices[s]));
39576
39953
  replacements.set(st.sectionPaths[s], encoder.encode(applySplices(st.scans[s].xml, sectionSplices[s])));
39577
39954
  }
39578
39955
  } catch (err) {
@@ -42311,7 +42688,7 @@ function scriptsOff(r, off) {
42311
42688
  }
42312
42689
  async function parseImage(buffer, options) {
42313
42690
  try {
42314
- const { parseImageDocument } = await import("./image-ocr-23R7RVHP.js");
42691
+ const { parseImageDocument } = await import("./image-ocr-3C6W3KZO.js");
42315
42692
  const { blocks, warnings } = await parseImageDocument(buffer, options);
42316
42693
  stripScriptTags({ blocks });
42317
42694
  return {
@@ -42371,7 +42748,7 @@ async function parseHwp(buffer, options) {
42371
42748
  async function parsePdf(buffer, options) {
42372
42749
  let parsePdfDocument;
42373
42750
  try {
42374
- const mod = await import("./parser-FXGAKPUI.js");
42751
+ const mod = await import("./parser-56I364YM.js");
42375
42752
  parsePdfDocument = mod.parsePdfDocument;
42376
42753
  } catch {
42377
42754
  return {