kordoc 3.11.0 → 3.13.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 (36) hide show
  1. package/README.md +13 -0
  2. package/dist/{-QMW2GDWP.js → -MRPDPE2X.js} +5 -5
  3. package/dist/{chunk-GETZFABK.js → chunk-33CIKNL4.js} +2 -2
  4. package/dist/{chunk-RCSDSN5Y.cjs → chunk-MEXUFQVC.cjs} +2 -2
  5. package/dist/{chunk-RCSDSN5Y.cjs.map → chunk-MEXUFQVC.cjs.map} +1 -1
  6. package/dist/{chunk-D4JKKSSI.js → chunk-O4WFPOFN.js} +2 -2
  7. package/dist/{chunk-SNSAZ7FA.js → chunk-Q6UXVJXI.js} +2 -2
  8. package/dist/{chunk-TUBD3EEF.js → chunk-TWACKS3K.js} +21 -5
  9. package/dist/{chunk-TUBD3EEF.js.map → chunk-TWACKS3K.js.map} +1 -1
  10. package/dist/{chunk-O27B5IRL.js → chunk-YXOT7P5B.js} +2 -2
  11. package/dist/cli.js +7 -7
  12. package/dist/index.cjs +134 -118
  13. package/dist/index.cjs.map +1 -1
  14. package/dist/index.js +18 -2
  15. package/dist/index.js.map +1 -1
  16. package/dist/mcp.js +5 -5
  17. package/dist/{parser-X34HD2KQ.cjs → parser-DZBI3EA2.cjs} +101 -15
  18. package/dist/parser-DZBI3EA2.cjs.map +1 -0
  19. package/dist/{parser-3EARWV2H.js → parser-XUNGOH76.js} +90 -4
  20. package/dist/parser-XUNGOH76.js.map +1 -0
  21. package/dist/{parser-STGI5I5K.js → parser-Z3IL2ESY.js} +89 -3
  22. package/dist/parser-Z3IL2ESY.js.map +1 -0
  23. package/dist/render-VZ4OGHZU.js +9 -0
  24. package/dist/{watch-KVYJ46S6.js → watch-G5NFIT5L.js} +5 -5
  25. package/package.json +1 -1
  26. package/dist/parser-3EARWV2H.js.map +0 -1
  27. package/dist/parser-STGI5I5K.js.map +0 -1
  28. package/dist/parser-X34HD2KQ.cjs.map +0 -1
  29. package/dist/render-FPWZ6YNZ.js +0 -9
  30. /package/dist/{-QMW2GDWP.js.map → -MRPDPE2X.js.map} +0 -0
  31. /package/dist/{chunk-GETZFABK.js.map → chunk-33CIKNL4.js.map} +0 -0
  32. /package/dist/{chunk-D4JKKSSI.js.map → chunk-O4WFPOFN.js.map} +0 -0
  33. /package/dist/{chunk-SNSAZ7FA.js.map → chunk-Q6UXVJXI.js.map} +0 -0
  34. /package/dist/{chunk-O27B5IRL.js.map → chunk-YXOT7P5B.js.map} +0 -0
  35. /package/dist/{render-FPWZ6YNZ.js.map → render-VZ4OGHZU.js.map} +0 -0
  36. /package/dist/{watch-KVYJ46S6.js.map → watch-G5NFIT5L.js.map} +0 -0
package/dist/mcp.js CHANGED
@@ -10,22 +10,22 @@ import {
10
10
  parse,
11
11
  patchHwp,
12
12
  patchHwpx
13
- } from "./chunk-TUBD3EEF.js";
13
+ } from "./chunk-TWACKS3K.js";
14
14
  import {
15
15
  detectFormat,
16
16
  detectZipFormat
17
17
  } from "./chunk-MEPHGCPQ.js";
18
- import "./chunk-GETZFABK.js";
18
+ import "./chunk-33CIKNL4.js";
19
19
  import {
20
20
  blocksToMarkdown
21
- } from "./chunk-O27B5IRL.js";
21
+ } from "./chunk-YXOT7P5B.js";
22
22
  import "./chunk-MOL7MDBG.js";
23
23
  import {
24
24
  KordocError,
25
25
  VERSION,
26
26
  sanitizeError,
27
27
  toArrayBuffer
28
- } from "./chunk-SNSAZ7FA.js";
28
+ } from "./chunk-Q6UXVJXI.js";
29
29
 
