kordoc 4.16.2 → 4.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/README.md +14 -13
  2. package/dist/{-4G6MA4X6.js → -PRAKO6M4.js} +11 -11
  3. package/dist/{chunk-AUWGDP4G.js → chunk-2KF5WZCR.js} +2 -2
  4. package/dist/{chunk-UTP2WCHS.js → chunk-4GSF2R7T.js} +4 -4
  5. package/dist/{chunk-TXUKTOG2.js → chunk-4XVNQAK5.js} +219 -23
  6. package/dist/chunk-4XVNQAK5.js.map +1 -0
  7. package/dist/chunk-5CDUL6PH.js +250 -0
  8. package/dist/chunk-5CDUL6PH.js.map +1 -0
  9. package/dist/{chunk-4VODJKFL.js → chunk-6RGGYQQC.js} +3 -3
  10. package/dist/{chunk-DES2LGFZ.js → chunk-A55JGNKD.js} +2 -2
  11. package/dist/chunk-AKB72TEH.cjs +248 -0
  12. package/dist/chunk-AKB72TEH.cjs.map +1 -0
  13. package/dist/{chunk-LEIAEWZ7.js → chunk-BFT5IM2R.js} +2 -2
  14. package/dist/{chunk-KIOQ4N37.js → chunk-BLPR4HRF.js} +2 -2
  15. package/dist/{chunk-JELRWAZC.js → chunk-BZG7K44Z.js} +2 -2
  16. package/dist/{chunk-F4NRLLY4.js → chunk-EFO6JZY6.js} +2 -2
  17. package/dist/chunk-GS7T56RP.cjs.map +1 -1
  18. package/dist/{chunk-JFLAM3MM.js → chunk-I5DJOP62.js} +2 -2
  19. package/dist/chunk-I5DJOP62.js.map +1 -0
  20. package/dist/chunk-J55UQC5H.cjs.map +1 -1
  21. package/dist/{chunk-QOCS7W7R.js → chunk-K2VYABZ3.js} +86 -43
  22. package/dist/chunk-K2VYABZ3.js.map +1 -0
  23. package/dist/chunk-MJBCXW5R.js +248 -0
  24. package/dist/chunk-MJBCXW5R.js.map +1 -0
  25. package/dist/{chunk-MLIS253L.js → chunk-ML4NHUR7.js} +2 -2
  26. package/dist/{chunk-GO5IFOUF.js → chunk-N6V7LQBL.js} +2 -2
  27. package/dist/{chunk-FKUDAIJI.cjs → chunk-O7OUX6NU.cjs} +12 -12
  28. package/dist/chunk-O7OUX6NU.cjs.map +1 -0
  29. package/dist/{chunk-S2PL227Q.js → chunk-PHID6WNG.js} +2 -2
  30. package/dist/{chunk-IQGIT2VX.js → chunk-QJWVMPB6.js} +34 -17
  31. package/dist/chunk-QJWVMPB6.js.map +1 -0
  32. package/dist/{chunk-STM3ORY7.cjs → chunk-QNJLLF4J.cjs} +2 -2
  33. package/dist/chunk-QNJLLF4J.cjs.map +1 -0
  34. package/dist/{chunk-FSDJLAOW.js → chunk-QPJXYJIK.js} +55 -1
  35. package/dist/chunk-QPJXYJIK.js.map +1 -0
  36. package/dist/{chunk-XTFN5WKS.cjs → chunk-R2BUANHQ.cjs} +6 -6
  37. package/dist/chunk-R2BUANHQ.cjs.map +1 -0
  38. package/dist/{chunk-OXLPVQYK.js → chunk-TDQ6XDB3.js} +3 -3
  39. package/dist/{chunk-SFEQYKYJ.js → chunk-WN6OD2CQ.js} +218 -22
  40. package/dist/chunk-WN6OD2CQ.js.map +1 -0
  41. package/dist/{chunk-5KS5PWJR.js → chunk-WY5JAR4O.js} +2 -2
  42. package/dist/{chunk-CEIATRDW.cjs → chunk-WYON5ANU.cjs} +3 -3
  43. package/dist/chunk-WYON5ANU.cjs.map +1 -0
  44. package/dist/{chunk-WDQTFAXY.cjs → chunk-XEPKOC2O.cjs} +240 -44
  45. package/dist/chunk-XEPKOC2O.cjs.map +1 -0
  46. package/dist/{chunk-7KNGSQU7.js → chunk-YZ5HHS6A.js} +2 -2
  47. package/dist/{chunk-P6ZDXTV6.js → chunk-ZF6KHPB7.js} +2 -2
  48. package/dist/chunks-YBFBLJ4G.js +10 -0
  49. package/dist/cli.js +36 -54
  50. package/dist/cli.js.map +1 -1
  51. package/dist/{formula-NARUOXRX.js → formula-7MMFBRGJ.js} +4 -4
  52. package/dist/{formula-WIMV5TUX.cjs → formula-ECNOZT36.cjs} +9 -9
  53. package/dist/formula-ECNOZT36.cjs.map +1 -0
  54. package/dist/{formula-EPKLPDU7.js → formula-SHBXRXOJ.js} +3 -3
  55. package/dist/{image-ocr-3WJ4QH3T.js → image-ocr-P6ECJCT2.js} +8 -8
  56. package/dist/{image-ocr-5BUJQ4TK.js → image-ocr-QCT3A7X5.js} +6 -6
  57. package/dist/{image-ocr-AXWXR6JV.cjs → image-ocr-VUDSP2B4.cjs} +15 -15
  58. package/dist/image-ocr-VUDSP2B4.cjs.map +1 -0
  59. package/dist/index.cjs +768 -710
  60. package/dist/index.cjs.map +1 -1
  61. package/dist/index.d.cts +4 -0
  62. package/dist/index.d.ts +4 -0
  63. package/dist/index.js +106 -48
  64. package/dist/index.js.map +1 -1
  65. package/dist/mcp.js +38 -43
  66. package/dist/mcp.js.map +1 -1
  67. package/dist/{model-bundle-IMBW7D2Z.js → model-bundle-OUHGCEZY.js} +5 -5
  68. package/dist/{models-SY75IBOE.js → models-6D6LMOTH.js} +5 -5
  69. package/dist/page-range-QHHFTL7X.cjs.map +1 -1
  70. package/dist/{parser-ZQM3664Z.js → parser-CTRB7PKD.js} +257 -46
  71. package/dist/parser-CTRB7PKD.js.map +1 -0
  72. package/dist/{parser-2LU4EVU3.cjs → parser-RQ4PJRTJ.cjs} +411 -200
  73. package/dist/parser-RQ4PJRTJ.cjs.map +1 -0
  74. package/dist/{parser-N6476XAC.js → parser-ZPRQ3SSU.js} +260 -49
  75. package/dist/parser-ZPRQ3SSU.js.map +1 -0
  76. package/dist/pdf-ocr-462ZFSHX.js +15 -0
  77. package/dist/pdf-ocr-L35FQYGP.js +18 -0
  78. package/dist/pdf-ocr-STK5EQFF.cjs +16 -0
  79. package/dist/pdf-ocr-STK5EQFF.cjs.map +1 -0
  80. package/dist/{profile-io-GJPKCYPT.js → profile-io-YZUW6MAN.js} +3 -3
  81. package/dist/{rasterize-UOALJQDS.js → rasterize-OUR2QJXX.js} +3 -3
  82. package/dist/{redact-doc-22SYW3KH.js → redact-doc-4OQKG4SM.js} +11 -11
  83. package/dist/{render-MJ4H3R23.js → render-XNO6PZJO.js} +7 -7
  84. package/dist/seal-CJ7C44JN.js +10 -0
  85. package/dist/{setup-2URYVUEO.js → setup-UU3EIHNI.js} +3 -3
  86. package/dist/visual-QRMRFPUK.js +20 -0
  87. package/dist/{watch-ALXZGTOB.js → watch-SR6Q5SQN.js} +12 -12
  88. package/package.json +2 -2
  89. package/dist/chunk-3IB7LBHC.js +0 -57
  90. package/dist/chunk-3IB7LBHC.js.map +0 -1
  91. package/dist/chunk-62W7QCEX.cjs +0 -57
  92. package/dist/chunk-62W7QCEX.cjs.map +0 -1
  93. package/dist/chunk-CEIATRDW.cjs.map +0 -1
  94. package/dist/chunk-FKUDAIJI.cjs.map +0 -1
  95. package/dist/chunk-FSDJLAOW.js.map +0 -1
  96. package/dist/chunk-IQGIT2VX.js.map +0 -1
  97. package/dist/chunk-J3IF6KGW.js +0 -59
  98. package/dist/chunk-J3IF6KGW.js.map +0 -1
  99. package/dist/chunk-JFLAM3MM.js.map +0 -1
  100. package/dist/chunk-QOCS7W7R.js.map +0 -1
  101. package/dist/chunk-SFEQYKYJ.js.map +0 -1
  102. package/dist/chunk-STM3ORY7.cjs.map +0 -1
  103. package/dist/chunk-TXUKTOG2.js.map +0 -1
  104. package/dist/chunk-WDQTFAXY.cjs.map +0 -1
  105. package/dist/chunk-XTFN5WKS.cjs.map +0 -1
  106. package/dist/chunks-NUNIKS2J.js +0 -10
  107. package/dist/formula-WIMV5TUX.cjs.map +0 -1
  108. package/dist/image-ocr-AXWXR6JV.cjs.map +0 -1
  109. package/dist/parser-2LU4EVU3.cjs.map +0 -1
  110. package/dist/parser-N6476XAC.js.map +0 -1
  111. package/dist/parser-ZQM3664Z.js.map +0 -1
  112. package/dist/pdf-ocr-6DEE23IP.js +0 -15
  113. package/dist/pdf-ocr-GHEJVPX2.cjs +0 -16
  114. package/dist/pdf-ocr-GHEJVPX2.cjs.map +0 -1
  115. package/dist/pdf-ocr-MQTWODVU.js +0 -18
  116. package/dist/seal-XWMRUTI4.js +0 -10
  117. package/dist/visual-USPS4QRC.js +0 -20
  118. /package/dist/{-4G6MA4X6.js.map → -PRAKO6M4.js.map} +0 -0
  119. /package/dist/{chunk-AUWGDP4G.js.map → chunk-2KF5WZCR.js.map} +0 -0
  120. /package/dist/{chunk-UTP2WCHS.js.map → chunk-4GSF2R7T.js.map} +0 -0
  121. /package/dist/{chunk-4VODJKFL.js.map → chunk-6RGGYQQC.js.map} +0 -0
  122. /package/dist/{chunk-DES2LGFZ.js.map → chunk-A55JGNKD.js.map} +0 -0
  123. /package/dist/{chunk-LEIAEWZ7.js.map → chunk-BFT5IM2R.js.map} +0 -0
  124. /package/dist/{chunk-KIOQ4N37.js.map → chunk-BLPR4HRF.js.map} +0 -0
  125. /package/dist/{chunk-JELRWAZC.js.map → chunk-BZG7K44Z.js.map} +0 -0
  126. /package/dist/{chunk-F4NRLLY4.js.map → chunk-EFO6JZY6.js.map} +0 -0
  127. /package/dist/{chunk-MLIS253L.js.map → chunk-ML4NHUR7.js.map} +0 -0
  128. /package/dist/{chunk-GO5IFOUF.js.map → chunk-N6V7LQBL.js.map} +0 -0
  129. /package/dist/{chunk-S2PL227Q.js.map → chunk-PHID6WNG.js.map} +0 -0
  130. /package/dist/{chunk-OXLPVQYK.js.map → chunk-TDQ6XDB3.js.map} +0 -0
  131. /package/dist/{chunk-5KS5PWJR.js.map → chunk-WY5JAR4O.js.map} +0 -0
  132. /package/dist/{chunk-7KNGSQU7.js.map → chunk-YZ5HHS6A.js.map} +0 -0
  133. /package/dist/{chunk-P6ZDXTV6.js.map → chunk-ZF6KHPB7.js.map} +0 -0
  134. /package/dist/{chunks-NUNIKS2J.js.map → chunks-YBFBLJ4G.js.map} +0 -0
  135. /package/dist/{formula-NARUOXRX.js.map → formula-7MMFBRGJ.js.map} +0 -0
  136. /package/dist/{formula-EPKLPDU7.js.map → formula-SHBXRXOJ.js.map} +0 -0
  137. /package/dist/{image-ocr-3WJ4QH3T.js.map → image-ocr-P6ECJCT2.js.map} +0 -0
  138. /package/dist/{image-ocr-5BUJQ4TK.js.map → image-ocr-QCT3A7X5.js.map} +0 -0
  139. /package/dist/{model-bundle-IMBW7D2Z.js.map → model-bundle-OUHGCEZY.js.map} +0 -0
  140. /package/dist/{models-SY75IBOE.js.map → models-6D6LMOTH.js.map} +0 -0
  141. /package/dist/{pdf-ocr-6DEE23IP.js.map → pdf-ocr-462ZFSHX.js.map} +0 -0
  142. /package/dist/{pdf-ocr-MQTWODVU.js.map → pdf-ocr-L35FQYGP.js.map} +0 -0
  143. /package/dist/{profile-io-GJPKCYPT.js.map → profile-io-YZUW6MAN.js.map} +0 -0
  144. /package/dist/{rasterize-UOALJQDS.js.map → rasterize-OUR2QJXX.js.map} +0 -0
  145. /package/dist/{redact-doc-22SYW3KH.js.map → redact-doc-4OQKG4SM.js.map} +0 -0
  146. /package/dist/{render-MJ4H3R23.js.map → render-XNO6PZJO.js.map} +0 -0
  147. /package/dist/{seal-XWMRUTI4.js.map → seal-CJ7C44JN.js.map} +0 -0
  148. /package/dist/{setup-2URYVUEO.js.map → setup-UU3EIHNI.js.map} +0 -0
  149. /package/dist/{visual-USPS4QRC.js.map → visual-QRMRFPUK.js.map} +0 -0
  150. /package/dist/{watch-ALXZGTOB.js.map → watch-SR6Q5SQN.js.map} +0 -0
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ALL_OCR_MODELS
4
- } from "./chunk-DES2LGFZ.js";
4
+ } from "./chunk-A55JGNKD.js";
5
5
  import {
6
6
  ALL_FORMULA_MODELS,
7
7
  getModelStatusIn,
8
8
  getModelsDir
9
- } from "./chunk-KIOQ4N37.js";
10
- import "./chunk-JELRWAZC.js";
11
- import "./chunk-P6ZDXTV6.js";
9
+ } from "./chunk-BLPR4HRF.js";
10
+ import "./chunk-BZG7K44Z.js";
11
+ import "./chunk-ZF6KHPB7.js";
12
12
 
