ronantakizawa/codereview-bench huggingface dataset:
Repository: discordjs/discord.js
File: packages/discord.js/src/client/actions/MessagePollVoteRemove.js (JavaScript)

Code before:
    const includePollPartial = this.client.options.partials.includes(Partials.Poll);
    if (message.partial && !includePollPartial) return false;

    if (!message.poll && includePollPartial) {
      message.poll = new Poll(
        this.client,
        { ...data, question: { text: '' }, answers: [], partial: true },
        message,
        channel,
      );
    }

    const includePollAnswerPartial = this.client.options.partials.includes(Partials.PollAnswer);
    if (message.partial && !includePollAnswerPartial) return false;

    let answer = message.poll?.answers?.get(data.answer_id);
    if (!answer && message.poll) {
      const pollAnswer = new PollAnswer(this.client, data, message.poll);

      message.poll.answers.set(data.answer_id, pollAnswer);

      answer = pollAnswer;
    }

    answer.voters.cache.delete(data.user_id);
    answer.voteCount = answer.voteCount > 0 ? answer.voteCount-- : 0;

    /**
     * Emitted whenever a user removes their vote in a poll.
     * @event Client#messagePollVoteRemove
     * @param {PollAnswer} pollAnswer The answer where the vote was removed
     * @param {Snowflake} userId The id of the user that removed their vote
     */
    this.client.emit(Events.MessagePollVoteRemove, answer, data.user_id);

    const { poll } = message;

    return { poll };
  }
}

module.exports = MessagePollVoteRemoveAction;


Review comment (suggestion):
```suggestion
    if (answer.voteCount > 0) {
      answer.voteCount--;
    }
```

Code after:
'use strict';

const { Action } = require('./Action.js');
const { Events } = require('../../util/Events.js');

class MessagePollVoteRemoveAction extends Action {
  handle(data) {
    const channel = this.getChannel({ id: data.channel_id, ...('guild_id' in data && { guild_id: data.guild_id }) });
    if (!channel?.isTextBased()) return false;

    const message = this.getMessage(data, channel);
    if (!message) return false;

    const poll = this.getPoll(data, message, channel);
    if (!poll) return false;

    const answer = poll.answers.get(data.answer_id);
    if (!answer) return false;

    answer.voters.cache.delete(data.user_id);

    if (answer.voteCount > 0) {
      answer.voteCount--;
    }

    /**
     * Emitted whenever a user removes their vote in a poll.
     * @event Client#messagePollVoteRemove
     * @param {PollAnswer} pollAnswer The answer where the vote was removed
     * @param {Snowflake} userId The id of the user that removed their vote
     */
    this.client.emit(Events.MessagePollVoteRemove, answer, data.user_id);

    return { poll };
  }
}

exports.MessagePollVoteRemoveAction = MessagePollVoteRemoveAction;
Repository: discordjs/discord.js
File: packages/discord.js/src/client/actions/MessagePollVoteAdd.js (JavaScript)

Code before:
class MessagePollVoteAddAction extends Action {
  handle(data) {
    const channel = this.getChannel(data);
    if (!channel?.isTextBased()) return false;

    const message = this.getMessage(data, channel);
    if (!message) return false;

    const includePollPartial = this.client.options.partials.includes(Partials.Poll);
    if (message.partial && !includePollPartial) return false;

    if (!message.poll && includePollPartial) {
      message.poll = new Poll(
        this.client,
        { ...data, question: { text: '' }, answers: [], partial: true },
        message,
        channel,
      );
    }

    const includePollAnswerPartial = this.client.options.partials.includes(Partials.PollAnswer);
    if (message.partial && includePollPartial && !includePollAnswerPartial) return false;

    let answer = message.poll?.answers?.get(data.answer_id);
    if (!answer && message.poll) {
      const pollAnswer = new PollAnswer(this.client, data, message.poll);

      message.poll.answers.set(data.answer_id, pollAnswer);

      answer = pollAnswer;
    }

    const user = this.getUser(data);

    answer.voters._add(user);
    answer.voteCount++;

    /**
     * Emitted whenever a user votes in a poll.
     * @event Client#messagePollVoteAdd
     * @param {PollAnswer} pollAnswer The answer that was voted on
     * @param {Snowflake} userId The id of the user that voted
     */
    this.client.emit(Events.MessagePollVoteAdd, answer, data.user_id);

    const { poll } = message;

    return { poll };
  }
}


