Repository: date-fns/date-fns
File: src/set/index.js (JavaScript)

Code before:
 * @param {Number} [options.minutes=0] - the number of minutes to be set
 * @param {Number} [options.seconds=0] - the number of seconds to be set
 * @param {Number} [options.milliseconds=0] - the number of milliseconds to be set
 * @returns {Date} the new date with options set
 * @throws {TypeError} 2 arguments required
 * @throws {RangeError} The options object must only contain number properties
 * @throws {RangeError} The options object must not contain a NaN
 */

export default function set(dirtyDate, dirtyOptions) {
  if (arguments.length < 2) {
    throw new TypeError(
      '2 arguments required, but only ' + arguments.length + ' present'
    )
  }

  var options = dirtyOptions || {}

  // check if properties of object are numbers and not NaN
  var isNumbers = Object.values(options).every(x => typeof x === 'number')
  var hasNaN = Object.values(options).every(x => isNaN(x))

  if (!isNumbers) {
    throw new RangeError('The options object must only contain numbers')
  } else if (hasNaN) {
    throw new RangeError('The options object must not contain a NaN')
  }

  var years = options.years == null ? 0 : toInteger(options.years)
  var months = options.months == null ? 0 : toInteger(options.months)
  var days = options.days == null ? 0 : toInteger(options.days)
  var hours = options.hours == null ? 0 : toInteger(options.hours)
  var minutes = options.minutes == null ? 0 : toInteger(options.minutes)
  var seconds = options.seconds == null ? 0 : toInteger(options.seconds)
  var milliseconds =
    options.milliseconds == null ? 0 : toInteger(options.milliseconds)

  var date = toDate(dirtyDate)

  // Check if date is Invalid Date because Date.prototype.setFullYear ignores the value of Invalid Date
  if (isNaN(date)) {
    return new Date(NaN)
  }

  if (years > 0) date.setFullYear(years)
  if (months > 0) date = setMonth(date, months)
  if (days > 0) date.setDate(days)
  if (hours > 0) date.setHours(hours)
  if (minutes > 0) date.setMinutes(minutes)
  if (seconds > 0) date.setSeconds(seconds)
  if (milliseconds > 0) date.setMilliseconds(milliseconds)

Review comment (refactor):
JS std lib usually returns NaN in math operations if any of the parameters were NaN and we'd like to preserve that behaviour:

```js
const date = new Date()
date.setHours(NaN)
date //=> Invalid Date
```

Please remove this exception

Code after:
 *
 * @param {Date|Number} date - the date to be changed
 * @param {Object} values - an object with options
 * @param {Number} values.year - the number of years to be set
 * @param {Number} values.month - the number of months to be set
 * @param {Number} values.date - the number of days to be set
 * @param {Number} values.hours - the number of hours to be set
 * @param {Number} values.minutes - the number of minutes to be set
 * @param {Number} values.seconds - the number of seconds to be set
 * @param {Number} values.milliseconds - the number of milliseconds to be set
 * @returns {Date} the new date with options set
 * @throws {TypeError} 2 arguments required
 * @throws {RangeError} `values` must be an object
 *
 * @example
 * // Transform 1 September 2014 into 20 October 2015 in a single line:
 * var result = set(new Date(2014, 8, 20), { year: 2015, month: 9, date: 20 })
 * //=> Tue Oct 20 2015 00:00:00
 *
 * @example
 * // Set 12 PM to 1 September 2014 01:23:45 to 1 September 2014 12:00:00:
 * var result = set(new Date(2014, 8, 1, 1, 23, 45), { hours: 12 })
 * //=> Mon Sep 01 2014 12:23:45
 */

export default function set(dirtyDate, values) {
  if (arguments.length < 2) {
    throw new TypeError(
      '2 arguments required, but only ' + arguments.length + ' present'
    )
  }

  if (typeof values !== 'object' || values === null) {
    throw new RangeError('values parameter must be an object')
  }

  var date = toDate(dirtyDate)

  // Check if date is Invalid Date because Date.prototype.setFullYear ignores the value of Invalid Date
  if (isNaN(date)) {
    return new Date(NaN)
  }

  if (values.year != null) {
    date.setFullYear(values.year)
  }

  if (values.month != null) {
    date = setMonth(date, values.month)
  }