fix(csv-stringify): do not alter the source record when columns is set - #504
Open
youdie006 wants to merge 1 commit into
Open
fix(csv-stringify): do not alter the source record when columns is set#504youdie006 wants to merge 1 commit into
youdie006 wants to merge 1 commit into
Conversation
When a record is an array and the `columns` option is shorter than that array, the stringifier called `chunk.splice(columns.length)`, which truncates the array owned by the caller instead of only limiting what is written. Bound the cast loop instead, leaving the input untouched. The object branch already reads through `get()` into a fresh local record. Assisted-by: Claude Code:claude-opus-5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When a record is an array and
columnsis shorter than that record,stringifytruncates the caller's array in place:https://github.com/adaltas/node-csv/blob/745f045/packages/csv-stringify/lib/api/index.js#L113-L120
chunkhere is the record the user passed in, not a copy, sosplicedeletes their data. The output is correct; the caller's input is destroyed as a side effect.Reproduction
Writing a narrow summary and then a full export from the same rows gives the wrong answer on the second call. Nothing warns the caller, and the loss is permanent.
Why this looks like an oversight rather than a contract
The object branch of the same function already avoids this: it reads through
get(chunk, columns[i].key)into a fresh localrecordand never writes back. Of the two record branches, the array branch was the only one that wrote into the caller's value, and a scan of.splice(/.sort(/.reverse(/Object.assign(across all five packages'lib/finds no other in-place write to caller data in the serialization path.columnswas already madereadonlyin #358 on the stated grounds that "this array has no reasons to be mutated bystringify". The same reasoning applies to the record itself, whichlib/index.d.tsstill types as the mutableInput = unknown[].Change
Bound the cast loop by
Math.min(chunk.length, columns.length)instead of shorteningchunk. Emitted output is unchanged in every case.Verification
test/option.columns.tsnext to its siblingis an array, should be the same length. It asserts both the output and that the input array is untouched. On currentmasterit fails at the input assertion withA has 2 and B has 3; with the change it passes.splicefails only the input-immutability assertion, while dropping the column bound fails only the output assertions (the new one and the existingis an array, should be the same length). So neither side is unpinned.npm testinpackages/csv-stringify(tsc --noEmit+ mocha): 210 passing, 1 pending.eslintandprettier --checkclean on both changed files.Assisted-by: Claude Code:claude-opus-5