Review comment (suggestion):
I'll combine these two poll partials `if` statements so there isn't any unnecessary extra work when either partial is disabled.

Code after:
    if (!channel?.isTextBased()) return false;

    const message = this.getMessage(data, channel);
    if (!message) return false;

    const poll = this.getPoll(data, message, channel);
    if (!poll) return false;

    const answer = poll.answers.get(data.answer_id);
    if (!answer) return false;

    const user = this.getUser(data);

    if (user) {
      answer.voters._add(user);
    }

    answer.voteCount++;

    /**
     * Emitted whenever a user votes in a poll.
     * @event Client#messagePollVoteAdd
     * @param {PollAnswer} pollAnswer The answer that was voted on
     * @param {Snowflake} userId The id of the user that voted
     */
    this.client.emit(Events.MessagePollVoteAdd, answer, data.user_id);

    return { poll };
  }
}

exports.MessagePollVoteAddAction = MessagePollVoteAddAction;
Repository: discordjs/discord.js
File: packages/discord.js/src/managers/PollAnswerVoterManager.js (JavaScript)

Code before:

  /**
   * Options used to fetch voters who voted for this poll answer.
   * @typedef {Object} FetchPollAnswerVotersOptions
   * @property {number} [limit] The maximum amount of users to fetch
   * @property {Snowflake} [after] The user id to fetch voters after
   */

  /**
   * Fetches all the voters that voted on this poll answer. Resolves with a collection of users, mapped by their ids.
   * @param {FetchPollAnswerVotersOptions} [options] Options for fetching the users
   * @returns {Promise<Collection<Snowflake, User>>}
   */
  async fetch({ after, limit }) {
    const poll = this.answer.poll;
    const query = makeURLSearchParams({ limit, after });
    const data = await this.client.rest.get(Routes.pollAnswerVoters(poll.channelId, poll.messageId, this.answer.id), {
      query,
    });

    const users = new Collection();
    for (const rawUser of data) {
      const user = this.client.users._add(rawUser);
      this.cache.set(user.id, user);
      users.set(user.id, user);
    }

    this.answer.voteCount = users.size;

    return users;
  }
}

module.exports = PollAnswerVoterManager;


Review comment (performance):
```suggestion
    const users = data.reduce((acc, rawUser) => {
      const user = this.client.users._add(rawUser);
      this.cache.set(user.id, user);
      users.set(user.id, user);
    }, new Collection());
```

Could also just return this directly, if the `voteCount` update after this is to be removed 

Code after:
'use strict';

const { Collection } = require('@discordjs/collection');
const { makeURLSearchParams } = require('@discordjs/rest');
const { Routes } = require('discord-api-types/v10');
const { CachedManager } = require('./CachedManager.js');
const { User } = require('../structures/User.js');

/**
 * Manages API methods for users who voted on a poll and stores their cache.
 * @extends {CachedManager}
 */
class PollAnswerVoterManager extends CachedManager {
  constructor(answer) {
    super(answer.client, User);

    /**
     * The poll answer that this manager belongs to
     * @type {PollAnswer}
     */
    this.answer = answer;
  }

  /**
   * The cache of this manager
   * @type {Collection<Snowflake, User>}
   * @name PollAnswerVoterManager#cache
   */

