kordoc 3.10.1 → 3.12.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 (34) hide show
  1. package/README.md +12 -0
  2. package/dist/{-LPEXY73L.js → -OPZIF3QT.js} +5 -5
  3. package/dist/{chunk-7UXZTZBJ.cjs → chunk-2C5GCXPJ.cjs} +2 -2
  4. package/dist/{chunk-7UXZTZBJ.cjs.map → chunk-2C5GCXPJ.cjs.map} +1 -1
  5. package/dist/{chunk-GFS4QWB6.js → chunk-7Z43WEML.js} +2 -2
  6. package/dist/{chunk-YXEE3DEQ.js → chunk-BUDM6ULT.js} +2 -2
  7. package/dist/{chunk-UR34PYAC.js → chunk-ILR7GF3W.js} +2 -2
  8. package/dist/{chunk-I6CX2RK4.js → chunk-NGKIAZ6G.js} +2 -2
  9. package/dist/{chunk-RMGYE4LT.js → chunk-RUYSNNYZ.js} +5 -5
  10. package/dist/cli.js +7 -7
  11. package/dist/index.cjs +118 -118
  12. package/dist/index.js +2 -2
  13. package/dist/mcp.js +5 -5
  14. package/dist/{parser-LJOS7VZM.js → parser-5FSEFR3R.js} +118 -3
  15. package/dist/parser-5FSEFR3R.js.map +1 -0
  16. package/dist/{parser-664URIIW.js → parser-AWEGMHHV.js} +117 -2
  17. package/dist/parser-AWEGMHHV.js.map +1 -0
  18. package/dist/{parser-AT22HMF5.cjs → parser-PCTX7LGN.cjs} +129 -14
  19. package/dist/parser-PCTX7LGN.cjs.map +1 -0
  20. package/dist/render-ATQNKOT2.js +9 -0
  21. package/dist/{watch-CZF6NA2V.js → watch-Y7BAYXJE.js} +5 -5
  22. package/package.json +1 -1
  23. package/dist/parser-664URIIW.js.map +0 -1
  24. package/dist/parser-AT22HMF5.cjs.map +0 -1
  25. package/dist/parser-LJOS7VZM.js.map +0 -1
  26. package/dist/render-XWOEGE3U.js +0 -9
  27. /package/dist/{-LPEXY73L.js.map → -OPZIF3QT.js.map} +0 -0
  28. /package/dist/{chunk-GFS4QWB6.js.map → chunk-7Z43WEML.js.map} +0 -0
  29. /package/dist/{chunk-YXEE3DEQ.js.map → chunk-BUDM6ULT.js.map} +0 -0
  30. /package/dist/{chunk-UR34PYAC.js.map → chunk-ILR7GF3W.js.map} +0 -0
  31. /package/dist/{chunk-I6CX2RK4.js.map → chunk-NGKIAZ6G.js.map} +0 -0
  32. /package/dist/{chunk-RMGYE4LT.js.map → chunk-RUYSNNYZ.js.map} +0 -0
  33. /package/dist/{render-XWOEGE3U.js.map → render-ATQNKOT2.js.map} +0 -0
  34. /package/dist/{watch-CZF6NA2V.js.map → watch-Y7BAYXJE.js.map} +0 -0
@@ -6,7 +6,7 @@
6
6
 
7
7
 
8
8
 
9
- var _chunk7UXZTZBJcjs = require('./chunk-7UXZTZBJ.cjs');
9
+ var _chunk2C5GCXPJcjs = require('./chunk-2C5GCXPJ.cjs');
10
10
 
11
11
 
12
12
  var _chunkDCZVOIEOcjs = require('./chunk-DCZVOIEO.cjs');
