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,88 +1,15 @@
1
+ #!/usr/bin/env node
1
2
  import {
2
3
  CELL_EDGES,
3
4
  HEADING_RATIO_H1,
4
5
  HEADING_RATIO_H2,
5
6
  HEADING_RATIO_H3,
6
7
  tidyScriptTags
7
- } from "./chunk-YDIVY65W.js";
8
- import {
9
- ensureModelsIn,
10
- getModelsDir
11
- } from "./chunk-INZGI6PI.js";
8
+ } from "./chunk-PTF4NCFM.js";
12
9
  import {
13
10
  safeMax,
14
11
  safeMin
15
- } from "./chunk-UDODNSDU.js";
16
-
17
- // src/ocr/models.ts
18
- import { join } from "path";
19
- import { stat } from "fs/promises";
20
- var OCR_DET_MODEL = {
21
- name: "PP-OCRv5 mobile det",
22
- filename: "det.onnx",
23
- url: "https://huggingface.co/PaddlePaddle/PP-OCRv5_mobile_det_onnx/resolve/main/inference.onnx",
24
- sha256: "a431985659dc921974177a95adcfbb90fd9e51989a5e04d70d0b75f597b6e61d",
25
- sizeMb: 5
26
- };
27
- var OCR_REC_MODEL = {
28
- name: "PP-OCRv5 korean rec",
29
- filename: "rec_korean.onnx",
30
- url: "https://huggingface.co/PaddlePaddle/korean_PP-OCRv5_mobile_rec_onnx/resolve/main/inference.onnx",
31
- sha256: "92f0b7785e64fc9090106a241cf4c1eb97472824558272751b88a2a4476d3a08",
32
- sizeMb: 13
33
- };
34
- var OCR_REC_DICT = {
35
- name: "PP-OCRv5 korean dict",
36
- filename: "rec_korean.yml",
37
- url: "https://huggingface.co/PaddlePaddle/korean_PP-OCRv5_mobile_rec_onnx/resolve/main/inference.yml",
38
- sha256: "f757fa1c40e99edcf27e9cce879b93eb2a51fa46f5ef39095689b8c37dd75998",
39
- sizeMb: 1
40
- };
41
- var ALL_OCR_MODELS = [OCR_DET_MODEL, OCR_REC_MODEL, OCR_REC_DICT];
42
- function getOcrModelsDir() {
43
- return getModelsDir("ppocr");
44
- }
45
- async function ensureOcrModels(onProgress) {
46
- return ensureModelsIn(getOcrModelsDir(), ALL_OCR_MODELS, onProgress);
47
- }
48
- async function ocrModelsCached() {
49
- const dir = getOcrModelsDir();
50
- for (const spec of ALL_OCR_MODELS) {
51
- try {
52
- if (!(await stat(join(dir, spec.filename))).size) return false;
53
- } catch {
54
- return false;
55
- }
56
- }
57
- return true;
58
- }
59
- function parseCharacterDict(yml) {
60
- const lines = yml.split("\n");
61
- const chars = [];
62
- let inDict = false;
63
- let dictIndent = -1;
64
- for (const line of lines) {
65
- if (!inDict) {
66
- const m2 = /^(\s*)character_dict:\s*$/.exec(line);
67
- if (m2) {
68
- inDict = true;
69
- dictIndent = m2[1].length;
70
- }
71
- continue;
72
- }
73
- const m = /^(\s*)- (.*)$/.exec(line);
74
- if (m && m[1].length >= dictIndent) {
75
- let v = m[2];
76
- if (v.length >= 2 && (v.startsWith("'") && v.endsWith("'") || v.startsWith('"') && v.endsWith('"'))) {
77
- v = v.slice(1, -1).replace(/''/g, "'");
78
- }
79
- chars.push(v);
80
- continue;
81
- }
82
- if (line.trim() !== "") break;
83
- }
84
- return chars;
85
- }
12
+ } from "./chunk-FZMGF6XU.js";
86
13
 
87
14
  // src/pdf/line-extract.ts
