ata-validator 1.10.0 → 1.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/formats.js CHANGED
@@ -21,13 +21,96 @@ function date (s) {
21
21
  return m >= 1 && m <= 12 && d >= 1 && d <= 31;
22
22
  }
23
23
 
24
+ // RFC 3339 date-time, read once. The form this replaces ran a regular
25
+ // expression for the shape and then `Date.parse` for the calendar, which
26
+ // builds a date object to answer a question about the string. Everything the
27
+ // parse rejected is checked here directly: month, the day count for that month
28
+ // in that year, and the ranges of the clock and the offset.
29
+ function daysInMonth (year, month) {
30
+ if (month === 2) {
31
+ const leap = (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
32
+ return leap ? 29 : 28;
33
+ }
34
+ return month === 4 || month === 6 || month === 9 || month === 11 ? 30 : 31;
35
+ }
36
+
37
+ function twoDigits (s, i) {
38
+ return (s.charCodeAt(i) - 48) * 10 + (s.charCodeAt(i + 1) - 48);
39
+ }
40
+
41
+ function dateTime (s) {
42
+ const n = s.length;
43
+ // The shortest accepted form is 2026-08-31T12:00:00Z
44
+ if (n < 20) return false;
45
+ // Separators sit at known indices, so they are read directly rather than
46
+ // asked for at every step of a scan. Each remaining digit is turned into
47
+ // its value once and checked as one unsigned compare, which also gives the
48
+ // field its number without a second read.
49
+ if (s.charCodeAt(4) !== 45 || s.charCodeAt(7) !== 45) return false;
50
+ const sep = s.charCodeAt(10);
51
+ if (sep !== 84 && sep !== 116) return false;
52
+ if (s.charCodeAt(13) !== 58 || s.charCodeAt(16) !== 58) return false;
53
+
54
+ const y0 = s.charCodeAt(0) - 48, y1 = s.charCodeAt(1) - 48;
55
+ const y2 = s.charCodeAt(2) - 48, y3 = s.charCodeAt(3) - 48;
56
+ if ((y0 >>> 0) > 9 || (y1 >>> 0) > 9 || (y2 >>> 0) > 9 || (y3 >>> 0) > 9) return false;
57
+ const year = y0 * 1000 + y1 * 100 + y2 * 10 + y3;
58
+
59
+ const mo0 = s.charCodeAt(5) - 48, mo1 = s.charCodeAt(6) - 48;
60
+ if ((mo0 >>> 0) > 9 || (mo1 >>> 0) > 9) return false;
61
+ const month = mo0 * 10 + mo1;
62
+ if (month < 1 || month > 12) return false;
63
+
64
+ const d0 = s.charCodeAt(8) - 48, d1 = s.charCodeAt(9) - 48;
65
+ if ((d0 >>> 0) > 9 || (d1 >>> 0) > 9) return false;
66
+ const day = d0 * 10 + d1;
67
+ if (day < 1 || day > daysInMonth(year, month)) return false;
68
+
69
+ const h0 = s.charCodeAt(11) - 48, h1 = s.charCodeAt(12) - 48;
70
+ if ((h0 >>> 0) > 9 || (h1 >>> 0) > 9 || h0 * 10 + h1 > 23) return false;
71
+ const mi0 = s.charCodeAt(14) - 48, mi1 = s.charCodeAt(15) - 48;
72
+ if ((mi0 >>> 0) > 5 || (mi1 >>> 0) > 9) return false;
73
+ const se0 = s.charCodeAt(17) - 48, se1 = s.charCodeAt(18) - 48;
74
+ if ((se0 >>> 0) > 5 || (se1 >>> 0) > 9) return false;
75
+
76
+ let i = 19;
77
+ if (s.charCodeAt(i) === 46) {
78
+ i++;
79
+ const start = i;
80
+ while (i < n) {
81
+ const c = s.charCodeAt(i);
82
+ if (c < 48 || c > 57) break;
83
+ i++;
84
+ }
85
+ if (i === start) return false;
86
+ }
87
+
88
+ const c = s.charCodeAt(i);
89
+ if (c === 90 || c === 122) return i === n - 1;
90
+ if (c !== 43 && c !== 45) return false;
91
+ if (n - i !== 6) return false;
92
+ if (!isDigit(s.charCodeAt(i + 1)) || !isDigit(s.charCodeAt(i + 2))) return false;
93
+ if (s.charCodeAt(i + 3) !== 58) return false;
94
+ if (!isDigit(s.charCodeAt(i + 4)) || !isDigit(s.charCodeAt(i + 5))) return false;
95
+ if (twoDigits(s, i + 1) > 23) return false;
96
+ if (twoDigits(s, i + 4) > 59) return false;
97
+ return true;
98
+ }
99
+
24
100
  // Four decimal octets, no leading zeros, no empty octets, nothing else.
101
+ // Also used for the dotted tail of an IPv4-mapped IPv6 address, which is why
102
+ // the work is done over a range rather than a whole string: taking a slice for
103
+ // it would allocate on a path that exists to avoid allocating.
25
104
  function ipv4 (s) {
26
- const n = s.length;
105
+ return ipv4Range(s, 0, s.length);
106
+ }
107
+
108
+ function ipv4Range (s, from, to) {
109
+ const n = to - from;
27
110
  if (n < 7 || n > 15) return false;
28
111
  let octets = 0, value = 0, digits = 0;
29
- for (let i = 0; i <= n; i++) {
30
- const c = i < n ? s.charCodeAt(i) : 46;
112
+ for (let i = from; i <= to; i++) {
113
+ const c = i < to ? s.charCodeAt(i) : 46;
31
114
  if (c === 46) {
32
115
  if (digits === 0 || value > 255) return false;
33
116
  octets++; value = 0; digits = 0;
@@ -41,6 +124,209 @@ function ipv4 (s) {
41
124
  return octets === 4;
42
125
  }
43
126
 
127
+ // RFC 4291 address: up to eight groups of one to four hex digits, at most one
128
+ // run of "::" standing in for the zero groups, and an optional dotted IPv4
129
+ // tail in the last position, which counts as two groups. The forms this
130
+ // replaces were a character-class test plus two `split(':')` calls, which
131
+ // allocated twice and accepted things like "12345::1"; they also disagreed
132
+ // with each other about an IPv4 tail. Answers match Node's own `net.isIPv6`,
133
+ // which the test uses as its oracle.
134
+ function ipv6 (s) {
135
+ const n = s.length;
136
+ if (n < 2 || n > 45) return false;
137
+
138
+ let end = n;
139
+ let groups = 0;
140
+ // A dot can only belong to a trailing IPv4 address, which fills two groups.
141
+ const dot = s.indexOf('.');
142
+ if (dot !== -1) {
143
+ const lastColon = s.lastIndexOf(':', dot);
144
+ if (lastColon === -1) return false;
145
+ if (!ipv4Range(s, lastColon + 1, n)) return false;
146
+ end = lastColon + 1; // keep the colon: the group scan ends on it
147
+ groups = 2;
148
+ }
149
+
150
+ let compressed = false;
151
+ let digits = 0;
152
+ let i = 0;
153
+
154
+ if (s.charCodeAt(0) === 58 && s.charCodeAt(1) !== 58) return false;
155
+
156
+ while (i < end) {
157
+ const c = s.charCodeAt(i);
158
+ if (c === 58) {
159
+ if (digits > 0) { groups++; digits = 0; }
160
+ if (i + 1 < n && s.charCodeAt(i + 1) === 58) {
161
+ if (compressed) return false;
162
+ compressed = true;
163
+ i += 2;
164
+ if (i < n && s.charCodeAt(i) === 58) return false;
165
+ continue;
166
+ }
167
+ i++;
168
+ // A single colon must have something on both sides, and the group scan
169
+ // ending on a colon only happens when an IPv4 tail follows it.
170
+ if (i === end && end === n) return false;
171
+ continue;
172
+ }
173
+ if (isDigit(c) || (c >= 97 && c <= 102) || (c >= 65 && c <= 70)) {
174
+ if (++digits > 4) return false;
175
+ i++;
176
+ continue;
177
+ }
178
+ return false;
179
+ }
180
+ if (digits > 0) groups++;
181
+
182
+ if (groups > 8) return false;
183
+ return compressed ? groups < 8 : groups === 8;
184
+ }
185
+
186
+ // Labels of letters, digits and hyphens, each 1 to 63 characters, none
187
+ // starting or ending with a hyphen, joined by single dots, 253 characters at
188
+ // most. Same answers as the expression it replaces, read once.
189
+ function hostname (s) {
190
+ const n = s.length;
191
+ if (n === 0 || n > 253) return false;
192
+ let labelLength = 0;
193
+ let previous = 46; // a dot, so a leading hyphen is refused like a leading dot
194
+ for (let i = 0; i < n; i++) {
195
+ const c = s.charCodeAt(i);
196
+ if (c === 46) {
197
+ if (labelLength === 0 || previous === 45) return false;
198
+ labelLength = 0;
199
+ previous = c;
200
+ continue;
201
+ }
202
+ const alnum = isDigit(c) || (c >= 97 && c <= 122) || (c >= 65 && c <= 90);
203
+ if (!alnum && c !== 45) return false;
204
+ if (c === 45 && previous === 46) return false; // label starts with a hyphen
205
+ if (++labelLength > 63) return false;
206
+ previous = c;
207
+ }
208
+ return labelLength !== 0 && previous !== 45;
209
+ }
210
+
211
+ // A scheme followed by a colon, and no control characters or spaces after it.
212
+ // Two expressions became one pass: the scheme is read from the front and the
213
+ // rest of the string is scanned once for characters a URI cannot hold.
214
+ function uri (s) {
215
+ const n = s.length;
216
+ if (n === 0) return false;
217
+ const first = s.charCodeAt(0);
218
+ if (!((first >= 97 && first <= 122) || (first >= 65 && first <= 90))) return false;
219
+ let colon = -1;
220
+ for (let i = 1; i < n; i++) {
221
+ const c = s.charCodeAt(i);
222
+ if (c === 58) { colon = i; break; }
223
+ // scheme characters: letters, digits, "+", "-", "."
224
+ if (!(isDigit(c) || (c >= 97 && c <= 122) || (c >= 65 && c <= 90) ||
225
+ c === 43 || c === 45 || c === 46)) return false;
226
+ }
227
+ if (colon === -1) return false;
228
+ return noReserved(s, colon + 1);
229
+ }
230
+
231
+ // The characters a URI cannot hold: C0 controls, space, DEL, and the rest of
232
+ // Unicode whitespace. Asking for that set directly costs more than it looks:
233
+ // `\s` pulls in the engine's Unicode machinery for eleven code points spread
234
+ // across the BMP. Asking instead whether anything at all sits outside printable
235
+ // ASCII is a one-byte character class, which the engine scans at its own speed
236
+ // and which no ordinary URI ever trips. Only a string that does trip it pays
237
+ // for the loop that decides the exact set, and that loop was measured slower
238
+ // than the engine on the common case, which is why it is not the first answer.
239
+ const NON_PRINTABLE = /[^\u0021-\u007e]/;
240
+
241
+ function noReserved (s, from) {
242
+ if (!NON_PRINTABLE.test(s)) return true;
243
+ const n = s.length;
244
+ for (let i = from; i < n; i++) {
245
+ const c = s.charCodeAt(i);
246
+ if (c > 32 && c < 127) continue;
247
+ if (c <= 32 || c === 127) return false;
248
+ if (c === 160 || c === 5760 || (c >= 8192 && c <= 8202) || c === 8232 ||
249
+ c === 8233 || c === 8239 || c === 8287 || c === 12288 || c === 65279) return false;
250
+ }
251
+ return true;
252
+ }
253
+
254
+ // Source twin of noReserved, same two tiers. `from` is an expression for the
255
+ // first index the loop reads; the variable names stay clear of the ones the
256
+ // other format emitters use.
257
+ function noReservedSource (v, from) {
258
+ return `if(/[^\\u0021-\\u007e]/.test(${v})){` +
259
+ `for(let _ri=${from};_ri<${v}.length;_ri++){const _rc=${v}.charCodeAt(_ri);` +
260
+ 'if(_rc>32&&_rc<127)continue;' +
261
+ 'if(_rc<=32||_rc===127)return false;' +
262
+ 'if(_rc===160||_rc===5760||(_rc>=8192&&_rc<=8202)||_rc===8232||' +
263
+ '_rc===8233||_rc===8239||_rc===8287||_rc===12288||_rc===65279)return false}}';
264
+ }
265
+
266
+ // 8-4-4-4-12 hexadecimal digits. The four hyphens are read by index, then
267
+ // each run of hex digits is read with fixed bounds, so no character pays for a
268
+ // test of where it sits. A digit is one unsigned compare and a letter is one
269
+ // more after folding case with a single OR, which is what a case-insensitive
270
+ // regex spends a state machine on.
271
+ function hexRun (s, from, to) {
272
+ for (let i = from; i < to; i++) {
273
+ const c = s.charCodeAt(i);
274
+ if (!((c - 48 >>> 0) < 10 || ((c | 32) - 97 >>> 0) < 6)) return false;
275
+ }
276
+ return true;
277
+ }
278
+
279
+ function uuid (s) {
280
+ if (s.length !== 36) return false;
281
+ if (s.charCodeAt(8) !== 45 || s.charCodeAt(13) !== 45 ||
282
+ s.charCodeAt(18) !== 45 || s.charCodeAt(23) !== 45) return false;
283
+ return hexRun(s, 0, 8) && hexRun(s, 9, 13) && hexRun(s, 14, 18) &&
284
+ hexRun(s, 19, 23) && hexRun(s, 24, 36);
285
+ }
286
+
287
+ // RFC 3339 full-time: HH:MM:SS, an optional fraction, an optional offset.
288
+ // Every position is known in advance, so the check reads fixed indices and
289
+ // compares digits as numbers instead of running a state machine over the
290
+ // string. The zone letter is accepted in either case, which is what the
291
+ // interpreter and the date-time check already did.
292
+ function time (s) {
293
+ const n = s.length;
294
+ if (n < 8) return false;
295
+ const h1 = s.charCodeAt(0) - 48, h2 = s.charCodeAt(1) - 48;
296
+ if ((h1 >>> 0) > 9 || (h2 >>> 0) > 9 || h1 * 10 + h2 > 23) return false;
297
+ if (s.charCodeAt(2) !== 58 || s.charCodeAt(5) !== 58) return false;
298
+ const m1 = s.charCodeAt(3) - 48, m2 = s.charCodeAt(4) - 48;
299
+ if ((m1 >>> 0) > 5 || (m2 >>> 0) > 9) return false;
300
+ const c1 = s.charCodeAt(6) - 48, c2 = s.charCodeAt(7) - 48;
301
+ if ((c1 >>> 0) > 5 || (c2 >>> 0) > 9) return false;
302
+ let i = 8;
303
+ if (i < n && s.charCodeAt(i) === 46) {
304
+ i++;
305
+ const start = i;
306
+ while (i < n) {
307
+ const c = s.charCodeAt(i) - 48;
308
+ if ((c >>> 0) > 9) break;
309
+ i++;
310
+ }
311
+ if (i === start) return false;
312
+ }
313
+ if (i === n) return true;
314
+ const z = s.charCodeAt(i);
315
+ if (z === 90 || z === 122) return i === n - 1;
316
+ if (z !== 43 && z !== 45) return false;
317
+ if (n - i !== 6 || s.charCodeAt(i + 3) !== 58) return false;
318
+ for (let k = 1; k <= 5; k++) {
319
+ if (k === 3) continue;
320
+ if ((s.charCodeAt(i + k) - 48 >>> 0) > 9) return false;
321
+ }
322
+ return true;
323
+ }
324
+
325
+ // Anything without a control character or whitespace.
326
+ function uriReference (s) {
327
+ return noReserved(s, 0);
328
+ }
329
+
44
330
  // Source twins. `v` is the expression holding the string; when `isStr` is
45
331
  // false the check is wrapped in a typeof guard, matching FORMAT_CODEGEN's
46
332
  // convention. Each returns a statement that `return false`s on mismatch.
@@ -50,8 +336,108 @@ function dateSource (v, isStr) {
50
336
  return guard(v, isStr, `if(${v}.length!==10)return false;for(let _i=0;_i<10;_i++){const _c=${v}.charCodeAt(_i);if(_i===4||_i===7){if(_c!==45)return false}else if(_c<48||_c>57)return false}const _m=(${v}.charCodeAt(5)-48)*10+(${v}.charCodeAt(6)-48),_d=(${v}.charCodeAt(8)-48)*10+(${v}.charCodeAt(9)-48);if(_m<1||_m>12||_d<1||_d>31)return false`);
51
337
  }
52
338
 
339
+ function dateTimeSource (v, isStr) {
340
+ return guard(v, isStr, `const _n=${v}.length;if(_n<20)return false;` +
341
+ `if(${v}.charCodeAt(4)!==45||${v}.charCodeAt(7)!==45)return false;` +
342
+ `const _sep=${v}.charCodeAt(10);if(_sep!==84&&_sep!==116)return false;` +
343
+ `if(${v}.charCodeAt(13)!==58||${v}.charCodeAt(16)!==58)return false;` +
344
+ `const _y0=${v}.charCodeAt(0)-48,_y1=${v}.charCodeAt(1)-48,_y2=${v}.charCodeAt(2)-48,_y3=${v}.charCodeAt(3)-48;` +
345
+ 'if((_y0>>>0)>9||(_y1>>>0)>9||(_y2>>>0)>9||(_y3>>>0)>9)return false;' +
346
+ 'const _y=_y0*1000+_y1*100+_y2*10+_y3;' +
347
+ `const _mo0=${v}.charCodeAt(5)-48,_mo1=${v}.charCodeAt(6)-48;` +
348
+ 'if((_mo0>>>0)>9||(_mo1>>>0)>9)return false;const _mo=_mo0*10+_mo1;if(_mo<1||_mo>12)return false;' +
349
+ `const _dm=_mo===2?(((_y%4===0&&_y%100!==0)||_y%400===0)?29:28):(_mo===4||_mo===6||_mo===9||_mo===11?30:31);` +
350
+ `const _d0=${v}.charCodeAt(8)-48,_d1=${v}.charCodeAt(9)-48;` +
351
+ 'if((_d0>>>0)>9||(_d1>>>0)>9)return false;const _d=_d0*10+_d1;if(_d<1||_d>_dm)return false;' +
352
+ `const _h0=${v}.charCodeAt(11)-48,_h1=${v}.charCodeAt(12)-48;` +
353
+ 'if((_h0>>>0)>9||(_h1>>>0)>9||_h0*10+_h1>23)return false;' +
354
+ `const _mi0=${v}.charCodeAt(14)-48,_mi1=${v}.charCodeAt(15)-48;` +
355
+ 'if((_mi0>>>0)>5||(_mi1>>>0)>9)return false;' +
356
+ `const _se0=${v}.charCodeAt(17)-48,_se1=${v}.charCodeAt(18)-48;` +
357
+ 'if((_se0>>>0)>5||(_se1>>>0)>9)return false;' +
358
+ `let _i2=19;if(${v}.charCodeAt(19)===46){_i2=20;const _st=_i2;while(_i2<_n){const _c2=${v}.charCodeAt(_i2);if(_c2<48||_c2>57)break;_i2++}if(_i2===_st)return false}` +
359
+ `const _tz=${v}.charCodeAt(_i2);` +
360
+ `if(_tz===90||_tz===122){if(_i2!==_n-1)return false}` +
361
+ `else{if(_tz!==43&&_tz!==45)return false;if(_n-_i2!==6)return false;` +
362
+ `const _oh=${v}.charCodeAt(_i2+1),_oh2=${v}.charCodeAt(_i2+2),_om=${v}.charCodeAt(_i2+4),_om2=${v}.charCodeAt(_i2+5);` +
363
+ `if(_oh<48||_oh>57||_oh2<48||_oh2>57||_om<48||_om>57||_om2<48||_om2>57)return false;` +
364
+ `if(${v}.charCodeAt(_i2+3)!==58)return false;` +
365
+ `if((_oh-48)*10+(_oh2-48)>23)return false;if((_om-48)*10+(_om2-48)>59)return false}`);
366
+ }
367
+
368
+ function hostnameSource (v, isStr) {
369
+ return guard(v, isStr, `const _n=${v}.length;if(_n===0||_n>253)return false;let _ll=0,_pv=46;` +
370
+ `for(let _i=0;_i<_n;_i++){const _c=${v}.charCodeAt(_i);` +
371
+ `if(_c===46){if(_ll===0||_pv===45)return false;_ll=0;_pv=_c;continue}` +
372
+ `const _an=(_c>=48&&_c<=57)||(_c>=97&&_c<=122)||(_c>=65&&_c<=90);` +
373
+ `if(!_an&&_c!==45)return false;` +
374
+ `if(_c===45&&_pv===46)return false;` +
375
+ `if(++_ll>63)return false;_pv=_c}` +
376
+ `if(_ll===0||_pv===45)return false`);
377
+ }
378
+
379
+ function uuidSource (v, isStr) {
380
+ const run = (from, to) => `for(let _ui=${from};_ui<${to};_ui++){const _uc=${v}.charCodeAt(_ui);` +
381
+ 'if(!((_uc-48>>>0)<10||((_uc|32)-97>>>0)<6))return false}';
382
+ return guard(v, isStr, `if(${v}.length!==36)return false;` +
383
+ `if(${v}.charCodeAt(8)!==45||${v}.charCodeAt(13)!==45||` +
384
+ `${v}.charCodeAt(18)!==45||${v}.charCodeAt(23)!==45)return false;` +
385
+ run(0, 8) + run(9, 13) + run(14, 18) + run(19, 23) + run(24, 36));
386
+ }
387
+
388
+ function timeSource (v, isStr) {
389
+ return guard(v, isStr, `const _n=${v}.length;if(_n<8)return false;` +
390
+ `const _h1=${v}.charCodeAt(0)-48,_h2=${v}.charCodeAt(1)-48;` +
391
+ 'if((_h1>>>0)>9||(_h2>>>0)>9||_h1*10+_h2>23)return false;' +
392
+ `if(${v}.charCodeAt(2)!==58||${v}.charCodeAt(5)!==58)return false;` +
393
+ `const _m1=${v}.charCodeAt(3)-48,_m2=${v}.charCodeAt(4)-48;` +
394
+ 'if((_m1>>>0)>5||(_m2>>>0)>9)return false;' +
395
+ `const _s1=${v}.charCodeAt(6)-48,_s2=${v}.charCodeAt(7)-48;` +
396
+ 'if((_s1>>>0)>5||(_s2>>>0)>9)return false;' +
397
+ `let _ti=8;if(_ti<_n&&${v}.charCodeAt(_ti)===46){_ti++;const _tf=_ti;` +
398
+ `while(_ti<_n){const _tc=${v}.charCodeAt(_ti)-48;if((_tc>>>0)>9)break;_ti++}` +
399
+ 'if(_ti===_tf)return false}' +
400
+ 'if(_ti!==_n){' +
401
+ `const _tz=${v}.charCodeAt(_ti);` +
402
+ 'if(_tz===90||_tz===122){if(_ti!==_n-1)return false}' +
403
+ 'else{if(_tz!==43&&_tz!==45)return false;' +
404
+ `if(_n-_ti!==6||${v}.charCodeAt(_ti+3)!==58)return false;` +
405
+ `if((${v}.charCodeAt(_ti+1)-48>>>0)>9||(${v}.charCodeAt(_ti+2)-48>>>0)>9||` +
406
+ `(${v}.charCodeAt(_ti+4)-48>>>0)>9||(${v}.charCodeAt(_ti+5)-48>>>0)>9)return false}}`);
407
+ }
408
+
409
+ function uriSource (v, isStr) {
410
+ return guard(v, isStr, `const _n=${v}.length;if(_n===0)return false;` +
411
+ `const _f=${v}.charCodeAt(0);if(!((_f>=97&&_f<=122)||(_f>=65&&_f<=90)))return false;` +
412
+ `let _co=-1;for(let _i=1;_i<_n;_i++){const _c=${v}.charCodeAt(_i);if(_c===58){_co=_i;break}` +
413
+ `if(!((_c>=48&&_c<=57)||(_c>=97&&_c<=122)||(_c>=65&&_c<=90)||_c===43||_c===45||_c===46))return false}` +
414
+ `if(_co===-1)return false;` +
415
+ noReservedSource(v, '_co+1'));
416
+ }
417
+
418
+ function ipv6Source (v, isStr) {
419
+ return guard(v, isStr, `const _n=${v}.length;if(_n<2||_n>45)return false;let _end=_n,_g=0;` +
420
+ `const _dot=${v}.indexOf('.');` +
421
+ `if(_dot!==-1){const _lc=${v}.lastIndexOf(':',_dot);if(_lc===-1)return false;` +
422
+ `{const _f=_lc+1,_t=_n,_ln=_t-_f;if(_ln<7||_ln>15)return false;let _o=0,_val=0,_dg=0;` +
423
+ `for(let _i=_f;_i<=_t;_i++){const _c=_i<_t?${v}.charCodeAt(_i):46;` +
424
+ `if(_c===46){if(_dg===0||_val>255)return false;_o++;_val=0;_dg=0;if(_o>4)return false}` +
425
+ `else if(_c>=48&&_c<=57){if(_dg===1&&_val===0)return false;_val=_val*10+(_c-48);_dg++;if(_dg>3)return false}` +
426
+ `else return false}if(_o!==4)return false}` +
427
+ `_end=_lc+1;_g=2}` +
428
+ `let _cp=false,_dg2=0,_i2=0;` +
429
+ `if(${v}.charCodeAt(0)===58&&${v}.charCodeAt(1)!==58)return false;` +
430
+ `while(_i2<_end){const _c2=${v}.charCodeAt(_i2);` +
431
+ `if(_c2===58){if(_dg2>0){_g++;_dg2=0}` +
432
+ `if(_i2+1<_n&&${v}.charCodeAt(_i2+1)===58){if(_cp)return false;_cp=true;_i2+=2;if(_i2<_n&&${v}.charCodeAt(_i2)===58)return false;continue}` +
433
+ `_i2++;if(_i2===_end&&_end===_n)return false;continue}` +
434
+ `if((_c2>=48&&_c2<=57)||(_c2>=97&&_c2<=102)||(_c2>=65&&_c2<=70)){if(++_dg2>4)return false;_i2++;continue}` +
435
+ `return false}` +
436
+ `if(_dg2>0)_g++;if(_g>8)return false;if(_cp){if(_g>=8)return false}else if(_g!==8)return false`);
437
+ }
438
+
53
439
  function ipv4Source (v, isStr) {
54
440
  return guard(v, isStr, `const _n=${v}.length;if(_n<7||_n>15)return false;let _o=0,_val=0,_dg=0;for(let _i=0;_i<=_n;_i++){const _c=_i<_n?${v}.charCodeAt(_i):46;if(_c===46){if(_dg===0||_val>255)return false;_o++;_val=0;_dg=0;if(_o>4)return false}else if(_c>=48&&_c<=57){if(_dg===1&&_val===0)return false;_val=_val*10+(_c-48);_dg++;if(_dg>3)return false}else return false}if(_o!==4)return false`);
55
441
  }
56
442
 
57
- module.exports = { date, ipv4, dateSource, ipv4Source };
443
+ module.exports = { date, ipv4, dateTime, ipv6, hostname, uri, uriReference, uuid, time, noReserved, dateSource, ipv4Source, dateTimeSource, ipv6Source, hostnameSource, uriSource, uuidSource, timeSource, noReservedSource };
@@ -251,15 +251,15 @@ const _formats = require('./formats');
251
251
  const FORMAT_CHECKS = {
252
252
  email: (s) => { const at = s.indexOf('@'); return at > 0 && at < s.length - 1 && s.indexOf('.', at) > at + 1; },
253
253
  date: _formats.date,
254
- 'date-time': (s) => /^\d{4}-\d{2}-\d{2}[Tt]\d{2}:\d{2}:\d{2}(\.\d+)?([Zz]|[+-]\d{2}:\d{2})$/.test(s) && !isNaN(Date.parse(s)),
255
- time: (s) => /^([01]\d|2[0-3]):[0-5]\d:[0-5]\d(\.\d+)?([Zz]|[+-]\d{2}:\d{2})?$/.test(s),
254
+ 'date-time': _formats.dateTime,
255
+ time: _formats.time,
256
256
  duration: (s) => /^P(?:\d+Y)?(?:\d+M)?(?:\d+W)?(?:\d+D)?(?:T(?:\d+H)?(?:\d+M)?(?:\d+(?:\.\d+)?S)?)?$/.test(s) && s !== 'P' && !s.endsWith('T'),
257
- uuid: (s) => s.length === 36 && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(s),
258
- uri: (s) => /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(s) && !/[\s\u0000-\u001f\u007f]/.test(s),
259
- 'uri-reference': (s) => !/[\s\u0000-\u001f\u007f]/.test(s),
257
+ uuid: _formats.uuid,
258
+ uri: _formats.uri,
259
+ 'uri-reference': _formats.uriReference,
260
260
  ipv4: _formats.ipv4,
261
- ipv6: (s) => s !== '' && /^[0-9a-fA-F:.]+$/.test(s) && s.split(':').length >= 3 && s.split(':').length <= 8,
262
- hostname: (s) => s.length > 0 && s.length <= 253 && /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test(s),
261
+ ipv6: _formats.ipv6,
262
+ hostname: _formats.hostname,
263
263
  regex: (s) => { try { new RegExp(s, 'u'); return true; } catch { try { new RegExp(s); return true; } catch { return false; } } },
264
264
  'json-pointer': (s) => s === '' || (/^\//.test(s) && !/~(?![01])/.test(s)),
265
265
  };