Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion assets/profiler-engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,22 @@
});
}

function xlsxHeaderText(value) {
if (typeof value === 'boolean') return value ? 'True' : 'False';
return value === null || value === undefined ? '' : String(value);
}

function normalizeXlsxBooleanHeaderCells(sheet) {
if (!sheet['!ref']) return;
var range = global.XLSX.utils.decode_range(sheet['!ref']);
for (var c = range.s.c; c <= range.e.c; c++) {
var cell = sheet[global.XLSX.utils.encode_cell({ r: range.s.r, c: c })];
if (cell && cell.t === 'b' && typeof cell.v === 'boolean') {
cell.w = xlsxHeaderText(cell.v);
}
}
}

async function parseXLSX(arrayBuffer) {
await loadSheetJS();

Expand All @@ -649,6 +665,7 @@
var date1904 = !!(workbook.Workbook && workbook.Workbook.WBProps &&
workbook.Workbook.WBProps.date1904);
stringifyXlsxDateCells(sheet, date1904);
normalizeXlsxBooleanHeaderCells(sheet);
var records = global.XLSX.utils.sheet_to_json(sheet, { defval: null, raw: true });

if (records.length === 0) {
Expand All @@ -658,7 +675,7 @@
// read the raw header row instead of erroring, to match.
var headerRow = global.XLSX.utils.sheet_to_json(sheet, { header: 1, raw: true })[0] || [];
var columns = headerRow.map(function (h) {
return h === null || h === undefined ? '' : String(h);
return xlsxHeaderText(h);
});
return { table: { columns: columns, rows: [] }, ignoredSheets: workbook.SheetNames.slice(1), sheetName: sheetName };
}
Expand Down
19 changes: 19 additions & 0 deletions tests/test_xlsx_edge_cases.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,3 +221,22 @@ def test_xlsx_numeric_header_cells_are_text_in_both_engines(tmp_path):
js = [d["name"] for d in json.loads(result.stdout)["dimensions"]]
assert py == js == ["2020", "sex"]
assert all(isinstance(name, str) for name in py)


@requires_openpyxl
def test_xlsx_boolean_header_cells_match_python_text_in_both_engines(tmp_path):
"""#1143: boolean headers use Python's "True"/"False" spelling, without changing text headers."""
from faircode import profile

wb = openpyxl.Workbook()
ws = wb.active
ws.append([True, False, "TRUE", "FALSE", "sex"])
for i in range(30):
ws.append([i % 3, (i + 1) % 2, i % 2, (i + 1) % 2, "m" if i % 2 else "f"])
path = _save_workbook(tmp_path, wb, "boolean_header.xlsx")
py = [d["name"] for d in profile(read_table(str(path)))["dimensions"]]
result = _run_js_parse(path)
assert result.returncode == 0, result.stderr
js = [d["name"] for d in json.loads(result.stdout)["dimensions"]]
assert py == js == ["True", "False", "TRUE", "FALSE", "sex"]
assert all(isinstance(name, str) for name in py)
Loading