\t, \n, \\ sequences within cells (the standard IANA text/tab-separated-values convention) — matching what you get pasting straight out of Excel or Google Sheets. Strips a UTF-8 BOM if present, and normalizes CRLF/CR/LF line endings. Output is built with JSON.stringify, so quotes, backslashes, and any JSON-looking text inside a cell are always escaped into valid JSON automatically — they stay as plain strings, never get re-parsed.
Type conversion rules (deterministic, no per-column exceptions):
true / false convert to booleans only as exact lowercase — TRUE, False, etc. stay strings. null/NULL (any case) converts to JSON null — this one is intentionally case-insensitive, unlike booleans. Plain integers and decimals (e.g. 42, -3.5) convert to numbers, except: values with a leading zero before more digits (007, 0000123) stay strings, since a real number can't have one; integers that would lose precision as a 64-bit float (beyond Number.MAX_SAFE_INTEGER, e.g. a 20-digit ID) stay strings so the digits are never silently altered; and a number so long it would overflow to Infinity stays a string too, since JSON.stringify would otherwise silently turn it into null. Scientific notation (1e3) stays a string unless you enable the checkbox above. Whitespace around a cell is trimmed only to detect its type — a value that isn't a recognized type is kept byte-for-byte as received.
Data-safety checks, always on: every data row's column count is checked against the header (or against row 1, if there's no header) — a mismatch is reported below with the row number and expected/actual counts, but the row is still converted, never dropped. A row with extra columns keeps them under synthetic
col_N keys instead of discarding them. A blank or duplicate header is renamed (col_N / name_2) with a warning, so two columns can never silently overwrite each other in the output. Only a trailing run of fully blank lines is ignored — a blank line in the middle of your data is kept as a real row.