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
@@ -1,12 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  blocksToPages
4
- } from "./chunk-TC6DQLYN.js";
4
+ } from "./chunk-2ZGP7A5T.js";
5
5
  import {
6
6
  allLinesegRemovalSplices,
7
7
  applySplices,
8
8
  buildParagraphSplices,
9
9
  buildRangeSplices,
10
+ changedLinesegRemovalSplices,
10
11
  decodeXmlEntities,
11
12
  escapeXmlText,
12
13
  findElementEnd,
@@ -16,7 +17,7 @@ import {
16
17
  patchZipEntries,
17
18
  readZipEntries,
18
19
  scanSectionXml
19
- } from "./chunk-3PCAJWGK.js";
20
+ } from "./chunk-HWIW3WK2.js";
20
21
  import {
21
22
  CONVERT_MAP,
22
23
  FLAG_COMPRESSED,
@@ -67,7 +68,7 @@ import {
67
68
  romanNumeral,
68
69
  simulateWrap,
69
70
  takeTocLeaders
70
- } from "./chunk-46PYORID.js";
71
+ } from "./chunk-QHNVH4TC.js";
71
72
  import {
72
73
  inlineImagesIntoMarkdown
73
74
  } from "./chunk-7FCNOKOR.js";
@@ -82,7 +83,7 @@ import {
82
83
  tidyScriptTags,
83
84
  unframeLayoutTables,
84
85
  wrapScript
85
- } from "./chunk-X6WXU4LA.js";
86
+ } from "./chunk-PTF4NCFM.js";
86
87
  import {
87
88
  parsePageRange
88
89
  } from "./chunk-VQFA55IC.js";
@@ -102,7 +103,7 @@ import {
102
103
  localName,
103
104
  rawTextContent,
104
105
  readZipEntry
105
- } from "./chunk-GK4QLKNT.js";
106
+ } from "./chunk-BG6LUCQL.js";
106
107
  import {
107
108
  MAX_COLS,
108
109
  MAX_ROWS,
@@ -117,7 +118,7 @@ import {
117
118
  hasStructuredCellContent,
118
119
  mapPuaText,
119
120
  noteSuffix
120
- } from "./chunk-RYRUQ73F.js";
121
+ } from "./chunk-RBRHO7WL.js";
121
122
  import {
122
123
  KordocError,
123
124
  classifyError,
@@ -133,7 +134,7 @@ import {
133
134
  toArrayBuffer,
134
135
  unescapeHtml,
135
136
  unzipLimitBytes
136
- } from "./chunk-Z2OOYQ4I.js";
137
+ } from "./chunk-FZMGF6XU.js";
137
138
 
138
139
  // src/table/visual.ts
139
140
  import { readFile as readFile2 } from "fs/promises";
@@ -18793,7 +18794,7 @@ function isKeywordLabel(text) {
18793
18794
  }
18794
18795
  return false;
18795
18796
  }