88
15
  import { OPS } from "pdfjs-dist/legacy/build/pdf.mjs";
@@ -1944,7 +1871,7 @@ function dropGridsInside(lineGrids, clipGrids, containers = [], verticals = [])
1944
1871
  const ga = area(g);
1945
1872
  return ga > 0 && ix * iy / ga >= 0.5;
1946
1873
  };
1947
- const inside = (c, g) => c.x1 >= g.x1 - 1 && c.x2 <= g.x2 + 1 && c.y1 >= g.y1 - 1 && c.y2 <= g.y2 + 1;
1874
+ const inside = (c, g) => c.x1 >= g.x1 - 3 && c.x2 <= g.x2 + 3 && c.y1 >= g.y1 - 3 && c.y2 <= g.y2 + 3;
1948
1875
  const stackedOnly = (g) => {
1949
1876
  const stacked = clipGrids.filter((c) => inside(c.bbox, g.bbox)).sort((a, b) => a.bbox.y1 - b.bbox.y1);
1950
1877
  if (stacked.length < 2 || g.colXs.length < 3 || stacked.reduce((s, c) => s + area(c.bbox), 0) < area(g.bbox) * 0.5) return false;
@@ -3415,6 +3342,49 @@ function isExamLayoutTable(table) {
3415
3342
  return layout >= texts.length * 0.6;
3416
3343
  }
3417
3344
 
3345
+ // src/pdf/cluster-cell-text.ts
3346
+ function clusterCellLines(items) {
3347
+ const hOf = (i) => i.h > 0 ? i.h : i.fontSize;
3348
+ const lines = [];
3349
+ for (const it of [...items].sort((a, b) => b.y - a.y || a.x - b.x)) {
3350
+ const bottom = it.y, top = it.y + hOf(it);
3351
+ const line = lines.find((l) => Math.min(l.top, top) - Math.max(l.bottom, bottom) >= Math.min(l.top - l.bottom, top - bottom) * 0.5);
3352
+ if (line) {
3353
+ line.items.push(it);
3354
+ line.bottom = Math.min(line.bottom, bottom);
3355
+ line.top = Math.max(line.top, top);
3356
+ } else lines.push({ bottom, top, items: [it] });
3357
+ }
3358
+ return lines.sort((a, b) => b.top - a.top).map(({ items: line }) => {
3359
+ line.sort((a, b) => a.x - b.x);
3360
+ let s = line[0].text;
3361
+ for (let i = 1; i < line.length; i++) {
3362
+ const gap = line[i].x - (line[i - 1].x + line[i - 1].w);
3363
+ const fs = (line[i].fontSize + line[i - 1].fontSize) / 2;
3364
+ s += (!isCjkLatinAutospace(line[i - 1].text, line[i].text, gap, fs) && (line[i].hasSpaceBefore && gap >= fs * 0.05 || gap > spaceGapThreshold(fs)) ? " " : "") + line[i].text;
3365
+ }
3366
+ const last = line.reduce((a, b) => b.x + b.w > a.x + a.w ? b : a);
3367
+ return {
3368
+ text: s,
3369
+ left: line[0].x,
3370
+ right: last.x + last.w,
3371
+ fontSize: line[0].fontSize,
3372
+ spaceAfter: last.spaceAfter,
3373
+ firstCharW: line[0].w / Math.max(1, [...line[0].text.replace(/<\/?u>|~~/g, "")].length)
3374
+ };
3375
+ });
3376
+ }
3377
+ var WRAP_INDENT_MAX = 3;
3378
+ function joinClusterCellLines(lines, box, lex) {
3379
+ let out = lines[0]?.text ?? "";
3380
+ for (let i = 1; i < lines.length; i++) {
3381
+ const a = lines[i - 1], b = lines[i];
3382
+ const join = !a.spaceAfter && cellLineWraps(box, box.x1, a.right, a.fontSize, b.firstCharW) && a.left - box.x1 <= WRAP_INDENT_MAX * a.fontSize && b.left - box.x1 <= WRAP_INDENT_MAX * b.fontSize && /<\/u>$/.test(a.text) === /^<u>/.test(b.text) && !startsNewItem(out, b.text) && wrapJoiner(out, b.text, lex, false) === "";
3383
+ out += (join ? "" : " ") + b.text;
3384
+ }
3385
+ return out;
3386
+ }
3387
+
3418
3388
  // src/pdf/cluster-detector.ts
3419
3389
  var Y_TOL = 3;
3420
3390
  var COL_CLUSTER_TOL = 15;
@@ -3423,7 +3393,7 @@ var MIN_COLS = 2;
3423
3393
  var MIN_GAP_FACTOR = 2;
3424
3394
  var MIN_GAP_ABSOLUTE = 20;
3425
3395
  var MIN_COL_FILL_RATIO = 0.4;
3426
- function detectClusterTables(items, pageNum, rejected) {
3396
+ function detectClusterTables(items, pageNum, rejected, lex) {
3427
3397
  const tab = sideTabGlyphs(items);
3428
3398
  if (tab.size) items = items.filter((i) => !tab.has(i));
3429
3399
  if (items.length < MIN_ROWS * MIN_COLS) return [];
@@ -3444,7 +3414,7 @@ function detectClusterTables(items, pageNum, rejected) {
3444
3414
  const mergedRows = mergeMultiLineRows(headerAndBelow, columns);
3445
3415
  const tableRegions = findTableRegionsByHeader(mergedRows, columns, headerItems);
3446
3416
  for (const region of tableRegions) {
3447
- const table = buildClusterTable(region.rows, columns, pageNum);
3417
+ const table = buildClusterTable(region.rows, columns, pageNum, lex);
3448
3418
  if (table) {
3449
3419
  expandUsedItems(table.usedItems, originMap);
3450
3420
  results.push(table);
@@ -3459,8 +3429,8 @@ function detectClusterTables(items, pageNum, rejected) {
3459
3429
  const tableRegions = findTableRegions(rows, columns);
3460
3430
  for (const region of tableRegions) {
3461
3431
  const own = extractColumnClusters(region.rows.filter((row) => hasSuspiciousGaps(row)));
3462
- const ownTable = own.length >= MIN_COLS && own.length < columns.length ? buildClusterTable(mergeMultiLineRows(region.rows, own), own, pageNum) : null;
3463
- const table = ownTable && ownTable.table.cells.every((row, r) => row.every((cell) => (r === 0 || cell.colSpan >= ownTable.table.cols || cell.text.trim().length <= 30) && !/\p{Co}/u.test(cell.text))) ? ownTable : buildClusterTable(mergeMultiLineRows(region.rows, columns), columns, pageNum);
3432
+ const ownTable = own.length >= MIN_COLS && own.length < columns.length ? buildClusterTable(mergeMultiLineRows(region.rows, own), own, pageNum, lex) : null;
3433
+ const table = ownTable && ownTable.table.cells.every((row, r) => row.every((cell) => (r === 0 || cell.colSpan >= ownTable.table.cols || cell.text.trim().length <= 30) && !/\p{Co}/u.test(cell.text))) ? ownTable : buildClusterTable(mergeMultiLineRows(region.rows, columns), columns, pageNum, lex);
3464
3434
  if (table) {
3465
3435
  expandUsedItems(table.usedItems, originMap);
3466
3436
  results.push(table);
@@ -4157,7 +4127,7 @@ function assignRowItems(items, columns, numCols, headerFace) {
4157
4127
  }
4158
4128
  return result;
4159
4129
  }
4160
- function buildClusterTable(rows, columns, pageNum) {
4130
+ function buildClusterTable(rows, columns, pageNum, lex) {
4161
4131
  const numCols = columns.length;
4162
4132
  const numRows = rows.length;
4163
4133
  if (numRows < MIN_ROWS || numCols < MIN_COLS) return null;
@@ -4166,6 +4136,7 @@ function buildClusterTable(rows, columns, pageNum) {
4166
4136
  () => Array.from({ length: numCols }, () => ({ text: "", colSpan: 1, rowSpan: 1 }))
4167
4137
  );
4168
4138
  const usedItems = /* @__PURE__ */ new Set();
4139
+ const lines = cells.map((row) => row.map(() => []));
4169
4140
  const headFaces = new Set(rows[0]?.items.map((i) => i.fontName));
4170
4141
  const headerFace = headFaces.size === 1 && rows.slice(1).every((row) => row.items.every((i) => !headFaces.has(i.fontName))) ? [...headFaces][0] : void 0;
4171
4142
  for (let r = 0; r < numRows; r++) {
@@ -4177,12 +4148,18 @@ function buildClusterTable(rows, columns, pageNum) {
4177
4148
  }
4178
4149
  const assignments = assignRowItems(row.items, columns, numCols, r === 0 ? headerFace : void 0);
4179
4150
  for (const { col, items } of assignments) {
4180
- const text = joinCellItems(items);
4181
- const existing = cells[r][col].text;
4182
- cells[r][col].text = existing ? existing + " " + text : text;
4151
+ const cell = lines[r][col];
4152
+ if (cell.length) cell[cell.length - 1].spaceAfter = true;
4153
+ cell.push(...clusterCellLines(items));
4183
4154
  for (const item of items) usedItems.add(item);
4184
4155
  }
4185
4156
  }
4157
+ const boxes = columns.map((_, c) => {
4158
+ const col = lines.flatMap((row) => row[c]);
4159
+ return { x1: Math.min(...col.map((l) => l.left)), x2: Math.max(...col.map((l) => l.right)) };
4160
+ });
4161
+ const textOf = (r, c) => joinClusterCellLines(lines[r][c], boxes[c], lex);
4162
+ for (let r = 0; r < numRows; r++) for (let c = 0; c < numCols; c++) if (lines[r][c].length) cells[r][c].text = textOf(r, c);
4186
4163
  let emptyRows = 0;
4187
4164
  for (const row of cells) {
4188
4165
  if (row.every((c) => c.text === "")) emptyRows++;
@@ -4202,9 +4179,9 @@ function buildClusterTable(rows, columns, pageNum) {
4202
4179
  if (cells[pr].some((c) => c.text.trim())) {
4203
4180
  if (cells[pr][0].colSpan > 1) break;
4204
4181
  for (let c = 0; c < numCols; c++) {
4205
- const prev = cells[pr][c].text.trim();
4206
- const curr = cells[r][c].text.trim();
4207
- if (curr) cells[pr][c].text = prev ? prev + " " + curr : curr;
4182
+ if (!cells[r][c].text.trim()) continue;
4183
+ lines[pr][c].push(...lines[r][c]);
4184
+ cells[pr][c].text = textOf(pr, c);
4208
4185
  }
4209
4186
  for (let c = 0; c < numCols; c++) cells[r][c].text = "";
4210
4187
  break;
@@ -4251,29 +4228,6 @@ function buildClusterTable(rows, columns, pageNum) {
4251
4228
  usedItems
4252
4229
  };
4253
4230
  }
4254
- function joinCellItems(items) {
4255
- const hOf = (i) => i.h > 0 ? i.h : i.fontSize;
4256
- const lines = [];
4257
- for (const it of [...items].sort((a, b) => b.y - a.y || a.x - b.x)) {
4258
- const bottom = it.y, top = it.y + hOf(it);
4259
- const line = lines.find((l) => Math.min(l.top, top) - Math.max(l.bottom, bottom) >= Math.min(l.top - l.bottom, top - bottom) * 0.5);
4260
- if (line) {
4261
- line.items.push(it);
4262
- line.bottom = Math.min(line.bottom, bottom);
4263
- line.top = Math.max(line.top, top);
4264
- } else lines.push({ bottom, top, items: [it] });
4265
- }
4266
- return lines.sort((a, b) => b.top - a.top).map(({ items: line }) => {
4267
- line.sort((a, b) => a.x - b.x);
4268
- let s = line[0].text;
4269
- for (let i = 1; i < line.length; i++) {
4270
- const gap = line[i].x - (line[i - 1].x + line[i - 1].w);
4271
- const fs = (line[i].fontSize + line[i - 1].fontSize) / 2;
4272
- s += (!isCjkLatinAutospace(line[i - 1].text, line[i].text, gap, fs) && (line[i].hasSpaceBefore && gap >= fs * 0.05 || gap > spaceGapThreshold(fs)) ? " " : "") + line[i].text;
4273
- }
4274
- return s;
4275
- }).join(" ");
4276
- }
4277
4231
 
4278
4232
  // src/pdf/page-regions.ts
4279
4233
  function splitTwoColumnProse(items, cutX) {
@@ -5717,6 +5671,20 @@ function detectSpecialKoreanTables(blocks) {
5717
5671
  flushKvTable();
5718
5672
  return result;
5719
5673
  }
5674
+ function tracksPages(occ) {
5675
+ const nums = occ.map((o) => [...o.text.matchAll(/\d+/g)].map((m) => +m[0]));
5676
+ if (!nums.length || nums.some((n) => n.length !== nums[0].length)) return false;
5677
+ return nums[0].some((_, j) => new Set(occ.map((o, k) => o.page - nums[k][j])).size === 1);
5678
+ }
5679
+ function looseVaryingNumber(occ) {
5680
+ const nums = occ.map((o) => [...o.text.matchAll(/\d+/g)]);
5681
+ if (!nums.length || nums.some((n) => n.length !== nums[0].length)) return false;
5682
+ const loose = (text, m) => !/\p{L}/u.test(text[m.index - 1] ?? " ") && !/\p{L}/u.test(text[m.index + m[0].length] ?? " ");
5683
+ for (let j = 0; j < nums[0].length; j++) {
5684
+ if (new Set(nums.map((n) => n[j][0])).size > 1 && occ.every((o, k) => loose(o.text, nums[k][j]))) return true;
5685
+ }
5686
+ return false;
5687
+ }
5720
5688
  function removeHeaderFooterBlocks(blocks, pageHeights, warnings, notes, tables = false, context = []) {
5721
5689
  if (context.length && !tables) {
5722
5690
  const removed = removeHeaderFooterBlocks([...blocks, ...context], pageHeights, [], notes).filter((index) => index < blocks.length);
@@ -5746,6 +5714,7 @@ function removeHeaderFooterBlocks(blocks, pageHeights, warnings, notes, tables =
5746
5714
  const patternCount = /* @__PURE__ */ new Map();
5747
5715
  const patternPages = /* @__PURE__ */ new Map();
5748
5716
  const patternNumbers = /* @__PURE__ */ new Map();
5717
+ const patternOcc = /* @__PURE__ */ new Map();
5749
5718
  for (const e of entries) {
5750
5719
  const norm = e.text.replace(/\d+/g, "#");
5751
5720
  patternCount.set(norm, (patternCount.get(norm) || 0) + 1);
@@ -5755,13 +5724,18 @@ function removeHeaderFooterBlocks(blocks, pageHeights, warnings, notes, tables =
5755
5724
  const pages = patternPages.get(norm) || /* @__PURE__ */ new Set();
5756
5725
  pages.add(e.page);
5757
5726
  patternPages.set(norm, pages);
5727
+ patternOcc.set(norm, [...patternOcc.get(norm) ?? [], e]);
5758
5728
  }
5759
5729
  const repeatedPatterns = /* @__PURE__ */ new Set();
5760
5730
  for (const [p, count] of patternCount) {
5761
5731
  const pages = [...patternPages.get(p) ?? []];
5762
5732
  const span2 = pages.length ? Math.max(...pages) - Math.min(...pages) + 1 : 0;
5763
- const pageNumbered = !tables && (patternNumbers.get(p)?.size ?? 0) > 1;
5764
- if (count >= MIN_REPEAT2 && pages.length >= MIN_REPEAT2 && (pages.length >= span2 * 0.4 || pageNumbered)) {
5733
+ const varying = !tables && (patternNumbers.get(p)?.size ?? 0) > 1;
5734
+ const occ = patternOcc.get(p) ?? [];
5735
+ const dense = pages.length >= span2 * 0.4;
5736
+ const loose = looseVaryingNumber(occ) && (entries === bottomEntries || dense || tracksPages(occ));
5737
+ const pageNumbered = varying && (loose || dense && new Set(occ.map((o) => o.text)).size * 2 <= occ.length);
5738
+ if (count >= MIN_REPEAT2 && pages.length >= MIN_REPEAT2 && (varying ? pageNumbered : dense)) {
5765
5739
  repeatedPatterns.add(p);
5766
5740
  }
5767
5741
  }
@@ -5799,6 +5773,59 @@ function removeHeaderFooterBlocks(blocks, pageHeights, warnings, notes, tables =
5799
5773
  }
5800
5774
  return [...removeSet].sort((a, b) => a - b);
5801
5775
  }
5776
+ function runningLinePatterns(removed, pageHeights) {
5777
+ const occ = /* @__PURE__ */ new Map();
5778
+ for (const b of removed) {
5779
+ const ph = b.bbox && b.pageNumber ? pageHeights.get(b.bbox.page) || pageHeights.get(b.pageNumber) : void 0;
5780
+ const key = b.text ? runningKey(b.text) : "";
5781
+ if (!ph || !b.bbox || !b.pageNumber || !/\p{L}/u.test(key) || ph - b.bbox.y <= ph * 0.5) continue;
5782
+ (occ.get(key) ?? occ.set(key, []).get(key)).push({ page: b.pageNumber, nums: (b.text.match(/\d+/g) ?? []).join(",") });
5783
+ }
5784
+ const out = /* @__PURE__ */ new Map();
5785
+ for (const [key, list] of occ) {
5786
+ if (!pageNumberAtEnd(key)) continue;
5787
+ const offsets = new Set(list.map((o) => o.page - +o.nums));
5788
+ if (offsets.size === 1) out.set(key, [...offsets][0]);
5789
+ }
5790
+ return out;
5791
+ }
5792
+ var runningKey = (s) => s.replace(/\d+/g, "#").replace(/\s+/g, " ").trim();
5793
+ var pageNumberAtEnd = (key) => (key.match(/#/g) ?? []).length === 1 && /#\s*[)\]]?$/.test(key);
5794
+ function stripAbsorbedRunningLines(blocks, pageHeights, running) {
5795
+ if (!running.size) return blocks;
5796
+ const matches = (line, page) => {
5797
+ const offset = running.get(runningKey(line));
5798
+ return offset !== void 0 && page - +(line.match(/\d+/g) ?? []).pop() === offset;
5799
+ };
5800
+ const out = [];
5801
+ for (const b of blocks) {
5802
+ const ph = b.bbox && b.pageNumber ? pageHeights.get(b.bbox.page) || pageHeights.get(b.pageNumber) : void 0;
5803
+ if (!ph || !b.bbox || !b.pageNumber || b.bbox.y > ph * 0.12) {
5804
+ out.push(b);
5805
+ continue;
5806
+ }
5807
+ if (b.type === "paragraph" && b.text) {
5808
+ const lines = b.text.split("\n");
5809
+ let hi = lines.length;
5810
+ while (hi > 0 && !lines[hi - 1].trim()) hi--;
5811
+ if (hi > 0 && matches(lines[hi - 1], b.pageNumber)) {
5812
+ const text = lines.slice(0, hi - 1).join("\n").trim();
5813
+ if (!text) continue;
5814
+ b.text = text;
5815
+ }
5816
+ } else if (b.type === "table" && b.table && b.table.cells.length) {
5817
+ const t = b.table, last = t.cells.length - 1;
5818
+ if (matches(t.cells[last].map((c) => c.text.trim()).filter(Boolean).join(" "), b.pageNumber) && !t.cells.slice(0, last).some((row, i) => row.some((c) => i + (c.rowSpan || 1) - 1 >= last))) {
5819
+ t.cells.pop();
5820
+ if (!t.cells.length) continue;
5821
+ t.rows = t.cells.length;
5822
+ t.hasHeader = t.hasHeader && t.rows > 1;
5823
+ }
5824
+ }
5825
+ out.push(b);
5826
+ }
5827
+ return out;
5828
+ }
5802
5829
 
5803
5830
  // src/pdf/table-meta.ts
5804
5831
  var CLIP_TABLES = /* @__PURE__ */ new WeakSet();
@@ -8274,7 +8301,7 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
8274
8301
  spaceAfter: i.spaceAfter
8275
8302
  }));
8276
8303
  const proseColumns = findTwoColumnProseCutX(clusterItems) !== null || detectPersistentColumnGutter(remaining.map((i) => ({ x: i.x, y: i.y, w: i.w, h: i.h > 0 ? i.h : i.fontSize }))) !== null;
8277
- const clusterResults = (proseColumns ? [] : detectClusterTables(clusterItems, pageNum)).filter((cr) => {
8304
+ const clusterResults = (proseColumns ? [] : detectClusterTables(clusterItems, pageNum, void 0, lex)).filter((cr) => {
8278
8305
  const b = cr.bbox;
8279
8306
  const overlapX = (x) => Math.min(x.x + x.width, b.x + b.width) - Math.max(x.x, b.x);
8280
8307
  return !blocks.some((x) => x.bbox && x.bbox.y >= b.y - 2 && x.bbox.y + x.bbox.height <= b.y + b.height + 2 && (x.type === "paragraph" ? (x.text?.match(/\p{L}/gu)?.length ?? 0) >= 10 && overlapX(x.bbox) >= 0.8 * b.width : x.type === "table" && !ocrPage && x.table?.cols === cr.table.cols && overlapX(x.bbox) >= 0.5 * Math.min(x.bbox.width, b.width)));
@@ -8626,7 +8653,7 @@ function extractPageBlocksFallback(items, pageNum, fullPage = false, detectTable
8626
8653
  if (regions) return regions.flatMap((region) => extractPageBlocksFallback(region, pageNum, false, detectTables, lex));
8627
8654
  }
8628
8655
  const rejected = { prose: 0 };
8629
- const clusterResults = detectTables ? detectClusterTables(clusterItems, pageNum, rejected) : [];
8656
+ const clusterResults = detectTables ? detectClusterTables(clusterItems, pageNum, rejected, lex) : [];
8630
8657
  if (clusterResults.length > 0) {
8631
8658
  const ciToIdx = /* @__PURE__ */ new Map();
8632
8659
  for (let ci = 0; ci < clusterItems.length; ci++) ciToIdx.set(clusterItems[ci], ci);
@@ -8811,13 +8838,6 @@ function rowParagraphs(block) {
8811
8838
  }
8812
8839
 
8813
8840
  export {
8814
- OCR_DET_MODEL,
8815
- OCR_REC_MODEL,
8816
- OCR_REC_DICT,
8817
- getOcrModelsDir,
8818
- ensureOcrModels,
8819
- ocrModelsCached,
8820
- parseCharacterDict,
8821
8841
  extractLines,
8822
8842
  extractImageRegions,
8823
8843
  filterHiddenText,
@@ -8847,6 +8867,8 @@ export {
8847
8867
  detectTableCaptions,
8848
8868
  detectKoreanListBlocks,
8849
8869
  removeHeaderFooterBlocks,
8870
+ runningLinePatterns,
8871
+ stripAbsorbedRunningLines,
8850
8872
  CLIP_TABLES,
8851
8873
  FRAME_TITLE_BLOCKS,
8852
8874
  TABLE_COLXS,
@@ -8869,4 +8891,4 @@ export {
8869
8891
  UNRULED_REGION_TABLES,
8870
8892
  mergeOcrImageRegions
8871
8893
  };
8872
- //# sourceMappingURL=chunk-DQ2YGTRS.js.map
8894
+ //# sourceMappingURL=chunk-KBV4WFZ6.js.map