# Literal integer group totals v1

Save `group-totals.mjs` beside a file named `group-totals-example.mjs` containing
the example below. Run `node group-totals-example.mjs` in Node 18+; the module also
works in modern JavaScript. No runtime dependencies.

```js
import assert from 'node:assert/strict';
import { analyzeGroupTotals } from './group-totals.mjs';
const result = analyzeGroupTotals(
  'team\tamount\nA\t9007199254740993\nB\t-2\nA\t+7',
  { groupColumn: 0, valueColumn: 1 },
);
assert.deepEqual(result.groups, [
  { value: 'A', sum: '9007199254741000', count: 2, sourceRows: [2, 4] },
  { value: 'B', sum: '-2', count: 1, sourceRows: [3] },
]);
assert.equal(result.tsv, 'group\tsum\tcount\trows\nA\t9007199254741000\t2\t2, 4\nB\t-2\t1\t3');
assert.equal(result.report, result.lines.join('\n'));
assert.equal(result.totalRows, 3);
assert.equal(result.hasHeader, true);
const noHeader = analyzeGroupTotals(' A\t001\nA\t-1\n A\t+2', {
  groupColumn: 0, valueColumn: 1, hasHeader: false,
});
assert.deepEqual(noHeader.groups, [
  { value: ' A', sum: '3', count: 2, sourceRows: [1, 3] },
  { value: 'A', sum: '-1', count: 1, sourceRows: [2] },
]);
assert.throws(() => analyzeGroupTotals('team\tamount\nA\t1.5', {
  groupColumn: 0, valueColumn: 1,
}));
console.log('Group totals example passed.');
```

Arguments: one literal TSV string and an options object with zero-based
`groupColumn` and `valueColumn` indices. `hasHeader` defaults to `true`; set it
to `false` to include the first row as data. Every row must have the same number
of fields. Header-only input is allowed. Selected columns must exist.

Groups use exact literal labels, in first-occurrence order. Spaces, case,
leading zeros, blank labels and formula-like labels remain distinct. Each group
contains `value`, an exact decimal `sum` string, `count`, and original
one-based `sourceRows` (including the header in row numbering). `totalRows`
counts data rows. `groupColumn`, `valueColumn` and `hasHeader` echo the options.
`tsv` contains a fixed `group`, `sum`, `count`, `rows` header and one row per
group; source row numbers are joined with comma and space. Header-only input
produces only this output header. `report` joins the human-readable `lines` with
newlines; group labels use JSON escaping in that report. `checked` counts data
rows and `issues` is zero for valid input.

Values must be signed or unsigned decimal integer strings (`-2`, `+7`, `001`).
BigInt arithmetic preserves totals beyond JavaScript's safe integer range.
Empty values, surrounding whitespace, decimal fractions, scientific notation,
commas, currency symbols and formulas are rejected. No trimming, case folding,
locale parsing or decimal rounding. Quotes do not escape tabs or newlines.
CRLF and bare CR become LF; exactly one final newline is ignored.

Limits: 100,000 UTF-16 code units, 500 rows including a header when present,
and 50 columns. TSV and report outputs are each capped at 300,000 characters.
Invalid, empty or ragged inputs and exceeded limits throw without partial output.
No network, telemetry, formula execution or spreadsheet writes. Copying literal
group labels does not certify safe spreadsheet import. This does not prove
customer use or time savings.

Use a spreadsheet pivot table or SUMIF/SUMIFS for totals already maintained in
Sheets or Excel, particularly when you need live recalculation or decimal and
locale-aware values. This module is for bounded literal integer TSV input.

Generate with `node scripts/build-group-totals.mjs`; verify browser-core bytes
with `node scripts/build-group-totals.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.