18796
- function fillInCellPatterns(cellText, values, matchedLabels, blockedLabels) {
18797
+ function fillInCellPatterns(cellText, values, matchedLabels, blockedLabels, annotationSkip) {
18797
18798
  let text = cellText;
18798
18799
  const matches = [];
18799
18800
  text = text.replace(
@@ -18830,7 +18831,7 @@ function fillInCellPatterns(cellText, values, matchedLabels, blockedLabels) {
18830
18831
  (match, keyword) => {
18831
18832
  const normalizedKw = normalizeLabel(keyword);
18832
18833
  const matchKey = values.available(normalizedKw) ? normalizedKw : void 0;
18833
- if (matchKey === void 0) return match;
18834
+ if (matchKey === void 0 || annotationSkip?.has(matchKey)) return match;
18834
18835
  const newValue = values.consume(matchKey);
18835
18836
  matchedLabels.add(matchKey);
18836
18837
  matches.push({ key: matchKey, label: keyword, value: newValue });
@@ -19055,6 +19056,17 @@ function isLabelCell(text) {
19055
19056
  }
19056
19057
  return false;
19057
19058
  }
19059
+ function isBlankValue(text) {
19060
+ return /^[\s_()()\-\u2014\u2013~.·,]*$/.test(text);
19061
+ }
19062
+ function isColumnHeaderRow(heads, below) {
19063
+ if (heads.length < 2 || below.some((b) => b === void 0)) return false;
19064
+ const hs = heads.map((h) => h.trim());
19065
+ if (hs.some((h) => !h || h.length > 40 || SENTENCE_ENDING_RE.test(h))) return false;
19066
+ const blanks = below.filter((b) => isBlankValue(b)).length;
19067
+ if (blanks === below.length) return true;
19068
+ return hs.length >= 3 && blanks >= hs.length - 1 && hs.every((h) => h.length <= 20 && isLabelCell(h));
19069
+ }
19058
19070
  function extractFormFields(blocks) {
19059
19071
  const fields = [];
19060
19072
  let totalTables = 0;
@@ -19087,10 +19099,47 @@ function collectTables(blocks, out = [], depth = 0) {
19087
19099
  }
19088
19100
  return out;
19089
19101
  }
19102
+ function coveredGrid(table2) {
19103
+ const covered = Array.from({ length: table2.rows }, () => new Array(table2.cols).fill(false));
19104
+ for (let r = 0; r < table2.rows; r++) {
19105
+ for (let c = 0; c < table2.cols; c++) {
19106
+ const cell2 = table2.cells[r]?.[c];
19107
+ if (!cell2 || covered[r][c]) continue;
19108
+ for (let rr = r; rr < Math.min(r + cell2.rowSpan, table2.rows); rr++) {
19109
+ for (let cc = c; cc < Math.min(c + cell2.colSpan, table2.cols); cc++) if (rr !== r || cc !== c) covered[rr][cc] = true;
19110
+ }
19111
+ }
19112
+ }
19113
+ return covered;
19114
+ }
19115
+ function columnHeaderRows(table2) {
19116
+ const covered = coveredGrid(table2);
19117
+ const rows = /* @__PURE__ */ new Set();
19118
+ for (let r = 0; r + 1 < table2.rows; r++) {
19119
+ const heads = [];
19120
+ for (let c = 0; c < table2.cols; c++) {
19121
+ const cell2 = table2.cells[r]?.[c];
19122
+ if (cell2 && !covered[r][c] && cell2.rowSpan <= 1) heads.push(c);
19123
+ }
19124
+ const below = heads.map((c) => covered[r + 1][c] ? void 0 : table2.cells[r + 1]?.[c]?.text);
19125
+ if (isColumnHeaderRow(heads.map((c) => table2.cells[r][c].text), below)) rows.add(r);
19126
+ }
19127
+ return rows;
19128
+ }
19090
19129
  function extractFromTable(table2) {
19091
19130
  const fields = [];
19131
+ const headerRows = table2.cols >= 2 ? columnHeaderRows(table2) : /* @__PURE__ */ new Set();
19132
+ const covered = headerRows.size > 0 ? coveredGrid(table2) : [];
19092
19133
  if (table2.cols >= 2) {
19093
19134
  for (let r = 0; r < table2.rows; r++) {
19135
+ if (headerRows.has(r)) {
19136
+ for (let c = 0; c < table2.cols; c++) {
19137
+ const cell2 = table2.cells[r]?.[c];
19138
+ if (!cell2 || covered[r][c] || cell2.rowSpan > 1 || !cell2.text.trim()) continue;
19139
+ fields.push({ label: cell2.text.trim().replace(/[::]\s*$/, ""), value: (table2.cells[r + 1]?.[c]?.text ?? "").trim(), row: r + 1, col: c });
19140
+ }
19141
+ continue;
19142
+ }
19094
19143
  for (let c = 0; c < table2.cols - 1; c++) {
19095
19144
  const labelCell = table2.cells[r]?.[c];
19096
19145
  const valueCell = table2.cells[r]?.[c + 1];
@@ -19494,10 +19543,17 @@ function fillClickHereInXml(xml, cursor, blockedLabels) {
19494
19543
  if (current === replacement) continue;
19495
19544
  splices.push({ start: region.start, end: region.end, replacement });
19496
19545
  }
19546
+ const changedAt = [];
19547
+ let delta = 0;
19548
+ for (const s of [...splices].sort((a, b) => a.start - b.start)) {
19549
+ changedAt.push(s.start + delta);
19550
+ delta += s.replacement.length - (s.end - s.start);
19551
+ }
19497
19552
  return {
19498
19553
  xml: splices.length > 0 ? applySplices(xml, splices) : null,
19499
19554
  filled,
19500
- matchedKeys
19555
+ matchedKeys,
19556
+ changedAt
19501
19557
  };
19502
19558
  }
19503
19559
  async function extractClickHereFields(hwpxBuffer) {
@@ -19520,6 +19576,7 @@ async function extractClickHereFields(hwpxBuffer) {
19520
19576
  }
19521
19577
 
19522
19578
  // src/form/filler-hwpx.ts
19579
+ var ANNOTATION_BLANK_RE = /[((][^))]*[::]\s*[))]/;
19523
19580
  async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19524
19581
  const u8 = new Uint8Array(hwpxBuffer);
19525
19582
  precheckZipSize(hwpxBuffer);
@@ -19538,13 +19595,13 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19538
19595
  const replacements = /* @__PURE__ */ new Map();
19539
19596
  const encoder = new TextEncoder();
19540
19597
  const sectionXmls = /* @__PURE__ */ new Map();
19541
- const fieldModified = /* @__PURE__ */ new Set();
19598
+ const fieldModified = /* @__PURE__ */ new Map();
19542
19599
  const fieldMatchedKeys = /* @__PURE__ */ new Set();
19543
19600
  for (const p of sectionPaths) {
19544
19601
  const xml = await zip.file(p).async("text");
19545
19602
  const outcome = fillClickHereInXml(xml, cursor, blockedLabels);
19546
19603
  sectionXmls.set(p, outcome.xml ?? xml);
19547
- if (outcome.xml !== null) fieldModified.add(p);
19604
+ if (outcome.xml !== null) fieldModified.set(p, outcome.changedAt);
19548
19605
  for (const f of outcome.filled) filled.push(f);
19549
19606
  for (const k of outcome.matchedKeys) fieldMatchedKeys.add(k);
19550
19607
  }
@@ -19552,9 +19609,31 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19552
19609
  matchedLabels.add(k);
19553
19610
  normalizedValues.delete(k);
19554
19611
  }
19612
+ const scans = sectionPaths.map((p, si) => scanSectionXml(sectionXmls.get(p), si));
19613
+ const annotationSkip = /* @__PURE__ */ new Set();
19614
+ for (let si = 0; si < scans.length; si++) {
19615
+ const xml = sectionXmls.get(sectionPaths[si]);
19616
+ for (const table2 of collectAllTables(scans[si])) {
19617
+ for (const row of table2.rows) {
19618
+ for (const cell2 of row) {
19619
+ const t = cell2.paragraphs.filter((p) => !p.inTextbox).map((p) => paraTText(p, xml) ?? p.text).join("");
19620
+ if (!isLabelCell(t) || ANNOTATION_BLANK_RE.test(t)) continue;
19621
+ const key = findMatchingKey(normalizeLabel(t), cursor);
19622
+ if (key !== void 0 && !cursor.isArray(key)) annotationSkip.add(key);
19623
+ }
19624
+ }
19625
+ }
19626
+ for (const para2 of scans[si].bodyParagraphs) {
19627
+ for (const seg of scanInlineSegments(paraTText(para2, xml) ?? para2.text)) {
19628
+ const key = matchInlineSegment(seg, cursor, blockedLabels)?.key;
19629
+ if (key !== void 0 && !cursor.isArray(key)) annotationSkip.add(key);
19630
+ }
19631
+ }
19632
+ }
19633
+ const firstTarget = /* @__PURE__ */ new Map();
19555
19634
  for (let si = 0; si < sectionPaths.length; si++) {
19556
19635
  const xml = sectionXmls.get(sectionPaths[si]);
19557
- const scan = scanSectionXml(xml, si);
19636
+ const scan = scans[si];
19558
19637
  const ledger = /* @__PURE__ */ new Map();
19559
19638
  const led = (p) => {
19560
19639
  let l = ledger.get(p);
@@ -19563,25 +19642,14 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19563
19642
  };
19564
19643
  const matchText = (p) => paraTText(p, xml) ?? p.text;
19565
19644
  const cellLabelText = (cell2) => cell2.paragraphs.filter((p) => !p.inTextbox).map((p) => matchText(p)).join("");
19566
- const allTables = [];
19567
- const collectTables2 = (tables, depth) => {
19568
- if (depth > 16) return;
19569
- for (const t of tables) {
19570
- allTables.push(t);
19571
- for (const row of t.rows) {
19572
- for (const cell2 of row) collectTables2(cell2.tables, depth + 1);
19573
- }
19574
- }
19575
- };
19576
- collectTables2(scan.tables, 0);
19577
- collectTables2(scan.orphanTables, 0);
19645
+ const allTables = collectAllTables(scan);
19578
19646
  const patternApplied = /* @__PURE__ */ new Set();
19579
19647
  for (const table2 of allTables) {
19580
19648
  for (const row of table2.rows) {
19581
19649
  for (const cell2 of row) {
19582
19650
  for (const para2 of cell2.paragraphs) {
19583
19651
  const text = matchText(para2);
19584
- const result = fillInCellPatterns(text, cursor, matchedLabels, blockedLabels);
19652
+ const result = fillInCellPatterns(text, cursor, matchedLabels, blockedLabels, annotationSkip);
19585
19653
  if (!result) continue;
19586
19654
  const l = led(para2);
19587
19655
  if (l.fullText !== void 0) continue;
@@ -19605,29 +19673,69 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19605
19673
  }
19606
19674
  }
19607
19675
  }
19676
+ const isForeignLabel = (text) => {
19677
+ if (isKeywordLabel(text)) return true;
19678
+ const t = text.trim();
19679
+ if (/^[①-⑳]/.test(t) && t.length <= 20) return true;
19680
+ if (ANNOTATION_BLANK_RE.test(t)) return false;
19681
+ const n = normalizeLabel(t);
19682
+ return !!n && cursor.has(n);
19683
+ };
19684
+ const laterOk = (key, current) => cursor.isArray(key) || !firstTarget.has(key) || isBlankValue(current) || current.trim() === firstTarget.get(key);
19685
+ const markFirst = (key, current) => {
19686
+ if (!cursor.isArray(key) && !firstTarget.has(key)) firstTarget.set(key, current.trim());
19687
+ };
19688
+ const fillInLabelCell = (cell2, labelText, key, rowIdx, colIdx) => {
19689
+ if (cell2.colSpan < 2) return;
19690
+ if (!cursor.isArray(key) && matchedLabels.has(key)) return;
19691
+ const paras = cell2.paragraphs.filter((p) => !p.inTextbox && matchText(p).trim());
19692
+ if (paras.length !== 1 || cell2.tables.length > 0) return;
19693
+ const l = led(paras[0]);
19694
+ if (l.fullText !== void 0 || l.ranges.length > 0) return;
19695
+ const value = cursor.consume(key);
19696
+ if (value === void 0) return;
19697
+ const text = matchText(paras[0]);
19698
+ l.ranges.push({ start: text.trimEnd().length, end: text.length, replacement: " " + value });
19699
+ l.filledIdx.push(filled.length);
19700
+ l.matchKeys.push(key);
19701
+ matchedLabels.add(key);
19702
+ markFirst(key, labelText);
19703
+ filled.push({ label: labelText.trim().replace(/[::]\s*$/, ""), value, row: rowIdx, col: colIdx, key });
19704
+ };
19608
19705
  for (const table2 of allTables) {
19609
- const skipHeaderRow = table2.rows.length >= 2 && (() => {
19610
- const first = table2.rows[0];
19611
- const allLabels = first.length > 0 && first.every((cell2) => {
19612
- const t = cellLabelText(cell2).trim();
19613
- return t.length > 0 && t.length <= 20 && isLabelCell(t);
19614
- });
19615
- if (!allLabels) return false;
19706
+ const firstRowAllLabels = table2.rows.length >= 2 && table2.rows[0].length > 0 && table2.rows[0].every((cell2) => {
19707
+ const t = cellLabelText(cell2).trim();
19708
+ return t.length > 0 && t.length <= 20 && isLabelCell(t);
19709
+ });
19710
+ const headerRows = /* @__PURE__ */ new Set();
19711
+ for (let r = 0; r + 1 < table2.rows.length; r++) {
19712
+ const heads = table2.rows[r].filter((c) => c.rowSpan <= 1);
19713
+ const below = heads.map((h) => table2.rows[r + 1].find((c) => c.colAddr === h.colAddr));
19714
+ if (isColumnHeaderRow(heads.map(cellLabelText), below.map((b) => b ? cellLabelText(b) : void 0))) headerRows.add(r);
19715
+ }
19716
+ const skipRows = new Set(headerRows);
19717
+ if (firstRowAllLabels) {
19616
19718
  const d0 = table2.rows[1][0];
19617
- return d0 === void 0 || !isLabelCell(cellLabelText(d0));
19618
- })();
19619
- for (let rowIdx = skipHeaderRow ? 1 : 0; rowIdx < table2.rows.length; rowIdx++) {
19719
+ if (d0 === void 0 || !isLabelCell(cellLabelText(d0))) skipRows.add(0);
19720
+ }
19721
+ for (let rowIdx = 0; rowIdx < table2.rows.length; rowIdx++) {
19722
+ if (skipRows.has(rowIdx)) continue;
19620
19723
  const cells = table2.rows[rowIdx];
19621
- for (let colIdx = 0; colIdx < cells.length - 1; colIdx++) {
19724
+ for (let colIdx = 0; colIdx < cells.length; colIdx++) {
19622
19725
  const labelText = cellLabelText(cells[colIdx]);
19623
19726
  if (!isLabelCell(labelText)) continue;
19624
- const valueCell = cells[colIdx + 1];
19625
- if (isKeywordLabel(cellLabelText(valueCell))) continue;
19626
19727
  const normalizedCellLabel = normalizeLabel(labelText);
19627
19728
  if (!normalizedCellLabel) continue;
19628
19729
  if (blockedLabels?.has(normalizedCellLabel)) continue;
19629
19730
  const matchKey = findMatchingKey(normalizedCellLabel, cursor);
19630
19731
  if (matchKey === void 0) continue;
19732
+ const valueCell = cells[colIdx + 1];
19733
+ const valueText = valueCell ? cellLabelText(valueCell) : "";
19734
+ if (!valueCell || isForeignLabel(valueText)) {
19735
+ fillInLabelCell(cells[colIdx], labelText, matchKey, rowIdx, colIdx);
19736
+ continue;
19737
+ }
19738
+ if (!laterOk(matchKey, valueText)) continue;
19631
19739
  if (patternApplied.has(valueCell)) {
19632
19740
  const target = valueCell.paragraphs.find((p) => p.tRanges.length > 0) ?? valueCell.paragraphs[0];
19633
19741
  if (!target) continue;
@@ -19639,6 +19747,7 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19639
19747
  l.filledIdx.push(filled.length);
19640
19748
  l.matchKeys.push(matchKey);
19641
19749
  matchedLabels.add(matchKey);
19750
+ markFirst(matchKey, valueText);
19642
19751
  filled.push({
19643
19752
  label: labelText.trim().replace(/[::]\s*$/, ""),
19644
19753
  value: newValue,
@@ -19662,6 +19771,7 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19662
19771
  lk.ranges = [];
19663
19772
  }
19664
19773
  matchedLabels.add(matchKey);
19774
+ markFirst(matchKey, valueText);
19665
19775
  filled.push({
19666
19776
  label: labelText.trim().replace(/[::]\s*$/, ""),
19667
19777
  value: newValue,
@@ -19672,65 +19782,67 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19672
19782
  }
19673
19783
  }
19674
19784
  }
19675
- if (table2.rows.length >= 2) {
19676
- const headerCells = table2.rows[0];
19677
- const allLabels = headerCells.length > 0 && headerCells.every((cell2) => {
19678
- const t = cellLabelText(cell2).trim();
19679
- return t.length > 0 && t.length <= 20 && isLabelCell(t);
19680
- });
19681
- if (allLabels) {
19682
- for (let rowIdx = 1; rowIdx < table2.rows.length; rowIdx++) {
19683
- const dataCells = table2.rows[rowIdx];
19684
- for (let colIdx = 0; colIdx < Math.min(headerCells.length, dataCells.length); colIdx++) {
19685
- const headerLabel = normalizeLabel(cellLabelText(headerCells[colIdx]));
19686
- if (blockedLabels?.has(headerLabel)) continue;
19687
- const matchKey = findMatchingKey(headerLabel, cursor);
19688
- if (matchKey === void 0) continue;
19689
- if (!cursor.isArray(matchKey) && matchedLabels.has(matchKey)) continue;
19690
- const dataCell = dataCells[colIdx];
19691
- if (patternApplied.has(dataCell)) {
19692
- const target = dataCell.paragraphs.find((p) => p.tRanges.length > 0) ?? dataCell.paragraphs[0];
19693
- if (!target) continue;
19694
- const l = led(target);
19695
- if (l.fullText !== void 0) continue;
19696
- const newValue2 = cursor.consume(matchKey);
19697
- if (newValue2 === void 0) continue;
19698
- l.ranges.push({ start: 0, end: 0, replacement: newValue2 + " " });
19699
- l.filledIdx.push(filled.length);
19700
- l.matchKeys.push(matchKey);
19701
- matchedLabels.add(matchKey);
19702
- filled.push({
19703
- label: cellLabelText(headerCells[colIdx]).trim(),
19704
- value: newValue2,
19705
- row: rowIdx,
19706
- col: colIdx,
19707
- key: matchKey
19708
- });
19709
- continue;
19710
- }
19711
- const newValue = cursor.consume(matchKey);
19712
- if (newValue === void 0) continue;
19713
- const paras = dataCell.paragraphs;
19714
- if (paras.length === 0) continue;
19715
- const l0 = led(paras[0]);
19716
- l0.fullText = newValue;
19717
- l0.ranges = [];
19718
- l0.filledIdx.push(filled.length);
19719
- l0.matchKeys.push(matchKey);
19720
- for (let k = 1; k < paras.length; k++) {
19721
- const lk = led(paras[k]);
19722
- lk.fullText = "";
19723
- lk.ranges = [];
19724
- }
19785
+ const verticalRows = new Set(headerRows);
19786
+ if (firstRowAllLabels) verticalRows.add(0);
19787
+ for (const h of [...verticalRows].sort((a, b) => a - b)) {
19788
+ const headerCells = table2.rows[h];
19789
+ const scalarSeen = /* @__PURE__ */ new Set();
19790
+ for (let rowIdx = h + 1; rowIdx < table2.rows.length && !verticalRows.has(rowIdx); rowIdx++) {
19791
+ const dataCells = table2.rows[rowIdx];
19792
+ for (let colIdx = 0; colIdx < headerCells.length; colIdx++) {
19793
+ const dataCell = dataCells.find((c) => c.colAddr === headerCells[colIdx].colAddr);
19794
+ if (!dataCell) continue;
19795
+ const headerLabel = normalizeLabel(cellLabelText(headerCells[colIdx]));
19796
+ if (!headerLabel || blockedLabels?.has(headerLabel)) continue;
19797
+ const matchKey = findMatchingKey(headerLabel, cursor);
19798
+ if (matchKey === void 0) continue;
19799
+ if (!cursor.isArray(matchKey) && (matchedLabels.has(matchKey) || scalarSeen.has(colIdx))) continue;
19800
+ if (!cursor.isArray(matchKey)) scalarSeen.add(colIdx);
19801
+ if (isForeignLabel(cellLabelText(dataCell))) continue;
19802
+ if (patternApplied.has(dataCell)) {
19803
+ const target = dataCell.paragraphs.find((p) => p.tRanges.length > 0) ?? dataCell.paragraphs[0];
19804
+ if (!target) continue;
19805
+ const l = led(target);
19806
+ if (l.fullText !== void 0) continue;
19807
+ const newValue2 = cursor.consume(matchKey);
19808
+ if (newValue2 === void 0) continue;
19809
+ l.ranges.push({ start: 0, end: 0, replacement: newValue2 + " " });
19810
+ l.filledIdx.push(filled.length);
19811
+ l.matchKeys.push(matchKey);
19725
19812
  matchedLabels.add(matchKey);
19813
+ markFirst(matchKey, cellLabelText(dataCell));
19726
19814
  filled.push({
19727
19815
  label: cellLabelText(headerCells[colIdx]).trim(),
19728
- value: newValue,
19816
+ value: newValue2,
19729
19817
  row: rowIdx,
19730
19818
  col: colIdx,
19731
19819
  key: matchKey
19732
19820
  });
19821
+ continue;
19822
+ }
19823
+ const newValue = cursor.consume(matchKey);
19824
+ if (newValue === void 0) continue;
19825
+ const paras = dataCell.paragraphs;
19826
+ if (paras.length === 0) continue;
19827
+ const l0 = led(paras[0]);
19828
+ l0.fullText = newValue;
19829
+ l0.ranges = [];
19830
+ l0.filledIdx.push(filled.length);
19831
+ l0.matchKeys.push(matchKey);
19832
+ for (let k = 1; k < paras.length; k++) {
19833
+ const lk = led(paras[k]);
19834
+ lk.fullText = "";
19835
+ lk.ranges = [];
19733
19836
  }
19837
+ matchedLabels.add(matchKey);
19838
+ markFirst(matchKey, cellLabelText(dataCell));
19839
+ filled.push({
19840
+ label: cellLabelText(headerCells[colIdx]).trim(),
19841
+ value: newValue,
19842
+ row: rowIdx,
19843
+ col: colIdx,
19844
+ key: matchKey
19845
+ });
19734
19846
  }
19735
19847
  }
19736
19848
  }
@@ -19746,9 +19858,11 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19746
19858
  const matched = matches[i];
19747
19859
  if (matched === void 0) continue;
19748
19860
  const matchKey = matched.key;
19861
+ const ve = clampSegmentEnd(text, seg, segments[i + 1], matches[i + 1]?.viaExt ?? false);
19862
+ if (!laterOk(matchKey, text.slice(seg.valueStart, ve))) continue;
19749
19863
  const newValue = cursor.consume(matchKey);
19750
19864
  if (newValue === void 0) continue;
19751
- const ve = clampSegmentEnd(text, seg, segments[i + 1], matches[i + 1]?.viaExt ?? false);
19865
+ markFirst(matchKey, text.slice(seg.valueStart, ve));
19752
19866
  const replacement = seg.valueStart === ve ? padInsertion(text, seg.valueStart, newValue) : newValue;
19753
19867
  const l = led(para2);
19754
19868
  l.ranges.push({ start: seg.valueStart, end: ve, replacement });
@@ -19802,8 +19916,10 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19802
19916
  for (const k of l.matchKeys) succeededKeys.add(k);
19803
19917
  splices.push(...paraSplices);
19804
19918
  }
19805
- if (splices.length > 0 || fieldModified.has(sectionPaths[si])) {
19806
- splices.push(...allLinesegRemovalSplices(xml));
19919
+ const fieldAt = fieldModified.get(sectionPaths[si]);
19920
+ if (splices.length > 0 || fieldAt) {
19921
+ const marks = (fieldAt ?? []).map((at) => ({ start: at, end: at, replacement: "" }));
19922
+ splices.push(...changedLinesegRemovalSplices(xml, [...splices, ...marks]));
19807
19923
  replacements.set(sectionPaths[si], encoder.encode(applySplices(xml, splices)));
19808
19924
  }
19809
19925
  }
@@ -19820,6 +19936,21 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19820
19936
  ...warnings.length > 0 ? { warnings } : {}
19821
19937
  };
19822
19938
  }
19939
+ function collectAllTables(scan) {
19940
+ const out = [];
19941
+ const walk = (tables, depth) => {
19942
+ if (depth > 16) return;
19943
+ for (const t of tables) {
19944
+ out.push(t);
19945
+ for (const row of t.rows) {
19946
+ for (const cell2 of row) walk(cell2.tables, depth + 1);
19947
+ }
19948
+ }
19949
+ };
19950
+ walk(scan.tables, 0);
19951
+ walk(scan.orphanTables, 0);
19952
+ return out;
19953
+ }
19823
19954
 
19824
19955
  // src/table/classifier.ts
19825
19956
  var DIAGRAM_KEYWORDS = /조직도|비상\s*연락망|연락망|체계도|업무\s*체계도|기구표|배치도|흐름도|추진\s*체계/u;
@@ -26816,7 +26947,7 @@ function parseCharPrs(headerDoc, hangulFonts) {
26816
26947
  if (color) def.textColor = color;
26817
26948
  if (cp.getAttribute("bold") === "1") def.bold = true;
26818
26949
  if (cp.getAttribute("italic") === "1") def.italic = true;
26819
- if (findChildByLocalName(cp, "underline")) def.underline = true;
26950
+ if (findChildByLocalName(cp, "underline")?.getAttribute("type") === "BOTTOM") def.underline = true;
26820
26951
  const fontRef = findChildByLocalName(cp, "fontRef");
26821
26952
  const hangul = fontRef?.getAttribute("hangul");
26822
26953
  if (hangul) {
@@ -28146,6 +28277,163 @@ function buildEmbeddedLineSplices(para2, xml, newLines) {
28146
28277
  return splices;
28147
28278
  }
28148
28279
 
28280
+ // src/roundtrip/inline-edit.ts
28281
+ var ESCAPABLE = /* @__PURE__ */ new Set(["~", "*", "_", "`", "|", "#", "<", "$", "\\"]);
28282
+ var isWs = (c) => c !== void 0 && /\s/.test(c);
28283
+ function parseEmphasis(text) {
28284
+ const toks = [];
28285
+ const pushText = (s, code = false) => {
28286
+ const last = toks[toks.length - 1];
28287
+ if (last && last.kind === "text" && !!last.code === code) last.text += s;
28288
+ else toks.push({ kind: "text", text: s, code });
28289
+ };
28290
+ for (let i = 0; i < text.length; ) {
28291
+ const c = text[i];
28292
+ if (c === "\\" && ESCAPABLE.has(text[i + 1])) {
28293
+ pushText(text[i + 1]);
28294
+ i += 2;
28295
+ continue;
28296
+ }
28297
+ if (c === "`") {
28298
+ const close = text.indexOf("`", i + 1);
28299
+ if (close > i + 1) {
28300
+ pushText(text.slice(i + 1, close), true);
28301
+ i = close + 1;
28302
+ continue;
28303
+ }
28304
+ }
28305
+ if (text.startsWith("<u>", i)) {
28306
+ toks.push({ kind: "u-open", text: "<u>" });
28307
+ i += 3;
28308
+ continue;
28309
+ }
28310
+ if (text.startsWith("</u>", i)) {
28311
+ toks.push({ kind: "u-close", text: "</u>" });
28312
+ i += 4;
28313
+ continue;
28314
+ }
28315
+ if (text.startsWith("~~", i)) {
28316
+ toks.push({ kind: "strike", text: "~~" });
28317
+ i += 2;
28318
+ continue;
28319
+ }
28320
+ if (c === "*") {
28321
+ let j = i;
28322
+ while (text[j] === "*") j++;
28323
+ toks.push({ kind: "star", text: text.slice(i, j), n: j - i });
28324
+ i = j;
28325
+ continue;
28326
+ }
28327
+ pushText(c);
28328
+ i++;
28329
+ }
28330
+ const charBefore = (k) => {
28331
+ const t = toks[k - 1];
28332
+ return t?.kind === "text" ? t.text[t.text.length - 1] : t ? "x" : void 0;
28333
+ };
28334
+ const charAfter = (k) => {
28335
+ const t = toks[k + 1];
28336
+ return t?.kind === "text" ? t.text[0] : t ? "x" : void 0;
28337
+ };
28338
+ const stack = [];
28339
+ for (let k = 0; k < toks.length; k++) {
28340
+ const t = toks[k];
28341
+ if (t.kind === "text") continue;
28342
+ const top = stack.length ? toks[stack[stack.length - 1]] : void 0;
28343
+ const canClose = t.kind === "u-close" || (t.kind === "star" || t.kind === "strike") && charBefore(k) !== void 0 && !isWs(charBefore(k));
28344
+ 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);
28345
+ if (canClose && matches) {
28346
+ top.paired = true;
28347
+ t.paired = true;
28348
+ stack.pop();
28349
+ continue;
28350
+ }
28351
+ const canOpen = t.kind === "u-open" || (t.kind === "star" || t.kind === "strike") && charAfter(k) !== void 0 && !isWs(charAfter(k));
28352
+ if (canOpen) stack.push(k);
28353
+ }
28354
+ const segs = [];
28355
+ let cur = "";
28356
+ const cut = () => {
28357
+ if (cur) segs.push(cur);
28358
+ cur = "";
28359
+ };
28360
+ for (const t of toks) {
28361
+ if (t.kind !== "text" && t.paired) {
28362
+ cut();
28363
+ continue;
28364
+ }
28365
+ if (t.code) {
28366
+ cut();
28367
+ segs.push(t.text);
28368
+ continue;
28369
+ }
28370
+ cur += t.text;
28371
+ }
28372
+ cut();
28373
+ return { plain: segs.join(""), segs };
28374
+ }
28375
+ function alignToRaw(raw, norm2) {
28376
+ const pos = new Array(norm2.length);
28377
+ let j = 0;
28378
+ for (let i = 0; i < norm2.length; i++) {
28379
+ for (; ; ) {
28380
+ if (j >= raw.length) return null;
28381
+ const a = norm2[i], b = raw[j];
28382
+ if (a === b || isWs(a) && isWs(b)) break;
28383
+ if (isWs(b)) {
28384
+ j++;
28385
+ continue;
28386
+ }
28387
+ return null;
28388
+ }
28389
+ pos[i] = j++;
28390
+ }
28391
+ if (raw.slice(j).trim() !== "") return null;
28392
+ return pos;
28393
+ }
28394
+ function commonEnds(a, b) {
28395
+ let p = 0;
28396
+ while (p < a.length && p < b.length && a[p] === b[p]) p++;
28397
+ let s = 0;
28398
+ while (s < a.length - p && s < b.length - p && a[a.length - 1 - s] === b[b.length - 1 - s]) s++;
28399
+ return { p, s };
28400
+ }
28401
+ function alignedTextEdits(raw, origNorm, newNorm, origSegs, newSegs) {
28402
+ if (!origNorm) return null;
28403
+ const pos = alignToRaw(raw, origNorm);
28404
+ if (!pos) return null;
28405
+ const ranges = [];
28406
+ const diffInto = (o, n, base) => {
28407
+ if (o === n) return;
28408
+ const { p, s } = commonEnds(o, n);
28409
+ ranges.push({ a: base + p, b: base + o.length - s, text: n.slice(p, n.length - s) });
28410
+ };
28411
+ if (origSegs && newSegs && origSegs.length === newSegs.length && origSegs.length > 1 && origSegs.join("") === origNorm && newSegs.join("") === newNorm) {
28412
+ let base = 0;
28413
+ for (let k = 0; k < origSegs.length; k++) {
28414
+ diffInto(origSegs[k], newSegs[k], base);
28415
+ base += origSegs[k].length;
28416
+ }
28417
+ } else {
28418
+ diffInto(origNorm, newNorm, 0);
28419
+ }
28420
+ const at = (a) => a < pos.length ? pos[a] : pos[pos.length - 1] + 1;
28421
+ return ranges.map((r) => ({ start: at(r.a), end: r.b > r.a ? pos[r.b - 1] + 1 : at(r.a), text: r.text }));
28422
+ }
28423
+ function minimalTextSplices(para2, xml, origPlain, newPlain, origSegs, newSegs) {
28424
+ const raw = paraTText(para2, xml);
28425
+ if (raw === null) return null;
28426
+ const edits = alignedTextEdits(raw, origPlain, newPlain, origSegs, newSegs);
28427
+ if (!edits || edits.length === 0) return null;
28428
+ const out = [];
28429
+ for (const e of edits) {
28430
+ const sp = buildRangeSplices(para2, xml, e.start, e.end, e.text);
28431
+ if (!sp) return null;
28432
+ out.push(...sp);
28433
+ }
28434
+ return out;
28435
+ }
28436
+
28149
28437
  // src/roundtrip/table-patch.ts
28150
28438
  function patchGfmTable(table2, scanTable, orig, edited, ctx, skip) {
28151
28439
  const replica = replicateGfmTable(table2);
@@ -28462,7 +28750,8 @@ function applyCellEdit(table2, scanTable, gridR, gridC, newLines, ctx, before, a
28462
28750
  }
28463
28751
  for (let i = 0; i < nonEmpty.length; i++) {
28464
28752
  if (assigned[i] === nonEmpty[i].text || normForMatch(assigned[i]) === normForMatch(nonEmpty[i].text)) continue;
28465
- const sp = buildParagraphSplices(nonEmpty[i], assigned[i], ctx.scans[nonEmpty[i].sectionIndex]?.xml);
28753
+ const xml = ctx.scans[nonEmpty[i].sectionIndex]?.xml;
28754
+ const sp = (xml ? minimalTextSplices(nonEmpty[i], xml, normForMatch(nonEmpty[i].text), assigned[i]) : null) ?? buildParagraphSplices(nonEmpty[i], assigned[i], xml);
28466
28755
  if (sp === null) return skip("\uC140 \uBB38\uB2E8\uC5D0 \uD14D\uC2A4\uD2B8 \uB178\uB4DC\uB97C \uB9CC\uB4E4 \uC218 \uC5C6\uC74C");
28467
28756
  splices.push(...sp);
28468
28757
  sectionIndex = nonEmpty[i].sectionIndex;
@@ -29334,7 +29623,13 @@ function patchParagraph(block, orig, edited, ctx, skip) {
29334
29623
  if (sanitizeText(newPlain) !== newPlain) {
29335
29624
  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");
29336
29625
  }
29337
- return stageParaPatch(ctx.scans[mapping.para.sectionIndex], mapping.para, newPlain, skip);
29626
+ let origMd = restoreBr(textUnitToPlain(orig.raw, block));
29627
+ if (block.footnoteText) origMd = origMd.replace(/\s*\(주: [\s\S]*\)$/, "");
29628
+ if (mapping.prefixStripped) {
29629
+ const origPrefix = block.text.split(" ", 1)[0];
29630
+ if (origMd.startsWith(origPrefix + " ")) origMd = origMd.slice(origPrefix.length + 1);
29631
+ }
29632
+ return stageParaPatch(ctx.scans[mapping.para.sectionIndex], mapping.para, newPlain, skip, origMd);
29338
29633
  }
29339
29634
  function patchGfmCells(scanTable, orig, edited, ctx, skip) {
29340
29635
  const origRows = parseGfmTable(orig.lines);
@@ -29650,6 +29945,39 @@ function rebuildCharShape(csData, coreStartUnit) {
29650
29945
  });
29651
29946
  return { buf, count: kept.length };
29652
29947
  }
29948
+ function shiftCharShape(csData, start, end, newLen) {
29949
+ const pairs = [];
29950
+ for (let o = 0; o + 8 <= csData.length; o += 8) pairs.push([csData.readUInt32LE(o), csData.readUInt32LE(o + 4)]);
29951
+ if (pairs.length === 0) return { buf: Buffer.from(csData.subarray(0, 8)), count: 1 };
29952
+ const delta = newLen - (end - start);
29953
+ const out = [];
29954
+ let inRange;
29955
+ for (const [p, id] of pairs) {
29956
+ if (p <= start) out.push([p, id]);
29957
+ else if (p <= end) inRange = id;
29958
+ else {
29959
+ if (inRange !== void 0) {
29960
+ out.push([start + newLen, inRange]);
29961
+ inRange = void 0;
29962
+ }
29963
+ out.push([p + delta, id]);
29964
+ }
29965
+ }
29966
+ if (inRange !== void 0) out.push([start + newLen, inRange]);
29967
+ const kept = [];
29968
+ for (const [p, id] of out) {
29969
+ const last = kept[kept.length - 1];
29970
+ if (last && last[0] === p) last[1] = id;
29971
+ else if (last && last[1] === id) continue;
29972
+ else kept.push([p, id]);
29973
+ }
29974
+ const buf = Buffer.alloc(kept.length * 8);
29975
+ kept.forEach(([p, id], k) => {
29976
+ buf.writeUInt32LE(p >>> 0, k * 8);
29977
+ buf.writeUInt32LE(id >>> 0, k * 8 + 4);
29978
+ });
29979
+ return { buf, count: kept.length };
29980
+ }
29653
29981
  var CRC_TABLE = (() => {
29654
29982
  const t = new Uint32Array(256);
29655
29983
  for (let n = 0; n < 256; n++) {
@@ -29688,7 +30016,7 @@ function synthesizeLineSegs(lineSegData, newRaw, startUnits) {
29688
30016
  }
29689
30017
  return { buf: Buffer.concat(segs), count: lines.length };
29690
30018
  }
29691
- function stageParaPatch(scan, para2, newPlain, skip) {
30019
+ function stageParaPatch(scan, para2, newPlain, skip, origPlain) {
29692
30020
  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");
29693
30021
  if (para2.textIdx === -2) return skip("\uBCF5\uC218 PARA_TEXT \uB808\uCF54\uB4DC \uBB38\uB2E8 \u2014 \uBBF8\uC9C0\uC6D0 (v1)");
29694
30022
  if (para2.rangeTagCount > 0) return skip("\uBC94\uC704 \uD0DC\uADF8(\uD615\uAD11\uD39C/\uAD50\uC815\uBD80\uD638) \uBB38\uB2E8 \u2014 \uBBF8\uC9C0\uC6D0 (v1)");
@@ -29730,15 +30058,16 @@ function stageParaPatch(scan, para2, newPlain, skip) {
29730
30058
  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");
29731
30059
  }
29732
30060
  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");
30061
+ const edit = origPlain !== void 0 && !origPlain.includes("\n") && !newPlain.includes("\n") ? alignedTextEdits(para2.rawText, origPlain, newPlain)?.[0] : void 0;
29733
30062
  const lead = para2.rawText.match(/^\s*/)[0];
29734
30063
  const trail = para2.rawText.match(/\s*$/)[0];
29735
- const newRaw = para2.rawText.trim() === para2.rawText ? newPlain : lead + newPlain + trail;
30064
+ 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;
29736
30065
  const newText = Buffer.concat([seg.prefix, Buffer.from(newRaw, "utf16le"), seg.suffix]);
29737
30066
  scan.repl.set(para2.textIdx, newText);
29738
30067
  const newHeader = Buffer.from(headerRec.data);
29739
30068
  const nChars = seg.prefixUnits + newRaw.length + seg.suffixUnits;
29740
30069
  newHeader.writeUInt32LE((para2.nCharsRaw & 2147483648 | nChars) >>> 0, 0);
29741
- const cs = rebuildCharShape(charShapeRec.data, seg.prefixUnits);
30070
+ const cs = edit ? shiftCharShape(charShapeRec.data, seg.prefixUnits + edit.start, seg.prefixUnits + edit.end, edit.text.length) : rebuildCharShape(charShapeRec.data, seg.prefixUnits);
29742
30071
  scan.repl.set(para2.charShapeIdx, cs.buf);
29743
30072
  newHeader.writeUInt16LE(cs.count, 12);
29744
30073
  if (newRaw.includes("\n")) {
@@ -29840,8 +30169,7 @@ async function patchHwpx(original, editedMarkdown, options) {
29840
30169
  for (let i = 0; i < scans.length; i++) {
29841
30170
  if (sectionSplices[i].length === 0) continue;
29842
30171
  edited.push({ name: sectionPaths[i], xml: scans[i].xml, splices: [...sectionSplices[i]] });
29843
- const claimed = sectionSplices[i].filter((s) => s.end > s.start);
29844
- sectionSplices[i].push(...allLinesegRemovalSplices(scans[i].xml).filter((ls) => !claimed.some((c) => ls.start >= c.start && ls.end <= c.end)));
30172
+ sectionSplices[i].push(...changedLinesegRemovalSplices(scans[i].xml, sectionSplices[i]));
29845
30173
  const newXml = applySplices(scans[i].xml, sectionSplices[i]);
29846
30174
  replacements.set(sectionPaths[i], encoder.encode(newXml));
29847
30175
  }
@@ -30134,9 +30462,13 @@ function patchParagraphUnit(block, orig, edited, ctx, skip) {
30134
30462
  if (block.text && block.text.includes("\n")) {
30135
30463
  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)");
30136
30464
  }
30137
- const origPlain = textUnitToPlain(orig.raw, block);
30138
- let newPlain = textUnitToPlain(edited.raw, block);
30465
+ const origInline = parseEmphasis(textUnitInline(orig.raw, block));
30466
+ const newInline = parseEmphasis(textUnitInline(edited.raw, block));
30467
+ let origPlain = origInline.plain;
30468
+ let newPlain = newInline.plain;
30469
+ const segsUsable = !block.footnoteText && !mapping.noteMarks?.length && !mapping.prefixStripped;
30139
30470
  if (block.footnoteText) {
30471
+ origPlain = origPlain.replace(/\s*\(주: [\s\S]*\)$/, "");
30140
30472
  const noteMatch = newPlain.match(/\s*\(주: ([\s\S]*)\)$/);
30141
30473
  if (noteMatch) {
30142
30474
  newPlain = newPlain.slice(0, noteMatch.index).trimEnd();
@@ -30148,12 +30480,14 @@ function patchParagraphUnit(block, orig, edited, ctx, skip) {
30148
30480
  }
30149
30481
  }
30150
30482
  if (mapping.noteMarks?.length) {
30483
+ origPlain = removeNoteMarks(origPlain, mapping.noteMarks).text;
30151
30484
  const r = removeNoteMarks(newPlain, mapping.noteMarks);
30152
30485
  newPlain = r.text;
30153
30486
  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(" ") });
30154
30487
  }
30155
30488
  if (mapping.prefixStripped) {
30156
30489
  const origPrefix = block.text.split(" ", 1)[0];
30490
+ if (origPlain.startsWith(origPrefix + " ")) origPlain = origPlain.slice(origPrefix.length + 1);
30157
30491
  const sp = newPlain.indexOf(" ");
30158
30492
  const newFirst = sp > 0 ? newPlain.slice(0, sp) : newPlain;
30159
30493
  if (newFirst === origPrefix || AUTONUM_PREFIX_RE.test(newFirst)) {
@@ -30163,16 +30497,22 @@ function patchParagraphUnit(block, orig, edited, ctx, skip) {
30163
30497
  }
30164
30498
  }
30165
30499
  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");
30166
- if (sanitizeText(newPlain) !== newPlain) {
30500
+ if (sanitizeText(newPlain) !== newPlain && sanitizeText(origPlain) === origPlain) {
30167
30501
  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");
30168
30502
  }
30169
30503
  const xml = ctx.scans[mapping.para.sectionIndex]?.xml;
30170
- const splices = (xml ? markerRunSplices(mapping.para, xml, newPlain) : null) ?? buildParagraphSplices(mapping.para, newPlain, xml);
30504
+ 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);
30171
30505
  if (splices === null) return skip("\uBB38\uB2E8\uC5D0 \uD14D\uC2A4\uD2B8 \uB178\uB4DC\uB97C \uB9CC\uB4E4 \uC218 \uC5C6\uC74C");
30172
30506
  ctx.sectionSplices[mapping.para.sectionIndex].push(...splices);
30507
+ if (segsUsable && origInline.segs.length !== newInline.segs.length) {
30508
+ 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 });
30509
+ }
30173
30510
  return 1;
30174
30511
  }
30175
30512
  function textUnitToPlain(raw, block) {
30513
+ return parseEmphasis(textUnitInline(raw, block)).plain;
30514
+ }
30515
+ function textUnitInline(raw, block) {
30176
30516
  let text = raw.split("\n").map((l) => l.trim()).filter(Boolean).join(" ");
30177
30517
  if (block.type === "heading" || block.text && /^\[별표\s*\d+/.test(sanitizeText(block.text))) {
30178
30518
  text = text.replace(/^#{1,6}\s+/, "");
@@ -30184,7 +30524,7 @@ function textUnitToPlain(raw, block) {
30184
30524
  if (/^\*[^*][\s\S]*\*$/.test(text) && block.text && /^\([^)]*조[^)]*관련\)$/.test(sanitizeText(block.text))) {
30185
30525
  text = text.slice(1, -1);
30186
30526
  }
30187
- return unescapeGfm(text);
30527
+ return text;
30188
30528
  }
30189
30529
  function diffUnitLists(a, b) {
30190
30530
  const pairs = alignUnits(a.map((u) => u.raw), b.map((u) => u.raw));
@@ -30555,7 +30895,7 @@ var HwpxSession = class _HwpxSession {
30555
30895
  try {
30556
30896
  for (let s = 0; s < st.scans.length; s++) {
30557
30897
  if (sectionSplices[s].length === 0) continue;
30558
- sectionSplices[s].push(...allLinesegRemovalSplices(st.scans[s].xml));
30898
+ sectionSplices[s].push(...changedLinesegRemovalSplices(st.scans[s].xml, sectionSplices[s]));
30559
30899
  replacements.set(st.sectionPaths[s], encoder.encode(applySplices(st.scans[s].xml, sectionSplices[s])));
30560
30900
  }
30561
30901
  } catch (err) {
@@ -30759,7 +31099,7 @@ function scriptsOff(r, off) {
30759
31099
  }
30760
31100
  async function parseImage(buffer, options) {
30761
31101
  try {
30762
- const { parseImageDocument } = await import("./image-ocr-IMLFZ2JC.js");
31102
+ const { parseImageDocument } = await import("./image-ocr-ITNY454I.js");
30763
31103
  const { blocks, warnings } = await parseImageDocument(buffer, options);
30764
31104
  stripScriptTags({ blocks });
30765
31105
  return {
@@ -30819,7 +31159,7 @@ async function parseHwp(buffer, options) {
30819
31159
  async function parsePdf(buffer, options) {
30820
31160
  let parsePdfDocument;
30821
31161
  try {
30822
- const mod = await import("./parser-JVUZ7EEV.js");
31162
+ const mod = await import("./parser-KFCY3NIN.js");
30823
31163
  parsePdfDocument = mod.parsePdfDocument;
30824
31164
  } catch {
30825
31165
  return {
@@ -31049,4 +31389,4 @@ export {
31049
31389
  parseHwpml,
31050
31390
  fillForm
31051
31391
  };
31052
- //# sourceMappingURL=chunk-QWOZRYUA.js.map
31392
+ //# sourceMappingURL=chunk-YM3K3LCD.js.map