formatferry 1.0.11 → 1.0.12
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/dist/index.js +98 -6
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -21361,16 +21361,45 @@ var DATE_LIKE_REGEX = /^\d{1,4}[-/.]\d{1,2}([-/.]\d{1,4})?$/;
|
|
|
21361
21361
|
var SUPERSCRIPT_MERGE_GAP_FACTOR = 0.3;
|
|
21362
21362
|
var VERTICAL_OVERLAP_THRESHOLD = 0.5;
|
|
21363
21363
|
var COLUMN_SUPPORT_THRESHOLD = 0.6;
|
|
21364
|
-
var COLUMN_GAP_MERGE_FACTOR = 0.
|
|
21364
|
+
var COLUMN_GAP_MERGE_FACTOR = 0.35;
|
|
21365
|
+
var COLUMN_BOUNDARY_VOTE_TOLERANCE_FACTOR = 0.5;
|
|
21366
|
+
var MIN_CELL_OVERLAP_SCORE = 0.35;
|
|
21367
|
+
var WIDE_WHITESPACE_MIN_RUN = 2;
|
|
21365
21368
|
var SHORT_CELL_THRESHOLD_LATIN = 40;
|
|
21366
21369
|
var SHORT_CELL_THRESHOLD_CJK = 20;
|
|
21367
21370
|
var MIN_CONFIDENCE_EMIT = 0.55;
|
|
21368
21371
|
var MIN_CONFIDENCE_HIGH = 0.7;
|
|
21369
21372
|
var PROSE_FLOW_MAX_FRACTION = 0.3;
|
|
21373
|
+
function splitWideWhitespaceItems(items) {
|
|
21374
|
+
const out = [];
|
|
21375
|
+
for (const it of items) {
|
|
21376
|
+
const tokens = splitAtWideRuns(it.str, WIDE_WHITESPACE_MIN_RUN);
|
|
21377
|
+
if (tokens.length < 2 || it.str.length < 4 || it.width <= 0) {
|
|
21378
|
+
out.push(it);
|
|
21379
|
+
continue;
|
|
21380
|
+
}
|
|
21381
|
+
const perChar = it.width / it.str.length;
|
|
21382
|
+
for (const t of tokens) {
|
|
21383
|
+
const subX = it.x + t.start * perChar;
|
|
21384
|
+
const subRight = it.x + t.end * perChar;
|
|
21385
|
+
const subWidth = Math.max(subRight - subX, perChar);
|
|
21386
|
+
out.push({
|
|
21387
|
+
...it,
|
|
21388
|
+
str: t.str,
|
|
21389
|
+
x: subX,
|
|
21390
|
+
width: subWidth,
|
|
21391
|
+
right: subX + subWidth
|
|
21392
|
+
});
|
|
21393
|
+
}
|
|
21394
|
+
}
|
|
21395
|
+
return out;
|
|
21396
|
+
}
|
|
21370
21397
|
function preFilterAndMerge(items) {
|
|
21371
|
-
const
|
|
21398
|
+
const filtered = items.filter(
|
|
21372
21399
|
(it) => it.str.trim().length > 0 && it.width > 0 && it.height > 0
|
|
21373
21400
|
);
|
|
21401
|
+
if (filtered.length === 0) return [];
|
|
21402
|
+
const alive = splitWideWhitespaceItems(filtered);
|
|
21374
21403
|
if (alive.length === 0) return [];
|
|
21375
21404
|
const widths = alive.map((it) => estimateCharWidth(it)).filter((w) => w > 0);
|
|
21376
21405
|
const medianCharWidth = median(widths) || 1;
|
|
@@ -21428,11 +21457,13 @@ function detectColumns(rows) {
|
|
|
21428
21457
|
if (allItems.length === 0) return [];
|
|
21429
21458
|
const medianCharWidth = median(allItems.map((it) => estimateCharWidth(it)).filter((w) => w > 0)) || 1;
|
|
21430
21459
|
const gapTol = medianCharWidth * COLUMN_GAP_MERGE_FACTOR;
|
|
21460
|
+
const hardBoundaries = voteColumnBoundaries(rows, medianCharWidth);
|
|
21431
21461
|
const intervals = allItems.map((it) => ({ x0: it.x, x1: it.right })).sort((a, b) => a.x0 - b.x0);
|
|
21432
21462
|
const merged = [];
|
|
21433
21463
|
for (const iv of intervals) {
|
|
21434
21464
|
const last = merged[merged.length - 1];
|
|
21435
|
-
|
|
21465
|
+
const crossesHardBoundary = last !== void 0 && hardBoundaries.some((b) => b >= last.x1 && b <= iv.x0);
|
|
21466
|
+
if (last && iv.x0 - last.x1 <= gapTol && !crossesHardBoundary) {
|
|
21436
21467
|
last.x1 = Math.max(last.x1, iv.x1);
|
|
21437
21468
|
} else {
|
|
21438
21469
|
merged.push({ ...iv });
|
|
@@ -21611,6 +21642,67 @@ function estimateCharWidth(item) {
|
|
|
21611
21642
|
const chars = item.str.length;
|
|
21612
21643
|
return chars > 0 ? item.width / chars : 0;
|
|
21613
21644
|
}
|
|
21645
|
+
function splitAtWideRuns(str, minRun) {
|
|
21646
|
+
const tokens = [];
|
|
21647
|
+
const isWs = (ch) => ch === " " || ch === " " || ch === "\xA0";
|
|
21648
|
+
let i = 0;
|
|
21649
|
+
while (i < str.length) {
|
|
21650
|
+
while (i < str.length && isWs(str[i])) i++;
|
|
21651
|
+
if (i >= str.length) break;
|
|
21652
|
+
const start = i;
|
|
21653
|
+
let end = i;
|
|
21654
|
+
while (i < str.length) {
|
|
21655
|
+
if (isWs(str[i])) {
|
|
21656
|
+
let j = i;
|
|
21657
|
+
while (j < str.length && isWs(str[j])) j++;
|
|
21658
|
+
if (j - i >= minRun) break;
|
|
21659
|
+
i = j;
|
|
21660
|
+
} else {
|
|
21661
|
+
i++;
|
|
21662
|
+
end = i;
|
|
21663
|
+
}
|
|
21664
|
+
}
|
|
21665
|
+
if (end > start) tokens.push({ str: str.slice(start, end), start, end });
|
|
21666
|
+
}
|
|
21667
|
+
return tokens;
|
|
21668
|
+
}
|
|
21669
|
+
function voteColumnBoundaries(rows, medianCharWidth) {
|
|
21670
|
+
if (rows.length < 2 || medianCharWidth <= 0) return [];
|
|
21671
|
+
const candidates = [];
|
|
21672
|
+
rows.forEach((row, rIdx) => {
|
|
21673
|
+
const sorted = [...row.items].sort((a, b) => a.x - b.x);
|
|
21674
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
21675
|
+
const gap = sorted[i].x - sorted[i - 1].right;
|
|
21676
|
+
if (gap > 0) {
|
|
21677
|
+
candidates.push({
|
|
21678
|
+
mid: (sorted[i - 1].right + sorted[i].x) / 2,
|
|
21679
|
+
rowIdx: rIdx
|
|
21680
|
+
});
|
|
21681
|
+
}
|
|
21682
|
+
}
|
|
21683
|
+
});
|
|
21684
|
+
if (candidates.length === 0) return [];
|
|
21685
|
+
candidates.sort((a, b) => a.mid - b.mid);
|
|
21686
|
+
const tolerance = medianCharWidth * COLUMN_BOUNDARY_VOTE_TOLERANCE_FACTOR;
|
|
21687
|
+
const clusters = [];
|
|
21688
|
+
for (const c of candidates) {
|
|
21689
|
+
const last = clusters[clusters.length - 1];
|
|
21690
|
+
if (last && c.mid - last.mids[last.mids.length - 1] <= tolerance) {
|
|
21691
|
+
last.mids.push(c.mid);
|
|
21692
|
+
last.rowSet.add(c.rowIdx);
|
|
21693
|
+
} else {
|
|
21694
|
+
clusters.push({ mids: [c.mid], rowSet: /* @__PURE__ */ new Set([c.rowIdx]) });
|
|
21695
|
+
}
|
|
21696
|
+
}
|
|
21697
|
+
const hard = [];
|
|
21698
|
+
for (const cl of clusters) {
|
|
21699
|
+
if (cl.rowSet.size / rows.length >= COLUMN_SUPPORT_THRESHOLD) {
|
|
21700
|
+
hard.push(median(cl.mids));
|
|
21701
|
+
}
|
|
21702
|
+
}
|
|
21703
|
+
hard.sort((a, b) => a - b);
|
|
21704
|
+
return hard;
|
|
21705
|
+
}
|
|
21614
21706
|
function median(xs) {
|
|
21615
21707
|
if (xs.length === 0) return 0;
|
|
21616
21708
|
const sorted = [...xs].sort((a, b) => a - b);
|
|
@@ -21702,7 +21794,7 @@ function assignRowToColumns(row, columns) {
|
|
|
21702
21794
|
best = c;
|
|
21703
21795
|
}
|
|
21704
21796
|
}
|
|
21705
|
-
if (best >= 0 && bestScore >
|
|
21797
|
+
if (best >= 0 && bestScore > MIN_CELL_OVERLAP_SCORE) buckets[best].push(item);
|
|
21706
21798
|
}
|
|
21707
21799
|
for (let c = 0; c < columns.length; c++) {
|
|
21708
21800
|
const bucket = buckets[c].sort((a, b) => a.x - b.x);
|
|
@@ -23862,8 +23954,8 @@ import { readFileSync as readFileSync4 } from "fs";
|
|
|
23862
23954
|
import { resolve, dirname as dirname3 } from "path";
|
|
23863
23955
|
import { fileURLToPath } from "url";
|
|
23864
23956
|
var getVersion = () => {
|
|
23865
|
-
if ("1.0.
|
|
23866
|
-
return "1.0.
|
|
23957
|
+
if ("1.0.12") {
|
|
23958
|
+
return "1.0.12";
|
|
23867
23959
|
}
|
|
23868
23960
|
try {
|
|
23869
23961
|
const __dirname = dirname3(fileURLToPath(import.meta.url));
|