13
13
  // src/shared/model-bundle.ts
14
14
  import { copyFile, mkdir } from "fs/promises";
@@ -101,4 +101,4 @@ export {
101
101
  importModels,
102
102
  modelCacheStatus
103
103
  };
104
- //# sourceMappingURL=model-bundle-IMBW7D2Z.js.map
104
+ //# sourceMappingURL=model-bundle-OUHGCEZY.js.map
@@ -10,10 +10,10 @@ import {
10
10
  ocrModelPath,
11
11
  ocrModelsCached,
12
12
  parseCharacterDict
13
- } from "./chunk-DES2LGFZ.js";
14
- import "./chunk-KIOQ4N37.js";
15
- import "./chunk-JELRWAZC.js";
16
- import "./chunk-P6ZDXTV6.js";
13
+ } from "./chunk-A55JGNKD.js";
14
+ import "./chunk-BLPR4HRF.js";
15
+ import "./chunk-BZG7K44Z.js";
16
+ import "./chunk-ZF6KHPB7.js";
17
17
  export {
18
18
  ALL_OCR_MODELS,
19
19
  OCR_DET_MODEL,
@@ -26,4 +26,4 @@ export {
26
26
  ocrModelsCached,
27
27
  parseCharacterDict
28
28
  };
29
- //# sourceMappingURL=models-SY75IBOE.js.map
29
+ //# sourceMappingURL=models-6D6LMOTH.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/mong-e/workspace/kordoc/dist/page-range-QHHFTL7X.cjs"],"names":[],"mappings":"AAAA;AACE;AACA;AACF,wDAA6B;AAC7B,gCAA6B;AAC7B;AACE;AACA;AACF,qIAAC","file":"/Users/mong-e/workspace/kordoc/dist/page-range-QHHFTL7X.cjs"}
1
+ {"version":3,"sources":["/Users/chris_gomdori/workspace/kordoc/dist/page-range-QHHFTL7X.cjs"],"names":[],"mappings":"AAAA;AACE;AACA;AACF,wDAA6B;AAC7B,gCAA6B;AAC7B;AACE;AACA;AACF,qIAAC","file":"/Users/chris_gomdori/workspace/kordoc/dist/page-range-QHHFTL7X.cjs"}
@@ -4,7 +4,7 @@ import {
4
4
  blocksToPages,
5
5
  encodePng,
6
6
  escapeLiteralDollar
7
- } from "./chunk-7KNGSQU7.js";
7
+ } from "./chunk-YZ5HHS6A.js";
8
8
  import {
9
9
  hasRequestedPagesAfter,
10
10
  parsePageRange
@@ -16,7 +16,12 @@ import {
16
16
  EMPTY_PARTS,
17
17
  FILLER_CELLS,
18
18
  IMAGE_CELLS,
19
+ NO_EDGES,
20
+ PART_COLXS,
21
+ ROW_RULES,
19
22
  TABLE_COLXS,
23
+ TABLE_ROWYS,
24
+ TABLE_TAIL,
20
25
  TOC_BLOCKS,
21
26
  WrapLexicon,
22
27
  collapseEvenSpacing,
@@ -34,6 +39,7 @@ import {
34
39
  extractLines,
35
40
  extractPageBlocksWithLines,
36
41
  filterHiddenText,
42
+ joinCellEdges,
37
43
  joinPageBreakWraps,
38
44
  latinSoftWrap,
39
45
  mergeStackedHeadingLines,
@@ -44,15 +50,18 @@ import {
44
50
  startsNewItem,
45
51
  trimTrailingEmptyTableCols,
46
52
  wrapJoiner
47
- } from "./chunk-TXUKTOG2.js";
53
+ } from "./chunk-4XVNQAK5.js";
48
54
  import {
49
- stripScriptTags
50
- } from "./chunk-3IB7LBHC.js";
51
- import "./chunk-F4NRLLY4.js";
55
+ CELL_EDGES,
56
+ CONTENT_CELLS,
57
+ stripScriptTags,
58
+ unframeLayoutTables
59
+ } from "./chunk-MJBCXW5R.js";
60
+ import "./chunk-EFO6JZY6.js";
52
61
  import {
53
62
  KordocError,
54
63
  sanitizeHref
55
- } from "./chunk-MLIS253L.js";
64
+ } from "./chunk-ML4NHUR7.js";
56
65
 
