Skip to content

Commit

Permalink
Merge pull request #5599 from Alanscut:issue_4985
Browse files Browse the repository at this point in the history
[feature] Enable exceptions for invali moments

Fixes #4985
  • Loading branch information
ichernev committed Dec 23, 2023
2 parents b4e0676 + 04ea4a6 commit c8785e7
Show file tree
Hide file tree
Showing 8 changed files with 146 additions and 3 deletions.
7 changes: 7 additions & 0 deletions src/lib/create/from-anything.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { configFromStringAndFormat } from './from-string-and-format';
import { configFromString } from './from-string';
import { configFromArray } from './from-array';
import { configFromObject } from './from-object';
import createError from '../utils/create-error';

function createFromConfig(config) {
var res = new Moment(checkOverflow(prepareConfig(config)));
Expand Down Expand Up @@ -83,6 +84,12 @@ function configFromInput(config) {
} else {
hooks.createFromInputFallback(config);
}
createError(
config._i + ' failed to build a Date using `new Date()`',
config._d,
config._i,
config._f
);
}

export function createLocalOrUTC(input, format, locale, strict, isUTC) {
Expand Down
7 changes: 7 additions & 0 deletions src/lib/create/from-array.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
import { createLocal } from './local';
import defaults from '../utils/defaults';
import getParsingFlags from './parsing-flags';
import createError from '../utils/create-error';

function currentDateArray(config) {
// hooks is actually the exported moment object
Expand Down Expand Up @@ -101,6 +102,12 @@ export function configFromArray(config) {
null,
input
);
createError(
config._i + ' failed to build a Date using `new Date()`',
config._d,
config._i,
config._f
);
expectedWeekday = config._useUTC
? config._d.getUTCDay()
: config._d.getDay();
Expand Down
7 changes: 7 additions & 0 deletions src/lib/create/from-string-and-array.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { configFromStringAndFormat } from './from-string-and-format';
import getParsingFlags from './parsing-flags';
import { isValid } from './valid';
import extend from '../utils/extend';
import createError from '../utils/create-error';

// date from string and array of format strings
export function configFromStringAndArray(config) {
Expand All @@ -18,6 +19,12 @@ export function configFromStringAndArray(config) {
if (configfLen === 0) {
getParsingFlags(config).invalidFormat = true;
config._d = new Date(NaN);
createError(
"Invalid `format`, its length shouldn't be 0",
config._d,
config._i,
config._f
);
return;
}

Expand Down
13 changes: 13 additions & 0 deletions src/lib/create/from-string-and-format.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import checkOverflow from './check-overflow';
import { YEAR, HOUR } from '../units/constants';
import { hooks } from '../utils/hooks';
import getParsingFlags from './parsing-flags';
import createError from '../utils/create-error';

// constant that refers to the ISO standard
hooks.ISO_8601 = function () {};
Expand All @@ -23,10 +24,22 @@ export function configFromStringAndFormat(config) {
// TODO: Move this to another part of the creation flow to prevent circular deps
if (config._f === hooks.ISO_8601) {
configFromISO(config);
createError(
config._i + ' does not match the `ISO 8601` standard',
config._d,
config._i,
config._f
);
return;
}
if (config._f === hooks.RFC_2822) {
configFromRFC2822(config);
createError(
config._i + ' does not match the `RFC 2822` standard',
config._d,
config._i,
config._f
);
return;
}
config._a = [];
Expand Down
28 changes: 25 additions & 3 deletions src/lib/create/from-string.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { deprecate } from '../utils/deprecate';
import getParsingFlags from './parsing-flags';
import { defaultLocaleMonthsShort } from '../units/month';
import { defaultLocaleWeekdaysShort } from '../units/day-of-week';
import createError from '../utils/create-error';

// iso 8601 regex
// 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)
Expand Down Expand Up @@ -223,28 +224,49 @@ export function configFromString(config) {
var matched = aspNetJsonRegex.exec(config._i);
if (matched !== null) {
config._d = new Date(+matched[1]);
return;
return createError(
matched[1] + ' failed to build a Date using `new Date()`',
config._d,
config._i,
config._f
);
}

configFromISO(config);
if (config._isValid === false) {
delete config._isValid;
} else {
return;
return createError(
config._i + ' does not match the `ISO 8601` standard',
config._d,
config._i,
config._f
);
}

configFromRFC2822(config);
if (config._isValid === false) {
delete config._isValid;
} else {
return;
return createError(
config._i + ' does not match the `RFC 2822` standard',
config._d,
config._i,
config._f
);
}

if (config._strict) {
config._isValid = false;
} else {
// Final attempt, use Input Fallback
hooks.createFromInputFallback(config);
createError(
config._i + ' failed to build a Date using `new Date()`',
config._d,
config._i,
config._f
);
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/lib/moment/constructor.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { hooks } from '../utils/hooks';
import isUndefined from '../utils/is-undefined';
import getParsingFlags from '../create/parsing-flags';
import createError from '../utils/create-error';

// Plugins that add properties should also add the key here (null value),
// so we can properly clone ourselves.
Expand Down Expand Up @@ -63,6 +64,7 @@ export function Moment(config) {
this._d = new Date(config._d != null ? config._d.getTime() : NaN);
if (!this.isValid()) {
this._d = new Date(NaN);
createError('invalid moment instance', config._d, config._i, config._f);
}
// Prevent infinite loop in case updateOffset creates new moment
// objects.
Expand Down
54 changes: 54 additions & 0 deletions src/lib/utils/create-error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { hooks } from './hooks';
import isDate from './is-date';

/**
* Update an Error with the specified date, input and format.
*
* @param {*} message The error message
* @param {*} date The date
* @param {*} input The input
* @param {*} format The format
*/
function makeError(message, date, input, format) {
var error = new Error(message);
error.date = date;
error.input = input;
error.format = format;
error.toJSON = function toJSON() {
return {
// Standard
message: this.message,
name: this.name,
// Microsoft
description: this.description,
number: this.number,
// Mozilla
fileName: this.fileName,
lineNumber: this.lineNumber,
columnNumber: this.columnNumber,
stack: this.stack,
};
};
return error;
}

/**
* Create an Error with the specified message, date, input and format.
*
* @param {*} message The error message
* @param {*} date The date
* @param {*} input The input
* @param {*} format The format
*/
export default function createError(message, date, input, format) {
if (hooks.suppressCreateError !== false) {
return;
}
if (isDate(date) && date.toString() !== 'Invalid Date') {
return;
}
throw makeError(message, date, input, format);
}

// Specify whether to disable throwing errors, ths default value is `true`
hooks.suppressCreateError = true;
31 changes: 31 additions & 0 deletions src/test/moment/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -2917,3 +2917,34 @@ test('k, kk', function (assert) {
}
}
});

test('Invalid date will throw an error', function (assert) {
var i,
data,
dataList = [
['10:32:17 027', null],
['20202-02-01', moment.ISO_8601],
['20202-02-01', moment.RFC_2822],
['20202-02-01', []],
[new Date(NaN), null],
];
moment.suppressCreateError = false;
for (i = 0; i < dataList.length; i++) {
data = dataList[i];
try {
moment(data[0], data[1]);
} catch (error) {
assert.ok(
error instanceof Error,
'Invalid date returns an instance of Error'
);
if (error.toJSON) {
assert.ok(
error.toJSON instanceof Function,
'Error instance contains toJSON method'
);
}
}
}
moment.suppressCreateError = true;
});

0 comments on commit c8785e7

Please sign in to comment.