@@ -201,10 +201,120 @@ function classifyAndAdd(seg, lineWidth, horizontals, verticals) {
201
201
  function preprocessLines(horizontals, verticals) {
202
202
  let h = horizontals.filter((l) => l.lineWidth <= MAX_LINE_WIDTH);
203
203
  let v = verticals.filter((l) => l.lineWidth <= MAX_LINE_WIDTH);
204
+ h = dropShadingStacks(h, "h");
205
+ v = dropShadingStacks(v, "v");
204
206
  h = mergeParallelLines(h, "h");
205
207
  v = mergeParallelLines(v, "v");
206
208
  return { horizontals: h, verticals: v };
207
209
  }
210
+ var STACK_GAP = 2;
211
+ var STACK_MIN_LINES = 6;
212
+ function dropShadingStacks(lines, dir) {
213
+ if (lines.length < STACK_MIN_LINES) return lines;
214
+ const groups = /* @__PURE__ */ new Map();
215
+ for (const l of lines) {
216
+ const key = dir === "h" ? `${Math.round(l.x1)}:${Math.round(l.x2)}` : `${Math.round(l.y1)}:${Math.round(l.y2)}`;
217
+ const arr = groups.get(key);
218
+ if (arr) arr.push(l);
219
+ else groups.set(key, [l]);
220
+ }
221
+ const dropped = /* @__PURE__ */ new Set();
222
+ for (const group of groups.values()) {
223
+ if (group.length < STACK_MIN_LINES) continue;
224
+ group.sort((a, b) => dir === "h" ? a.y1 - b.y1 : a.x1 - b.x1);
225
+ let runStart = 0;
226
+ for (let i = 1; i <= group.length; i++) {
227
+ const gap = i < group.length ? dir === "h" ? group[i].y1 - group[i - 1].y1 : group[i].x1 - group[i - 1].x1 : Infinity;
228
+ if (gap < STACK_GAP) continue;
229
+ if (i - runStart >= STACK_MIN_LINES) {
230
+ for (let j = runStart; j < i; j++) dropped.add(group[j]);
231
+ }
232
+ runStart = i;
233
+ }
234
+ }
235
+ return dropped.size ? lines.filter((l) => !dropped.has(l)) : lines;
236
+ }
237
+ var EDGE_ALIGN_TOL = 3;
238
+ var EDGE_MIN_RULES = 3;
239
+ var EDGE_MIN_SPAN = 12;
240
+ var EDGE_INSET = 15;
241
+ var EDGE_NEAR = 10;
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
+ }
273
+ function closeOpenTableEdges(horizontals, verticals) {
274
+ if (horizontals.length < EDGE_MIN_RULES) return verticals;
275
+ const groups = [];
276
+ for (const hl of chainCollinearRules(horizontals)) {
277
+ let placed = false;
278
+ for (const g2 of groups) {
279
+ if (Math.abs(g2[0].x1 - hl.x1) <= EDGE_ALIGN_TOL && Math.abs(g2[0].x2 - hl.x2) <= EDGE_ALIGN_TOL) {
280
+ g2.push(hl);
281
+ placed = true;
282
+ break;
283
+ }
284
+ }
285
+ if (!placed) groups.push([hl]);
286
+ }
287
+ const synthesized = [];
288
+ for (const g2 of groups) {
289
+ if (g2.length < EDGE_MIN_RULES) continue;
290
+ let yMin = Infinity, yMax = -Infinity, x1 = 0, x2 = 0;
291
+ for (const hl of g2) {
292
+ if (hl.y1 < yMin) yMin = hl.y1;
293
+ if (hl.y1 > yMax) yMax = hl.y1;
294
+ x1 += hl.x1;
295
+ x2 += hl.x2;
296
+ }
297
+ x1 /= g2.length;
298
+ x2 /= g2.length;
299
+ if (yMax - yMin < EDGE_MIN_SPAN) continue;
300
+ const crossCount = (v) => {
301
+ let n = 0;
302
+ for (const hl of g2) {
303
+ if (v.x1 >= hl.x1 - EDGE_CONNECT_TOL && v.x1 <= hl.x2 + EDGE_CONNECT_TOL && hl.y1 >= v.y1 - EDGE_CONNECT_TOL && hl.y1 <= v.y2 + EDGE_CONNECT_TOL) n++;
304
+ }
305
+ return n;
306
+ };
307
+ const hasInterior = verticals.some((v) => v.x1 > x1 + EDGE_INSET && v.x1 < x2 - EDGE_INSET && crossCount(v) >= 2);
308
+ if (!hasInterior) continue;
309
+ for (const edgeX of [x1, x2]) {
310
+ const closed = verticals.some((v) => Math.abs(v.x1 - edgeX) <= EDGE_NEAR && v.y1 <= yMax + EDGE_CONNECT_TOL && v.y2 >= yMin - EDGE_CONNECT_TOL);
311
+ if (!closed) {
312
+ synthesized.push({ x1: edgeX, y1: yMin, x2: edgeX, y2: yMax, lineWidth: 0.5 });
313
+ }
314
+ }
315
+ }
316
+ return synthesized.length ? [...verticals, ...synthesized] : verticals;
317
+ }
208
318
  function mergeParallelLines(lines, dir) {
209
319
  if (lines.length <= 1) return lines;
210
320
  const sorted = [...lines].sort((a, b) => {
@@ -1976,14 +2086,14 @@ function isProseSpread(items) {
1976
2086
  for (let i = 1; i < sorted.length; i++) {
1977
2087
  gaps.push(sorted[i].x - (sorted[i - 1].x + sorted[i - 1].w));
1978
2088
  }
1979
- const maxGap = _chunk7UXZTZBJcjs.safeMax.call(void 0, gaps);
2089
+ const maxGap = _chunk2C5GCXPJcjs.safeMax.call(void 0, gaps);
1980
2090
  const avgLen = items.reduce((s, i) => s + i.text.length, 0) / items.length;
1981
2091
  return maxGap < 40 && avgLen < 5;
1982
2092
  }
1983
2093
  function detectColumns(yLines) {
1984
2094
  const allItems = yLines.flat();
1985
2095
  if (allItems.length === 0) return null;
1986
- const pageWidth = _chunk7UXZTZBJcjs.safeMax.call(void 0, allItems.map((i) => i.x + i.w)) - _chunk7UXZTZBJcjs.safeMin.call(void 0, allItems.map((i) => i.x));
2096
+ const pageWidth = _chunk2C5GCXPJcjs.safeMax.call(void 0, allItems.map((i) => i.x + i.w)) - _chunk2C5GCXPJcjs.safeMin.call(void 0, allItems.map((i) => i.x));
1987
2097
  if (pageWidth < 100) return null;
1988
2098
  let bigoLineIdx = -1;
1989
2099
  for (let i = 0; i < yLines.length; i++) {
@@ -2205,9 +2315,9 @@ function detectHeadings(blocks, medianFontSize) {
2205
2315
  if (/^\d+$/.test(text)) continue;
2206
2316
  const ratio = block.style.fontSize / medianFontSize;
2207
2317
  let level = 0;
2208
- if (ratio >= _chunk7UXZTZBJcjs.HEADING_RATIO_H1) level = 1;
2209
- else if (ratio >= _chunk7UXZTZBJcjs.HEADING_RATIO_H2) level = 2;
2210
- else if (ratio >= _chunk7UXZTZBJcjs.HEADING_RATIO_H3) level = 3;
2318
+ if (ratio >= _chunk2C5GCXPJcjs.HEADING_RATIO_H1) level = 1;
2319
+ else if (ratio >= _chunk2C5GCXPJcjs.HEADING_RATIO_H2) level = 2;
2320
+ else if (ratio >= _chunk2C5GCXPJcjs.HEADING_RATIO_H3) level = 3;
2211
2321
  if (level > 0) {
2212
2322
  block.type = "heading";
2213
2323
  block.level = level;
@@ -2218,6 +2328,10 @@ function detectHeadings(blocks, medianFontSize) {
2218
2328
  function shouldDemoteTable(table) {
2219
2329
  const allCells = table.cells.flatMap((row) => row.map((c) => c.text.trim())).filter(Boolean);
2220
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;
2221
2335
  if (table.rows <= 3 && table.cols <= 3) {
2222
2336
  const totalCells2 = table.rows * table.cols;
2223
2337
  const emptyCells2 = totalCells2 - allCells.length;
@@ -2555,6 +2669,7 @@ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeigh
2555
2669
  let { horizontals, verticals } = extractLines(opList.fnArray, opList.argsArray);
2556
2670
  ({ horizontals, verticals } = filterPageBorderLines(horizontals, verticals, pageWidth, pageHeight));
2557
2671
  ({ horizontals, verticals } = preprocessLines(horizontals, verticals));
2672
+ verticals = closeOpenTableEdges(horizontals, verticals);
2558
2673
  markStrikethroughItems(items, horizontals);
2559
2674
  wrapStrikethroughRuns(items);
2560
2675
  const grids = buildTableGrids(horizontals, verticals);
@@ -2726,7 +2841,7 @@ function extractBlocksWithGrids(items, pageNum, grids, horizontals, verticals) {
2726
2841
  }
2727
2842
  if (remaining.length > 0) {
2728
2843
  const allY = remaining.map((i) => i.y);
2729
- const pageH = _chunk7UXZTZBJcjs.safeMax.call(void 0, allY) - _chunk7UXZTZBJcjs.safeMin.call(void 0, allY);
2844
+ const pageH = _chunk2C5GCXPJcjs.safeMax.call(void 0, allY) - _chunk2C5GCXPJcjs.safeMin.call(void 0, allY);
2730
2845
  const groups = xyCutOrder(remaining, Math.max(15, pageH * 0.03));
2731
2846
  const textBlocks = [];
2732
2847
  for (const group of groups) {
@@ -2902,7 +3017,7 @@ function extractPageBlocksFallback(items, pageNum, fullPage = false) {
2902
3017
  blocks.push({ type: "paragraph", text: tableText, pageNumber: pageNum, bbox, style: dominantStyle(items) });
2903
3018
  } else {
2904
3019
  const allY = items.map((i) => i.y);
2905
- const pageHeight = _chunk7UXZTZBJcjs.safeMax.call(void 0, allY) - _chunk7UXZTZBJcjs.safeMin.call(void 0, allY);
3020
+ const pageHeight = _chunk2C5GCXPJcjs.safeMax.call(void 0, allY) - _chunk2C5GCXPJcjs.safeMin.call(void 0, allY);
2906
3021
  const gapThreshold = Math.max(15, pageHeight * 0.03);
2907
3022
  const orderedGroups = proseCutX !== null ? splitTwoColumnProse(items, proseCutX) : xyCutOrder(items, gapThreshold);
2908
3023
  for (const group of orderedGroups) {
@@ -3155,7 +3270,7 @@ async function loadPdfWithTimeout(buffer) {
3155
3270
  new Promise((_, reject) => {
3156
3271
  timer = setTimeout(() => {
3157
3272
  loadingTask.destroy();
3158
- reject(new (0, _chunk7UXZTZBJcjs.KordocError)("PDF \uB85C\uB529 \uD0C0\uC784\uC544\uC6C3 (30\uCD08 \uCD08\uACFC)"));
3273
+ reject(new (0, _chunk2C5GCXPJcjs.KordocError)("PDF \uB85C\uB529 \uD0C0\uC784\uC544\uC6C3 (30\uCD08 \uCD08\uACFC)"));
3159
3274
  }, PDF_LOAD_TIMEOUT_MS);
3160
3275
  })
3161
3276
  ]);
@@ -3168,7 +3283,7 @@ async function parsePdfDocument(buffer, options) {
3168
3283
  const doc = await loadPdfWithTimeout(buffer);
3169
3284
  try {
3170
3285
  const pageCount = doc.numPages;
3171
- if (pageCount === 0) throw new (0, _chunk7UXZTZBJcjs.KordocError)("PDF\uC5D0 \uD398\uC774\uC9C0\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.");
3286
+ if (pageCount === 0) throw new (0, _chunk2C5GCXPJcjs.KordocError)("PDF\uC5D0 \uD398\uC774\uC9C0\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.");
3172
3287
  const metadata = { pageCount };
3173
3288
  await extractPdfMetadata(doc, metadata);
3174
3289
  const blocks = [];
@@ -3228,11 +3343,11 @@ async function parsePdfDocument(buffer, options) {
3228
3343
  pageText += pageText ? "\n" + t : t;
3229
3344
  }
3230
3345
  pageQuality.push(computePageQuality(i, pageText));
3231
- if (totalTextBytes > MAX_TOTAL_TEXT) throw new (0, _chunk7UXZTZBJcjs.KordocError)("\uD14D\uC2A4\uD2B8 \uCD94\uCD9C \uD06C\uAE30 \uCD08\uACFC");
3346
+ if (totalTextBytes > MAX_TOTAL_TEXT) throw new (0, _chunk2C5GCXPJcjs.KordocError)("\uD14D\uC2A4\uD2B8 \uCD94\uCD9C \uD06C\uAE30 \uCD08\uACFC");
3232
3347
  parsedPages++;
3233
3348
  _optionalChain([options, 'optionalAccess', _36 => _36.onProgress, 'optionalCall', _37 => _37(parsedPages, totalTarget)]);
3234
3349
  } catch (pageErr) {
3235
- if (pageErr instanceof _chunk7UXZTZBJcjs.KordocError) throw pageErr;
3350
+ if (pageErr instanceof _chunk2C5GCXPJcjs.KordocError) throw pageErr;
3236
3351
  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" });
3237
3352
  }
3238
3353
  }
@@ -3300,7 +3415,7 @@ async function parsePdfDocument(buffer, options) {
3300
3415
  detectKoreanListBlocks(blocks);
3301
3416
  const outline = blocks.filter((b) => b.type === "heading" && b.level && b.text).map((b) => ({ level: b.level, text: b.text, pageNumber: b.pageNumber }));
3302
3417
  sanitizeBlockControlChars(blocks);
3303
- let markdown = cleanPdfText(_chunk7UXZTZBJcjs.blocksToMarkdown.call(void 0, blocks));
3418
+ let markdown = cleanPdfText(_chunk2C5GCXPJcjs.blocksToMarkdown.call(void 0, blocks));
3304
3419
  return {
3305
3420
  markdown,
3306
3421
  blocks,
@@ -3359,4 +3474,4 @@ async function extractPdfMetadataOnly(buffer) {
3359
3474
 
3360
3475
 
3361
3476
  exports.cleanPdfText = cleanPdfText; exports.detectKoreanListBlocks = detectKoreanListBlocks; exports.detectTableCaptions = detectTableCaptions; exports.extractPdfMetadataOnly = extractPdfMetadataOnly; exports.mergeCrossPageTables = mergeCrossPageTables; exports.parsePdfDocument = parsePdfDocument; exports.removeHeaderFooterBlocks = removeHeaderFooterBlocks;
3362
- //# sourceMappingURL=parser-AT22HMF5.cjs.map
3477
+ //# sourceMappingURL=parser-PCTX7LGN.cjs.map