30
30
  // src/mcp.ts
31
31
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -196,7 +196,7 @@ server.tool(
196
196
  break;
197
197
  case "pdf":
198
198
  try {
199
- const { extractPdfMetadataOnly } = await import("./parser-3EARWV2H.js");
199
+ const { extractPdfMetadataOnly } = await import("./parser-XUNGOH76.js");
200
200
  metadata = await extractPdfMetadataOnly(buffer);
201
201
  } catch {
202
202
  metadata = void 0;
@@ -6,7 +6,7 @@
6
6
 
7
7
 
8
8
 
9
- var _chunkRCSDSN5Ycjs = require('./chunk-RCSDSN5Y.cjs');
9
+ var _chunkMEXUFQVCcjs = require('./chunk-MEXUFQVC.cjs');
10
10
 
11
11
 
12
12
  var _chunkDCZVOIEOcjs = require('./chunk-DCZVOIEO.cjs');
@@ -240,10 +240,40 @@ var EDGE_MIN_SPAN = 12;
240
240
  var EDGE_INSET = 15;
241
241
  var EDGE_NEAR = 10;
242
242
  var EDGE_CONNECT_TOL = 5;
243
+ var CHAIN_Y_TOL = 1.5;
244
+ var CHAIN_GAP = 3;
245
+ function chainCollinearRules(horizontals) {
246
+ if (horizontals.length <= 1) return horizontals;
247
+ const sorted = [...horizontals].sort((a, b) => a.y1 - b.y1 || a.x1 - b.x1);
248
+ const rules = [];
249
+ let bandStart = 0;
250
+ const flushBand = (end) => {
251
+ const band = sorted.slice(bandStart, end).sort((a, b) => a.x1 - b.x1);
252
+ let cur = { ...band[0] };
253
+ for (let i = 1; i < band.length; i++) {
254
+ const seg = band[i];
255
+ if (seg.x1 - cur.x2 <= CHAIN_GAP) {
256
+ if (seg.x2 > cur.x2) cur.x2 = seg.x2;
257
+ if (seg.lineWidth > cur.lineWidth) cur.lineWidth = seg.lineWidth;
258
+ } else {
259
+ rules.push(cur);
260
+ cur = { ...seg };
261
+ }
262
+ }
263
+ rules.push(cur);
264
+ };
265
+ for (let i = 1; i <= sorted.length; i++) {
266
+ if (i === sorted.length || sorted[i].y1 - sorted[bandStart].y1 > CHAIN_Y_TOL) {
267
+ flushBand(i);
268
+ bandStart = i;
269
+ }
270
+ }
271
+ return rules;
272
+ }
243
273
  function closeOpenTableEdges(horizontals, verticals) {
244
274
  if (horizontals.length < EDGE_MIN_RULES) return verticals;
245
275
  const groups = [];
246
- for (const hl of horizontals) {
276
+ for (const hl of chainCollinearRules(horizontals)) {
247
277
  let placed = false;
248
278
  for (const g2 of groups) {
249
279
  if (Math.abs(g2[0].x1 - hl.x1) <= EDGE_ALIGN_TOL && Math.abs(g2[0].x2 - hl.x2) <= EDGE_ALIGN_TOL) {
@@ -2056,14 +2086,14 @@ function isProseSpread(items) {
2056
2086
  for (let i = 1; i < sorted.length; i++) {
2057
2087
  gaps.push(sorted[i].x - (sorted[i - 1].x + sorted[i - 1].w));
2058
2088
  }
2059
- const maxGap = _chunkRCSDSN5Ycjs.safeMax.call(void 0, gaps);
2089
+ const maxGap = _chunkMEXUFQVCcjs.safeMax.call(void 0, gaps);
2060
2090
  const avgLen = items.reduce((s, i) => s + i.text.length, 0) / items.length;
2061
2091
  return maxGap < 40 && avgLen < 5;
2062
2092
  }
2063
2093
  function detectColumns(yLines) {
2064
2094
  const allItems = yLines.flat();
2065
2095
  if (allItems.length === 0) return null;
2066
- const pageWidth = _chunkRCSDSN5Ycjs.safeMax.call(void 0, allItems.map((i) => i.x + i.w)) - _chunkRCSDSN5Ycjs.safeMin.call(void 0, allItems.map((i) => i.x));
2096
+ const pageWidth = _chunkMEXUFQVCcjs.safeMax.call(void 0, allItems.map((i) => i.x + i.w)) - _chunkMEXUFQVCcjs.safeMin.call(void 0, allItems.map((i) => i.x));
2067
2097
  if (pageWidth < 100) return null;
2068
2098
  let bigoLineIdx = -1;
2069
2099
  for (let i = 0; i < yLines.length; i++) {
@@ -2285,9 +2315,9 @@ function detectHeadings(blocks, medianFontSize) {
2285
2315
  if (/^\d+$/.test(text)) continue;
2286
2316
  const ratio = block.style.fontSize / medianFontSize;
2287
2317
  let level = 0;
2288
- if (ratio >= _chunkRCSDSN5Ycjs.HEADING_RATIO_H1) level = 1;
2289
- else if (ratio >= _chunkRCSDSN5Ycjs.HEADING_RATIO_H2) level = 2;
2290
- else if (ratio >= _chunkRCSDSN5Ycjs.HEADING_RATIO_H3) level = 3;
2318
+ if (ratio >= _chunkMEXUFQVCcjs.HEADING_RATIO_H1) level = 1;
2319
+ else if (ratio >= _chunkMEXUFQVCcjs.HEADING_RATIO_H2) level = 2;
2320
+ else if (ratio >= _chunkMEXUFQVCcjs.HEADING_RATIO_H3) level = 3;
2291
2321
  if (level > 0) {
2292
2322
  block.type = "heading";
2293
2323
  block.level = level;
@@ -2298,6 +2328,10 @@ function detectHeadings(blocks, medianFontSize) {
2298
2328
  function shouldDemoteTable(table) {
2299
2329
  const allCells = table.cells.flatMap((row) => row.map((c) => c.text.trim())).filter(Boolean);
2300
2330
  const allText = allCells.join(" ");
2331
+ if (table.rows >= 2 && table.cols >= 2 && table.cells[0].every((c) => {
2332
+ const t = c.text.trim();
2333
+ return t.length > 0 && t.length <= 12 && !/[□■◆○●▶ㅇ<>]/.test(t);
2334
+ }) && table.cells.slice(1).some((row) => row.some((c) => c.text.trim() !== ""))) return false;
2301
2335
  if (table.rows <= 3 && table.cols <= 3) {
2302
2336
  const totalCells2 = table.rows * table.cols;
2303
2337
  const emptyCells2 = totalCells2 - allCells.length;
@@ -2687,6 +2721,54 @@ function wrapStrikethroughRuns(items) {
2687
2721
  arr[arr.length - 1].text = arr[arr.length - 1].text + "~~";
2688
2722
  }
2689
2723
  }
2724
+ var PROSEBOX_FULLWIDTH_MIN = 0.6;
2725
+ var PROSEBOX_LONG_CELL_CHARS = 80;
2726
+ var PROSEBOX_LONG_CELL_MIN = 3;
2727
+ var PROSEBOX_LONG_CELL_RATIO = 0.4;
2728
+ var PROSEBOX_X_TOL = 8;
2729
+ function verticalCoverageAt(verticals, x, yMin, yMax) {
2730
+ const tol = PROSEBOX_X_TOL;
2731
+ const spans = [];
2732
+ for (const v of verticals) {
2733
+ if (Math.abs(v.x1 - x) > tol) continue;
2734
+ const lo = Math.max(v.y1, yMin), hi = Math.min(v.y2, yMax);
2735
+ if (hi > lo) spans.push([lo, hi]);
2736
+ }
2737
+ if (spans.length === 0) return 0;
2738
+ spans.sort((a, b) => a[0] - b[0]);
2739
+ let total = 0, s = spans[0][0], e = spans[0][1];
2740
+ for (let i = 1; i < spans.length; i++) {
2741
+ if (spans[i][0] <= e) {
2742
+ if (spans[i][1] > e) e = spans[i][1];
2743
+ } else {
2744
+ total += e - s;
2745
+ s = spans[i][0];
2746
+ e = spans[i][1];
2747
+ }
2748
+ }
2749
+ return total + (e - s);
2750
+ }
2751
+ function isProseBoxGrid(grid, verticals, table) {
2752
+ const numCols = grid.colXs.length - 1;
2753
+ if (numCols < 2 || grid.rowYs.length < 3) return false;
2754
+ const gyMax = grid.rowYs[0], gyMin = grid.rowYs[grid.rowYs.length - 1];
2755
+ const span = gyMax - gyMin;
2756
+ if (span <= 0) return false;
2757
+ const interior = grid.colXs.slice(1, -1);
2758
+ let fullWidthHeight = 0;
2759
+ for (let r = 0; r < grid.rowYs.length - 1; r++) {
2760
+ const top = grid.rowYs[r], bot = grid.rowYs[r + 1];
2761
+ const h = top - bot;
2762
+ if (h <= 0) continue;
2763
+ const hasDivider = interior.some((cx) => verticalCoverageAt(verticals, cx, bot, top) >= h * 0.5);
2764
+ if (!hasDivider) fullWidthHeight += h;
2765
+ }
2766
+ if (fullWidthHeight < span * PROSEBOX_FULLWIDTH_MIN) return false;
2767
+ const texts = table.cells.flat().map((c) => c.text.trim()).filter(Boolean);
2768
+ const longCells = texts.filter((s) => s.length > PROSEBOX_LONG_CELL_CHARS).length;
2769
+ if (longCells < PROSEBOX_LONG_CELL_MIN || longCells < texts.length * PROSEBOX_LONG_CELL_RATIO) return false;
2770
+ return true;
2771
+ }
2690
2772
  function extractBlocksWithGrids(items, pageNum, grids, horizontals, verticals) {
2691
2773
  const blocks = [];
2692
2774
  const usedItems = /* @__PURE__ */ new Set();
@@ -2761,6 +2843,10 @@ function extractBlocksWithGrids(items, pageNum, grids, horizontals, verticals) {
2761
2843
  };
2762
2844
  const hasContent = finalGrid.some((row) => row.some((cell) => cell.text.trim() !== ""));
2763
2845
  if (!hasContent) continue;
2846
+ if (isProseBoxGrid(grid, verticals, irTable)) {
2847
+ for (const it of tableItems) usedItems.delete(it);
2848
+ continue;
2849
+ }
2764
2850
  const tableBbox = {
2765
2851
  page: pageNum,
2766
2852
  x: grid.bbox.x1,
@@ -2807,7 +2893,7 @@ function extractBlocksWithGrids(items, pageNum, grids, horizontals, verticals) {
2807
2893
  }
2808
2894
  if (remaining.length > 0) {
2809
2895
  const allY = remaining.map((i) => i.y);
2810
- const pageH = _chunkRCSDSN5Ycjs.safeMax.call(void 0, allY) - _chunkRCSDSN5Ycjs.safeMin.call(void 0, allY);
2896
+ const pageH = _chunkMEXUFQVCcjs.safeMax.call(void 0, allY) - _chunkMEXUFQVCcjs.safeMin.call(void 0, allY);
2811
2897
  const groups = xyCutOrder(remaining, Math.max(15, pageH * 0.03));
2812
2898
  const textBlocks = [];
2813
2899
  for (const group of groups) {
@@ -2983,7 +3069,7 @@ function extractPageBlocksFallback(items, pageNum, fullPage = false) {
2983
3069
  blocks.push({ type: "paragraph", text: tableText, pageNumber: pageNum, bbox, style: dominantStyle(items) });
2984
3070
  } else {
2985
3071
  const allY = items.map((i) => i.y);
2986
- const pageHeight = _chunkRCSDSN5Ycjs.safeMax.call(void 0, allY) - _chunkRCSDSN5Ycjs.safeMin.call(void 0, allY);
3072
+ const pageHeight = _chunkMEXUFQVCcjs.safeMax.call(void 0, allY) - _chunkMEXUFQVCcjs.safeMin.call(void 0, allY);
2987
3073
  const gapThreshold = Math.max(15, pageHeight * 0.03);
2988
3074
  const orderedGroups = proseCutX !== null ? splitTwoColumnProse(items, proseCutX) : xyCutOrder(items, gapThreshold);
2989
3075
  for (const group of orderedGroups) {
@@ -3236,7 +3322,7 @@ async function loadPdfWithTimeout(buffer) {
3236
3322
  new Promise((_, reject) => {
3237
3323
  timer = setTimeout(() => {
3238
3324
  loadingTask.destroy();
3239
- reject(new (0, _chunkRCSDSN5Ycjs.KordocError)("PDF \uB85C\uB529 \uD0C0\uC784\uC544\uC6C3 (30\uCD08 \uCD08\uACFC)"));
3325
+ reject(new (0, _chunkMEXUFQVCcjs.KordocError)("PDF \uB85C\uB529 \uD0C0\uC784\uC544\uC6C3 (30\uCD08 \uCD08\uACFC)"));
3240
3326
  }, PDF_LOAD_TIMEOUT_MS);
3241
3327
  })
3242
3328
  ]);
@@ -3249,7 +3335,7 @@ async function parsePdfDocument(buffer, options) {
3249
3335
  const doc = await loadPdfWithTimeout(buffer);
3250
3336
  try {
3251
3337
  const pageCount = doc.numPages;
3252
- if (pageCount === 0) throw new (0, _chunkRCSDSN5Ycjs.KordocError)("PDF\uC5D0 \uD398\uC774\uC9C0\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.");
3338
+ if (pageCount === 0) throw new (0, _chunkMEXUFQVCcjs.KordocError)("PDF\uC5D0 \uD398\uC774\uC9C0\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.");
3253
3339
  const metadata = { pageCount };
3254
3340
  await extractPdfMetadata(doc, metadata);
3255
3341
  const blocks = [];
@@ -3309,11 +3395,11 @@ async function parsePdfDocument(buffer, options) {
3309
3395
  pageText += pageText ? "\n" + t : t;
3310
3396
  }
3311
3397
  pageQuality.push(computePageQuality(i, pageText));
3312
- if (totalTextBytes > MAX_TOTAL_TEXT) throw new (0, _chunkRCSDSN5Ycjs.KordocError)("\uD14D\uC2A4\uD2B8 \uCD94\uCD9C \uD06C\uAE30 \uCD08\uACFC");
3398
+ if (totalTextBytes > MAX_TOTAL_TEXT) throw new (0, _chunkMEXUFQVCcjs.KordocError)("\uD14D\uC2A4\uD2B8 \uCD94\uCD9C \uD06C\uAE30 \uCD08\uACFC");
3313
3399
  parsedPages++;
3314
3400
  _optionalChain([options, 'optionalAccess', _36 => _36.onProgress, 'optionalCall', _37 => _37(parsedPages, totalTarget)]);
3315
3401
  } catch (pageErr) {
3316
- if (pageErr instanceof _chunkRCSDSN5Ycjs.KordocError) throw pageErr;
3402
+ if (pageErr instanceof _chunkMEXUFQVCcjs.KordocError) throw pageErr;
3317
3403
  warnings.push({ page: i, message: `\uD398\uC774\uC9C0 ${i} \uD30C\uC2F1 \uC2E4\uD328: ${pageErr instanceof Error ? pageErr.message : "\uC54C \uC218 \uC5C6\uB294 \uC624\uB958"}`, code: "PARTIAL_PARSE" });
3318
3404
  }
3319
3405
  }
@@ -3381,7 +3467,7 @@ async function parsePdfDocument(buffer, options) {
3381
3467
  detectKoreanListBlocks(blocks);
3382
3468
  const outline = blocks.filter((b) => b.type === "heading" && b.level && b.text).map((b) => ({ level: b.level, text: b.text, pageNumber: b.pageNumber }));
3383
3469
  sanitizeBlockControlChars(blocks);
3384
- let markdown = cleanPdfText(_chunkRCSDSN5Ycjs.blocksToMarkdown.call(void 0, blocks));
3470
+ let markdown = cleanPdfText(_chunkMEXUFQVCcjs.blocksToMarkdown.call(void 0, blocks));
3385
3471
  return {
3386
3472
  markdown,
3387
3473
  blocks,
@@ -3440,4 +3526,4 @@ async function extractPdfMetadataOnly(buffer) {
3440
3526
 
3441
3527
 
3442
3528
  exports.cleanPdfText = cleanPdfText; exports.detectKoreanListBlocks = detectKoreanListBlocks; exports.detectTableCaptions = detectTableCaptions; exports.extractPdfMetadataOnly = extractPdfMetadataOnly; exports.mergeCrossPageTables = mergeCrossPageTables; exports.parsePdfDocument = parsePdfDocument; exports.removeHeaderFooterBlocks = removeHeaderFooterBlocks;
3443
- //# sourceMappingURL=parser-X34HD2KQ.cjs.map
3529
+ //# sourceMappingURL=parser-DZBI3EA2.cjs.map