# Literal find and replace v1

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

```js
import assert from 'node:assert/strict';
import { literalReplace } from './literal-replace.mjs';
const result = literalReplace(
  'team\tnote\nA\tdraft draft\nB\tDraft draft',
  { columns: '2', search: 'draft', replacement: 'ready', header: true },
);
assert.equal(result.tsv, 'team\tnote\nA\tready ready\nB\tDraft ready');
assert.equal(result.changedCells, 2);
assert.equal(result.replacements, 3);
const literal = literalReplace('text\n.*.*', {
  columns: '1', search: '.*', replacement: '$&', header: true,
});
assert.equal(literal.tsv, 'text\n$&$&');
const overlap = literalReplace('aaaaa', {
  columns: '1', search: 'aa', replacement: 'b', header: false,
});
assert.equal(overlap.tsv, 'bba');
assert.equal(overlap.replacements, 2);
assert.throws(() => literalReplace('text\ndraft', {
  columns: '1', search: '', replacement: 'ready', header: true,
}));
console.log('Literal replace example passed.');
```

Arguments: one literal TSV string and an options object with `columns`,
`search`, `replacement`, and `header`. Columns are one-based comma-separated
numbers without leading zeros, such as `'2'` or `'1,3'`. Surrounding spaces
are accepted; duplicates and out-of-range columns are rejected. With `header: true`, the first row is preserved
and excluded from replacement. Every row must have the same number of fields.

Replacement is global, case-sensitive, and nonoverlapping within each selected
cell. Search and replacement are literal strings: regex punctuation and `$&`,
`$1`, or `$$` have no special meaning. Replacement text is never searched again.
An empty replacement deletes matches; an empty search is rejected. No trimming,
case folding, formula execution, or locale interpretation. Tabs and line breaks
in search or replacement are rejected. Quotes do not escape tabs or newlines.
CRLF and bare CR become LF; exactly one final newline is ignored on input.
Output adds a newline terminator when its final row is empty, preserving that
row if the output is parsed again. A single empty output row is serialized as
`\n`; a final empty row after other rows therefore ends with `\n\n`.

`tsv` is the resulting literal table; `report` is a human-readable summary.
`changedCells` counts cells whose final text changed; `replacements` counts
matched occurrences. `rows` counts data rows, excluding the header when present; `columns` is the
width of the parsed table. Identity replacements count matched occurrences but
produce no changed cells. The report lists original one-based row and column
positions for each changed cell, including the header in row numbering.

Limits: 100,000 UTF-16 code units, 500 rows including a header when present,
50 columns, and 2,000 selection characters. TSV and report outputs are each capped at 300,000 characters.
Invalid, empty or ragged input and exceeded limits throw without partial output.

The module performs no network requests, telemetry, file writes, or Google
Sheets writes. Input stays in the calling process; the example prints only a
success message. The module returns strings for you to inspect and handle.
Literal text can still contain formula-like values. Review the output before
importing into a spreadsheet and use an import method that preserves text;
replacement does not certify spreadsheet-safe output. Use fictional or redacted
input when sharing examples or reports. This preview does not prove customer
use or time savings.

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