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.
- package/README.md +12 -0
- package/dist/{-LPEXY73L.js → -OPZIF3QT.js} +5 -5
- package/dist/{chunk-7UXZTZBJ.cjs → chunk-2C5GCXPJ.cjs} +2 -2
- package/dist/{chunk-7UXZTZBJ.cjs.map → chunk-2C5GCXPJ.cjs.map} +1 -1
- package/dist/{chunk-GFS4QWB6.js → chunk-7Z43WEML.js} +2 -2
- package/dist/{chunk-YXEE3DEQ.js → chunk-BUDM6ULT.js} +2 -2
- package/dist/{chunk-UR34PYAC.js → chunk-ILR7GF3W.js} +2 -2
- package/dist/{chunk-I6CX2RK4.js → chunk-NGKIAZ6G.js} +2 -2
- package/dist/{chunk-RMGYE4LT.js → chunk-RUYSNNYZ.js} +5 -5
- package/dist/cli.js +7 -7
- package/dist/index.cjs +118 -118
- package/dist/index.js +2 -2
- package/dist/mcp.js +5 -5
- package/dist/{parser-LJOS7VZM.js → parser-5FSEFR3R.js} +118 -3
- package/dist/parser-5FSEFR3R.js.map +1 -0
- package/dist/{parser-664URIIW.js → parser-AWEGMHHV.js} +117 -2
- package/dist/parser-AWEGMHHV.js.map +1 -0
- package/dist/{parser-AT22HMF5.cjs → parser-PCTX7LGN.cjs} +129 -14
- package/dist/parser-PCTX7LGN.cjs.map +1 -0
- package/dist/render-ATQNKOT2.js +9 -0
- package/dist/{watch-CZF6NA2V.js → watch-Y7BAYXJE.js} +5 -5
- package/package.json +1 -1
- package/dist/parser-664URIIW.js.map +0 -1
- package/dist/parser-AT22HMF5.cjs.map +0 -1
- package/dist/parser-LJOS7VZM.js.map +0 -1
- package/dist/render-XWOEGE3U.js +0 -9
- /package/dist/{-LPEXY73L.js.map → -OPZIF3QT.js.map} +0 -0
- /package/dist/{chunk-GFS4QWB6.js.map → chunk-7Z43WEML.js.map} +0 -0
- /package/dist/{chunk-YXEE3DEQ.js.map → chunk-BUDM6ULT.js.map} +0 -0
- /package/dist/{chunk-UR34PYAC.js.map → chunk-ILR7GF3W.js.map} +0 -0
- /package/dist/{chunk-I6CX2RK4.js.map → chunk-NGKIAZ6G.js.map} +0 -0
- /package/dist/{chunk-RMGYE4LT.js.map → chunk-RUYSNNYZ.js.map} +0 -0
- /package/dist/{render-XWOEGE3U.js.map → render-ATQNKOT2.js.map} +0 -0
- /package/dist/{watch-CZF6NA2V.js.map → watch-Y7BAYXJE.js.map} +0 -0
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
var
|
|
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 =
|
|
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 =
|
|
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 >=
|
|
2209
|
-
else if (ratio >=
|
|
2210
|
-
else if (ratio >=
|
|
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 =
|
|
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 =
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
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(
|
|
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-
|
|
3477
|
+
//# sourceMappingURL=parser-PCTX7LGN.cjs.map
|