# Literal first nonempty value v1

Save `first-nonempty.mjs` beside `first-nonempty-example.mjs` containing this
example. Run `node first-nonempty-example.mjs` with Node 18+; no runtime dependencies.

```js
import assert from 'node:assert/strict';
import { firstNonempty } from './first-nonempty.mjs';
const options = { columns: '2,1', header: true };
const result = firstNonempty('primary\tfallback\nAlex\tJo\nSam\t\n\t', options);
assert.equal(result.tsv, 'primary\tfallback\tfirst_nonempty\nAlex\tJo\tJo\nSam\t\tSam\n\t\t');
assert.equal(result.rows, 3);
assert.equal(result.selected, 2);
assert.equal(result.empty, 1);
assert.throws(() => firstNonempty('a\tb', { columns: '3', header: false }));
console.log('First nonempty example passed.');
```

Choose explicit comma-separated, ordered one-based column numbers in a
rectangular literal TSV table. For example, `columns: '3,1,2'` checks column 3,
then column 1, then column 2 for each data row. The first cell whose value is
not exactly an empty string is appended as a new column. If every selected
cell is empty, an empty cell is appended. Original rows and cells retain their
order and values. Spaces, `0`, `false`, and formula-like text are nonempty;
there is no trimming, type conversion, inferred column, or formula evaluation.
Spaces around column selectors are allowed. Selectors must be unique positive
whole numbers without leading zeros and must identify existing columns.

`header: true` treats the first row as a header and appends the name
`first_nonempty`. Header-only tables are valid. `header: false` treats every
row as data. CRLF and bare CR become LF; one terminal newline is ignored.
Quotes do not escape tabs or newlines. Empty input and ragged rows are errors.

`tsv` is the original table plus the selected value column. `report` records
original one-based source row positions, including any header in the numbering,
and the selected source column or that all selected cells were empty.
`rows` counts data rows; `selected` counts
rows with a nonempty selected value and `empty` counts rows whose selected
columns are all empty.

Input is capped at 100,000 characters, 500 rows including any header, and
50 columns. TSV and report are each capped at 300,000 characters. Exceeded
limits throw without partial output.

No network requests, telemetry, formulas or spreadsheet writes. Input stays
in the calling process. Native spreadsheet conditional selection is an
alternative. Formula-like cells remain literal here; this does not guarantee
safe spreadsheet import or prevent a spreadsheet from evaluating them after
import. Inspect the result and import as text. Downloading does not establish
independent use or time savings.

Generate with `node scripts/build-first-nonempty.mjs`; check exact browser-core
bytes with `node scripts/build-first-nonempty.mjs --check`.

## License

MIT License

Copyright (c) 2026 QuasiLife

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
