@ix-xs/node-comfort 1.2.0 → 2.0.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/CHANGELOG.md +190 -0
- package/README.md +136 -549
- package/index.js +80 -35
- package/package.json +160 -33
- package/src/Arr.js +887 -419
- package/src/Async.js +585 -0
- package/src/Cache.js +329 -0
- package/src/Checker.js +971 -539
- package/src/Cli.js +1034 -0
- package/src/Color.js +415 -0
- package/src/Crypto.js +707 -0
- package/src/Emitter.js +289 -0
- package/src/Env.js +555 -0
- package/src/FS.js +1483 -894
- package/src/Func.js +670 -353
- package/src/Http.js +538 -0
- package/src/Id.js +384 -201
- package/src/Logger.js +739 -378
- package/src/Num.js +844 -361
- package/src/Obj.js +855 -372
- package/src/SQLite.js +1308 -1005
- package/src/Schema.js +1586 -0
- package/src/Str.js +983 -436
- package/src/Sys.js +511 -0
- package/src/Time.js +1260 -422
- package/src/Utils.js +321 -325
- package/src/errors.js +292 -0
- package/types/index.d.ts +693 -526
- package/types/src/Arr.d.ts +455 -145
- package/types/src/Arr.d.ts.map +1 -1
- package/types/src/Async.d.ts +321 -0
- package/types/src/Async.d.ts.map +1 -0
- package/types/src/Cache.d.ts +195 -0
- package/types/src/Cache.d.ts.map +1 -0
- package/types/src/Checker.d.ts +501 -235
- package/types/src/Checker.d.ts.map +1 -1
- package/types/src/Cli.d.ts +582 -0
- package/types/src/Cli.d.ts.map +1 -0
- package/types/src/Color.d.ts +294 -0
- package/types/src/Color.d.ts.map +1 -0
- package/types/src/Crypto.d.ts +534 -0
- package/types/src/Crypto.d.ts.map +1 -0
- package/types/src/Emitter.d.ts +170 -0
- package/types/src/Emitter.d.ts.map +1 -0
- package/types/src/Env.d.ts +382 -0
- package/types/src/Env.d.ts.map +1 -0
- package/types/src/FS.d.ts +686 -238
- package/types/src/FS.d.ts.map +1 -1
- package/types/src/Func.d.ts +380 -135
- package/types/src/Func.d.ts.map +1 -1
- package/types/src/Http.d.ts +374 -0
- package/types/src/Http.d.ts.map +1 -0
- package/types/src/Id.d.ts +149 -68
- package/types/src/Id.d.ts.map +1 -1
- package/types/src/Logger.d.ts +363 -46
- package/types/src/Logger.d.ts.map +1 -1
- package/types/src/Num.d.ts +473 -137
- package/types/src/Num.d.ts.map +1 -1
- package/types/src/Obj.d.ts +390 -104
- package/types/src/Obj.d.ts.map +1 -1
- package/types/src/SQLite.d.ts +646 -309
- package/types/src/SQLite.d.ts.map +1 -1
- package/types/src/Schema.d.ts +940 -0
- package/types/src/Schema.d.ts.map +1 -0
- package/types/src/Str.d.ts +569 -166
- package/types/src/Str.d.ts.map +1 -1
- package/types/src/Sys.d.ts +269 -0
- package/types/src/Sys.d.ts.map +1 -0
- package/types/src/Time.d.ts +663 -204
- package/types/src/Time.d.ts.map +1 -1
- package/types/src/Utils.d.ts +154 -102
- package/types/src/Utils.d.ts.map +1 -1
- package/types/src/errors.d.ts +292 -0
- package/types/src/errors.d.ts.map +1 -0
- package/types/index.d.ts.map +0 -1
package/src/Checker.js
CHANGED
|
@@ -1,547 +1,979 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Type checks and validators. Every `isX` accepts anything and never throws,
|
|
5
|
+
* and most of them are type guards: inside `if (nc.isString(value))`, your
|
|
6
|
+
* editor knows `value` is a string, in JavaScript too.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* if (nc.isEmail(body.email) && nc.isPort(body.port)) connect(body);
|
|
10
|
+
* nc.assert(user, "User not found");
|
|
11
|
+
*/
|
|
12
|
+
|
|
1
13
|
const { types } = require("node:util");
|
|
2
14
|
|
|
3
15
|
/**
|
|
4
|
-
*
|
|
16
|
+
* Any built-in typed array.
|
|
17
|
+
* @typedef {Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array | BigInt64Array | BigUint64Array} AnyTypedArray
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Any primitive value.
|
|
22
|
+
* @typedef {string | number | boolean | symbol | bigint | null | undefined} Primitive
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Options for `isURL()`.
|
|
27
|
+
* @typedef {object} IsURLOptions
|
|
28
|
+
* @property {string[]} [protocols] Accepted protocols, colon included. Defaults to `["http:", "https:"]`.
|
|
29
|
+
* @property {boolean} [requireTld] Require a domain like `example.com`, rejecting `localhost` and bare IPs.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Options for `isUUID()`.
|
|
34
|
+
* @typedef {object} IsUUIDOptions
|
|
35
|
+
* @property {1|2|3|4|5|6|7|8} [version] Only accept this version. Otherwise versions 1 to 8 pass, plus the nil and max UUIDs.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Options for `isBase64()`.
|
|
40
|
+
* @typedef {object} IsBase64Options
|
|
41
|
+
* @property {boolean} [urlSafe] Expect the URL-safe alphabet (`-` and `_`), padding optional.
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Is it an array?
|
|
5
46
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
47
|
+
* @example
|
|
48
|
+
* nc.isArray([1, 2]); // true
|
|
49
|
+
* nc.isArray({ length: 0 }); // false
|
|
50
|
+
*
|
|
51
|
+
* @param {unknown} value
|
|
52
|
+
* @returns {value is any[]}
|
|
9
53
|
*/
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
54
|
+
function isArray(value) {
|
|
55
|
+
return Array.isArray(value);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Is it a number? `NaN` is rejected, `Infinity` passes (see `isFinite`).
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* nc.isNumber(42); // true
|
|
63
|
+
* nc.isNumber(NaN); // false
|
|
64
|
+
* nc.isNumber("42"); // false, use isNumeric for strings
|
|
65
|
+
*
|
|
66
|
+
* @param {unknown} value
|
|
67
|
+
* @returns {value is number}
|
|
68
|
+
*/
|
|
69
|
+
function isNumber(value) {
|
|
70
|
+
return typeof value === "number" && !Number.isNaN(value);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Is it a finite number? Unlike the global `isFinite`, strings are rejected.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* nc.isFinite(42); // true
|
|
78
|
+
* nc.isFinite(Infinity); // false
|
|
79
|
+
* nc.isFinite("42"); // false
|
|
80
|
+
*
|
|
81
|
+
* @param {unknown} value
|
|
82
|
+
* @returns {value is number}
|
|
83
|
+
*/
|
|
84
|
+
function isFinite(value) {
|
|
85
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Is it an integer?
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* nc.isInteger(4); // true
|
|
93
|
+
* nc.isInteger(4.5); // false
|
|
94
|
+
*
|
|
95
|
+
* @param {unknown} value
|
|
96
|
+
* @returns {value is number}
|
|
97
|
+
*/
|
|
98
|
+
function isInteger(value) {
|
|
99
|
+
return Number.isInteger(value);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Is it an integer JavaScript can represent exactly (up to 2^53 - 1)?
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* nc.isSafeInteger(2 ** 53 - 1); // true
|
|
107
|
+
* nc.isSafeInteger(2 ** 53); // false
|
|
108
|
+
*
|
|
109
|
+
* @param {unknown} value
|
|
110
|
+
* @returns {value is number}
|
|
111
|
+
*/
|
|
112
|
+
function isSafeInteger(value) {
|
|
113
|
+
return Number.isSafeInteger(value);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Is it a finite number with a decimal part?
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* nc.isFloat(4.2); // true
|
|
121
|
+
* nc.isFloat(4); // false
|
|
122
|
+
*
|
|
123
|
+
* @param {unknown} value
|
|
124
|
+
* @returns {value is number}
|
|
125
|
+
*/
|
|
126
|
+
function isFloat(value) {
|
|
127
|
+
return typeof value === "number" && Number.isFinite(value) && !Number.isInteger(value);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Is it a number greater than zero?
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* nc.isPositive(3); // true
|
|
135
|
+
* nc.isPositive(0); // false
|
|
136
|
+
*
|
|
137
|
+
* @param {unknown} value
|
|
138
|
+
* @returns {value is number}
|
|
139
|
+
*/
|
|
140
|
+
function isPositive(value) {
|
|
141
|
+
return typeof value === "number" && value > 0;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Is it a number lower than zero?
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* nc.isNegative(-3); // true
|
|
149
|
+
* nc.isNegative(0); // false
|
|
150
|
+
*
|
|
151
|
+
* @param {unknown} value
|
|
152
|
+
* @returns {value is number}
|
|
153
|
+
*/
|
|
154
|
+
function isNegative(value) {
|
|
155
|
+
return typeof value === "number" && value < 0;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Is it `true` or `false`? Truthy and falsy values don't count.
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* nc.isBoolean(false); // true
|
|
163
|
+
* nc.isBoolean(0); // false
|
|
164
|
+
*
|
|
165
|
+
* @param {unknown} value
|
|
166
|
+
* @returns {value is boolean}
|
|
167
|
+
*/
|
|
168
|
+
function isBoolean(value) {
|
|
169
|
+
return typeof value === "boolean";
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Is it a string?
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* nc.isString("hello"); // true
|
|
177
|
+
* nc.isString(new String("hello")); // false
|
|
178
|
+
*
|
|
179
|
+
* @param {unknown} value
|
|
180
|
+
* @returns {value is string}
|
|
181
|
+
*/
|
|
182
|
+
function isString(value) {
|
|
183
|
+
return typeof value === "string";
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Is it a symbol?
|
|
188
|
+
*
|
|
189
|
+
* @param {unknown} value
|
|
190
|
+
* @returns {value is symbol}
|
|
191
|
+
*/
|
|
192
|
+
function isSymbol(value) {
|
|
193
|
+
return typeof value === "symbol";
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Is it a bigint?
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* nc.isBigInt(10n); // true
|
|
201
|
+
* nc.isBigInt(10); // false
|
|
202
|
+
*
|
|
203
|
+
* @param {unknown} value
|
|
204
|
+
* @returns {value is bigint}
|
|
205
|
+
*/
|
|
206
|
+
function isBigInt(value) {
|
|
207
|
+
return typeof value === "bigint";
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Is it `undefined`?
|
|
212
|
+
*
|
|
213
|
+
* @param {unknown} value
|
|
214
|
+
* @returns {value is undefined}
|
|
215
|
+
*/
|
|
216
|
+
function isUndefined(value) {
|
|
217
|
+
return value === undefined;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Is it `null`?
|
|
222
|
+
*
|
|
223
|
+
* @param {unknown} value
|
|
224
|
+
* @returns {value is null}
|
|
225
|
+
*/
|
|
226
|
+
function isNull(value) {
|
|
227
|
+
return value === null;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Is it `null` or `undefined`?
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* nc.isNil(undefined); // true
|
|
235
|
+
* nc.isNil(0); // false
|
|
236
|
+
*
|
|
237
|
+
* @param {unknown} value
|
|
238
|
+
* @returns {value is null | undefined}
|
|
239
|
+
*/
|
|
240
|
+
function isNil(value) {
|
|
241
|
+
return value === null || value === undefined;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Is it anything but `null` or `undefined`? Pass it to `filter()` to drop
|
|
246
|
+
* missing values and keep the right type.
|
|
247
|
+
*
|
|
248
|
+
* @example
|
|
249
|
+
* const ids = [1, null, 2, undefined].filter(nc.isDefined); // number[]
|
|
250
|
+
*
|
|
251
|
+
* @template T
|
|
252
|
+
* @param {T} value
|
|
253
|
+
* @returns {value is NonNullable<T>}
|
|
254
|
+
*/
|
|
255
|
+
function isDefined(value) {
|
|
256
|
+
return value !== null && value !== undefined;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Is it a primitive (string, number, boolean, symbol, bigint, `null` or `undefined`)?
|
|
261
|
+
*
|
|
262
|
+
* @param {unknown} value
|
|
263
|
+
* @returns {value is Primitive}
|
|
264
|
+
*/
|
|
265
|
+
function isPrimitive(value) {
|
|
266
|
+
return value === null || (typeof value !== "object" && typeof value !== "function");
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Is it callable? Classes, async and generator functions count.
|
|
271
|
+
*
|
|
272
|
+
* @param {unknown} value
|
|
273
|
+
* @returns {value is (...args: any[]) => any}
|
|
274
|
+
*/
|
|
275
|
+
function isFunction(value) {
|
|
276
|
+
return typeof value === "function";
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Was it declared with `async`? A function that merely returns a promise
|
|
281
|
+
* doesn't count.
|
|
282
|
+
*
|
|
283
|
+
* @example
|
|
284
|
+
* nc.isAsyncFunction(async () => {}); // true
|
|
285
|
+
* nc.isAsyncFunction(() => Promise.resolve()); // false
|
|
286
|
+
*
|
|
287
|
+
* @param {unknown} value
|
|
288
|
+
* @returns {value is (...args: any[]) => Promise<any>}
|
|
289
|
+
*/
|
|
290
|
+
function isAsyncFunction(value) {
|
|
291
|
+
return types.isAsyncFunction(value);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Is it a generator function (`function*`)?
|
|
296
|
+
*
|
|
297
|
+
* @param {unknown} value
|
|
298
|
+
* @returns {value is (...args: any[]) => Generator}
|
|
299
|
+
*/
|
|
300
|
+
function isGeneratorFunction(value) {
|
|
301
|
+
return types.isGeneratorFunction(value);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Is it a generator object, the result of calling a `function*`?
|
|
306
|
+
*
|
|
307
|
+
* @param {unknown} value
|
|
308
|
+
* @returns {value is Generator}
|
|
309
|
+
*/
|
|
310
|
+
function isGenerator(value) {
|
|
311
|
+
return types.isGeneratorObject(value);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Is it a `class` rather than a plain function?
|
|
316
|
+
*
|
|
317
|
+
* @example
|
|
318
|
+
* nc.isClass(class User {}); // true
|
|
319
|
+
* nc.isClass(function () {}); // false
|
|
320
|
+
*
|
|
321
|
+
* @param {unknown} value
|
|
322
|
+
* @returns {value is new (...args: any[]) => any}
|
|
323
|
+
*/
|
|
324
|
+
function isClass(value) {
|
|
325
|
+
return typeof value === "function" && /^class[\s{]/.test(Function.prototype.toString.call(value));
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Is it an object, and not `null`? Arrays, dates and class instances count;
|
|
330
|
+
* use `isPlainObject` for `{}` literals only.
|
|
331
|
+
*
|
|
332
|
+
* @param {unknown} value
|
|
333
|
+
* @returns {value is object}
|
|
334
|
+
*/
|
|
335
|
+
function isObject(value) {
|
|
336
|
+
return typeof value === "object" && value !== null;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Is it a plain object, made with `{}`, `new Object()` or
|
|
341
|
+
* `Object.create(null)`? Arrays, dates, maps and class instances are rejected.
|
|
342
|
+
*
|
|
343
|
+
* @example
|
|
344
|
+
* nc.isPlainObject({ a: 1 }); // true
|
|
345
|
+
* nc.isPlainObject(new Date()); // false
|
|
346
|
+
*
|
|
347
|
+
* @param {unknown} value
|
|
348
|
+
* @returns {value is Record<string, unknown>}
|
|
349
|
+
*/
|
|
350
|
+
function isPlainObject(value) {
|
|
351
|
+
if (typeof value !== "object" || value === null) return false;
|
|
352
|
+
const proto = Object.getPrototypeOf(value);
|
|
353
|
+
// The last check accepts objects from another realm (a worker, a `vm`).
|
|
354
|
+
return proto === null || proto === Object.prototype || Object.getPrototypeOf(proto) === null;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Can it be awaited like a promise (anything with a `then` method)?
|
|
359
|
+
*
|
|
360
|
+
* @param {unknown} value
|
|
361
|
+
* @returns {value is PromiseLike<any>}
|
|
362
|
+
*/
|
|
363
|
+
function isPromise(value) {
|
|
364
|
+
return (
|
|
365
|
+
types.isPromise(value) ||
|
|
366
|
+
(value !== null &&
|
|
367
|
+
(typeof value === "object" || typeof value === "function") &&
|
|
368
|
+
typeof (/** @type {{ then?: unknown }} */ (value)).then === "function")
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Is it a regular expression?
|
|
374
|
+
*
|
|
375
|
+
* @param {unknown} value
|
|
376
|
+
* @returns {value is RegExp}
|
|
377
|
+
*/
|
|
378
|
+
function isRegExp(value) {
|
|
379
|
+
return types.isRegExp(value);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Is it a `Date`, valid or not? Use `isValidDate` to reject `Invalid Date`.
|
|
384
|
+
*
|
|
385
|
+
* @param {unknown} value
|
|
386
|
+
* @returns {value is Date}
|
|
387
|
+
*/
|
|
388
|
+
function isDate(value) {
|
|
389
|
+
return types.isDate(value);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Is it a `Date` holding a real point in time?
|
|
394
|
+
*
|
|
395
|
+
* @example
|
|
396
|
+
* nc.isValidDate(new Date()); // true
|
|
397
|
+
* nc.isValidDate(new Date("nope")); // false
|
|
398
|
+
*
|
|
399
|
+
* @param {unknown} value
|
|
400
|
+
* @returns {value is Date}
|
|
401
|
+
*/
|
|
402
|
+
function isValidDate(value) {
|
|
403
|
+
return types.isDate(value) && !Number.isNaN(/** @type {Date} */ (value).getTime());
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Is it a `Map`?
|
|
408
|
+
*
|
|
409
|
+
* @param {unknown} value
|
|
410
|
+
* @returns {value is Map<unknown, unknown>}
|
|
411
|
+
*/
|
|
412
|
+
function isMap(value) {
|
|
413
|
+
return types.isMap(value);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Is it a `Set`?
|
|
418
|
+
*
|
|
419
|
+
* @param {unknown} value
|
|
420
|
+
* @returns {value is Set<unknown>}
|
|
421
|
+
*/
|
|
422
|
+
function isSet(value) {
|
|
423
|
+
return types.isSet(value);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Is it a `WeakMap`?
|
|
428
|
+
*
|
|
429
|
+
* @param {unknown} value
|
|
430
|
+
* @returns {value is WeakMap<object, unknown>}
|
|
431
|
+
*/
|
|
432
|
+
function isWeakMap(value) {
|
|
433
|
+
return types.isWeakMap(value);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Is it a `WeakSet`?
|
|
438
|
+
*
|
|
439
|
+
* @param {unknown} value
|
|
440
|
+
* @returns {value is WeakSet<object>}
|
|
441
|
+
*/
|
|
442
|
+
function isWeakSet(value) {
|
|
443
|
+
return types.isWeakSet(value);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Does it work with `for...of`? Strings, arrays, maps, sets and generators do.
|
|
448
|
+
*
|
|
449
|
+
* @param {unknown} value
|
|
450
|
+
* @returns {value is Iterable<unknown>}
|
|
451
|
+
*/
|
|
452
|
+
function isIterable(value) {
|
|
453
|
+
return value != null && typeof (/** @type {any} */ (value))[Symbol.iterator] === "function";
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Does it work with `for await...of`, like streams and async generators?
|
|
458
|
+
*
|
|
459
|
+
* @param {unknown} value
|
|
460
|
+
* @returns {value is AsyncIterable<unknown>}
|
|
461
|
+
*/
|
|
462
|
+
function isAsyncIterable(value) {
|
|
463
|
+
return value != null && typeof (/** @type {any} */ (value))[Symbol.asyncIterator] === "function";
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Is it a Node.js `Buffer`?
|
|
468
|
+
*
|
|
469
|
+
* @param {unknown} value
|
|
470
|
+
* @returns {value is Buffer}
|
|
471
|
+
*/
|
|
472
|
+
function isBuffer(value) {
|
|
473
|
+
return Buffer.isBuffer(value);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* Is it a typed array (`Uint8Array`, `Float64Array`...)? Buffers count.
|
|
478
|
+
*
|
|
479
|
+
* @param {unknown} value
|
|
480
|
+
* @returns {value is AnyTypedArray}
|
|
481
|
+
*/
|
|
482
|
+
function isTypedArray(value) {
|
|
483
|
+
return types.isTypedArray(value);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Is it an `Error`, including subclasses and errors from other realms?
|
|
488
|
+
*
|
|
489
|
+
* @param {unknown} value
|
|
490
|
+
* @returns {value is Error}
|
|
491
|
+
*/
|
|
492
|
+
function isError(value) {
|
|
493
|
+
return types.isNativeError(value) || value instanceof Error;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Is it empty? `null`, `undefined`, `""`, `[]`, `{}` and empty maps and sets
|
|
498
|
+
* are. Numbers, booleans and functions never are.
|
|
499
|
+
*
|
|
500
|
+
* @example
|
|
501
|
+
* nc.isEmpty({}); // true
|
|
502
|
+
* nc.isEmpty(0); // false
|
|
503
|
+
* nc.isEmpty(" "); // false, see isBlank
|
|
504
|
+
*
|
|
505
|
+
* @param {unknown} value
|
|
506
|
+
* @returns {boolean}
|
|
507
|
+
*/
|
|
508
|
+
function isEmpty(value) {
|
|
509
|
+
if (value === null || value === undefined) return true;
|
|
510
|
+
if (typeof value === "string" || Array.isArray(value)) return value.length === 0;
|
|
511
|
+
if (types.isMap(value) || types.isSet(value)) return /** @type {Map<unknown, unknown>} */ (value).size === 0;
|
|
512
|
+
if (typeof value === "object") return Object.keys(value).length === 0;
|
|
513
|
+
return false;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Is it `null`, `undefined`, or a string with nothing but whitespace?
|
|
518
|
+
*
|
|
519
|
+
* @example
|
|
520
|
+
* nc.isBlank(" \n"); // true
|
|
521
|
+
* nc.isBlank(" a "); // false
|
|
522
|
+
*
|
|
523
|
+
* @param {unknown} value
|
|
524
|
+
* @returns {boolean}
|
|
525
|
+
*/
|
|
526
|
+
function isBlank(value) {
|
|
527
|
+
if (value === null || value === undefined) return true;
|
|
528
|
+
return typeof value === "string" && value.trim() === "";
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* Is it an array where every item passes `guard`?
|
|
533
|
+
*
|
|
534
|
+
* @example
|
|
535
|
+
* if (nc.isArrayOf(input, nc.isString)) input.join(", "); // input: string[]
|
|
536
|
+
*
|
|
537
|
+
* @template T
|
|
538
|
+
* @param {unknown} value
|
|
539
|
+
* @param {(item: unknown) => item is T} guard Checked against every item, like `nc.isString`.
|
|
540
|
+
* @returns {value is T[]}
|
|
541
|
+
*/
|
|
542
|
+
function isArrayOf(value, guard) {
|
|
543
|
+
return Array.isArray(value) && value.every((item) => guard(item));
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* Is it one of the allowed values? With a constant list, the value gets the
|
|
548
|
+
* matching literal type.
|
|
549
|
+
*
|
|
550
|
+
* @example
|
|
551
|
+
* const ROLES = ["admin", "user"] as const;
|
|
552
|
+
* if (nc.isOneOf(input, ROLES)) input; // "admin" | "user"
|
|
553
|
+
*
|
|
554
|
+
* @template {readonly unknown[]} L
|
|
555
|
+
* @param {unknown} value
|
|
556
|
+
* @param {L} allowed
|
|
557
|
+
* @returns {value is L[number]}
|
|
558
|
+
*/
|
|
559
|
+
function isOneOf(value, allowed) {
|
|
560
|
+
return allowed.includes(value);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Does it look like an email address? The rules are practical rather than
|
|
565
|
+
* the full RFC: one `@`, no stray dots, a real top-level domain.
|
|
566
|
+
* International addresses are accepted.
|
|
567
|
+
*
|
|
568
|
+
* @example
|
|
569
|
+
* nc.isEmail("jose@exemple.fr"); // true
|
|
570
|
+
* nc.isEmail("john..doe@example.com"); // false
|
|
571
|
+
* nc.isEmail("john@localhost"); // false
|
|
572
|
+
*
|
|
573
|
+
* @param {unknown} value
|
|
574
|
+
* @returns {value is string}
|
|
575
|
+
*/
|
|
576
|
+
function isEmail(value) {
|
|
577
|
+
if (typeof value !== "string" || value.length > 254) return false;
|
|
578
|
+
return /^(?!\.)(?!.*\.\.)[\p{L}\p{N}.!#$%&'*+/=?^_`{|}~-]+(?<!\.)@(?:[\p{L}\p{N}](?:[\p{L}\p{N}-]{0,61}[\p{L}\p{N}])?\.)+\p{L}{2,}$/u.test(value);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* Is it an absolute URL with an allowed protocol (http and https by default)?
|
|
583
|
+
*
|
|
584
|
+
* @example
|
|
585
|
+
* nc.isURL("https://example.com/a?b=1"); // true
|
|
586
|
+
* nc.isURL("ftp://example.com", { protocols: ["ftp:"] }); // true
|
|
587
|
+
* nc.isURL("http://localhost:3000", { requireTld: true }); // false
|
|
588
|
+
*
|
|
589
|
+
* @param {unknown} value
|
|
590
|
+
* @param {IsURLOptions} [options]
|
|
591
|
+
* @returns {value is string}
|
|
592
|
+
*/
|
|
593
|
+
function isURL(value, options = {}) {
|
|
594
|
+
if (typeof value !== "string") return false;
|
|
595
|
+
const protocols = options.protocols ?? ["http:", "https:"];
|
|
596
|
+
try {
|
|
597
|
+
const url = new URL(value);
|
|
598
|
+
if (!protocols.includes(url.protocol)) return false;
|
|
599
|
+
if (options.requireTld && !/\.[a-z]{2,}$/i.test(url.hostname)) return false;
|
|
600
|
+
return true;
|
|
601
|
+
} catch {
|
|
453
602
|
return false;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* Is it a UUID?
|
|
608
|
+
*
|
|
609
|
+
* @example
|
|
610
|
+
* nc.isUUID(nc.id.uuid()); // true
|
|
611
|
+
* nc.isUUID(id, { version: 7 }); // only v7
|
|
612
|
+
*
|
|
613
|
+
* @param {unknown} value
|
|
614
|
+
* @param {IsUUIDOptions} [options]
|
|
615
|
+
* @returns {value is string}
|
|
616
|
+
*/
|
|
617
|
+
function isUUID(value, options = {}) {
|
|
618
|
+
if (typeof value !== "string") return false;
|
|
619
|
+
if (options.version === undefined && /^(0{8}-0{4}-0{4}-0{4}-0{12}|f{8}-f{4}-f{4}-f{4}-f{12})$/i.test(value)) return true;
|
|
620
|
+
const version = options.version === undefined ? "[1-8]" : String(options.version);
|
|
621
|
+
return new RegExp(`^[0-9a-f]{8}-[0-9a-f]{4}-${version}[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$`, "i").test(value);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* Is it a string of valid JSON?
|
|
626
|
+
*
|
|
627
|
+
* @example
|
|
628
|
+
* nc.isJSON('{"a":1}'); // true
|
|
629
|
+
* nc.isJSON("{a:1}"); // false
|
|
630
|
+
*
|
|
631
|
+
* @param {unknown} value
|
|
632
|
+
* @returns {value is string}
|
|
633
|
+
*/
|
|
634
|
+
function isJSON(value) {
|
|
635
|
+
if (typeof value !== "string") return false;
|
|
636
|
+
try {
|
|
637
|
+
JSON.parse(value);
|
|
638
|
+
return true;
|
|
639
|
+
} catch {
|
|
640
|
+
return false;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
/**
|
|
645
|
+
* Is it a finite number, or a string that is exactly one (spaces around are fine)?
|
|
646
|
+
*
|
|
647
|
+
* @example
|
|
648
|
+
* nc.isNumeric("4.2e3"); // true
|
|
649
|
+
* nc.isNumeric(" 12 "); // true
|
|
650
|
+
* nc.isNumeric("12px"); // false
|
|
651
|
+
*
|
|
652
|
+
* @param {unknown} value
|
|
653
|
+
* @returns {value is number | string}
|
|
654
|
+
*/
|
|
655
|
+
function isNumeric(value) {
|
|
656
|
+
if (typeof value === "number") return Number.isFinite(value);
|
|
657
|
+
if (typeof value !== "string" || value.trim() === "") return false;
|
|
658
|
+
return Number.isFinite(Number(value));
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
/**
|
|
662
|
+
* Is it an IP address?
|
|
663
|
+
*
|
|
664
|
+
* @example
|
|
665
|
+
* nc.isIP("192.168.0.1"); // true
|
|
666
|
+
* nc.isIP("::1"); // true
|
|
667
|
+
* nc.isIP("::1", 4); // false
|
|
668
|
+
*
|
|
669
|
+
* @param {unknown} value
|
|
670
|
+
* @param {4|6} [version] Only accept IPv4 or IPv6.
|
|
671
|
+
* @returns {value is string}
|
|
672
|
+
*/
|
|
673
|
+
function isIP(value, version) {
|
|
674
|
+
if (typeof value !== "string") return false;
|
|
675
|
+
const detected = require("node:net").isIP(value);
|
|
676
|
+
return version === undefined ? detected !== 0 : detected === version;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
/**
|
|
680
|
+
* Is it an IPv4 address, like `192.168.0.1`?
|
|
681
|
+
*
|
|
682
|
+
* @param {unknown} value
|
|
683
|
+
* @returns {value is string}
|
|
684
|
+
*/
|
|
685
|
+
function isIPv4(value) {
|
|
686
|
+
return isIP(value, 4);
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
/**
|
|
690
|
+
* Is it an IPv6 address, like `::1`?
|
|
691
|
+
*
|
|
692
|
+
* @param {unknown} value
|
|
693
|
+
* @returns {value is string}
|
|
694
|
+
*/
|
|
695
|
+
function isIPv6(value) {
|
|
696
|
+
return isIP(value, 6);
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* Is it a valid port (0 to 65535), as a number or a numeric string?
|
|
701
|
+
*
|
|
702
|
+
* @example
|
|
703
|
+
* nc.isPort("8080"); // true
|
|
704
|
+
* nc.isPort(70000); // false
|
|
705
|
+
*
|
|
706
|
+
* @param {unknown} value
|
|
707
|
+
* @returns {boolean}
|
|
708
|
+
*/
|
|
709
|
+
function isPort(value) {
|
|
710
|
+
const n = typeof value === "string" && /^\d+$/.test(value.trim()) ? Number(value) : value;
|
|
711
|
+
return Number.isInteger(n) && /** @type {number} */ (n) >= 0 && /** @type {number} */ (n) <= 65535;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
/**
|
|
715
|
+
* Is it a hexadecimal string? A `0x` prefix is allowed.
|
|
716
|
+
*
|
|
717
|
+
* @param {unknown} value
|
|
718
|
+
* @returns {value is string}
|
|
719
|
+
*/
|
|
720
|
+
function isHex(value) {
|
|
721
|
+
return typeof value === "string" && /^(0x)?[0-9a-f]+$/i.test(value);
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
/**
|
|
725
|
+
* Is it a CSS hex color (`#rgb`, `#rgba`, `#rrggbb` or `#rrggbbaa`)?
|
|
726
|
+
*
|
|
727
|
+
* @example
|
|
728
|
+
* nc.isHexColor("#f80"); // true
|
|
729
|
+
* nc.isHexColor("f80"); // false, the # is required
|
|
730
|
+
*
|
|
731
|
+
* @param {unknown} value
|
|
732
|
+
* @returns {value is string}
|
|
733
|
+
*/
|
|
734
|
+
function isHexColor(value) {
|
|
735
|
+
return typeof value === "string" && /^#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(value);
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
/**
|
|
739
|
+
* Is it valid Base64?
|
|
740
|
+
*
|
|
741
|
+
* @example
|
|
742
|
+
* nc.isBase64("aGVsbG8="); // true
|
|
743
|
+
* nc.isBase64("aGVsbG8", { urlSafe: true }); // true
|
|
744
|
+
*
|
|
745
|
+
* @param {unknown} value
|
|
746
|
+
* @param {IsBase64Options} [options]
|
|
747
|
+
* @returns {value is string}
|
|
748
|
+
*/
|
|
749
|
+
function isBase64(value, options = {}) {
|
|
750
|
+
if (typeof value !== "string" || value === "") return false;
|
|
751
|
+
if (options.urlSafe) return /^[A-Za-z0-9_-]+={0,2}$/.test(value) && value.replace(/=+$/, "").length % 4 !== 1;
|
|
752
|
+
return value.length % 4 === 0 && /^[A-Za-z0-9+/]+={0,2}$/.test(value);
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
/**
|
|
756
|
+
* Is it a semantic version? A leading `v` is fine.
|
|
757
|
+
*
|
|
758
|
+
* @example
|
|
759
|
+
* nc.isSemver("v2.0.0-rc.1"); // true
|
|
760
|
+
* nc.isSemver("1.2"); // false
|
|
761
|
+
*
|
|
762
|
+
* @param {unknown} value
|
|
763
|
+
* @returns {value is string}
|
|
764
|
+
*/
|
|
765
|
+
function isSemver(value) {
|
|
766
|
+
return (
|
|
767
|
+
typeof value === "string" &&
|
|
768
|
+
/^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/.test(value)
|
|
769
|
+
);
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
/**
|
|
773
|
+
* Is it an ISO 8601 date or date-time, and a real calendar date?
|
|
774
|
+
*
|
|
775
|
+
* @example
|
|
776
|
+
* nc.isISODate("2024-02-29T10:00:00Z"); // true
|
|
777
|
+
* nc.isISODate("2023-02-29"); // false, not a leap year
|
|
778
|
+
*
|
|
779
|
+
* @param {unknown} value
|
|
780
|
+
* @returns {value is string}
|
|
781
|
+
*/
|
|
782
|
+
function isISODate(value) {
|
|
783
|
+
if (typeof value !== "string") return false;
|
|
784
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.\d{1,9})?)?(Z|[+-]\d{2}:?\d{2})?)?$/.exec(value);
|
|
785
|
+
if (!match) return false;
|
|
786
|
+
const [, y, m, d, hh = "0", mm = "0", ss = "0"] = match;
|
|
787
|
+
const year = Number(y);
|
|
788
|
+
const month = Number(m);
|
|
789
|
+
const day = Number(d);
|
|
790
|
+
if (month < 1 || month > 12 || day < 1) return false;
|
|
791
|
+
const daysInMonth = new Date(Date.UTC(year, month, 0)).getUTCDate();
|
|
792
|
+
return day <= daysInMonth && Number(hh) <= 23 && Number(mm) <= 59 && Number(ss) <= 59;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
/**
|
|
796
|
+
* Is it a URL slug like `my-first-post`? See `nc.str.slugify()` to make one.
|
|
797
|
+
*
|
|
798
|
+
* @param {unknown} value
|
|
799
|
+
* @returns {value is string}
|
|
800
|
+
*/
|
|
801
|
+
function isSlug(value) {
|
|
802
|
+
return typeof value === "string" && /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(value);
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
/**
|
|
806
|
+
* Is it made only of letters, in any alphabet?
|
|
807
|
+
*
|
|
808
|
+
* @example
|
|
809
|
+
* nc.isAlpha("Élodie"); // true
|
|
810
|
+
* nc.isAlpha("abc1"); // false
|
|
811
|
+
*
|
|
812
|
+
* @param {unknown} value
|
|
813
|
+
* @returns {value is string}
|
|
814
|
+
*/
|
|
815
|
+
function isAlpha(value) {
|
|
816
|
+
return typeof value === "string" && /^\p{L}+$/u.test(value);
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
/**
|
|
820
|
+
* Is it made only of letters and digits, in any alphabet?
|
|
821
|
+
*
|
|
822
|
+
* @param {unknown} value
|
|
823
|
+
* @returns {value is string}
|
|
824
|
+
*/
|
|
825
|
+
function isAlphanumeric(value) {
|
|
826
|
+
return typeof value === "string" && /^[\p{L}\p{N}]+$/u.test(value);
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
/**
|
|
830
|
+
* Could it be a card number? Checks the length and the Luhn checksum;
|
|
831
|
+
* spaces and dashes are ignored.
|
|
832
|
+
*
|
|
833
|
+
* @example
|
|
834
|
+
* nc.isCreditCard("4242 4242 4242 4242"); // true
|
|
835
|
+
*
|
|
836
|
+
* @param {unknown} value
|
|
837
|
+
* @returns {value is string}
|
|
838
|
+
*/
|
|
839
|
+
function isCreditCard(value) {
|
|
840
|
+
if (typeof value !== "string") return false;
|
|
841
|
+
const digits = value.replace(/[\s-]/g, "");
|
|
842
|
+
if (!/^\d{12,19}$/.test(digits)) return false;
|
|
843
|
+
let sum = 0;
|
|
844
|
+
let double = false;
|
|
845
|
+
for (let i = digits.length - 1; i >= 0; i--) {
|
|
846
|
+
let digit = digits.charCodeAt(i) - 48;
|
|
847
|
+
if (double) {
|
|
848
|
+
digit *= 2;
|
|
849
|
+
if (digit > 9) digit -= 9;
|
|
527
850
|
}
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
851
|
+
sum += digit;
|
|
852
|
+
double = !double;
|
|
853
|
+
}
|
|
854
|
+
return sum % 10 === 0;
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
/**
|
|
858
|
+
* Does it look like a JSON Web Token? The signature is not verified; use
|
|
859
|
+
* `nc.crypto.verifyJWT()` for that.
|
|
860
|
+
*
|
|
861
|
+
* @param {unknown} value
|
|
862
|
+
* @returns {value is string}
|
|
863
|
+
*/
|
|
864
|
+
function isJWT(value) {
|
|
865
|
+
if (typeof value !== "string") return false;
|
|
866
|
+
const parts = value.split(".");
|
|
867
|
+
if (parts.length !== 3 || !parts.slice(0, 2).every((p) => /^[A-Za-z0-9_-]+$/.test(p))) return false;
|
|
868
|
+
if (parts[2] !== "" && !/^[A-Za-z0-9_-]+$/.test(parts[2])) return false;
|
|
869
|
+
try {
|
|
870
|
+
const header = JSON.parse(Buffer.from(parts[0], "base64url").toString("utf8"));
|
|
871
|
+
return isPlainObject(header) && typeof header.alg === "string";
|
|
872
|
+
} catch {
|
|
873
|
+
return false;
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
/**
|
|
878
|
+
* Throws an `AssertionError` if `condition` is falsy. Afterwards, TypeScript
|
|
879
|
+
* knows the condition holds.
|
|
880
|
+
*
|
|
881
|
+
* @example
|
|
882
|
+
* const user = users.find((u) => u.id === id);
|
|
883
|
+
* nc.assert(user, `User ${id} not found`);
|
|
884
|
+
* user.name; // no "possibly undefined" here
|
|
885
|
+
*
|
|
886
|
+
* @param {unknown} condition
|
|
887
|
+
* @param {string | (() => string)} [message="Assertion failed"] A message, or a function that builds it.
|
|
888
|
+
* @returns {asserts condition}
|
|
889
|
+
* @throws {AssertionError}
|
|
890
|
+
*/
|
|
891
|
+
function assert(condition, message = "Assertion failed") {
|
|
892
|
+
if (!condition) throw new (require("./errors.js").AssertionError)(typeof message === "function" ? message() : message);
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
/**
|
|
896
|
+
* Throws an `AssertionError` unless `value` passes `guard`. Afterwards,
|
|
897
|
+
* `value` has the guarded type.
|
|
898
|
+
*
|
|
899
|
+
* @example
|
|
900
|
+
* nc.assertType(config.port, nc.isInteger, "port must be an integer");
|
|
901
|
+
*
|
|
902
|
+
* @template T
|
|
903
|
+
* @param {unknown} value
|
|
904
|
+
* @param {(value: unknown) => value is T} guard A check like `nc.isString`.
|
|
905
|
+
* @param {string | (() => string)} [message]
|
|
906
|
+
* @returns {asserts value is T}
|
|
907
|
+
* @throws {AssertionError}
|
|
908
|
+
*/
|
|
909
|
+
function assertType(value, guard, message) {
|
|
910
|
+
if (!guard(value)) {
|
|
911
|
+
const text = typeof message === "function" ? message() : message;
|
|
912
|
+
throw new (require("./errors.js").AssertionError)(text ?? `Expected value to pass ${guard.name || "the type guard"}`);
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
module.exports = {
|
|
917
|
+
isArray,
|
|
918
|
+
isNumber,
|
|
919
|
+
isFinite,
|
|
920
|
+
isInteger,
|
|
921
|
+
isSafeInteger,
|
|
922
|
+
isFloat,
|
|
923
|
+
isPositive,
|
|
924
|
+
isNegative,
|
|
925
|
+
isBoolean,
|
|
926
|
+
isString,
|
|
927
|
+
isSymbol,
|
|
928
|
+
isBigInt,
|
|
929
|
+
isUndefined,
|
|
930
|
+
isNull,
|
|
931
|
+
isNil,
|
|
932
|
+
isDefined,
|
|
933
|
+
isPrimitive,
|
|
934
|
+
isFunction,
|
|
935
|
+
isAsyncFunction,
|
|
936
|
+
isGeneratorFunction,
|
|
937
|
+
isGenerator,
|
|
938
|
+
isClass,
|
|
939
|
+
isObject,
|
|
940
|
+
isPlainObject,
|
|
941
|
+
isPromise,
|
|
942
|
+
isRegExp,
|
|
943
|
+
isDate,
|
|
944
|
+
isValidDate,
|
|
945
|
+
isMap,
|
|
946
|
+
isSet,
|
|
947
|
+
isWeakMap,
|
|
948
|
+
isWeakSet,
|
|
949
|
+
isIterable,
|
|
950
|
+
isAsyncIterable,
|
|
951
|
+
isBuffer,
|
|
952
|
+
isTypedArray,
|
|
953
|
+
isError,
|
|
954
|
+
isEmpty,
|
|
955
|
+
isBlank,
|
|
956
|
+
isArrayOf,
|
|
957
|
+
isOneOf,
|
|
958
|
+
isEmail,
|
|
959
|
+
isURL,
|
|
960
|
+
isUUID,
|
|
961
|
+
isJSON,
|
|
962
|
+
isNumeric,
|
|
963
|
+
isIP,
|
|
964
|
+
isIPv4,
|
|
965
|
+
isIPv6,
|
|
966
|
+
isPort,
|
|
967
|
+
isHex,
|
|
968
|
+
isHexColor,
|
|
969
|
+
isBase64,
|
|
970
|
+
isSemver,
|
|
971
|
+
isISODate,
|
|
972
|
+
isSlug,
|
|
973
|
+
isAlpha,
|
|
974
|
+
isAlphanumeric,
|
|
975
|
+
isCreditCard,
|
|
976
|
+
isJWT,
|
|
977
|
+
assert,
|
|
978
|
+
assertType,
|
|
547
979
|
};
|