57
66
  // src/pdf/ocr-region-merge.ts
58
67
  function mergeOcrImageRegions(blocks, page, regions, ocrBlocks) {
@@ -673,6 +682,7 @@ function splitContactTables(blocks) {
673
682
 
674
683
  // src/pdf/table-parts.ts
675
684
  var PART_COL_TOL = 1;
685
+ var PART_COL_SNAP = 0.3;
676
686
  function anchorsOf(table) {
677
687
  const out = [];
678
688
  const covered = /* @__PURE__ */ new Set();
@@ -690,9 +700,22 @@ function anchorsOf(table) {
690
700
  return out;
691
701
  }
692
702
  function unionCoords(a, b) {
703
+ const drift = a.length === b.length && a.every((x, i) => Math.abs(x - b[i]) <= PART_COL_TOL);
704
+ const tol = drift ? PART_COL_TOL : PART_COL_SNAP;
705
+ const pairs = [];
706
+ for (const v of b) for (const x of a) if (Math.abs(x - v) <= tol) pairs.push([Math.abs(x - v), v, x]);
707
+ pairs.sort((p, q) => p[0] - q[0]);
708
+ const map = /* @__PURE__ */ new Map(), taken = /* @__PURE__ */ new Set();
709
+ for (const [, v, x] of pairs) if (!map.has(v) && !taken.has(x)) {
710
+ map.set(v, x);
711
+ taken.add(x);
712
+ }
693
713
  const out = [...a];
694
- for (const v of b) if (!a.some((x) => Math.abs(x - v) <= PART_COL_TOL)) out.push(v);
695
- return out.sort((x, y) => x - y);
714
+ for (const v of b) if (!map.has(v)) {
715
+ map.set(v, v);
716
+ out.push(v);
717
+ }
718
+ return { U: out.sort((x, y) => x - y), map };
696
719
  }
697
720
  var indexOf = (coords, x) => {
698
721
  let best = -1, bestD = Infinity;
@@ -709,18 +732,31 @@ var rowText = (anchors, r) => anchors.filter((a) => a.r === r).map((a) => a.cell
709
732
  var hasText = (t) => t.replace(/\|/g, "") !== "";
710
733
  function joinSplitParts(prev, pcx, curr, ccx, dx = 0, prevBottom, lex) {
711
734
  if (pcx.length !== prev.cols + 1 || ccx.length !== curr.cols + 1) return null;
712
- const U = unionCoords(pcx, ccx);
735
+ const { U, map } = unionCoords(pcx, ccx);
736
+ const cxU = ccx.map((v) => map.get(v) ?? v);
713
737
  const cols = U.length - 1;
714
738
  if (cols < 1) return null;
715
739
  const pa = anchorsOf(prev), ca = anchorsOf(curr);
716
- let skip = 0;
740
+ let skip = 0, head = 0;
717
741
  while (skip < Math.min(3, curr.rows - 1, prev.rows) && rowText(ca, skip) !== "" && rowText(ca, skip) === rowText(pa, skip)) skip++;
718
742
  for (let h = 1; h <= 2 && !skip; h++) {
743
+ head = h;
719
744
  while (skip < Math.min(3, curr.rows - 1, prev.rows - h) && hasText(rowText(ca, skip)) && rowText(ca, skip) === rowText(pa, h + skip)) skip++;
720
745
  }
746
+ const sameSpans = (u, d) => {
747
+ if (u.length !== d.length || !u.length) return false;
748
+ const shift = pcx[u[u.length - 1].c + u[u.length - 1].cs] - ccx[d[d.length - 1].c + d[d.length - 1].cs];
749
+ return u.every((a, n) => Math.abs(pcx[a.c] - ccx[d[n].c] - shift) <= CONTINUATION_COL_TOL && Math.abs(pcx[a.c + a.cs] - ccx[d[n].c + d[n].cs] - shift) <= CONTINUATION_COL_TOL);
750
+ };
751
+ for (let k = 0; k < skip; k++) {
752
+ if (sameSpans(pa.filter((a) => a.r === head + k), ca.filter((a) => a.r === k))) continue;
753
+ if (hasText(rowText(ca, k))) return null;
754
+ skip = k;
755
+ }
721
756
  const rows = prev.rows + curr.rows - skip;
722
757
  const grid = Array.from({ length: rows }, () => Array.from({ length: cols }, () => ({ text: "", colSpan: 1, rowSpan: 1 })));
723
758
  const owner = Array.from({ length: rows }, () => new Array(cols).fill(null));
759
+ let edged = false;
724
760
  const place = (a, x, rowOff, shift = 0) => {
725
761
  const c1 = indexOf(U, x[a.c]), c2 = indexOf(U, x[a.c + a.cs]);
726
762
  if (c1 < 0 || c2 <= c1) return false;
@@ -733,12 +769,17 @@ function joinSplitParts(prev, pcx, curr, ccx, dx = 0, prevBottom, lex) {
733
769
  const lines = CELL_LINES.get(a.cell);
734
770
  if (lines) CELL_LINES.set(grid[r][c1], shift ? lines.map((l) => ({ ...l, l: l.l + shift, r: l.r + shift })) : lines);
735
771
  if (IMAGE_CELLS.has(a.cell)) IMAGE_CELLS.add(grid[r][c1]);
772
+ const edges = CELL_EDGES.get(a.cell);
773
+ if (edges) {
774
+ CELL_EDGES.set(grid[r][c1], edges);
775
+ edged = true;
776
+ }
736
777
  return true;
737
778
  };
738
779
  for (const a of pa) if (!FILLER_CELLS.has(a.cell) && !place(a, pcx, 0)) return null;
739
780
  for (const a of ca) {
740
781
  if (a.r < skip || FILLER_CELLS.has(a.cell)) continue;
741
- if (!place(a, ccx, prev.rows - skip, dx)) return null;
782
+ if (!place(a, cxU, prev.rows - skip, dx)) return null;
742
783
  }
743
784
  const first = prev.rows;
744
785
  for (let c = 0; c < cols; c++) {
@@ -762,12 +803,32 @@ function joinSplitParts(prev, pcx, curr, ccx, dx = 0, prevBottom, lex) {
762
803
  for (let rr = above.r; rr < above.r + newRs; rr++) for (let dc = above.c; dc < above.c + above.cs; dc++) owner[rr][dc] = grown;
763
804
  }
764
805
  for (let r = 0; r < rows; r++) for (let c = 0; c < cols; c++) if (owner[r][c] === null) FILLER_CELLS.add(grid[r][c]);
806
+ if (edged) {
807
+ for (let r = 0; r < rows; r++) for (let c = 0; c < cols; c++) if (owner[r][c] === null) CELL_EDGES.set(grid[r][c], NO_EDGES);
808
+ }
809
+ for (let c = 0; c < cols && U[c + 1] <= pcx[0] + PART_COL_TOL; c++) {
810
+ let r = prev.rows;
811
+ while (r < rows && owner[r][c] === null) r++;
812
+ const through = { r: 0, c, rs: r, cs: 1, cell: grid[0][c] };
813
+ for (let rr = 0; rr < r; rr++) owner[rr][c] = through;
814
+ }
765
815
  const table = { rows, cols, cells: grid, hasHeader: prev.hasHeader, ...prev.caption ? { caption: prev.caption } : {} };
766
- let split = rows > prev.rows && mergeSplitRow(table, owner, prev.rows, U);
767
- if (rows > prev.rows && !split && prevBottom !== void 0 && mergeStraddlingCells(table, owner, prev.rows, prevBottom, lex)) split = mergeSplitRow(table, owner, prev.rows, U, true);
816
+ const pr = ROW_RULES.get(prev), cr = ROW_RULES.get(curr);
817
+ const shifted = dx !== 0;
818
+ const cut = {
819
+ open: !!pr && !!cr && !pr.bottom && !cr.top && pr.innerOpen + cr.innerOpen === 0 && pr.innerRuled + cr.innerRuled > 0,
820
+ ruled: !!pr && !!cr && pr.bottom && cr.top,
821
+ list: !shifted ? "any" : skip > 0 && ca.filter((a) => a.r < skip && a.cell.text.trim()).length < 2 ? "none" : "multi"
822
+ };
823
+ let split = rows > prev.rows && mergeSplitRow(table, owner, prev.rows, U, false, cut);
824
+ if (rows > prev.rows && !split && prevBottom !== void 0 && mergeStraddlingCells(table, owner, prev.rows, prevBottom, lex, U)) split = mergeSplitRow(table, owner, prev.rows, U, true, { ...cut, open: false });
825
+ if (pr && cr) {
826
+ const cutRuled = pr.bottom || cr.top;
827
+ ROW_RULES.set(table, { top: pr.top, bottom: cr.bottom, innerRuled: pr.innerRuled + cr.innerRuled + (!split && cutRuled ? 1 : 0), innerOpen: pr.innerOpen + cr.innerOpen + (!split && !cutRuled ? 1 : 0) });
828
+ }
768
829
  return { table, colXs: U, split, header: ca.filter((a) => a.r < skip && a.cell.text.trim()).length >= 2 };
769
830
  }
770
- function mergeStraddlingCells(table, owner, first, prevBottom, lex) {
831
+ function mergeStraddlingCells(table, owner, first, prevBottom, lex, colXs) {
771
832
  const last = first - 1;
772
833
  const straddles = owner[first].some((o, c) => o !== null && o === owner[last][c]);
773
834
  let firstNew = table.cols;
@@ -791,6 +852,19 @@ function mergeStraddlingCells(table, owner, first, prevBottom, lex) {
791
852
  const tail = table.cells[u.r][u.c].text.trim().split(/\s+/).pop() ?? "", head = table.cells[first][d.c].text.trim().split(/\s+/)[0] ?? "";
792
853
  if (/^[가-힣]{2,}$/.test(tail) && /^[가-힣]{2,}/.test(head) && lex.evidence2(tail, head) === "") midWord = true;
793
854
  }
855
+ const crossed = /* @__PURE__ */ new Set();
856
+ const shape = (u, d) => `${u.r}:${u.rs}:${d.rs}`;
857
+ if (straddles && colXs) for (let c = 0; c < table.cols; ) {
858
+ const u = owner[last][c], d = owner[first][c];
859
+ if (!u) {
860
+ c++;
861
+ continue;
862
+ }
863
+ c = u.c + u.cs;
864
+ if (!d || d === u || u.r + u.rs - 1 !== last || d.r !== first || d.c !== u.c || d.cs !== u.cs || u.rs < 2) continue;
865
+ const a = table.cells[u.r][u.c], b = table.cells[first][d.c];
866
+ if (hasContent(a) && hasContent(b) && continuesAcross(a, b, colXs[u.c], colXs[u.c + u.cs])) crossed.add(shape(u, d));
867
+ }
794
868
  let merged = false;
795
869
  for (let c = 0; c < table.cols; ) {
796
870
  const u = owner[last][c], d = owner[first][c];
@@ -801,13 +875,16 @@ function mergeStraddlingCells(table, owner, first, prevBottom, lex) {
801
875
  c = u.c + u.cs;
802
876
  if (!d || d === u || u.r + u.rs - 1 !== last || d.r !== first || d.c !== u.c || d.cs !== u.cs) continue;
803
877
  const a = table.cells[u.r][u.c], b = table.cells[first][d.c];
804
- if (!(u.rs >= 2 && u.c + u.cs <= firstNew && hasContent(a) && !hasContent(b))) {
878
+ if (!crossed.has(shape(u, d)) && !(u.rs >= 2 && u.c + u.cs <= firstNew && hasContent(a) && !hasContent(b))) {
805
879
  if (!straddles && !midWord) continue;
806
880
  if (u.r >= last && d.rs < 2) continue;
807
881
  const U = CELL_LINES.get(a);
808
- if (!U?.length || U.length > STRADDLE_MAX_LINES || !hasContent(b)) continue;
809
- const lu = U[U.length - 1];
810
- if (!midWord && lu.y - prevBottom > (u.r >= last ? STRADDLE_BOTTOM_ONE_ROW : STRADDLE_BOTTOM) * (lu.h || 10)) continue;
882
+ if (!U?.length || !hasContent(b)) continue;
883
+ if (!(straddles && filledToBottom(U, prevBottom) && clauseContinues(a, b))) {
884
+ if (U.length > STRADDLE_MAX_LINES) continue;
885
+ const lu = U[U.length - 1];
886
+ if (!midWord && lu.y - prevBottom > (u.r >= last ? STRADDLE_BOTTOM_ONE_ROW : STRADDLE_BOTTOM) * (lu.h || 10)) continue;
887
+ }
811
888
  }
812
889
  appendCell(a, b);
813
890
  a.rowSpan = first + d.rs - u.r;
@@ -818,6 +895,11 @@ function mergeStraddlingCells(table, owner, first, prevBottom, lex) {
818
895
  }
819
896
  return merged;
820
897
  }
898
+ function filledToBottom(U, bottom) {
899
+ if (U.length < 2) return false;
900
+ const lu = U[U.length - 1];
901
+ return lu.y - bottom < (U[0].y - lu.y) / (U.length - 1) + FILL_SLACK * (lu.h || 10);
902
+ }
821
903
  var FULL_LINE_TOL = 1;
822
904
  var FULL_LINE_MIN_FRAC = 0.5;
823
905
  var FULL_LINE_EDGE_MIN = 12;
@@ -826,6 +908,7 @@ var SHORT_LINE_GAP = 1.5;
826
908
  var STRADDLE_MAX_LINES = 3;
827
909
  var STRADDLE_BOTTOM = 1.2;
828
910
  var STRADDLE_BOTTOM_ONE_ROW = 0.55;
911
+ var FILL_SLACK = 0.5;
829
912
  var CARRIED_MIN_COL_W = 4;
830
913
  var LABEL_ROOM = 1.5;
831
914
  var HANGING_MIN = 0.5;
@@ -847,10 +930,16 @@ function continuesAcross(u, d, x1, x2) {
847
930
  maxR = Math.max(maxR, x2 - (minL - x1));
848
931
  if (maxR - last.r > FULL_LINE_TOL * fs) return false;
849
932
  if (U.length === 1 && x2 - last.r > Math.max(FULL_LINE_EDGE_MIN, SINGLE_LINE_WORD_GAP * fs)) return false;
850
- if (last.r - last.l < FULL_LINE_MIN_FRAC * (x2 - x1)) return false;
851
- const leftAligned = (l) => l.l - minL <= fs && maxR - l.r > SHORT_LINE_GAP * fs;
852
- const hanging = U.length >= 2 && U.every((l) => maxR - l.r <= FULL_LINE_TOL * fs) && last.l - minL >= HANGING_MIN * fs && Math.abs(D[0].l - last.l) <= HANGING_TOL;
853
- return U.some(leftAligned) || D.some(leftAligned) || hanging;
933
+ const indented = last.l - minL >= HANGING_MIN * fs;
934
+ if (last.r - last.l < FULL_LINE_MIN_FRAC * (indented ? x2 - last.l : x2 - x1)) return false;
935
+ const newItem = startsNewItem(u.text, d.text);
936
+ const all = D.length ? U.concat(D) : U;
937
+ const leftAligned = (l) => maxR - l.r > SHORT_LINE_GAP * fs && (l.l - minL <= fs || !newItem && all.some((o) => o !== l && Math.abs(o.l - l.l) <= HANGING_TOL && Math.abs(o.r - l.r) >= HANGING_MIN * fs));
938
+ const hanging = U.length >= 2 && U.every((l) => maxR - l.r <= FULL_LINE_TOL * fs) && indented && Math.abs(D[0].l - last.l) <= HANGING_TOL;
939
+ const hangingHead = !indented && D.length >= 2 && D[0].l - last.l >= HANGING_MIN * fs && maxR - D[0].r <= FULL_LINE_TOL * fs && D.every((l) => Math.abs(l.l - D[0].l) <= HANGING_TOL);
940
+ const d0 = D[0];
941
+ const hangStart = U.length === 1 && !newItem && d0.l - last.l >= HANGING_MIN * fs && D.every((l) => l.l >= d0.l - HANGING_TOL) && (Math.abs(d0.r - last.r) <= HANGING_TOL && d0.r - d0.l >= FULL_LINE_MIN_FRAC * (x2 - x1) || last.r - d0.r > SHORT_LINE_GAP * fs && Math.abs(d0.l + d0.r - last.l - last.r) / 2 >= HANGING_MIN * fs);
942
+ return U.some(leftAligned) || D.some(leftAligned) || hanging || hangingHead || hangStart;
854
943
  }
855
944
  var OUTLINE_HEAD = /^[□■]\s*\S/;
856
945
  var OUTLINE_ITEM = /^[ㅇ○◦\-‐–·․‧※*]\s*\S/;
@@ -859,14 +948,19 @@ function outlineContinues(u, d) {
859
948
  const D = d.text.split("\n").map((l) => l.trim()).filter(Boolean);
860
949
  return U.length >= 2 && D.length >= 1 && U.some((l) => OUTLINE_HEAD.test(l)) && OUTLINE_ITEM.test(D[0]);
861
950
  }
862
- function lineEnded(c, x1, x2, next = "") {
951
+ function lineEnded(c, x1, x2, next) {
863
952
  const L = CELL_LINES.get(c);
864
953
  if (!L || L.length !== 1) return false;
865
954
  const l = L[0], h = l.h || 10;
866
- const word = next.trim().split(/\s+/)[0] ?? "";
955
+ const d0 = next ? CELL_LINES.get(next)?.[0] : void 0;
956
+ if (d0 && d0.l - l.l >= HANGING_MIN * h) return false;
957
+ return x2 - l.r - (l.l - x1) >= Math.max(LABEL_ROOM, firstWordUnits(next?.text ?? "")) * h;
958
+ }
959
+ function firstWordUnits(text) {
960
+ const word = text.trim().replace(/^([(\[「『<〈])\s+/, "$1").split(/\s+/)[0] ?? "";
867
961
  let units = 0;
868
962
  for (const ch of word) units += /[가-힣\u3400-\u9fff]/.test(ch) ? 1 : 0.55;
869
- return x2 - l.r - (l.l - x1) >= Math.max(LABEL_ROOM, units) * h;
963
+ return units;
870
964
  }
871
965
  function appendCell(a, b) {
872
966
  if (a.blocks?.length || b.blocks?.length) {
@@ -874,6 +968,7 @@ function appendCell(a, b) {
874
968
  a.blocks = [...asBlocks(a), ...asBlocks(b)];
875
969
  }
876
970
  if (b.text.trim()) a.text = a.text.trim() ? a.text + "\n" + b.text : b.text;
971
+ joinCellEdges(a, b);
877
972
  }
878
973
  var hasContent = (cell) => !!cell.text.trim() || !!cell.blocks?.length || IMAGE_CELLS.has(cell);
879
974
  var CLAUSE_OPEN_ENDING = /(?:하는|되는|하고|하며|하여|되어|되고|되며|이며|으며|어야|아야|여야)$/;
@@ -887,11 +982,42 @@ function clauseContinues(u, d) {
887
982
  const last = tail[tail.length - 1], before = tail[tail.length - 2];
888
983
  return last === "\uC744" && batchim(before) || last === "\uB97C" && !batchim(before) || CLAUSE_OPEN_ENDING.test(tail);
889
984
  }
985
+ function wordOverflows(u, d, x1, x2) {
986
+ const U = CELL_LINES.get(u);
987
+ if (!U?.length || startsNewItem(u.text, d.text)) return false;
988
+ const last = U[U.length - 1], units = firstWordUnits(d.text);
989
+ return units > 0 && last.r - last.l + units * (last.h || 10) > x2 - x1;
990
+ }
991
+ var KO_ORDER = "\uAC00\uB098\uB2E4\uB77C\uB9C8\uBC14\uC0AC\uC544\uC790\uCC28\uCE74\uD0C0\uD30C\uD558";
992
+ function itemMark(line) {
993
+ let m = /^(\d{1,2})([.)])(?!\d)/.exec(line);
994
+ if (m) return { style: "1" + m[2], n: +m[1] };
995
+ if (m = /^\((\d{1,2})\)/.exec(line)) return { style: "(1)", n: +m[1] };
996
+ if ((m = /^([가-하])([.)])/.exec(line)) && KO_ORDER.includes(m[1])) return { style: "\uAC00" + m[2], n: KO_ORDER.indexOf(m[1]) };
997
+ if ((m = /^\(([가-하])\)/.exec(line)) && KO_ORDER.includes(m[1])) return { style: "(\uAC00)", n: KO_ORDER.indexOf(m[1]) };
998
+ if (m = /^[①-⑳]/.exec(line)) return { style: "\u2460", n: m[0].charCodeAt(0) };
999
+ if (m = /^([A-Z])\.\s/.exec(line)) return { style: "A.", n: m[1].charCodeAt(0) };
1000
+ return null;
1001
+ }
1002
+ function listContinues(u, d, multi = false) {
1003
+ const head = itemMark(d.text.trim());
1004
+ if (!head) return false;
1005
+ const marks = u.text.split("\n").map((l) => itemMark(l.trim()));
1006
+ let last = -1, count = 0;
1007
+ marks.forEach((m, i) => {
1008
+ if (m?.style === head.style) {
1009
+ last = i;
1010
+ count++;
1011
+ }
1012
+ });
1013
+ return last >= 0 && marks[last].n + 1 === head.n && (count >= 2 || !multi && last > 0);
1014
+ }
890
1015
  function outlineOnly(pairs, cell) {
891
1016
  const filled = pairs.filter(([, d]) => hasContent(d.cell));
892
1017
  return filled.length === 1 && outlineContinues(cell(filled[0][0]), cell(filled[0][1]));
893
1018
  }
894
- function mergeSplitRow(table, owner, first, colXs, textOnly = false) {
1019
+ var NO_CUT = { open: false, ruled: false, list: "any" };
1020
+ function mergeSplitRow(table, owner, first, colXs, textOnly = false, cut = NO_CUT) {
895
1021
  const last = first - 1;
896
1022
  const pairs = [];
897
1023
  let carried = false;
@@ -904,19 +1030,30 @@ function mergeSplitRow(table, owner, first, colXs, textOnly = false) {
904
1030
  }
905
1031
  if (!a || !b) return false;
906
1032
  if (a !== b) {
907
- if (a.c !== b.c || a.cs !== b.cs || a.r + a.rs - 1 !== last || b.r !== first || b.rs !== 1) return false;
1033
+ if (a.c !== b.c || a.cs !== b.cs || a.r + a.rs - 1 !== last || b.r !== first) return false;
1034
+ if (b.rs > 1 && (a.rs > 1 || !hasContent(a.cell))) return false;
908
1035
  pairs.push([a, b]);
909
1036
  } else if (a.r === last && a.rs === 2) carried = true;
910
1037
  c = a.c + a.cs;
911
1038
  }
912
- const carriedSplit = !textOnly && carried && pairs.filter(([u, d]) => hasContent(u.cell) && hasContent(d.cell)).length <= 1 && !pairs.some(([u, d]) => !hasContent(u.cell) && hasContent(d.cell));
1039
+ const newCell = pairs.some(([u, d]) => !hasContent(u.cell) && hasContent(d.cell));
913
1040
  const cell = (a) => table.cells[a.r][a.c];
1041
+ const contentPairs = pairs.filter(([u, d]) => hasContent(u.cell) && hasContent(d.cell));
1042
+ const carriedSplit = !textOnly && carried && !newCell && (contentPairs.length <= 1 || contentPairs.every(([, d]) => d.rs > 1) || !cut.ruled && contentPairs.some(([u, d]) => wordOverflows(cell(u), cell(d), colXs[u.c], colXs[u.c + u.cs])));
914
1043
  if (!carriedSplit) {
915
1044
  const norm = (c) => c.text.replace(/\s+/g, "");
916
- if (pairs.some(([u, d]) => hasContent(d.cell) && norm(cell(d)) !== norm(cell(u)) && lineEnded(cell(u), colXs[u.c], colXs[u.c + u.cs], cell(d).text))) return false;
917
- if (!outlineOnly(pairs, cell) && !pairs.some(([u, d]) => continuesAcross(cell(u), cell(d), colXs[u.c], colXs[u.c + u.cs])) && !pairs.some(([u, d]) => clauseContinues(cell(u), cell(d)))) return false;
1045
+ if (pairs.some(([u, d]) => hasContent(d.cell) && norm(cell(d)) !== norm(cell(u)) && lineEnded(cell(u), colXs[u.c], colXs[u.c + u.cs], cell(d)))) return false;
1046
+ const flows = ([u, d]) => continuesAcross(cell(u), cell(d), colXs[u.c], colXs[u.c + u.cs]) || clauseContinues(cell(u), cell(d));
1047
+ if (!(cut.open && !newCell)) {
1048
+ if (pairs.some((p) => p[1].rs > 1 && !flows(p))) return false;
1049
+ const one = pairs.filter(([, d]) => d.rs === 1);
1050
+ if (!outlineOnly(pairs, cell) && !one.some(flows) && (cut.list === "none" || !one.some(([u, d]) => listContinues(cell(u), cell(d), cut.list === "multi")))) return false;
1051
+ }
1052
+ }
1053
+ for (const [u, d] of pairs) {
1054
+ appendCell(table.cells[u.r][u.c], table.cells[d.r][d.c]);
1055
+ if (d.rs > 1) table.cells[u.r][u.c].rowSpan = u.rs + d.rs;
918
1056
  }
919
- for (const [u, d] of pairs) appendCell(table.cells[u.r][u.c], table.cells[d.r][d.c]);
920
1057
  for (let r = 0; r < first; r++) for (let c = 0; c < table.cols; c++) {
921
1058
  const o = owner[r][c];
922
1059
  if (o && o.r === r && o.c === c && r + table.cells[r][c].rowSpan > first) table.cells[r][c].rowSpan--;
@@ -964,11 +1101,14 @@ function sameHeadShape(a, b) {
964
1101
  function mergeCrossPageTables(blocks, pageHeights, lex) {
965
1102
  mergeColumnFlow(blocks, pageHeights, lex);
966
1103
  for (let i = blocks.length - 2; i >= 0; i--) {
967
- const prev = blocks[i];
968
- if (prev.type !== "table" || !prev.table || !prev.bbox || !prev.pageNumber) continue;
1104
+ const tail = tailOf(blocks[i]);
1105
+ if (tail.type !== "table" || !tail.table || !tail.bbox || !tail.pageNumber) continue;
969
1106
  let j = i + 1;
970
- while (j < blocks.length && (blocks[j].type !== "table" || insideTable(blocks[j], prev) || leftColumnOf(blocks[j], prev)) && (blocks[j].pageNumber ?? 0) <= prev.pageNumber + 1) j++;
1107
+ const skip = (b) => b.type !== "table" || [blocks[i], tail].some((t) => insideTable(b, t) || leftColumnOf(b, t));
1108
+ while (j < blocks.length && skip(blocks[j]) && (blocks[j].pageNumber ?? 0) <= tail.pageNumber + 1) j++;
971
1109
  const curr = blocks[j];
1110
+ const prev = tail !== blocks[i] && curr?.pageNumber === tail.pageNumber ? blocks[i] : tail;
1111
+ if (!prev.table || !prev.bbox || !prev.pageNumber) continue;
972
1112
  if (!curr || curr.type !== "table" || !curr.table || !curr.bbox || curr.pageNumber !== prev.pageNumber + 1) continue;
973
1113
  if (startsWithUnitRow(prev.table) && startsWithUnitRow(curr.table)) continue;
974
1114
  const joined = j === i + 1 || blocks.slice(i + 1, j).every((b) => besideOwn(b, prev, curr) || insideTable(b, prev)) ? looksContinued(prev, curr, pageHeights) && !restartsTable(blocks, i, curr.table, pageHeights) ? joinClipParts(prev, curr, pageHeights, lex) ?? false : null : null;
@@ -1051,24 +1191,36 @@ function joinClipParts(prev, curr, pageHeights, lex) {
1051
1191
  if (!CLIP_TABLES.has(pt) || !CLIP_TABLES.has(ct)) return null;
1052
1192
  const px = TABLE_COLXS.get(pt), cx = TABLE_COLXS.get(ct);
1053
1193
  if (!px || !cx) return null;
1054
- let xs = cx, shifted = false, dx = 0, foreign = false;
1194
+ let xs = cx, shifted = false, dx = 0, foreign = false, within = false;
1055
1195
  if (!shiftedSame(px, cx, false)) {
1056
1196
  if (!pageHeights?.get(prev.pageNumber) || !pageHeights?.get(curr.pageNumber)) return null;
1057
1197
  dx = px[px.length - 1] - cx[cx.length - 1];
1058
- if (Math.abs(dx) > CONTINUATION_COL_TOL) {
1198
+ within = Math.abs(dx) > CONTINUATION_COL_TOL && cx.length >= 3 && cx.every((x) => px.some((p) => Math.abs(p - x) <= CONTINUATION_COL_TOL));
1199
+ if (Math.abs(dx) > CONTINUATION_COL_TOL && !within) {
1059
1200
  xs = cx.map((x) => x + dx);
1060
1201
  shifted = true;
1061
1202
  } else dx = 0;
1062
- if (!px.some((x) => Math.abs(x - xs[0]) <= CONTINUATION_COL_TOL)) return null;
1063
- const inner = xs.slice(1, -1);
1064
- foreign = inner.length > 0 && !inner.some((x) => px.some((p) => Math.abs(p - x) <= CONTINUATION_COL_TOL)) && headingRow(ct.cells[0] ?? []);
1203
+ if (!px.some((x) => Math.abs(x - xs[0]) <= CONTINUATION_COL_TOL) && !prevLacksLeftCols(prev, px, xs, pageHeights)) return null;
1204
+ const unrelated = (b) => {
1205
+ const inner = b.slice(1, -1).map((x) => x + dx);
1206
+ return inner.length > 0 && !inner.some((x) => px.some((p) => Math.abs(p - x) <= CONTINUATION_COL_TOL));
1207
+ };
1208
+ foreign = unrelated(cx) && unrelated(PART_COLXS.get(ct) ?? cx) && (headingRow(ct.cells[0] ?? []) || px.length > FOREIGN_FIRST_ROW_CELLS && anchorsOf(ct).filter((a) => a.r === 0).length >= FOREIGN_FIRST_ROW_CELLS);
1065
1209
  }
1066
1210
  const res = joinSplitParts(pt, px, ct, xs, dx, prev.bbox?.y, lex);
1067
- if (!res || (shifted || foreign) && !res.split && !res.header) return null;
1211
+ if (!res || (shifted || foreign || within) && !res.split && !res.header) return null;
1068
1212
  TABLE_COLXS.set(res.table, res.colXs);
1213
+ const ys = TABLE_ROWYS.get(pt);
1214
+ if (ys) TABLE_ROWYS.set(res.table, ys);
1215
+ PART_COLXS.set(res.table, PART_COLXS.get(pt) ?? px);
1069
1216
  CLIP_TABLES.add(res.table);
1070
1217
  return res.table;
1071
1218
  }
1219
+ function prevLacksLeftCols(prev, px, xs, pageHeights) {
1220
+ const ph = pageHeights?.get(prev.pageNumber);
1221
+ if (!ph || prev.bbox.y + prev.bbox.height < ph * (1 - PAGE_EDGE_BAND)) return false;
1222
+ return xs[0] < px[0] && xs.slice(1, -1).some((x) => Math.abs(x - px[0]) <= CONTINUATION_COL_TOL);
1223
+ }
1072
1224
  function headingRow(row) {
1073
1225
  const heads = row.map((c) => c.text.replace(/\s+/g, "")).filter(Boolean);
1074
1226
  if (heads.length === 1) return heads[0].length <= 8 || /^[①-⑳❶-❿]/.test(heads[0]);
@@ -1077,13 +1229,36 @@ function headingRow(row) {
1077
1229
  var ANNEX_HEAD_RE = /^\s*[<\[(【]?\s*(?:붙\s*임|참\s*고|별\s*첨|별\s*지|별\s*표|첨\s*부|부\s*록)(?:\s*\d|\s*$|\s*[>\])】])|^\s*■/;
1078
1230
  function looksContinued(prev, curr, pageHeights) {
1079
1231
  const ph = pageHeights?.get(prev.pageNumber), ch = pageHeights?.get(curr.pageNumber);
1080
- if (ph && ch && (prev.bbox.y > ph * PAGE_EDGE_BAND || curr.bbox.y + curr.bbox.height < ch * (1 - PAGE_EDGE_BAND))) return false;
1232
+ if (ph && ch && (prev.bbox.y > ph * PAGE_EDGE_BAND && !pushedLead(prev, curr) || curr.bbox.y + curr.bbox.height < ch * (1 - PAGE_EDGE_BAND))) return false;
1081
1233
  const firstRow = curr.table.cells[0] ?? [];
1082
1234
  const firstText = firstRow.find((c) => c.text.trim())?.text ?? "";
1083
1235
  if (!ANNEX_HEAD_RE.test(firstText)) return true;
1084
1236
  const filled = firstRow.map((c) => c.text.replace(/\s+/g, "")).filter(Boolean);
1085
1237
  return filled.length >= 2 && filled.every((t) => t === filled[0]);
1086
1238
  }
1239
+ function pushedLead(prev, curr) {
1240
+ if (!CLIP_TABLES.has(prev.table) || !CLIP_TABLES.has(curr.table)) return false;
1241
+ const lead = leadRows(curr.table);
1242
+ return lead.image && lead.height > prev.bbox.y;
1243
+ }
1244
+ function leadRows(t) {
1245
+ const ys = TABLE_ROWYS.get(t);
1246
+ if (!ys || ys.length < 2) return { height: 0, image: false };
1247
+ const anchors = anchorsOf(t);
1248
+ let end = 1, image = false;
1249
+ for (let r = 0; r < end; r++) {
1250
+ for (const a of anchors) {
1251
+ if (a.r !== r) continue;
1252
+ end = Math.max(end, r + a.rs);
1253
+ if (IMAGE_CELLS.has(a.cell)) image = true;
1254
+ }
1255
+ }
1256
+ return { height: ys[0] - ys[Math.min(end, ys.length - 1)], image };
1257
+ }
1258
+ function tailOf(b) {
1259
+ const t = b.table && TABLE_TAIL.get(b.table);
1260
+ return t && b.bbox ? { ...b, pageNumber: t.page, bbox: { ...b.bbox, page: t.page, y: t.y, height: t.height } } : b;
1261
+ }
1087
1262
  function firstRowSig(t) {
1088
1263
  const x = TABLE_COLXS.get(t);
1089
1264
  if (!x || x.length !== t.cols + 1) return null;
@@ -1134,14 +1309,14 @@ function chainHead(blocks, i, pageHeights) {
1134
1309
  break;
1135
1310
  }
1136
1311
  }
1137
- const pb = blocks[p];
1312
+ const pb = tailOf(blocks[p]);
1138
1313
  if (pb.pageNumber !== (cur.pageNumber ?? 0) - 1) break;
1139
1314
  if (!blocks.slice(p + 1, k).every((b) => besideOwn(b, pb, cur) || insideTable(b, pb))) break;
1140
1315
  if (!looksContinued(pb, cur, pageHeights)) break;
1141
1316
  const px = TABLE_COLXS.get(pb.table), cx = TABLE_COLXS.get(cur.table);
1142
1317
  if (!px || !cx) break;
1143
1318
  const dx = px[px.length - 1] - cx[cx.length - 1];
1144
- if (!shiftedSame(px, cx) && !px.some((x) => Math.abs(x - (cx[0] + dx)) <= CONTINUATION_COL_TOL)) break;
1319
+ if (!shiftedSame(px, cx) && !px.some((x) => Math.abs(x - (cx[0] + dx)) <= CONTINUATION_COL_TOL) && !prevLacksLeftCols(pb, px, cx, pageHeights)) break;
1145
1320
  k = p;
1146
1321
  }
1147
1322
  return k;
@@ -1155,6 +1330,7 @@ function rowTextsEqual(a, b) {
1155
1330
  return a.some((c) => c.text.trim() !== "");
1156
1331
  }
1157
1332
  var CONTINUATION_COL_TOL = 2;
1333
+ var FOREIGN_FIRST_ROW_CELLS = 3;
1158
1334
  function shiftedSame(px, cx, allowShift = true) {
1159
1335
  if (px.length !== cx.length) return false;
1160
1336
  const dx = allowShift ? px[px.length - 1] - cx[cx.length - 1] : 0;
@@ -1199,6 +1375,10 @@ function mergeContinuedCells(blocks, pageHeights) {
1199
1375
  const at = cell.blocks || add.blocks ? cellBlocks(cell, prev.pageNumber).length : -1;
1200
1376
  if (cell.blocks || add.blocks) cell.blocks = [...cellBlocks(cell, prev.pageNumber), ...cellBlocks(add, part.pageNumber)];
1201
1377
  cell.text = [cell.text, add.text].filter((s) => s.trim()).join("\n");
1378
+ joinCellEdges(cell, add);
1379
+ const lines = CELL_LINES.get(add);
1380
+ if (lines?.length) CELL_LINES.set(cell, [...CELL_LINES.get(cell) ?? [], ...lines]);
1381
+ if (part.pageNumber && part.bbox) TABLE_TAIL.set(prev.table, TABLE_TAIL.get(part.table) ?? { page: part.pageNumber, y: part.bbox.y, height: part.bbox.height });
1202
1382
  if (cell.text.trim() || cell.blocks?.length) EMPTY_PARTS.delete(prev.table);
1203
1383
  blocks.splice(j, 1);
1204
1384
  if (cell.blocks && at > 0) {
@@ -1231,6 +1411,7 @@ function fillNestedContinuation(blocks, at) {
1231
1411
  if (!cell || !add || cell.text.trim() || cell.blocks?.length) return;
1232
1412
  cell.text = add.text;
1233
1413
  if (add.blocks) cell.blocks = add.blocks;
1414
+ joinCellEdges(cell, add);
1234
1415
  blocks.splice(at, 1);
1235
1416
  }
1236
1417
 
@@ -2507,7 +2688,7 @@ function mergeLinkRuns(markdown) {
2507
2688
 
2508
2689
  // src/pdf/formula-ocr.ts
2509
2690
  async function applyFormulaOcr(buffer, blocks, pageFilter, effectivePageCount, warnings, _onProgress) {
2510
- const formulaMod = await import("./formula-EPKLPDU7.js");
2691
+ const formulaMod = await import("./formula-SHBXRXOJ.js");
2511
2692
  const { FormulaPipeline, ensureFormulaModels } = formulaMod;
2512
2693
  await ensureFormulaModels((p) => {
2513
2694
  if (p.phase === "download" && p.total) {
@@ -2890,7 +3071,7 @@ async function parsePdfDocument(buffer, options) {
2890
3071
  }
2891
3072
  if (targets.size > 0) {
2892
3073
  try {
2893
- const { runPdfOcr } = await import("./pdf-ocr-6DEE23IP.js");
3074
+ const { runPdfOcr } = await import("./pdf-ocr-462ZFSHX.js");
2894
3075
  const mode = typeof options?.ocr === "function" ? options.ocr : "builtin";
2895
3076
  const regionPages = new Map([...ocrRegions].filter(([p]) => options?.ocr !== "force" && !isImageBased && !pageQuality.find((q) => q.page === p)?.needsOcr));
2896
3077
  const ocrPageBlocks = await runPdfOcr(ocrBuffer, targets, mode, warnings, options?.onProgress, options?.tables !== false, vectorPageOps, regionPages);
@@ -3015,6 +3196,28 @@ async function parsePdfDocument(buffer, options) {
3015
3196
  return b.bbox.y > h * 0.1 && b.bbox.y + b.bbox.height < h * 0.9;
3016
3197
  });
3017
3198
  joinLatinCellWraps(outBlocks);
3199
+ if (options?.layoutTables !== "keep" && await isHancomPdf(doc)) {
3200
+ const shown = /* @__PURE__ */ new Map();
3201
+ const markContent = (bs) => {
3202
+ for (const b of bs ?? []) if (b.table) for (const row of b.table.cells) for (const c of row) {
3203
+ if (IMAGE_CELLS.has(c)) CONTENT_CELLS.add(c);
3204
+ markContent(c.blocks);
3205
+ }
3206
+ };
3207
+ const visual = (bs) => bs.flatMap((b) => {
3208
+ if (b.type !== "table") return [b];
3209
+ let v = shown.get(b);
3210
+ if (!v) {
3211
+ markContent([b]);
3212
+ shown.set(b, v = unframeLayoutTables([b], !!options?.keepTrailingEmptyCols));
3213
+ }
3214
+ return v;
3215
+ });
3216
+ outBlocks = visual(outBlocks);
3217
+ const kept = visual(blocks);
3218
+ blocks.length = 0;
3219
+ for (const b of kept) blocks.push(b);
3220
+ }
3018
3221
  const finishMarkdown = (bs) => mergeLinkRuns(cleanPdfText(blocksToMarkdown(bs), { keepLoneNumbers: true }));
3019
3222
  let markdown = finishMarkdown(outBlocks);
3020
3223
  return {
@@ -3051,6 +3254,14 @@ async function extractPdfMetadata(doc, metadata) {
3051
3254
  } catch {
3052
3255
  }
3053
3256
  }
3257
+ async function isHancomPdf(doc) {
3258
+ try {
3259
+ const info = (await doc.getMetadata())?.info;
3260
+ return [info?.Producer, info?.Creator].some((v) => typeof v === "string" && /^\s*(?:hancom\b|hwp\b)/i.test(v));
3261
+ } catch {
3262
+ return false;
3263
+ }
3264
+ }
3054
3265
  function parsePdfDate(dateStr) {
3055
3266
  const m = dateStr.match(/D:(\d{4})(\d{2})?(\d{2})?(\d{2})?(\d{2})?(\d{2})?/);
3056
3267
  if (!m) return void 0;
@@ -3090,4 +3301,4 @@ export {
3090
3301
  parsePdfDocument,
3091
3302
  removeHeaderFooterBlocks
3092
3303
  };
3093
- //# sourceMappingURL=parser-ZQM3664Z.js.map
3304
+ //# sourceMappingURL=parser-CTRB7PKD.js.map