@opencraw/cli 0.1.10 → 0.1.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.esm.js
CHANGED
|
@@ -558,6 +558,41 @@ function tryParse(text) {
|
|
|
558
558
|
}
|
|
559
559
|
}
|
|
560
560
|
|
|
561
|
+
/**
|
|
562
|
+
* Whether a cell holds a figure (an amount, a count, a date written in
|
|
563
|
+
* digits) rather than words: it starts with a number, or its digits are at
|
|
564
|
+
* least as many as its letters. `2,820`, `$560`, `2659 $560`, `(£0.58m)`,
|
|
565
|
+
* `-3 days` and `2026` are figures; `FY26 Lodging Rate`,
|
|
566
|
+
* `FM Classes A, B1 & C3` and `(APRIL 1, 2020)` are words that happen to
|
|
567
|
+
* contain digits.
|
|
568
|
+
*
|
|
569
|
+
* @param cell - The cell's text.
|
|
570
|
+
* @returns Whether it is a figure.
|
|
571
|
+
*/
|
|
572
|
+
function isFigure(cell) {
|
|
573
|
+
if (/^[\s(+\-–−<>=~$€£¥]*\d/u.test(cell)) return true;
|
|
574
|
+
const digits = cell.match(/\d/g)?.length ?? 0;
|
|
575
|
+
return digits > 0 && digits >= (cell.match(/\p{L}/gu)?.length ?? 0);
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* A row that reads like a table's header: at least two cells, none a figure.
|
|
579
|
+
*
|
|
580
|
+
* @param cells - The row's non-empty cells.
|
|
581
|
+
* @returns Whether it could be a header.
|
|
582
|
+
*/
|
|
583
|
+
function isHeaderRow(cells) {
|
|
584
|
+
return cells.length >= 2 && cells.every(cell => !isFigure(cell));
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* A row that reads like a table's data: at least two cells, one a figure.
|
|
588
|
+
*
|
|
589
|
+
* @param cells - The row's non-empty cells.
|
|
590
|
+
* @returns Whether it looks like data.
|
|
591
|
+
*/
|
|
592
|
+
function isDataRow(cells) {
|
|
593
|
+
return cells.length >= 2 && cells.some(cell => isFigure(cell));
|
|
594
|
+
}
|
|
595
|
+
|
|
561
596
|
/** Rows shown per sheet in a probe, at most. */
|
|
562
597
|
const ROW_LIMIT$1 = 20;
|
|
563
598
|
/** How far below a header row a probe looks for the first data row. */
|
|
@@ -596,23 +631,34 @@ function describeWorkbook(document) {
|
|
|
596
631
|
function headersOf(sheet) {
|
|
597
632
|
const rows = filledRows(sheet);
|
|
598
633
|
const merged = mergedRows(sheet);
|
|
599
|
-
|
|
634
|
+
const headers = [];
|
|
635
|
+
// The table a row belongs to: the header it follows, until an empty row ends the block.
|
|
636
|
+
let table;
|
|
637
|
+
for (const [position, {
|
|
600
638
|
index,
|
|
601
639
|
cells
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
if (
|
|
640
|
+
}] of rows.entries()) {
|
|
641
|
+
const previous = rows[position - 1]?.index;
|
|
642
|
+
if (previous === undefined || index > previous + 1) table = undefined;
|
|
643
|
+
const secondHeaderRow = table?.merged === true && index === table.header + 1;
|
|
644
|
+
if (table !== undefined && !secondHeaderRow) continue;
|
|
645
|
+
if (!isHeaderRow(cells) || rows.slice(position + 1, position + 1 + LOOKAHEAD).every(row => !isDataRow(row.cells))) continue;
|
|
605
646
|
const header = {
|
|
606
647
|
sheet: sheet.name,
|
|
607
648
|
row: index + 1,
|
|
608
649
|
text: cells.join(' | '),
|
|
609
650
|
selector: `^${escape$1(cells[0])}`
|
|
610
651
|
};
|
|
611
|
-
|
|
652
|
+
headers.push(merged.has(index) ? {
|
|
612
653
|
...header,
|
|
613
654
|
hint: 'merged header cells: try "headerRows": 2'
|
|
614
|
-
} : header
|
|
615
|
-
|
|
655
|
+
} : header);
|
|
656
|
+
table ??= {
|
|
657
|
+
header: index,
|
|
658
|
+
merged: merged.has(index)
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
return headers;
|
|
616
662
|
}
|
|
617
663
|
/** The non-empty rows, as their non-empty cells, whitespace collapsed. */
|
|
618
664
|
function filledRows(sheet) {
|
|
@@ -826,7 +872,7 @@ function describePdf(document) {
|
|
|
826
872
|
const headers = rows.filter(({
|
|
827
873
|
row,
|
|
828
874
|
next
|
|
829
|
-
}) => row.cells.
|
|
875
|
+
}) => isHeaderRow(row.cells.map(cell => cell.text)) && next.some(candidate => isDataRow(candidate.cells.map(cell => cell.text))));
|
|
830
876
|
return {
|
|
831
877
|
pages: document.pages.length,
|
|
832
878
|
rows: rows.slice(0, ROW_LIMIT).map(({
|
|
@@ -846,10 +892,6 @@ function describePdf(document) {
|
|
|
846
892
|
}))
|
|
847
893
|
};
|
|
848
894
|
}
|
|
849
|
-
/** A row of at least two cells, one with a digit: data, not a heading. */
|
|
850
|
-
function dataRow(row) {
|
|
851
|
-
return row.cells.length >= 2 && row.cells.some(cell => /\d/.test(cell.text));
|
|
852
|
-
}
|
|
853
895
|
function escape(text) {
|
|
854
896
|
return text.replaceAll(/[$()*+.?[\\\]^{|}]/g, String.raw`\$&`);
|
|
855
897
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a cell holds a figure (an amount, a count, a date written in
|
|
3
|
+
* digits) rather than words: it starts with a number, or its digits are at
|
|
4
|
+
* least as many as its letters. `2,820`, `$560`, `2659 $560`, `(£0.58m)`,
|
|
5
|
+
* `-3 days` and `2026` are figures; `FY26 Lodging Rate`,
|
|
6
|
+
* `FM Classes A, B1 & C3` and `(APRIL 1, 2020)` are words that happen to
|
|
7
|
+
* contain digits.
|
|
8
|
+
*
|
|
9
|
+
* @param cell - The cell's text.
|
|
10
|
+
* @returns Whether it is a figure.
|
|
11
|
+
*/
|
|
12
|
+
export declare function isFigure(cell: string): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* A row that reads like a table's header: at least two cells, none a figure.
|
|
15
|
+
*
|
|
16
|
+
* @param cells - The row's non-empty cells.
|
|
17
|
+
* @returns Whether it could be a header.
|
|
18
|
+
*/
|
|
19
|
+
export declare function isHeaderRow(cells: readonly string[]): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* A row that reads like a table's data: at least two cells, one a figure.
|
|
22
|
+
*
|
|
23
|
+
* @param cells - The row's non-empty cells.
|
|
24
|
+
* @returns Whether it looks like data.
|
|
25
|
+
*/
|
|
26
|
+
export declare function isDataRow(cells: readonly string[]): boolean;
|
|
27
|
+
//# sourceMappingURL=table-header.policy.d.ts.map
|
|
@@ -19,9 +19,10 @@ export interface WorkbookFindings {
|
|
|
19
19
|
text: string;
|
|
20
20
|
}[];
|
|
21
21
|
/**
|
|
22
|
-
* Rows of
|
|
23
|
-
* table headers, with the `sheet` and `selector` a `table` extract
|
|
24
|
-
* a hint when the header has merged cells (a header over two
|
|
22
|
+
* Rows of words (no cell a figure) with a data row (a figure) just below:
|
|
23
|
+
* likely table headers, with the `sheet` and `selector` a `table` extract
|
|
24
|
+
* needs, and a hint when the header has merged cells (a header over two
|
|
25
|
+
* rows). The rows right under a header are its table's body, not headers.
|
|
25
26
|
*/
|
|
26
27
|
headers: {
|
|
27
28
|
sheet: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opencraw/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.esm.js",
|
|
6
6
|
"module": "./dist/index.esm.js",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"!**/*.js.map"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@opencraw/core": "^0.1.
|
|
27
|
+
"@opencraw/core": "^0.1.12",
|
|
28
28
|
"playwright": "^1.63.0"
|
|
29
29
|
},
|
|
30
30
|
"publishConfig": {
|