juxscript 1.1.206 → 1.1.207
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/lib/components/dataframe.d.ts.map +1 -1
- package/lib/components/dataframe.js +16 -44
- package/lib/components/dataframe.ts +17 -43
- package/lib/storage/TabularDriver.d.ts +10 -4
- package/lib/storage/TabularDriver.d.ts.map +1 -1
- package/lib/storage/TabularDriver.js +61 -23
- package/lib/storage/TabularDriver.ts +57 -23
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dataframe.d.ts","sourceRoot":"","sources":["dataframe.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"dataframe.d.ts","sourceRoot":"","sources":["dataframe.ts"],"names":[],"mappings":"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"}
|
|
@@ -502,45 +502,15 @@ export class DataFrameComponent extends BaseComponent {
|
|
|
502
502
|
if (!this._rawFileData?.file)
|
|
503
503
|
return;
|
|
504
504
|
this._cleanupReshapeModal();
|
|
505
|
-
//
|
|
506
|
-
const
|
|
507
|
-
|
|
508
|
-
const workbook = XLSX.read(buffer, {
|
|
509
|
-
type: 'array',
|
|
510
|
-
sheetRows: 20,
|
|
511
|
-
dense: false
|
|
512
|
-
});
|
|
513
|
-
const sheetName = workbook.SheetNames[0];
|
|
514
|
-
const worksheet = workbook.Sheets[sheetName];
|
|
515
|
-
const ref = worksheet['!ref'];
|
|
516
|
-
if (!ref)
|
|
505
|
+
// ✅ Use the SAME cell-reading method as the parser
|
|
506
|
+
const rawRows = await this._driver.readRawExcelRows(this._rawFileData.file, 15);
|
|
507
|
+
if (rawRows.length === 0)
|
|
517
508
|
return;
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
const endCol = range.e.c;
|
|
522
|
-
const readCellValue = (r, c) => {
|
|
523
|
-
const addr = XLSX.utils.encode_cell({ r, c });
|
|
524
|
-
const cell = worksheet[addr];
|
|
525
|
-
if (!cell)
|
|
526
|
-
return null;
|
|
527
|
-
if (cell.w !== undefined)
|
|
528
|
-
return cell.w;
|
|
529
|
-
if (cell.v !== undefined)
|
|
530
|
-
return cell.v;
|
|
531
|
-
return null;
|
|
532
|
-
};
|
|
533
|
-
// Build raw row data with actual sheet row indices
|
|
534
|
-
const rawRows = [];
|
|
535
|
-
for (let r = 0; r <= endRow; r++) {
|
|
536
|
-
const values = [];
|
|
537
|
-
for (let c = startCol; c <= endCol; c++) {
|
|
538
|
-
values.push(readCellValue(r, c));
|
|
539
|
-
}
|
|
540
|
-
rawRows.push({ sheetRow: r, values });
|
|
541
|
-
}
|
|
509
|
+
// Log what we got so we can verify alignment
|
|
510
|
+
console.log('[DataFrame Preview] Raw rows from readRawExcelRows:');
|
|
511
|
+
rawRows.forEach(r => console.log(` sheetRow ${r.sheetRow}:`, r.values.slice(0, 5)));
|
|
542
512
|
// Auto-detect best header row
|
|
543
|
-
let selectedSheetRow = 0;
|
|
513
|
+
let selectedSheetRow = rawRows[0].sheetRow;
|
|
544
514
|
for (const { sheetRow, values } of rawRows) {
|
|
545
515
|
const nonEmpty = values.filter(v => v !== null && v !== undefined && String(v).trim() !== '');
|
|
546
516
|
if (nonEmpty.length < values.length * 0.5)
|
|
@@ -584,6 +554,7 @@ export class DataFrameComponent extends BaseComponent {
|
|
|
584
554
|
click: async () => {
|
|
585
555
|
const input = document.getElementById(`${this._id}-header-row`);
|
|
586
556
|
const headerRow = parseInt(input.value) || 0;
|
|
557
|
+
console.log(`[DataFrame] Apply clicked: headerRow=${headerRow}`);
|
|
587
558
|
this.state.loading = true;
|
|
588
559
|
this._updateStatus('Re-parsing with new settings...', 'loading');
|
|
589
560
|
try {
|
|
@@ -626,22 +597,22 @@ export class DataFrameComponent extends BaseComponent {
|
|
|
626
597
|
const vals = rawRows.find(r => r.sheetRow === row)?.values ?? [];
|
|
627
598
|
const headerNames = vals.filter((v) => v != null && String(v).trim() !== '').map((v) => String(v).trim());
|
|
628
599
|
const preview = headerNames.slice(0, 4).join(', ') + (headerNames.length > 4 ? '…' : '');
|
|
629
|
-
if (row > 0) {
|
|
630
|
-
hintDiv.innerHTML = `
|
|
600
|
+
if (row > rawRows[0].sheetRow) {
|
|
601
|
+
hintDiv.innerHTML = `Sheet row <strong>${row}</strong> selected as header. Columns: <code>${this._escapeHtml(preview)}</code>. Rows before it will be skipped.`;
|
|
631
602
|
}
|
|
632
603
|
else {
|
|
633
|
-
hintDiv.innerHTML = `
|
|
604
|
+
hintDiv.innerHTML = `Sheet row <strong>${row}</strong> (first row) selected as header. Columns: <code>${this._escapeHtml(preview)}</code>`;
|
|
634
605
|
}
|
|
635
606
|
};
|
|
636
607
|
const renderPreview = (selected) => {
|
|
637
608
|
if (!previewDiv)
|
|
638
609
|
return;
|
|
639
610
|
previewDiv.innerHTML = this._buildClickablePreviewHTML(rawRows, selected);
|
|
640
|
-
// Wire click handlers on each row
|
|
641
611
|
previewDiv.querySelectorAll('tr[data-sheet-row]').forEach(tr => {
|
|
642
612
|
tr.addEventListener('click', () => {
|
|
643
613
|
const rowIdx = parseInt(tr.dataset.sheetRow);
|
|
644
614
|
hiddenInput.value = String(rowIdx);
|
|
615
|
+
console.log(`[DataFrame Preview] Clicked sheetRow=${rowIdx}`);
|
|
645
616
|
updateHint(rowIdx);
|
|
646
617
|
renderPreview(rowIdx);
|
|
647
618
|
});
|
|
@@ -759,11 +730,11 @@ export class DataFrameComponent extends BaseComponent {
|
|
|
759
730
|
const vals = rawRows.find(r => r.sheetRow === row)?.values ?? [];
|
|
760
731
|
const headerNames = vals.filter((v) => v != null && String(v).trim() !== '').map((v) => String(v).trim());
|
|
761
732
|
const preview = headerNames.slice(0, 4).join(', ') + (headerNames.length > 4 ? '…' : '');
|
|
762
|
-
if (row > 0) {
|
|
763
|
-
hintDiv.innerHTML = `
|
|
733
|
+
if (row > rawRows[0].sheetRow) {
|
|
734
|
+
hintDiv.innerHTML = `Sheet row <strong>${row}</strong> selected as header. Columns: <code>${this._escapeHtml(preview)}</code>. Rows before it will be skipped.`;
|
|
764
735
|
}
|
|
765
736
|
else {
|
|
766
|
-
hintDiv.innerHTML = `
|
|
737
|
+
hintDiv.innerHTML = `Sheet row <strong>${row}</strong> (first row) selected as header. Columns: <code>${this._escapeHtml(preview)}</code>`;
|
|
767
738
|
}
|
|
768
739
|
};
|
|
769
740
|
const reparse = () => {
|
|
@@ -786,6 +757,7 @@ export class DataFrameComponent extends BaseComponent {
|
|
|
786
757
|
tr.addEventListener('click', () => {
|
|
787
758
|
const rowIdx = parseInt(tr.dataset.sheetRow);
|
|
788
759
|
hiddenInput.value = String(rowIdx);
|
|
760
|
+
console.log(`[DataFrame Preview] Clicked sheetRow=${rowIdx}`);
|
|
789
761
|
updateHint(rowIdx);
|
|
790
762
|
renderPreview(rowIdx);
|
|
791
763
|
});
|
|
@@ -617,46 +617,17 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
|
|
|
617
617
|
|
|
618
618
|
this._cleanupReshapeModal();
|
|
619
619
|
|
|
620
|
-
//
|
|
621
|
-
const
|
|
622
|
-
const buffer = await this._rawFileData.file.arrayBuffer();
|
|
623
|
-
const workbook = XLSX.read(buffer, {
|
|
624
|
-
type: 'array',
|
|
625
|
-
sheetRows: 20,
|
|
626
|
-
dense: false
|
|
627
|
-
});
|
|
620
|
+
// ✅ Use the SAME cell-reading method as the parser
|
|
621
|
+
const rawRows = await this._driver.readRawExcelRows(this._rawFileData.file, 15);
|
|
628
622
|
|
|
629
|
-
|
|
630
|
-
const worksheet = workbook.Sheets[sheetName];
|
|
631
|
-
const ref = worksheet['!ref'];
|
|
632
|
-
if (!ref) return;
|
|
633
|
-
|
|
634
|
-
const range = XLSX.utils.decode_range(ref);
|
|
635
|
-
const endRow = Math.min(range.e.r, 14); // Show up to 15 rows
|
|
636
|
-
const startCol = range.s.c;
|
|
637
|
-
const endCol = range.e.c;
|
|
638
|
-
|
|
639
|
-
const readCellValue = (r: number, c: number): any => {
|
|
640
|
-
const addr = XLSX.utils.encode_cell({ r, c });
|
|
641
|
-
const cell = worksheet[addr];
|
|
642
|
-
if (!cell) return null;
|
|
643
|
-
if (cell.w !== undefined) return cell.w;
|
|
644
|
-
if (cell.v !== undefined) return cell.v;
|
|
645
|
-
return null;
|
|
646
|
-
};
|
|
623
|
+
if (rawRows.length === 0) return;
|
|
647
624
|
|
|
648
|
-
//
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
const values: any[] = [];
|
|
652
|
-
for (let c = startCol; c <= endCol; c++) {
|
|
653
|
-
values.push(readCellValue(r, c));
|
|
654
|
-
}
|
|
655
|
-
rawRows.push({ sheetRow: r, values });
|
|
656
|
-
}
|
|
625
|
+
// Log what we got so we can verify alignment
|
|
626
|
+
console.log('[DataFrame Preview] Raw rows from readRawExcelRows:');
|
|
627
|
+
rawRows.forEach(r => console.log(` sheetRow ${r.sheetRow}:`, r.values.slice(0, 5)));
|
|
657
628
|
|
|
658
629
|
// Auto-detect best header row
|
|
659
|
-
let selectedSheetRow = 0;
|
|
630
|
+
let selectedSheetRow = rawRows[0].sheetRow;
|
|
660
631
|
for (const { sheetRow, values } of rawRows) {
|
|
661
632
|
const nonEmpty = values.filter(v => v !== null && v !== undefined && String(v).trim() !== '');
|
|
662
633
|
if (nonEmpty.length < values.length * 0.5) continue;
|
|
@@ -703,6 +674,8 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
|
|
|
703
674
|
const input = document.getElementById(`${this._id}-header-row`) as HTMLInputElement;
|
|
704
675
|
const headerRow = parseInt(input.value) || 0;
|
|
705
676
|
|
|
677
|
+
console.log(`[DataFrame] Apply clicked: headerRow=${headerRow}`);
|
|
678
|
+
|
|
706
679
|
this.state.loading = true;
|
|
707
680
|
this._updateStatus('Re-parsing with new settings...', 'loading');
|
|
708
681
|
|
|
@@ -752,10 +725,10 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
|
|
|
752
725
|
const vals = rawRows.find(r => r.sheetRow === row)?.values ?? [];
|
|
753
726
|
const headerNames = vals.filter((v: any) => v != null && String(v).trim() !== '').map((v: any) => String(v).trim());
|
|
754
727
|
const preview = headerNames.slice(0, 4).join(', ') + (headerNames.length > 4 ? '…' : '');
|
|
755
|
-
if (row > 0) {
|
|
756
|
-
hintDiv.innerHTML = `
|
|
728
|
+
if (row > rawRows[0].sheetRow) {
|
|
729
|
+
hintDiv.innerHTML = `Sheet row <strong>${row}</strong> selected as header. Columns: <code>${this._escapeHtml(preview)}</code>. Rows before it will be skipped.`;
|
|
757
730
|
} else {
|
|
758
|
-
hintDiv.innerHTML = `
|
|
731
|
+
hintDiv.innerHTML = `Sheet row <strong>${row}</strong> (first row) selected as header. Columns: <code>${this._escapeHtml(preview)}</code>`;
|
|
759
732
|
}
|
|
760
733
|
};
|
|
761
734
|
|
|
@@ -763,11 +736,11 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
|
|
|
763
736
|
if (!previewDiv) return;
|
|
764
737
|
previewDiv.innerHTML = this._buildClickablePreviewHTML(rawRows, selected);
|
|
765
738
|
|
|
766
|
-
// Wire click handlers on each row
|
|
767
739
|
previewDiv.querySelectorAll('tr[data-sheet-row]').forEach(tr => {
|
|
768
740
|
tr.addEventListener('click', () => {
|
|
769
741
|
const rowIdx = parseInt((tr as HTMLElement).dataset.sheetRow!);
|
|
770
742
|
hiddenInput.value = String(rowIdx);
|
|
743
|
+
console.log(`[DataFrame Preview] Clicked sheetRow=${rowIdx}`);
|
|
771
744
|
updateHint(rowIdx);
|
|
772
745
|
renderPreview(rowIdx);
|
|
773
746
|
});
|
|
@@ -898,10 +871,10 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
|
|
|
898
871
|
const vals = rawRows.find(r => r.sheetRow === row)?.values ?? [];
|
|
899
872
|
const headerNames = vals.filter((v: any) => v != null && String(v).trim() !== '').map((v: any) => String(v).trim());
|
|
900
873
|
const preview = headerNames.slice(0, 4).join(', ') + (headerNames.length > 4 ? '…' : '');
|
|
901
|
-
if (row > 0) {
|
|
902
|
-
hintDiv.innerHTML = `
|
|
874
|
+
if (row > rawRows[0].sheetRow) {
|
|
875
|
+
hintDiv.innerHTML = `Sheet row <strong>${row}</strong> selected as header. Columns: <code>${this._escapeHtml(preview)}</code>. Rows before it will be skipped.`;
|
|
903
876
|
} else {
|
|
904
|
-
hintDiv.innerHTML = `
|
|
877
|
+
hintDiv.innerHTML = `Sheet row <strong>${row}</strong> (first row) selected as header. Columns: <code>${this._escapeHtml(preview)}</code>`;
|
|
905
878
|
}
|
|
906
879
|
};
|
|
907
880
|
|
|
@@ -926,6 +899,7 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
|
|
|
926
899
|
tr.addEventListener('click', () => {
|
|
927
900
|
const rowIdx = parseInt((tr as HTMLElement).dataset.sheetRow!);
|
|
928
901
|
hiddenInput.value = String(rowIdx);
|
|
902
|
+
console.log(`[DataFrame Preview] Clicked sheetRow=${rowIdx}`);
|
|
929
903
|
updateHint(rowIdx);
|
|
930
904
|
renderPreview(rowIdx);
|
|
931
905
|
});
|
|
@@ -87,12 +87,18 @@ export declare class TabularDriver {
|
|
|
87
87
|
* Fetch and stream-parse a remote CSV/TSV file
|
|
88
88
|
*/
|
|
89
89
|
fetch(url: string, options?: ParseOptions): Promise<DataFrame>;
|
|
90
|
+
/**
|
|
91
|
+
* Read raw cell values from first sheet of an Excel file.
|
|
92
|
+
* Returns rows with their actual sheet row indices.
|
|
93
|
+
* Used by both the preview UI and the parser to ensure consistency.
|
|
94
|
+
*/
|
|
95
|
+
readRawExcelRows(file: File, maxRows?: number): Promise<{
|
|
96
|
+
sheetRow: number;
|
|
97
|
+
values: any[];
|
|
98
|
+
}[]>;
|
|
90
99
|
/**
|
|
91
100
|
* ✅ FIXED: Stream Excel file with optional headerRow override
|
|
92
|
-
* headerRow is
|
|
93
|
-
*
|
|
94
|
-
* Uses direct cell access instead of sheet_to_json to avoid
|
|
95
|
-
* issues with blank row handling and sparse arrays.
|
|
101
|
+
* headerRow is the absolute sheet row index (same as sheetRow from readRawExcelRows).
|
|
96
102
|
*/
|
|
97
103
|
streamFileMultiSheet(file: File, options?: ParseOptions): Promise<Record<string, DataFrame>>;
|
|
98
104
|
private _splitLines;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TabularDriver.d.ts","sourceRoot":"","sources":["TabularDriver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,MAAM,WAAW,WAAW;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,YAAY;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mBAAmB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,qBAAa,aAAa;IACtB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,GAAG,CAA4B;gBAE3B,MAAM,GAAE,MAAsB,EAAE,SAAS,GAAE,MAAiB;IAKlE,IAAI,IAAI,OAAO,CAAC,WAAW,CAAC;IA4BlC;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAgCxB;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAwBxB;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,SAAS;IA6D7D;;;OAGG;IACG,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,SAAS,CAAC;IAoG5E;;OAEG;YACW,UAAU;IAuExB;;OAEG;IACG,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAiBlD;;OAEG;IACG,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IAuBzF;;OAEG;IACG,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAwBjD;;OAEG;IACG,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IA4BzD;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAqBlH;;OAEG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYjC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB5B;;OAEG;IACG,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,SAAS,CAAC;IA0ExE
|
|
1
|
+
{"version":3,"file":"TabularDriver.d.ts","sourceRoot":"","sources":["TabularDriver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,MAAM,WAAW,WAAW;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,YAAY;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mBAAmB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,qBAAa,aAAa;IACtB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,GAAG,CAA4B;gBAE3B,MAAM,GAAE,MAAsB,EAAE,SAAS,GAAE,MAAiB;IAKlE,IAAI,IAAI,OAAO,CAAC,WAAW,CAAC;IA4BlC;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAgCxB;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAwBxB;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,SAAS;IA6D7D;;;OAGG;IACG,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,SAAS,CAAC;IAoG5E;;OAEG;YACW,UAAU;IAuExB;;OAEG;IACG,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAiBlD;;OAEG;IACG,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IAuBzF;;OAEG;IACG,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAwBjD;;OAEG;IACG,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IA4BzD;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAqBlH;;OAEG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYjC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB5B;;OAEG;IACG,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,SAAS,CAAC;IA0ExE;;;;OAIG;IACG,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,GAAE,MAAW,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,GAAG,EAAE,CAAA;KAAE,EAAE,CAAC;IA6CxG;;;OAGG;IACG,oBAAoB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAwItG,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,UAAU;IAmClB,OAAO,CAAC,SAAS;IAYjB,KAAK,IAAI,IAAI;CAMhB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,aAAa,CAEhF"}
|
|
@@ -486,12 +486,63 @@ export class TabularDriver {
|
|
|
486
486
|
df = df.select(...selectCols);
|
|
487
487
|
return df;
|
|
488
488
|
}
|
|
489
|
+
/**
|
|
490
|
+
* Read raw cell values from first sheet of an Excel file.
|
|
491
|
+
* Returns rows with their actual sheet row indices.
|
|
492
|
+
* Used by both the preview UI and the parser to ensure consistency.
|
|
493
|
+
*/
|
|
494
|
+
async readRawExcelRows(file, maxRows = 15) {
|
|
495
|
+
let XLSX;
|
|
496
|
+
try {
|
|
497
|
+
XLSX = await import('xlsx');
|
|
498
|
+
}
|
|
499
|
+
catch {
|
|
500
|
+
throw new Error('XLSX support requires the "xlsx" package.');
|
|
501
|
+
}
|
|
502
|
+
const buffer = await file.arrayBuffer();
|
|
503
|
+
const workbook = XLSX.read(buffer, {
|
|
504
|
+
type: 'array',
|
|
505
|
+
sheetRows: maxRows + 5,
|
|
506
|
+
dense: false
|
|
507
|
+
});
|
|
508
|
+
const sheetName = workbook.SheetNames[0];
|
|
509
|
+
const worksheet = workbook.Sheets[sheetName];
|
|
510
|
+
const ref = worksheet['!ref'];
|
|
511
|
+
if (!ref)
|
|
512
|
+
return [];
|
|
513
|
+
const range = XLSX.utils.decode_range(ref);
|
|
514
|
+
const startRow = range.s.r;
|
|
515
|
+
const endRow = Math.min(range.e.r, startRow + maxRows - 1);
|
|
516
|
+
const startCol = range.s.c;
|
|
517
|
+
const endCol = range.e.c;
|
|
518
|
+
console.log(`[readRawExcelRows] ref=${ref}, startRow=${startRow}, endRow=${endRow}, cols=${startCol}-${endCol}`);
|
|
519
|
+
const rows = [];
|
|
520
|
+
for (let r = startRow; r <= endRow; r++) {
|
|
521
|
+
const values = [];
|
|
522
|
+
for (let c = startCol; c <= endCol; c++) {
|
|
523
|
+
const addr = XLSX.utils.encode_cell({ r, c });
|
|
524
|
+
const cell = worksheet[addr];
|
|
525
|
+
if (!cell) {
|
|
526
|
+
values.push(null);
|
|
527
|
+
continue;
|
|
528
|
+
}
|
|
529
|
+
if (cell.w !== undefined) {
|
|
530
|
+
values.push(cell.w);
|
|
531
|
+
continue;
|
|
532
|
+
}
|
|
533
|
+
if (cell.v !== undefined) {
|
|
534
|
+
values.push(cell.v);
|
|
535
|
+
continue;
|
|
536
|
+
}
|
|
537
|
+
values.push(null);
|
|
538
|
+
}
|
|
539
|
+
rows.push({ sheetRow: r, values });
|
|
540
|
+
}
|
|
541
|
+
return rows;
|
|
542
|
+
}
|
|
489
543
|
/**
|
|
490
544
|
* ✅ FIXED: Stream Excel file with optional headerRow override
|
|
491
|
-
* headerRow is
|
|
492
|
-
*
|
|
493
|
-
* Uses direct cell access instead of sheet_to_json to avoid
|
|
494
|
-
* issues with blank row handling and sparse arrays.
|
|
545
|
+
* headerRow is the absolute sheet row index (same as sheetRow from readRawExcelRows).
|
|
495
546
|
*/
|
|
496
547
|
async streamFileMultiSheet(file, options = {}) {
|
|
497
548
|
const { maxSheetSize = 100000, sheetChunkSize = 10000, onProgress, headerRow = 0 } = options;
|
|
@@ -531,7 +582,6 @@ export class TabularDriver {
|
|
|
531
582
|
processedSheets++;
|
|
532
583
|
continue;
|
|
533
584
|
}
|
|
534
|
-
// Direct cell reader - bypasses sheet_to_json completely
|
|
535
585
|
const readCellValue = (r, c) => {
|
|
536
586
|
const addr = XLSX.utils.encode_cell({ r, c });
|
|
537
587
|
const cell = worksheet[addr];
|
|
@@ -550,46 +600,37 @@ export class TabularDriver {
|
|
|
550
600
|
}
|
|
551
601
|
return vals;
|
|
552
602
|
};
|
|
553
|
-
//
|
|
554
|
-
//
|
|
555
|
-
// sees row 0 as the first row regardless of where the sheet
|
|
556
|
-
// range begins. We simply use headerRow as the absolute sheet
|
|
557
|
-
// row index.
|
|
603
|
+
// headerRow is the absolute sheet row index — same value as
|
|
604
|
+
// sheetRow from readRawExcelRows(). No offset needed.
|
|
558
605
|
const headerSheetRow = headerRow;
|
|
559
|
-
console.log(`[TabularDriver] Sheet "${sheetName}": range=${ref}, startRow=${startRow}, endRow=${endRow}
|
|
560
|
-
console.log(`[TabularDriver] headerRow=${headerRow}, headerSheetRow=${headerSheetRow}
|
|
606
|
+
console.log(`[TabularDriver] Sheet "${sheetName}": range=${ref}, startRow=${startRow}, endRow=${endRow}`);
|
|
607
|
+
console.log(`[TabularDriver] headerRow=${headerRow}, headerSheetRow=${headerSheetRow}`);
|
|
561
608
|
if (headerSheetRow > endRow) {
|
|
562
|
-
console.warn(`[TabularDriver] headerRow ${headerRow}
|
|
609
|
+
console.warn(`[TabularDriver] headerRow ${headerRow} exceeds endRow ${endRow}`);
|
|
563
610
|
processedSheets++;
|
|
564
611
|
continue;
|
|
565
612
|
}
|
|
566
|
-
// Read header values directly from cells
|
|
567
613
|
const headerValues = readRow(headerSheetRow);
|
|
568
614
|
console.log(`[TabularDriver] Raw header values at sheet row ${headerSheetRow}:`, headerValues);
|
|
569
|
-
// Build headers array
|
|
570
615
|
const headers = headerValues.map((h, i) => {
|
|
571
616
|
if (h === null || h === undefined || String(h).trim() === '') {
|
|
572
617
|
return `__EMPTY${i > 0 ? '_' + i : ''}`;
|
|
573
618
|
}
|
|
574
619
|
return String(h).trim();
|
|
575
620
|
});
|
|
576
|
-
// Count valid headers
|
|
577
621
|
const validHeaders = headers.filter(h => !h.startsWith('__EMPTY'));
|
|
578
622
|
console.log(`[TabularDriver] Headers (${validHeaders.length} valid / ${headers.length} total):`, headers);
|
|
579
623
|
if (validHeaders.length === 0) {
|
|
580
|
-
console.warn(`[TabularDriver] No valid headers found at row ${headerRow}
|
|
581
|
-
// Log surrounding rows for debugging
|
|
624
|
+
console.warn(`[TabularDriver] No valid headers found at row ${headerRow} in sheet "${sheetName}"`);
|
|
582
625
|
for (let debugR = Math.max(startRow, headerSheetRow - 2); debugR <= Math.min(endRow, headerSheetRow + 2); debugR++) {
|
|
583
626
|
console.log(`[TabularDriver] row ${debugR}:`, readRow(debugR));
|
|
584
627
|
}
|
|
585
628
|
processedSheets++;
|
|
586
629
|
continue;
|
|
587
630
|
}
|
|
588
|
-
// Build data rows: everything after the header row
|
|
589
631
|
const rows = [];
|
|
590
632
|
for (let r = headerSheetRow + 1; r <= endRow; r++) {
|
|
591
633
|
const rowData = readRow(r);
|
|
592
|
-
// Skip completely empty rows
|
|
593
634
|
const hasContent = rowData.some(cell => cell !== null && cell !== undefined && String(cell).trim() !== '');
|
|
594
635
|
if (!hasContent)
|
|
595
636
|
continue;
|
|
@@ -600,9 +641,6 @@ export class TabularDriver {
|
|
|
600
641
|
rows.push(row);
|
|
601
642
|
}
|
|
602
643
|
console.log(`[TabularDriver] Built ${rows.length} data rows for sheet "${sheetName}"`);
|
|
603
|
-
if (rows.length > 0) {
|
|
604
|
-
console.log(`[TabularDriver] First row:`, rows[0]);
|
|
605
|
-
}
|
|
606
644
|
if (rows.length > 0) {
|
|
607
645
|
sheets[sheetName] = new DataFrame(rows);
|
|
608
646
|
}
|
|
@@ -606,12 +606,59 @@ export class TabularDriver {
|
|
|
606
606
|
return df;
|
|
607
607
|
}
|
|
608
608
|
|
|
609
|
+
/**
|
|
610
|
+
* Read raw cell values from first sheet of an Excel file.
|
|
611
|
+
* Returns rows with their actual sheet row indices.
|
|
612
|
+
* Used by both the preview UI and the parser to ensure consistency.
|
|
613
|
+
*/
|
|
614
|
+
async readRawExcelRows(file: File, maxRows: number = 15): Promise<{ sheetRow: number; values: any[] }[]> {
|
|
615
|
+
let XLSX: any;
|
|
616
|
+
try {
|
|
617
|
+
XLSX = await import('xlsx');
|
|
618
|
+
} catch {
|
|
619
|
+
throw new Error('XLSX support requires the "xlsx" package.');
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
const buffer = await file.arrayBuffer();
|
|
623
|
+
const workbook = XLSX.read(buffer, {
|
|
624
|
+
type: 'array',
|
|
625
|
+
sheetRows: maxRows + 5,
|
|
626
|
+
dense: false
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
const sheetName = workbook.SheetNames[0];
|
|
630
|
+
const worksheet = workbook.Sheets[sheetName];
|
|
631
|
+
const ref = worksheet['!ref'];
|
|
632
|
+
if (!ref) return [];
|
|
633
|
+
|
|
634
|
+
const range = XLSX.utils.decode_range(ref);
|
|
635
|
+
const startRow = range.s.r;
|
|
636
|
+
const endRow = Math.min(range.e.r, startRow + maxRows - 1);
|
|
637
|
+
const startCol = range.s.c;
|
|
638
|
+
const endCol = range.e.c;
|
|
639
|
+
|
|
640
|
+
console.log(`[readRawExcelRows] ref=${ref}, startRow=${startRow}, endRow=${endRow}, cols=${startCol}-${endCol}`);
|
|
641
|
+
|
|
642
|
+
const rows: { sheetRow: number; values: any[] }[] = [];
|
|
643
|
+
for (let r = startRow; r <= endRow; r++) {
|
|
644
|
+
const values: any[] = [];
|
|
645
|
+
for (let c = startCol; c <= endCol; c++) {
|
|
646
|
+
const addr = XLSX.utils.encode_cell({ r, c });
|
|
647
|
+
const cell = worksheet[addr];
|
|
648
|
+
if (!cell) { values.push(null); continue; }
|
|
649
|
+
if (cell.w !== undefined) { values.push(cell.w); continue; }
|
|
650
|
+
if (cell.v !== undefined) { values.push(cell.v); continue; }
|
|
651
|
+
values.push(null);
|
|
652
|
+
}
|
|
653
|
+
rows.push({ sheetRow: r, values });
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
return rows;
|
|
657
|
+
}
|
|
658
|
+
|
|
609
659
|
/**
|
|
610
660
|
* ✅ FIXED: Stream Excel file with optional headerRow override
|
|
611
|
-
* headerRow is
|
|
612
|
-
*
|
|
613
|
-
* Uses direct cell access instead of sheet_to_json to avoid
|
|
614
|
-
* issues with blank row handling and sparse arrays.
|
|
661
|
+
* headerRow is the absolute sheet row index (same as sheetRow from readRawExcelRows).
|
|
615
662
|
*/
|
|
616
663
|
async streamFileMultiSheet(file: File, options: ParseOptions = {}): Promise<Record<string, DataFrame>> {
|
|
617
664
|
const { maxSheetSize = 100000, sheetChunkSize = 10000, onProgress, headerRow = 0 } = options;
|
|
@@ -659,7 +706,6 @@ export class TabularDriver {
|
|
|
659
706
|
continue;
|
|
660
707
|
}
|
|
661
708
|
|
|
662
|
-
// Direct cell reader - bypasses sheet_to_json completely
|
|
663
709
|
const readCellValue = (r: number, c: number): any => {
|
|
664
710
|
const addr = XLSX.utils.encode_cell({ r, c });
|
|
665
711
|
const cell = worksheet[addr];
|
|
@@ -677,27 +723,22 @@ export class TabularDriver {
|
|
|
677
723
|
return vals;
|
|
678
724
|
};
|
|
679
725
|
|
|
680
|
-
//
|
|
681
|
-
//
|
|
682
|
-
// sees row 0 as the first row regardless of where the sheet
|
|
683
|
-
// range begins. We simply use headerRow as the absolute sheet
|
|
684
|
-
// row index.
|
|
726
|
+
// headerRow is the absolute sheet row index — same value as
|
|
727
|
+
// sheetRow from readRawExcelRows(). No offset needed.
|
|
685
728
|
const headerSheetRow = headerRow;
|
|
686
729
|
|
|
687
|
-
console.log(`[TabularDriver] Sheet "${sheetName}": range=${ref}, startRow=${startRow}, endRow=${endRow}
|
|
688
|
-
console.log(`[TabularDriver] headerRow=${headerRow}, headerSheetRow=${headerSheetRow}
|
|
730
|
+
console.log(`[TabularDriver] Sheet "${sheetName}": range=${ref}, startRow=${startRow}, endRow=${endRow}`);
|
|
731
|
+
console.log(`[TabularDriver] headerRow=${headerRow}, headerSheetRow=${headerSheetRow}`);
|
|
689
732
|
|
|
690
733
|
if (headerSheetRow > endRow) {
|
|
691
|
-
console.warn(`[TabularDriver] headerRow ${headerRow}
|
|
734
|
+
console.warn(`[TabularDriver] headerRow ${headerRow} exceeds endRow ${endRow}`);
|
|
692
735
|
processedSheets++;
|
|
693
736
|
continue;
|
|
694
737
|
}
|
|
695
738
|
|
|
696
|
-
// Read header values directly from cells
|
|
697
739
|
const headerValues = readRow(headerSheetRow);
|
|
698
740
|
console.log(`[TabularDriver] Raw header values at sheet row ${headerSheetRow}:`, headerValues);
|
|
699
741
|
|
|
700
|
-
// Build headers array
|
|
701
742
|
const headers: string[] = headerValues.map((h: any, i: number) => {
|
|
702
743
|
if (h === null || h === undefined || String(h).trim() === '') {
|
|
703
744
|
return `__EMPTY${i > 0 ? '_' + i : ''}`;
|
|
@@ -705,13 +746,11 @@ export class TabularDriver {
|
|
|
705
746
|
return String(h).trim();
|
|
706
747
|
});
|
|
707
748
|
|
|
708
|
-
// Count valid headers
|
|
709
749
|
const validHeaders = headers.filter(h => !h.startsWith('__EMPTY'));
|
|
710
750
|
console.log(`[TabularDriver] Headers (${validHeaders.length} valid / ${headers.length} total):`, headers);
|
|
711
751
|
|
|
712
752
|
if (validHeaders.length === 0) {
|
|
713
|
-
console.warn(`[TabularDriver] No valid headers found at row ${headerRow}
|
|
714
|
-
// Log surrounding rows for debugging
|
|
753
|
+
console.warn(`[TabularDriver] No valid headers found at row ${headerRow} in sheet "${sheetName}"`);
|
|
715
754
|
for (let debugR = Math.max(startRow, headerSheetRow - 2); debugR <= Math.min(endRow, headerSheetRow + 2); debugR++) {
|
|
716
755
|
console.log(`[TabularDriver] row ${debugR}:`, readRow(debugR));
|
|
717
756
|
}
|
|
@@ -719,12 +758,10 @@ export class TabularDriver {
|
|
|
719
758
|
continue;
|
|
720
759
|
}
|
|
721
760
|
|
|
722
|
-
// Build data rows: everything after the header row
|
|
723
761
|
const rows: Record<string, any>[] = [];
|
|
724
762
|
for (let r = headerSheetRow + 1; r <= endRow; r++) {
|
|
725
763
|
const rowData = readRow(r);
|
|
726
764
|
|
|
727
|
-
// Skip completely empty rows
|
|
728
765
|
const hasContent = rowData.some(cell =>
|
|
729
766
|
cell !== null && cell !== undefined && String(cell).trim() !== ''
|
|
730
767
|
);
|
|
@@ -738,9 +775,6 @@ export class TabularDriver {
|
|
|
738
775
|
}
|
|
739
776
|
|
|
740
777
|
console.log(`[TabularDriver] Built ${rows.length} data rows for sheet "${sheetName}"`);
|
|
741
|
-
if (rows.length > 0) {
|
|
742
|
-
console.log(`[TabularDriver] First row:`, rows[0]);
|
|
743
|
-
}
|
|
744
778
|
|
|
745
779
|
if (rows.length > 0) {
|
|
746
780
|
sheets[sheetName] = new DataFrame(rows);
|