  /**
   * Fetches the users that voted on this poll answer. Resolves with a collection of users, mapped by their ids.
   * @param {BaseFetchPollAnswerVotersOptions} [options={}] Options for fetching the users
   * @returns {Promise<Collection<Snowflake, User>>}
   */
  async fetch({ after, limit } = {}) {
    const poll = this.answer.poll;
    const query = makeURLSearchParams({ limit, after });
    const data = await this.client.rest.get(Routes.pollAnswerVoters(poll.channelId, poll.messageId, this.answer.id), {
      query,
    });

    return data.users.reduce((coll, rawUser) => {
      const user = this.client.users._add(rawUser);
      this.cache.set(user.id, user);
      return coll.set(user.id, user);
    }, new Collection());
  }
}

exports.PollAnswerVoterManager = PollAnswerVoterManager;
Repository: discordjs/discord.js
File: packages/discord.js/src/structures/Poll.js (JavaScript)

Code before:
const Base = require('./Base');
const { PollAnswer } = require('./PollAnswer');
const { DiscordjsError } = require('../errors/DJSError');
const { ErrorCodes } = require('../errors/index');

/**
 * Represents a Poll
 * @extends {Base}
 */
class Poll extends Base {
  constructor(client, data, message, channel) {
    super(client);

    /**
     * The id of the channel that this poll is in
     * @type {Snowflake}
     */
    this.channelId = data.channel_id;

    /**
     * The channel that this poll is in
     * @name Poll#channel
     * @type {TextBasedChannel}
     * @readonly
     */

    Object.defineProperty(this, 'channel', { value: channel });

    /**
     * The id of the message that started this poll
     * @type {Snowflake}
     */
    this.messageId = data.message_id;

    /**
     * The message that started this poll
     * @name Poll#message
     * @type {Message}
     * @readonly
     */

    Object.defineProperty(this, 'message', { value: message });

    /**
     * The media for a poll's question
     * @typedef {Object} PollQuestionMedia
     * @property {string} text The text of this question
     */

    /**
     * The media for this poll's question

Review comment (suggestion):
These can be updated to reference `this.channel` directly (instead of `this.message.channel`) and `this.messageId` (instead of `this.message.id`)

https://github.com/discordjs/discord.js/blob/f4b29119211dd8cb145091392dc0868fc63989ed/packages/discord.js/src/structures/Poll.js#L176

https://github.com/discordjs/discord.js/blob/f4b29119211dd8cb145091392dc0868fc63989ed/packages/discord.js/src/structures/Poll.js#L159

Code after:
const { Base } = require('./Base.js');
const { PollAnswer } = require('./PollAnswer.js');
const { DiscordjsError, ErrorCodes } = require('../errors/index.js');

/**
 * Represents a Poll
 * @extends {Base}
 */
class Poll extends Base {
  constructor(client, data, message, channel) {
    super(client);

    /**
     * The id of the channel that this poll is in
     * @type {Snowflake}
     */
    this.channelId = data.channel_id ?? channel.id;

    /**
     * The channel that this poll is in
     * @name Poll#channel
     * @type {TextBasedChannel}
     * @readonly
     */

    Object.defineProperty(this, 'channel', { value: channel });

    /**
     * The id of the message that started this poll
     * @type {Snowflake}
     */
    this.messageId = data.message_id ?? message.id;

    /**
     * The message that started this poll
     * @name Poll#message
     * @type {Message}
     * @readonly
     */

    Object.defineProperty(this, 'message', { value: message });

    this._patch(data);
  }

  _patch(data) {
    if (data.results) {
      /**
       * Whether this poll's results have been precisely counted
       * @type {boolean}
       */
Repository: discordjs/discord.js
File: packages/discord.js/src/structures/Poll.js (JavaScript)

Code before:
  /**
   * Whether or not this poll is a partial
   * @type {boolean}
   * @readonly
   */
  get partial() {
    return (
      typeof this.question.text !== 'string' ||
      typeof this.layoutType !== 'number' ||
      typeof this.allowMultiselect !== 'boolean' ||
      this._partial
    );
  }

  /**
   * Fetches the message that started this poll, then updates the poll from the fetched message.
   * @returns {Promise<Poll>}
   */
  async fetch() {
    const message = await this.message.channel.messages.fetch(this.message.id);

    const existing = message.poll;
    this._patch({ ...existing, partial: false });

    return this;
  }

  /**
   * Ends this poll.
   * @returns {Promise<Message>}
   */
  end() {
    if (Date.now() > this.expiresTimestamp) {
      return Promise.reject(new DiscordjsError(ErrorCodes.PollAlreadyExpired));
    }

    return this.message.channel.messages.endPoll(this.message.id);
  }
}

exports.Poll = Poll;


Review comment (suggestion):
I don't believe this to be the right approach, considering the poll will be recreated by the message manager fetch call at the beginning.
https://github.com/discordjs/discord.js/blob/f4b29119211dd8cb145091392dc0868fc63989ed/packages/discord.js/src/structures/Message.js#L411-L417
Perhaps the `Message#_patch()` should be adapted to call the poll's `_patch` (if its already set) instead of recreating it everytime. The `_patch()` call in this `fetch()` method would then be removed (or this fetch() method could just be removed entirely). 

Code after:
  }

  /**
   * Whether this poll is a partial
   * @type {boolean}
   * @readonly
   */
  get partial() {
    return this.allowMultiselect === null;
  }

  /**
   * Fetches the message that started this poll, then updates the poll from the fetched message.
   * @returns {Promise<Poll>}
   */
  async fetch() {
    await this.channel.messages.fetch(this.messageId);

    return this;
  }

  /**
   * Ends this poll.
   * @returns {Promise<Message>}
   */
  async end() {
    if (Date.now() > this.expiresTimestamp) {
      throw new DiscordjsError(ErrorCodes.PollAlreadyExpired);
    }

    return this.channel.messages.endPoll(this.messageId);
  }
}

exports.Poll = Poll;
Repository: discordjs/discord.js
File: packages/discord.js/src/structures/PollAnswer.js (JavaScript)

Code before:
'use strict';

const Base = require('./Base');
const { Emoji } = require('./Emoji');
const PollAnswerVoterManager = require('../managers/PollAnswerVoterManager');

/**
 * Represents an answer to a {@link Poll}
 * @extends {Base}
 */
class PollAnswer extends Base {
  constructor(client, data, poll) {
    super(client);

    /**
     * The {@link Poll} this answer is part of
     * @name PollAnswer#poll
     * @type {Poll | PartialPoll}
     * @readonly
     */
    Object.defineProperty(this, 'poll', { value: poll });

    /**
     * The id of this answer
     * @type {number}
     */
    this.id = data.answer_id;

    /**
     * The text of this answer
     * @type {?string}
     */
    this.text = data.poll_media?.text ?? null;

    /**
     * The manager of the voters that voted for this answer
     * @type {PollAnswerVoterManager}
     */
    this.voters = new PollAnswerVoterManager(this, []);

    /**
     * The raw emoji of this answer
     * @name PollAnswer#_emoji

Review comment (suggestion):
Consistency with the rest of the codebase.
```suggestion
     * @type {Poll|PartialPoll}
```

Code after:
'use strict';

const { Base } = require('./Base.js');
const { Emoji } = require('./Emoji.js');
const { PollAnswerVoterManager } = require('../managers/PollAnswerVoterManager.js');
const { resolveGuildEmoji } = require('../util/Util.js');

/**
 * Represents an answer to a {@link Poll}
 * @extends {Base}
 */
class PollAnswer extends Base {
  constructor(client, data, poll) {
    super(client);

    /**
     * The {@link Poll} this answer is part of
     * @name PollAnswer#poll
     * @type {Poll|PartialPoll}
     * @readonly
     */
    Object.defineProperty(this, 'poll', { value: poll });

    /**
     * The id of this answer
     * @type {number}
     */
    this.id = data.answer_id;

    /**
     * The manager of the voters for this answer
     * @type {PollAnswerVoterManager}
     */
    this.voters = new PollAnswerVoterManager(this);

    /**
     * The raw emoji of this answer
     * @name PollAnswer#_emoji
     * @type {?APIPartialEmoji}
     * @private
     */
    Object.defineProperty(this, '_emoji', { value: null });
Repository: discordjs/discord.js
File: packages/discord.js/src/structures/PollAnswer.js (JavaScript)

Code before:
class PollAnswer extends Base {
  constructor(client, data, poll) {
    super(client);

    /**
     * The {@link Poll} this answer is part of
     * @name PollAnswer#poll
     * @type {Poll | PartialPoll}
     * @readonly
     */
    Object.defineProperty(this, 'poll', { value: poll });

    /**
     * The id of this answer
     * @type {number}
     */
    this.id = data.answer_id;

    /**
     * The text of this answer
     * @type {?string}
     */
    this.text = data.poll_media?.text ?? null;

    /**
     * The manager of the voters that voted for this answer
     * @type {PollAnswerVoterManager}
     */
    this.voters = new PollAnswerVoterManager(this, []);

    /**
     * The raw emoji of this answer
     * @name PollAnswer#_emoji
     * @type {?APIPartialEmoji}
     * @private
     */
    Object.defineProperty(this, '_emoji', { value: data.poll_media?.emoji ?? null });

    this._patch(data);
  }

  _patch(data) {
    // This `count` field comes from `poll.results.answer_counts`
    if ('count' in data) {
      /**
       * The amount of votes this answer has
       * @type {number}
       */
      this.voteCount = data.count;
    } else if (data.poll_media?.text) {
      this.text = data.poll_media?.text ?? null;

Review comment (suggestion):
```suggestion
     * The manager of the voters for this answer
```

```suggestion
     * The manager of the users that voted for this answer
```

Code after:
 */
class PollAnswer extends Base {
  constructor(client, data, poll) {
    super(client);

    /**
     * The {@link Poll} this answer is part of
     * @name PollAnswer#poll
     * @type {Poll|PartialPoll}
     * @readonly
     */
    Object.defineProperty(this, 'poll', { value: poll });

    /**
     * The id of this answer
     * @type {number}
     */
    this.id = data.answer_id;

    /**
     * The manager of the voters for this answer
     * @type {PollAnswerVoterManager}
     */
    this.voters = new PollAnswerVoterManager(this);

    /**
     * The raw emoji of this answer
     * @name PollAnswer#_emoji
     * @type {?APIPartialEmoji}
     * @private
     */
    Object.defineProperty(this, '_emoji', { value: null });

    this._patch(data);
  }

  _patch(data) {
    // This `count` field comes from `poll.results.answer_counts`
    if ('count' in data) {
      /**
       * The amount of votes this answer has
       * @type {number}
       */
      this.voteCount = data.count;
    } else {
      this.voteCount ??= this.voters.cache.size;
    }

    /**
     * The text of this answer
     * @type {?string}
Repository: discordjs/discord.js
File: packages/discord.js/src/structures/Poll.js (JavaScript)

Code before:
    /**
     * The message that started this poll
     * @name Poll#message
     * @type {Message}
     * @readonly
     */

    Object.defineProperty(this, 'message', { value: message });

    /**
     * The media for a poll's question
     * @typedef {Object} PollQuestionMedia
     * @property {string} text The text of this question
     */

    /**
     * The media for this poll's question
     * @type {PollQuestionMedia}
     */
    this.question = {
      text: data.question.text,
    };

    /**
     * The answers of this poll
     * @type {Collection<number, PollAnswer | PartialPollAnswer>}
     */
    this.answers = data.answers.reduce(
      (acc, answer) => acc.set(answer.answer_id, new PollAnswer(this.client, answer, this)),
      new Collection(),
    );

    /**
     * The timestamp when this poll expires
     * @type {?number}
     */
    this.expiresTimestamp = Date.parse(data.expiry) ?? null;

    /**
     * Whether this poll allows multiple answers
     * @type {boolean}
     */
    this.allowMultiselect = data.allow_multiselect;

    /**
     * The layout type of this poll
     * @type {PollLayoutType}
     */
    this.layoutType = data.layout_type;

    /**

Review comment (suggestion):
```suggestion
     * @type {Collection<number, PollAnswer|PartialPollAnswer>}
```

Code after:
     * The message that started this poll
     * @name Poll#message
     * @type {Message}
     * @readonly
     */

    Object.defineProperty(this, 'message', { value: message });

    this._patch(data);
  }

  _patch(data) {
    if (data.results) {
      /**
       * Whether this poll's results have been precisely counted
       * @type {boolean}
       */
      this.resultsFinalized = data.results.is_finalized;

      for (const answerResult of data.results.answer_counts) {
        const answer = this.answers.get(answerResult.id);
        answer?._patch(answerResult);
      }
    } else {
      this.resultsFinalized ??= false;
    }

    if ('allow_multiselect' in data) {
      /**
       * Whether this poll allows multiple answers
       * @type {boolean}
       */
      this.allowMultiselect = data.allow_multiselect;
    } else {
      this.allowMultiselect ??= null;
    }

    if ('layout_type' in data) {
      /**
       * The layout type of this poll
       * @type {PollLayoutType}
       */
      this.layoutType = data.layout_type;
    } else {
      this.layoutType ??= null;
    }

    if ('expiry' in data) {
      /**
       * The timestamp when this poll expires
       * @type {?number}
Repository: discordjs/discord.js
File: packages/discord.js/src/structures/PollAnswer.js (JavaScript)

Code before:

    /**
     * The {@link Poll} this answer is part of
     * @name PollAnswer#poll
     * @type {Poll | PartialPoll}
     * @readonly
     */
    Object.defineProperty(this, 'poll', { value: poll });

    /**
     * The id of this answer
     * @type {number}
     */
    this.id = data.answer_id;

    /**
     * The text of this answer
     * @type {?string}
     */
    this.text = data.poll_media?.text ?? null;

    /**
     * The manager of the voters that voted for this answer
     * @type {PollAnswerVoterManager}
     */
    this.voters = new PollAnswerVoterManager(this, []);

    /**
     * The raw emoji of this answer
     * @name PollAnswer#_emoji
     * @type {?APIPartialEmoji}
     * @private
     */
    Object.defineProperty(this, '_emoji', { value: data.poll_media?.emoji ?? null });

    this._patch(data);
  }

  _patch(data) {
    // This `count` field comes from `poll.results.answer_counts`
    if ('count' in data) {
      /**
       * The amount of votes this answer has
       * @type {number}
       */
      this.voteCount = data.count;
    } else if (data.poll_media?.text) {
      this.text = data.poll_media?.text ?? null;
    } else if (data.poll_media?.emoji) {
      Object.defineProperty(this, '_emoji', { value: data.poll_media?.emoji ?? null });
    } else {

Review comment (suggestion):
Let's get rid of this second argument (and the parameter on the class itself)
```suggestion
    this.voters = new PollAnswerVoterManager(this);
```

Code after:
    super(client);

    /**
     * The {@link Poll} this answer is part of
     * @name PollAnswer#poll
     * @type {Poll|PartialPoll}
     * @readonly
     */
    Object.defineProperty(this, 'poll', { value: poll });

    /**
     * The id of this answer
     * @type {number}
     */
    this.id = data.answer_id;

    /**
     * The manager of the voters for this answer
     * @type {PollAnswerVoterManager}
     */
    this.voters = new PollAnswerVoterManager(this);

    /**
     * The raw emoji of this answer
     * @name PollAnswer#_emoji
     * @type {?APIPartialEmoji}
     * @private
     */
    Object.defineProperty(this, '_emoji', { value: null });

    this._patch(data);
  }

  _patch(data) {
    // This `count` field comes from `poll.results.answer_counts`
    if ('count' in data) {
      /**
       * The amount of votes this answer has
       * @type {number}
       */
      this.voteCount = data.count;
    } else {
      this.voteCount ??= this.voters.cache.size;
    }

    /**
     * The text of this answer
     * @type {?string}
     */
    this.text ??= data.poll_media?.text ?? null;