Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: don't mutate user provided array #10014

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

imranbarbhuiya
Copy link
Contributor

@imranbarbhuiya imranbarbhuiya commented Dec 2, 2023

Please describe the changes this PR makes and why it should be merged:

Calling embed.setFields twice will mutate the array passed in the first call. This PR fixes it.

I was going to change it in spliceFieldsonly but thought this issue might be present in other builders too so doing it in normalizeArray makes more sense

Status and versioning classification:

  • Code changes have been tested against the Discord API, or there are no code changes
  • I know how to update typings and have done so, or typings don't need updating

Copy link

vercel bot commented Dec 2, 2023

The latest updates on your projects. Learn more about Vercel for Git ↗︎

2 Ignored Deployments
Name Status Preview Comments Updated (UTC)
discord-js ⬜️ Ignored (Inspect) Visit Preview Dec 2, 2023 7:15pm
discord-js-guide ⬜️ Ignored (Inspect) Visit Preview Dec 2, 2023 7:15pm

Copy link

codecov bot commented Dec 2, 2023

Codecov Report

All modified and coverable lines are covered by tests ✅

Comparison is base (a44ada6) 58.45% compared to head (ff61597) 58.45%.
Report is 3 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main   #10014   +/-   ##
=======================================
  Coverage   58.45%   58.45%           
=======================================
  Files         241      241           
  Lines       17130    17130           
  Branches     1241     1241           
=======================================
  Hits        10014    10014           
  Misses       7071     7071           
  Partials       45       45           
Flag Coverage Δ
builders 95.53% <100.00%> (ø)
next ∅ <ø> (∅)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@Jiralite
Copy link
Member

Jiralite commented Dec 2, 2023

Is it possible to write tests for this?

@Jiralite Jiralite added this to the builders 1.8.0 milestone Dec 2, 2023
@Jiralite Jiralite changed the title fix(builders): don't mutate user provided array fix: don't mutate user provided array Dec 2, 2023
@Syjalo
Copy link
Contributor

Syjalo commented Dec 2, 2023

.addFields(), not .setFields()

const embed = new EmbedBuilder();
const fields1 = [{ name: '1', value: '1' }, { name: '2', value: '2' }, { name: '3', value: '3' }];
const fields2 = [{ name: '4', value: '4' }, { name: '5', value: '5' }, { name: '6', value: '6' }];

embed.addFields(fields1);
embed.addFields(fields2);

console.log(fields1);
/**
[
  { name: '1', value: '1' },
  { name: '2', value: '2' },
  { name: '3', value: '3' },
  { name: '4', value: '4' },
  { name: '5', value: '5' },
  { name: '6', value: '6' }
]
**/
console.log(fields2);
/**
[
  { name: '4', value: '4' },
  { name: '5', value: '5' },
  { name: '6', value: '6' }
]
**/

@vladfrangu
Copy link
Member

This is an incomplete PR i'd say - it needs to also clone the array in the other case

@imranbarbhuiya
Copy link
Contributor Author

This is an incomplete PR i'd say - it needs to also clone the array in the other case

all the methods uses normalizeArray so ig it covers all the cases?

@imranbarbhuiya
Copy link
Contributor Author

.addFields(), not .setFields()

const embed = new EmbedBuilder();
const fields1 = [{ name: '1', value: '1' }, { name: '2', value: '2' }, { name: '3', value: '3' }];
const fields2 = [{ name: '4', value: '4' }, { name: '5', value: '5' }, { name: '6', value: '6' }];

embed.addFields(fields1);
embed.addFields(fields2);

console.log(fields1);
/**
[
  { name: '1', value: '1' },
  { name: '2', value: '2' },
  { name: '3', value: '3' },
  { name: '4', value: '4' },
  { name: '5', value: '5' },
  { name: '6', value: '6' }
]
**/
console.log(fields2);
/**
[
  { name: '4', value: '4' },
  { name: '5', value: '5' },
  { name: '6', value: '6' }
]
**/

calling setFields twice or using addFields all has this issue but this pr should fix both cases

@imranbarbhuiya
Copy link
Contributor Author

Is it possible to write tests for this?

ok

@Jiralite
Copy link
Member

Jiralite commented Dec 2, 2023

I asked for tests because I couldn't reproduce this via setFields(), by after @Syjalo's comment, I was able to reproduce with addFields(). Seeing the tests should be fairly obvious as to what the expected and current behaviour is!

@imranbarbhuiya
Copy link
Contributor Author

imranbarbhuiya commented Dec 2, 2023

I asked for tests because I couldn't reproduce this via setFields(), by after @Syjalo's comment, I was able to reproduce with addFields(). Seeing the tests should be fairly obvious as to what the expected and current behaviour is!

it happens when u use setFields first with a, run again with a new value, log a and it's mutated. I added test for normalizeArray to return cloned array, should I also add for embed fields?

.vscode/settings.json Outdated Show resolved Hide resolved
@Jiralite
Copy link
Member

Jiralite commented Dec 2, 2023

it happens when u use setFields first with a, run again with a new value, log a and it's mutated.

Do you mind sharing a code sample—not sure I'm getting it.

@imranbarbhuiya
Copy link
Contributor Author

it happens when u use setFields first with a, run again with a new value, log a and it's mutated.

Do you mind sharing a code sample—not sure I'm getting it.

I just tried and then checked my original code and yeah it was addFields then setFields, sorry for the confusion

Copy link
Member

@almeidx almeidx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More often than not, the output of this function is already going to be cloned (.map(), spread, etc.). Perhaps we should instead fix the Embed.addFields() method, which seems to be the only place where the value is not being cloned.

However, if you choose to keep it as it is, we should remove this clone:

this.data.default_values = normalizedValues.slice();

expect(normalizeArray([1, 2, 3])).toEqual([1, 2, 3]);
});

test('always returns a clone', () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a test case for rest too

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rest doesnt gets cloned in normalizeArray as the original input wasn't an array but rest params

@imranbarbhuiya
Copy link
Contributor Author

More often than not, the output of this function is already going to be cloned (.map(), spread, etc.). Perhaps we should instead fix the Embed.addFields() method, which seems to be the only place where the value is not being cloned.

However, if you choose to keep it as it is, we should remove this clone:

this.data.default_values = normalizedValues.slice();

Can i get a core members feedback on which one to prefer here?


test('always returns a clone', () => {
const arr = [1, 2, 3];
expect(normalizeArray([arr])).not.toBe(arr);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should check toEqual(arr) to make sure the output is the same as the input followed by the not.toBe(arr) to signal that the arrays are equal but they're not the same instance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Review in Progress
Development

Successfully merging this pull request may close these issues.

None yet

6 participants