kordoc 3.8.1 → 3.8.3

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 (32) hide show
  1. package/README.md +12 -0
  2. package/dist/{-LD4BZDDJ.js → -F5IXBLQQ.js} +3 -3
  3. package/dist/{chunk-PELBIL4K.js → chunk-7J73IGMK.js} +2 -2
  4. package/dist/{chunk-KT2BCHXI.js → chunk-B27QMVL7.js} +872 -825
  5. package/dist/chunk-B27QMVL7.js.map +1 -0
  6. package/dist/{chunk-IFYJFWD2.js → chunk-KIWKBRCJ.js} +2 -2
  7. package/dist/{chunk-LFCS3UVG.cjs → chunk-XL6O3VAY.cjs} +2 -2
  8. package/dist/{chunk-LFCS3UVG.cjs.map → chunk-XL6O3VAY.cjs.map} +1 -1
  9. package/dist/cli.js +4 -4
  10. package/dist/index.cjs +1065 -1018
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.cts +17 -8
  13. package/dist/index.d.ts +17 -8
  14. package/dist/index.js +871 -824
  15. package/dist/index.js.map +1 -1
  16. package/dist/mcp.js +3 -3
  17. package/dist/{parser-FFEBMLSH.js → parser-6GP535ZB.js} +211 -25
  18. package/dist/parser-6GP535ZB.js.map +1 -0
  19. package/dist/{parser-XEDROIM7.js → parser-TM3AS25T.js} +211 -25
  20. package/dist/parser-TM3AS25T.js.map +1 -0
  21. package/dist/{parser-IXK5V7YG.cjs → parser-WWKYMRGJ.cjs} +240 -52
  22. package/dist/parser-WWKYMRGJ.cjs.map +1 -0
  23. package/dist/{watch-MAWCDNFI.js → watch-HETTZ7BO.js} +3 -3
  24. package/package.json +2 -1
  25. package/dist/chunk-KT2BCHXI.js.map +0 -1
  26. package/dist/parser-FFEBMLSH.js.map +0 -1
  27. package/dist/parser-IXK5V7YG.cjs.map +0 -1
  28. package/dist/parser-XEDROIM7.js.map +0 -1
  29. /package/dist/{-LD4BZDDJ.js.map → -F5IXBLQQ.js.map} +0 -0
  30. /package/dist/{chunk-PELBIL4K.js.map → chunk-7J73IGMK.js.map} +0 -0
  31. /package/dist/{chunk-IFYJFWD2.js.map → chunk-KIWKBRCJ.js.map} +0 -0
  32. /package/dist/{watch-MAWCDNFI.js.map → watch-HETTZ7BO.js.map} +0 -0
package/dist/mcp.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  parse,
11
11
  patchHwp,
12
12
  patchHwpx
13
- } from "./chunk-KT2BCHXI.js";
13
+ } from "./chunk-B27QMVL7.js";
14
14
  import {
15
15
  detectFormat,
16
16
  detectZipFormat
@@ -21,7 +21,7 @@ import {
21
21
  blocksToMarkdown,
22
22
  sanitizeError,
23
23
  toArrayBuffer
24
- } from "./chunk-IFYJFWD2.js";
24
+ } from "./chunk-KIWKBRCJ.js";
25
25
  import "./chunk-MOL7MDBG.js";
26
26
 
27
27
  // src/mcp.ts
