Skip to content

Commit 55ca773

Browse files
authored
fix*isISO8601): add strictSeparator option (#1486)
1 parent 13c0129 commit 55ca773

File tree

5 files changed

+124
-14
lines changed

5 files changed

+124
-14
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ Validator | Description
122122
**isIPRange(str)** | check if the string is an IP Range(version 4 only).
123123
**isISBN(str [, version])** | check if the string is an ISBN (version 10 or 13).
124124
**isISIN(str)** | check if the string is an [ISIN][ISIN] (stock/security identifier).
125-
**isISO8601(str)** | check if the string is a valid [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) date; for additional checks for valid dates, e.g. invalidates dates like `2009-02-29`, pass `options` object as a second parameter with `options.strict = true`.
125+
**isISO8601(str)** | check if the string is a valid [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) date. <br/>`options` is an object which defaults to `{ strict: false, strictSeparator: false }`. If `strict` is true, date strings with invalid dates like `2009-02-29` will be invalid. If `strictSeparator` is true, date strings with date and time separated by anything other than a T will be invalid.
126126
**isISO31661Alpha2(str)** | check if the string is a valid [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) officially assigned country code.
127127
**isISO31661Alpha3(str)** | check if the string is a valid [ISO 3166-1 alpha-3](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3) officially assigned country code.
128128
**isISRC(str)** | check if the string is a [ISRC](https://en.wikipedia.org/wiki/International_Standard_Recording_Code).

src/lib/isISO8601.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import assertString from './util/assertString';
33
/* eslint-disable max-len */
44
// from http://goo.gl/0ejHHW
55
const iso8601 = /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/;
6+
// same as above, except with a strict 'T' separator between date and time
7+
const iso8601StrictSeparator = /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T]((([01]\d|2[0-3])((:?)[0-5]\d)?|24:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/;
68
/* eslint-enable max-len */
79
const isValidDate = (str) => {
810
// str must have passed the ISO8601 check
@@ -34,10 +36,9 @@ const isValidDate = (str) => {
3436
return true;
3537
};
3638

37-
export default function isISO8601(str, options) {
39+
export default function isISO8601(str, options = {}) {
3840
assertString(str);
39-
const check = iso8601.test(str);
40-
if (!options) return check;
41+
const check = options.strictSeparator ? iso8601StrictSeparator.test(str) : iso8601.test(str);
4142
if (check && options.strict) return isValidDate(str);
4243
return check;
4344
}

test/validators.js

+107
Original file line numberDiff line numberDiff line change
@@ -8542,6 +8542,113 @@ describe('Validators', () => {
85428542
});
85438543
});
85448544

8545+
it('should validate ISO 8601 dates, with strictSeparator = true', () => {
8546+
test({
8547+
validator: 'isISO8601',
8548+
args: [
8549+
{ strictSeparator: true },
8550+
],
8551+
valid: [
8552+
'2009-12T12:34',
8553+
'2009',
8554+
'2009-05-19',
8555+
'2009-05-19',
8556+
'20090519',
8557+
'2009123',
8558+
'2009-05',
8559+
'2009-123',
8560+
'2009-222',
8561+
'2009-001',
8562+
'2009-W01-1',
8563+
'2009-W51-1',
8564+
'2009-W511',
8565+
'2009-W33',
8566+
'2009W511',
8567+
'2009-05-19',
8568+
'2009-05-19T14:39Z',
8569+
'2009-W21-2',
8570+
'2009-W21-2T01:22',
8571+
'2009-139',
8572+
'20090621T0545Z',
8573+
'2007-04-06T00:00',
8574+
'2007-04-05T24:00',
8575+
'2010-02-18T16:23:48.5',
8576+
'2010-02-18T16:23:48,444',
8577+
'2010-02-18T16:23:48,3-06:00',
8578+
'2010-02-18T16:23.4',
8579+
'2010-02-18T16:23,25',
8580+
'2010-02-18T16:23.33+0600',
8581+
'2010-02-18T16.23334444',
8582+
'2010-02-18T16,2283',
8583+
'2009-10-10',
8584+
'2020-366',
8585+
'2000-366',
8586+
],
8587+
invalid: [
8588+
'200905',
8589+
'2009367',
8590+
'2009-',
8591+
'2007-04-05T24:50',
8592+
'2009-000',
8593+
'2009-M511',
8594+
'2009M511',
8595+
'2009-05-19T14a39r',
8596+
'2009-05-19T14:3924',
8597+
'2009-0519',
8598+
'2009-05-1914:39',
8599+
'2009-05-19 14:',
8600+
'2009-05-19r14:39',
8601+
'2009-05-19 14a39a22',
8602+
'200912-01',
8603+
'2009-05-19 14:39:22+06a00',
8604+
'2009-05-19 146922.500',
8605+
'2010-02-18T16.5:23.35:48',
8606+
'2010-02-18T16:23.35:48',
8607+
'2010-02-18T16:23.35:48.45',
8608+
'2009-05-19 14.5.44',
8609+
'2010-02-18T16:23.33.600',
8610+
'2010-02-18T16,25:23:48,444',
8611+
'2010-13-1',
8612+
'2009-05-19 00:00',
8613+
// Previously valid cases
8614+
'2009-05-19 14',
8615+
'2009-05-19 14:31',
8616+
'2009-05-19 14:39:22',
8617+
'2009-05-19 14:39:22-06:00',
8618+
'2009-05-19 14:39:22+0600',
8619+
'2009-05-19 14:39:22-01',
8620+
],
8621+
});
8622+
});
8623+
8624+
it('should validate ISO 8601 dates, with strict = true and strictSeparator = true (regression)', () => {
8625+
test({
8626+
validator: 'isISO8601',
8627+
args: [
8628+
{ strict: true, strictSeparator: true },
8629+
],
8630+
valid: [
8631+
'2000-02-29',
8632+
'2009-123',
8633+
'2009-222',
8634+
'2020-366',
8635+
'2400-366',
8636+
],
8637+
invalid: [
8638+
'2010-02-30',
8639+
'2009-02-29',
8640+
'2009-366',
8641+
'2019-02-31',
8642+
'2009-05-19 14',
8643+
'2009-05-19 14:31',
8644+
'2009-05-19 14:39:22',
8645+
'2009-05-19 14:39:22-06:00',
8646+
'2009-05-19 14:39:22+0600',
8647+
'2009-05-19 14:39:22-01',
8648+
],
8649+
});
8650+
});
8651+
85458652
it('should validate RFC 3339 dates', () => {
85468653
test({
85478654
validator: 'isRFC3339',

validator.js

+11-9
Original file line numberDiff line numberDiff line change
@@ -457,11 +457,7 @@ function isFQDN(str, options) {
457457
return false; // reject numeric TLDs
458458
}
459459

460-
if (options.allow_underscores) {
461-
part = part.replace(/_/g, '');
462-
}
463-
464-
if (!/^[a-z\u00a1-\uffff0-9-]+$/i.test(part)) {
460+
if (!/^[a-z_\u00a1-\uffff0-9-]+$/i.test(part)) {
465461
return false;
466462
} // disallow full-width chars
467463

@@ -473,6 +469,10 @@ function isFQDN(str, options) {
473469
if (part[0] === '-' || part[part.length - 1] === '-') {
474470
return false;
475471
}
472+
473+
if (!options.allow_underscores && /_/.test(part)) {
474+
return false;
475+
}
476476
}
477477

478478
return true;
@@ -2598,7 +2598,9 @@ function isBtcAddress(str) {
25982598
/* eslint-disable max-len */
25992599
// from http://goo.gl/0ejHHW
26002600

2601-
var iso8601 = /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/;
2601+
var iso8601 = /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/; // same as above, except with a strict 'T' separator between date and time
2602+
2603+
var iso8601StrictSeparator = /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-3])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T]((([01]\d|2[0-3])((:?)[0-5]\d)?|24:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/;
26022604
/* eslint-enable max-len */
26032605

26042606
var isValidDate = function isValidDate(str) {
@@ -2632,10 +2634,10 @@ var isValidDate = function isValidDate(str) {
26322634
return true;
26332635
};
26342636

2635-
function isISO8601(str, options) {
2637+
function isISO8601(str) {
2638+
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
26362639
assertString(str);
2637-
var check = iso8601.test(str);
2638-
if (!options) return check;
2640+
var check = options.strictSeparator ? iso8601StrictSeparator.test(str) : iso8601.test(str);
26392641
if (check && options.strict) return isValidDate(str);
26402642
return check;
26412643
}

validator.min.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)