@@ -193,7 +193,7 @@ server.tool(
193
193
  break;
194
194
  case "pdf":
195
195
  try {
196
- const { extractPdfMetadataOnly } = await import("./parser-FFEBMLSH.js");
196
+ const { extractPdfMetadataOnly } = await import("./parser-6GP535ZB.js");
197
197
  metadata = await extractPdfMetadataOnly(buffer);
198
198
  } catch {
199
199
  metadata = void 0;
@@ -7,7 +7,7 @@ import {
7
7
  blocksToMarkdown,
8
8
  safeMax,
9
9
  safeMin
10
- } from "./chunk-IFYJFWD2.js";
10
+ } from "./chunk-KIWKBRCJ.js";
11
11
  import {
12
12
  parsePageRange
13
13
  } from "./chunk-MOL7MDBG.js";
@@ -21,21 +21,30 @@ function extractLines(fnArray, argsArray) {
21
21
  const horizontals = [];
22
22
  const verticals = [];
23
23
  let lineWidth = 1;
24
+ let ctm = [1, 0, 0, 1, 0, 0];
25
+ const ctmStack = [];
26
+ const applyCtm = (x, y) => [ctm[0] * x + ctm[2] * y + ctm[4], ctm[1] * x + ctm[3] * y + ctm[5]];
27
+ const ctmScale = () => (Math.hypot(ctm[0], ctm[1]) + Math.hypot(ctm[2], ctm[3])) / 2;
24
28
  let currentPath = [];
25
29
  let pathStartX = 0, pathStartY = 0;
26
30
  let curX = 0, curY = 0;
27
- function pushRectangle(path, rx, ry, rw, rh) {
28
- if (Math.abs(rh) < ORIENTATION_TOL * 2) {
29
- path.push({ x1: rx, y1: ry + rh / 2, x2: rx + rw, y2: ry + rh / 2 });
30
- } else if (Math.abs(rw) < ORIENTATION_TOL * 2) {
31
- path.push({ x1: rx + rw / 2, y1: ry, x2: rx + rw / 2, y2: ry + rh });
31
+ function pushSeg(x1, y1, x2, y2) {
32
+ const [tx1, ty1] = applyCtm(x1, y1);
33
+ const [tx2, ty2] = applyCtm(x2, y2);
34
+ currentPath.push({ x1: tx1, y1: ty1, x2: tx2, y2: ty2 });
35
+ }
36
+ function pushRectangle(rx, ry, rw, rh) {
37
+ const effH = Math.abs(rh) * Math.hypot(ctm[2], ctm[3]);
38
+ const effW = Math.abs(rw) * Math.hypot(ctm[0], ctm[1]);
39
+ if (effH < ORIENTATION_TOL * 2) {
40
+ pushSeg(rx, ry + rh / 2, rx + rw, ry + rh / 2);
41
+ } else if (effW < ORIENTATION_TOL * 2) {
42
+ pushSeg(rx + rw / 2, ry, rx + rw / 2, ry + rh);
32
43
  } else {
33
- path.push(
34
- { x1: rx, y1: ry, x2: rx + rw, y2: ry },
35
- { x1: rx + rw, y1: ry, x2: rx + rw, y2: ry + rh },
36
- { x1: rx + rw, y1: ry + rh, x2: rx, y2: ry + rh },
37
- { x1: rx, y1: ry + rh, x2: rx, y2: ry }
38
- );
44
+ pushSeg(rx, ry, rx + rw, ry);
45
+ pushSeg(rx + rw, ry, rx + rw, ry + rh);
46
+ pushSeg(rx + rw, ry + rh, rx, ry + rh);
47
+ pushSeg(rx, ry + rh, rx, ry);
39
48
  }
40
49
  }
41
50
  function flushPath(isStroke) {
@@ -43,8 +52,9 @@ function extractLines(fnArray, argsArray) {
43
52
  currentPath = [];
44
53
  return;
45
54
  }
55
+ const effWidth = lineWidth * ctmScale();
46
56
  for (const seg of currentPath) {
47
- classifyAndAdd(seg, lineWidth, horizontals, verticals);
57
+ classifyAndAdd(seg, effWidth, horizontals, verticals);
48
58
  }
49
59
  currentPath = [];
50
60
  }
@@ -55,6 +65,24 @@ function extractLines(fnArray, argsArray) {
55
65
  case OPS.setLineWidth:
56
66
  lineWidth = args[0] || 1;
57
67
  break;
68
+ case OPS.save:
69
+ ctmStack.push(ctm.slice());
70
+ break;
71
+ case OPS.restore:
72
+ ctm = ctmStack.pop() ?? [1, 0, 0, 1, 0, 0];
73
+ break;
74
+ case OPS.transform: {
75
+ const t = args;
76
+ ctm = [
77
+ ctm[0] * t[0] + ctm[2] * t[1],
78
+ ctm[1] * t[0] + ctm[3] * t[1],
79
+ ctm[0] * t[2] + ctm[2] * t[3],
80
+ ctm[1] * t[2] + ctm[3] * t[3],
81
+ ctm[0] * t[4] + ctm[2] * t[5] + ctm[4],
82
+ ctm[1] * t[4] + ctm[3] * t[5] + ctm[5]
83
+ ];
84
+ break;
85
+ }
58
86
  case OPS.constructPath: {
59
87
  const arg0 = args[0];
60
88
  if (Array.isArray(arg0)) {
@@ -69,16 +97,16 @@ function extractLines(fnArray, argsArray) {
69
97
  pathStartY = curY;
70
98
  } else if (subOp === OPS.lineTo) {
71
99
  const x2 = coords[ci++], y2 = coords[ci++];
72
- currentPath.push({ x1: curX, y1: curY, x2, y2 });
100
+ pushSeg(curX, curY, x2, y2);
73
101
  curX = x2;
74
102
  curY = y2;
75
103
  } else if (subOp === OPS.rectangle) {
76
104
  const rx = coords[ci++], ry = coords[ci++];
77
105
  const rw = coords[ci++], rh = coords[ci++];
78
- pushRectangle(currentPath, rx, ry, rw, rh);
106
+ pushRectangle(rx, ry, rw, rh);
79
107
  } else if (subOp === OPS.closePath) {
80
108
  if (curX !== pathStartX || curY !== pathStartY) {
81
- currentPath.push({ x1: curX, y1: curY, x2: pathStartX, y2: pathStartY });
109
+ pushSeg(curX, curY, pathStartX, pathStartY);
82
110
  }
83
111
  curX = pathStartX;
84
112
  curY = pathStartY;
@@ -104,7 +132,7 @@ function extractLines(fnArray, argsArray) {
104
132
  pathStartY = curY;
105
133
  } else if (drawOp === 1 /* lineTo */) {
106
134
  const x2 = pathData[di++], y2 = pathData[di++];
107
- currentPath.push({ x1: curX, y1: curY, x2, y2 });
135
+ pushSeg(curX, curY, x2, y2);
108
136
  curX = x2;
109
137
  curY = y2;
110
138
  } else if (drawOp === 2 /* curveTo */) {
@@ -113,7 +141,7 @@ function extractLines(fnArray, argsArray) {
113
141
  di += 4;
114
142
  } else if (drawOp === 4 /* closePath */) {
115
143
  if (curX !== pathStartX || curY !== pathStartY) {
116
- currentPath.push({ x1: curX, y1: curY, x2: pathStartX, y2: pathStartY });
144
+ pushSeg(curX, curY, pathStartX, pathStartY);
117
145
  }
118
146
  curX = pathStartX;
119
147
  curY = pathStartY;
@@ -1235,7 +1263,106 @@ function detectClusterTables(items, pageNum) {
1235
1263
  }
1236
1264
  }
1237
1265
  }
1238
- return results;
1266
+ return results.filter((r) => !isTwoColumnProse(r));
1267
+ }
1268
+ function isTwoColumnProse(r) {
1269
+ const t = r.table;
1270
+ if (t.rows < 8) return false;
1271
+ const dense = [];
1272
+ for (let c = 0; c < t.cols; c++) {
1273
+ const filled = t.cells.filter((row) => row[c]?.text.trim()).length;
1274
+ if (filled / t.rows >= 0.3) dense.push(c);
1275
+ }
1276
+ if (dense.length !== 2) return false;
1277
+ for (const c of dense) {
1278
+ const lens = t.cells.map((row) => row[c]?.text.replace(/\s+/g, "").length ?? 0).filter((n) => n > 0);
1279
+ const avg = lens.reduce((s, v) => s + v, 0) / (lens.length || 1);
1280
+ if (avg < 12) return false;
1281
+ }
1282
+ return findTwoColumnProseCutX([...r.usedItems]) !== null;
1283
+ }
1284
+ function findTwoColumnProseCutX(items) {
1285
+ const lines = groupByBaseline(items);
1286
+ if (lines.length < 8) return null;
1287
+ let minX = Infinity;
1288
+ let maxX = -Infinity;
1289
+ for (const i of items) {
1290
+ if (i.x < minX) minX = i.x;
1291
+ if (i.x + i.w > maxX) maxX = i.x + i.w;
1292
+ }
1293
+ if (!Number.isFinite(maxX - minX)) return null;
1294
+ if (maxX - minX < 100) return null;
1295
+ const lo = minX + (maxX - minX) * 0.3;
1296
+ const hi = minX + (maxX - minX) * 0.7;
1297
+ const step = Math.max(2, (hi - lo) / 400);
1298
+ let cutX = 0;
1299
+ let bestCover = Infinity;
1300
+ for (let x = lo; x <= hi; x += step) {
1301
+ let cover = 0;
1302
+ for (const line of lines) {
1303
+ if (line.items.some((i) => i.x < x && i.x + i.w > x)) cover++;
1304
+ }
1305
+ if (cover < bestCover) {
1306
+ bestCover = cover;
1307
+ cutX = x;
1308
+ }
1309
+ }
1310
+ if (bestCover / lines.length > 0.15) return null;
1311
+ const left = [];
1312
+ const right = [];
1313
+ let twoSide = 0;
1314
+ for (const line of lines) {
1315
+ let hasL = false;
1316
+ let hasR = false;
1317
+ for (const i of line.items) {
1318
+ if (i.x + i.w <= cutX) {
1319
+ left.push(i);
1320
+ hasL = true;
1321
+ } else if (i.x >= cutX) {
1322
+ right.push(i);
1323
+ hasR = true;
1324
+ }
1325
+ }
1326
+ if (hasL && hasR) twoSide++;
1327
+ }
1328
+ if (twoSide / lines.length < 0.55) return null;
1329
+ if (left.length < 5 || right.length < 5) return null;
1330
+ const allText = items.map((i) => i.text).join("").replace(/\s+/g, "");
1331
+ const digits = (allText.match(/[\d,.%△—-]/g) || []).length;
1332
+ if (allText.length === 0 || digits / allText.length > 0.15) return null;
1333
+ const stats = [left, right].map((side) => {
1334
+ let sMinX = Infinity;
1335
+ let sMaxR = -Infinity;
1336
+ let fsSum = 0;
1337
+ const rowEnds = /* @__PURE__ */ new Map();
1338
+ const rowLens = /* @__PURE__ */ new Map();
1339
+ const rowFirst = /* @__PURE__ */ new Map();
1340
+ for (const i of side) {
1341
+ if (i.x < sMinX) sMinX = i.x;
1342
+ const rgt = i.x + i.w;
1343
+ if (rgt > sMaxR) sMaxR = rgt;
1344
+ fsSum += i.fontSize;
1345
+ const key = Math.round(i.y / 4);
1346
+ rowEnds.set(key, Math.max(rowEnds.get(key) ?? -Infinity, rgt));
1347
+ rowLens.set(key, (rowLens.get(key) ?? 0) + i.text.replace(/\s+/g, "").length);
1348
+ const f = rowFirst.get(key);
1349
+ if (!f || i.x < f.x) rowFirst.set(key, i);
1350
+ }
1351
+ const ends = [...rowEnds.values()].sort((a, b) => a - b);
1352
+ const p85 = ends[Math.floor(ends.length * 0.85)] ?? sMaxR;
1353
+ const fs = fsSum / side.length;
1354
+ const justified = ends.filter((e) => Math.abs(e - p85) <= fs).length / ends.length;
1355
+ const lens = [...rowLens.values()];
1356
+ const avgLen = lens.reduce((s, v) => s + v, 0) / (lens.length || 1);
1357
+ const markers = [...rowFirst.values()].filter((i) => /^[•▪◦‣∙·\-–—□■◇◆▶※*]/.test(i.text)).length;
1358
+ return { width: sMaxR - sMinX, justified, avgLen, markerRatio: markers / (rowFirst.size || 1) };
1359
+ });
1360
+ if (stats.some((s) => s.avgLen < 12)) return null;
1361
+ if (stats.some((s) => s.markerRatio > 0.1)) return null;
1362
+ const widthSym = Math.min(stats[0].width, stats[1].width) / Math.max(stats[0].width, stats[1].width);
1363
+ if (widthSym < 0.6) return null;
1364
+ if (Math.min(stats[0].justified, stats[1].justified) < 0.55) return null;
1365
+ return cutX;
1239
1366
  }
1240
1367
  function mergeEvenSpacedClusters(items) {
1241
1368
  const originMap = /* @__PURE__ */ new Map();
@@ -2432,7 +2559,7 @@ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeigh
2432
2559
  if (grids.length > 0) {
2433
2560
  return extractBlocksWithGrids(items, pageNum, grids, horizontals, verticals);
2434
2561
  }
2435
- return extractPageBlocksFallback(items, pageNum);
2562
+ return extractPageBlocksFallback(items, pageNum, true);
2436
2563
  }
2437
2564
  var STRIKE_MAX_THICKNESS = 2;
2438
2565
  var STRIKE_MAX_THICKNESS_RATIO = 0.25;
@@ -2677,7 +2804,53 @@ function mergeAdjacentTableBlocks(blocks) {
2677
2804
  }
2678
2805
  return result;
2679
2806
  }
2680
- function extractPageBlocksFallback(items, pageNum) {
2807
+ function splitTwoColumnProse(items, cutX) {
2808
+ const left = [];
2809
+ const right = [];
2810
+ const cross = [];
2811
+ for (const i of items) {
2812
+ if (i.x + i.w <= cutX) left.push(i);
2813
+ else if (i.x >= cutX) right.push(i);
2814
+ else cross.push(i);
2815
+ }
2816
+ if (cross.length === 0) {
2817
+ return [left, right].filter((g2) => g2.length > 0);
2818
+ }
2819
+ cross.sort((a, b) => b.y - a.y);
2820
+ const crossLines = [];
2821
+ for (const c of cross) {
2822
+ const last = crossLines[crossLines.length - 1];
2823
+ if (last && Math.abs(last[0].y - c.y) <= 3) last.push(c);
2824
+ else crossLines.push([c]);
2825
+ }
2826
+ const bandItem = (arr) => arr.filter((i) => {
2827
+ for (const cl of crossLines) {
2828
+ if (Math.abs(cl[0].y - i.y) <= 3) {
2829
+ cl.push(i);
2830
+ return false;
2831
+ }
2832
+ }
2833
+ return true;
2834
+ });
2835
+ const leftRest = bandItem(left);
2836
+ const rightRest = bandItem(right);
2837
+ const boundYs = crossLines.map((cl) => cl[0].y);
2838
+ const bandOf = (y) => {
2839
+ let k = 0;
2840
+ while (k < boundYs.length && y < boundYs[k]) k++;
2841
+ return k;
2842
+ };
2843
+ const groups = [];
2844
+ for (let k = 0; k <= crossLines.length; k++) {
2845
+ const L = leftRest.filter((i) => bandOf(i.y) === k);
2846
+ const R = rightRest.filter((i) => bandOf(i.y) === k);
2847
+ if (L.length > 0) groups.push(L);
2848
+ if (R.length > 0) groups.push(R);
2849
+ if (k < crossLines.length) groups.push(crossLines[k]);
2850
+ }
2851
+ return groups;
2852
+ }
2853
+ function extractPageBlocksFallback(items, pageNum, fullPage = false) {
2681
2854
  if (items.length === 0) return [];
2682
2855
  const blocks = [];
2683
2856
  const clusterItems = items.map((i) => ({
@@ -2718,8 +2891,9 @@ function extractPageBlocksFallback(items, pageNum) {
2718
2891
  return by - ay;
2719
2892
  });
2720
2893
  } else {
2894
+ const proseCutX = fullPage ? findTwoColumnProseCutX(items) : null;
2721
2895
  const allYLines = mergeSuperscriptLines(groupByY(items));
2722
- const columns = detectColumns(allYLines);
2896
+ const columns = proseCutX !== null ? null : detectColumns(allYLines);
2723
2897
  if (columns && columns.length >= 3) {
2724
2898
  const tableText = extractWithColumns(allYLines, columns);
2725
2899
  const bbox = computeBBox(items, pageNum);
@@ -2728,7 +2902,7 @@ function extractPageBlocksFallback(items, pageNum) {
2728
2902
  const allY = items.map((i) => i.y);
2729
2903
  const pageHeight = safeMax(allY) - safeMin(allY);
2730
2904
  const gapThreshold = Math.max(15, pageHeight * 0.03);
2731
- const orderedGroups = xyCutOrder(items, gapThreshold);
2905
+ const orderedGroups = proseCutX !== null ? splitTwoColumnProse(items, proseCutX) : xyCutOrder(items, gapThreshold);
2732
2906
  for (const group of orderedGroups) {
2733
2907
  if (group.length === 0) continue;
2734
2908
  const yLines = mergeSuperscriptLines(groupByY(group));
@@ -2949,16 +3123,28 @@ g.pdfjsWorker = pdfjsWorker;
2949
3123
 
2950
3124
  // src/pdf/parser.ts
2951
3125
  import { getDocument, GlobalWorkerOptions } from "pdfjs-dist/legacy/build/pdf.mjs";
3126
+ import { createRequire } from "module";
3127
+ import { dirname, join } from "path";
2952
3128
  GlobalWorkerOptions.workerSrc = "";
2953
3129
  var MAX_PAGES = 5e3;
2954
3130
  var MAX_TOTAL_TEXT = 100 * 1024 * 1024;
2955
3131
  var PDF_LOAD_TIMEOUT_MS = 3e4;
3132
+ var pdfjsAssets = {};
3133
+ try {
3134
+ const _require = createRequire(import.meta.url);
3135
+ const pkgDir = dirname(_require.resolve("pdfjs-dist/package.json"));
3136
+ pdfjsAssets.cMapUrl = join(pkgDir, "cmaps") + "/";
3137
+ pdfjsAssets.cMapPacked = true;
3138
+ pdfjsAssets.standardFontDataUrl = join(pkgDir, "standard_fonts") + "/";
3139
+ } catch {
3140
+ }
2956
3141
  async function loadPdfWithTimeout(buffer) {
2957
3142
  const loadingTask = getDocument({
2958
3143
  data: new Uint8Array(buffer),
2959
3144
  useSystemFonts: true,
2960
3145
  disableFontFace: true,
2961
- isEvalSupported: false
3146
+ isEvalSupported: false,
3147
+ ...pdfjsAssets
2962
3148
  });
2963
3149
  let timer;
2964
3150
  try {
@@ -3171,4 +3357,4 @@ export {
3171
3357
  parsePdfDocument,
3172
3358
  removeHeaderFooterBlocks
3173
3359
  };
3174
- //# sourceMappingURL=parser-FFEBMLSH.js.map
3360
+ //# sourceMappingURL=parser-6GP535ZB.js.map