@ix-xs/node-comfort 1.1.31 → 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.
Files changed (77) hide show
  1. package/CHANGELOG.md +190 -0
  2. package/LICENSE +21 -0
  3. package/README.md +210 -748
  4. package/index.js +84 -13
  5. package/package.json +201 -21
  6. package/src/Arr.js +901 -0
  7. package/src/Async.js +585 -0
  8. package/src/Cache.js +329 -0
  9. package/src/Checker.js +979 -188
  10. package/src/Cli.js +1034 -0
  11. package/src/Color.js +415 -0
  12. package/src/Crypto.js +707 -0
  13. package/src/Emitter.js +289 -0
  14. package/src/Env.js +555 -0
  15. package/src/FS.js +1483 -768
  16. package/src/Func.js +692 -0
  17. package/src/Http.js +538 -0
  18. package/src/Id.js +418 -0
  19. package/src/Logger.js +739 -307
  20. package/src/Num.js +849 -0
  21. package/src/Obj.js +904 -0
  22. package/src/SQLite.js +1308 -994
  23. package/src/Schema.js +1586 -0
  24. package/src/Str.js +999 -0
  25. package/src/Sys.js +511 -0
  26. package/src/Time.js +1323 -0
  27. package/src/Utils.js +321 -325
  28. package/src/errors.js +292 -0
  29. package/types/index.d.ts +693 -120
  30. package/types/src/Arr.d.ts +562 -0
  31. package/types/src/Arr.d.ts.map +1 -0
  32. package/types/src/Async.d.ts +321 -0
  33. package/types/src/Async.d.ts.map +1 -0
  34. package/types/src/Cache.d.ts +195 -0
  35. package/types/src/Cache.d.ts.map +1 -0
  36. package/types/src/Checker.d.ts +609 -81
  37. package/types/src/Checker.d.ts.map +1 -1
  38. package/types/src/Cli.d.ts +582 -0
  39. package/types/src/Cli.d.ts.map +1 -0
  40. package/types/src/Color.d.ts +294 -0
  41. package/types/src/Color.d.ts.map +1 -0
  42. package/types/src/Crypto.d.ts +534 -0
  43. package/types/src/Crypto.d.ts.map +1 -0
  44. package/types/src/Emitter.d.ts +170 -0
  45. package/types/src/Emitter.d.ts.map +1 -0
  46. package/types/src/Env.d.ts +382 -0
  47. package/types/src/Env.d.ts.map +1 -0
  48. package/types/src/FS.d.ts +709 -201
  49. package/types/src/FS.d.ts.map +1 -1
  50. package/types/src/Func.d.ts +455 -0
  51. package/types/src/Func.d.ts.map +1 -0
  52. package/types/src/Http.d.ts +374 -0
  53. package/types/src/Http.d.ts.map +1 -0
  54. package/types/src/Id.d.ts +200 -0
  55. package/types/src/Id.d.ts.map +1 -0
  56. package/types/src/Logger.d.ts +374 -24
  57. package/types/src/Logger.d.ts.map +1 -1
  58. package/types/src/Num.d.ts +578 -0
  59. package/types/src/Num.d.ts.map +1 -0
  60. package/types/src/Obj.d.ts +475 -0
  61. package/types/src/Obj.d.ts.map +1 -0
  62. package/types/src/SQLite.d.ts +647 -305
  63. package/types/src/SQLite.d.ts.map +1 -1
  64. package/types/src/Schema.d.ts +940 -0
  65. package/types/src/Schema.d.ts.map +1 -0
  66. package/types/src/Str.d.ts +696 -0
  67. package/types/src/Str.d.ts.map +1 -0
  68. package/types/src/Sys.d.ts +269 -0
  69. package/types/src/Sys.d.ts.map +1 -0
  70. package/types/src/Time.d.ts +664 -0
  71. package/types/src/Time.d.ts.map +1 -0
  72. package/types/src/Utils.d.ts +154 -102
  73. package/types/src/Utils.d.ts.map +1 -1
  74. package/types/src/errors.d.ts +292 -0
  75. package/types/src/errors.d.ts.map +1 -0
  76. package/tsconfig.json +0 -18
  77. package/types/index.d.ts.map +0 -1
package/src/Checker.js CHANGED
@@ -1,188 +1,979 @@
1
- const { types } = require("node:util");
2
-
3
- /**
4
- * Tiny runtime type-checking helper.
5
- *
6
- * All methods are simple boolean guards that work on any input value.
7
- */
8
- module.exports = {
9
- /**
10
- * Checks if a value is a real Array.
11
- *
12
- * @example
13
- * nodeComfort.Checker.isArray([1, 2, 3]); // true
14
- * nodeComfort.Checker.isArray("not array"); // false
15
- *
16
- * @param {*} value - Value to check.
17
- * @returns {boolean} True if the value is an Array.
18
- */
19
- isArray(value) {
20
- return Array.isArray(value);
21
- },
22
-
23
- /**
24
- * Checks if a value is a number (excluding NaN).
25
- *
26
- * @example
27
- * nodeComfort.Checker.isNumber(42); // true
28
- * nodeComfort.Checker.isNumber(NaN); // false
29
- * nodeComfort.Checker.isNumber("42"); // false
30
- *
31
- * @param {*} value - Value to check.
32
- * @returns {boolean} True if the value is a finite number or Infinity/-Infinity.
33
- */
34
- isNumber(value) {
35
- return typeof value === "number" && !Number.isNaN(value);
36
- },
37
-
38
- /**
39
- * Checks if a value is a function.
40
- *
41
- * @example
42
- * nodeComfort.Checker.isFunction(() => {}); // true
43
- * nodeComfort.Checker.isFunction(class {}); // true
44
- * nodeComfort.Checker.isFunction("fn"); // false
45
- *
46
- * @param {*} value - Value to check.
47
- * @returns {boolean} True if the value is a function.
48
- */
49
- isFunction(value) {
50
- return typeof value === "function";
51
- },
52
-
53
- /**
54
- * Checks if a value is a non-null object.
55
- *
56
- * Note: Arrays, Maps, Sets, Dates, etc. are also considered objects here.
57
- *
58
- * @example
59
- * nodeComfort.Checker.isObject({}); // true
60
- * nodeComfort.Checker.isObject([]); // true
61
- * nodeComfort.Checker.isObject(null); // false
62
- * nodeComfort.Checker.isObject("str"); // false
63
- *
64
- * @param {*} value - Value to check.
65
- * @returns {boolean} True if the value is a non-null object.
66
- */
67
- isObject(value) {
68
- return typeof value === "object" && value !== null;
69
- },
70
-
71
- /**
72
- * Checks if a value is a boolean.
73
- *
74
- * @example
75
- * nodeComfort.Checker.isBoolean(true); // true
76
- * nodeComfort.Checker.isBoolean(false); // true
77
- * nodeComfort.Checker.isBoolean(0); // false
78
- *
79
- * @param {*} value - Value to check.
80
- * @returns {boolean} True if the value is a boolean.
81
- */
82
- isBoolean(value) {
83
- return typeof value === "boolean";
84
- },
85
-
86
- /**
87
- * Checks if a value is a string.
88
- *
89
- * @example
90
- * nodeComfort.Checker.isString("hello"); // true
91
- * nodeComfort.Checker.isString(123); // false
92
- *
93
- * @param {*} value - Value to check.
94
- * @returns {boolean} True if the value is a string.
95
- */
96
- isString(value) {
97
- return typeof value === "string";
98
- },
99
-
100
- /**
101
- * Checks if a value is exactly undefined.
102
- *
103
- * @example
104
- * nodeComfort.Checker.isUndefined(undefined); // true
105
- * nodeComfort.Checker.isUndefined(null); // false
106
- *
107
- * @param {*} value - Value to check.
108
- * @returns {boolean} True if the value is undefined.
109
- */
110
- isUndefined(value) {
111
- return typeof value === "undefined";
112
- },
113
-
114
- /**
115
- * Checks if a value is exactly null.
116
- *
117
- * @example
118
- * nodeComfort.Checker.isNull(null); // true
119
- * nodeComfort.Checker.isNull(undefined); // false
120
- *
121
- * @param {*} value - Value to check.
122
- * @returns {boolean} True if the value is null.
123
- */
124
- isNull(value) {
125
- return value === null;
126
- },
127
-
128
- /**
129
- * Checks if a value is a built-in Date instance.
130
- *
131
- * Uses `util.types.isDate` under the hood to handle cross-realm Dates.
132
- *
133
- * @example
134
- * nodeComfort.Checker.isDate(new Date()); // true
135
- * nodeComfort.Checker.isDate("2024-01-01"); // false
136
- *
137
- * @param {*} value - Value to check.
138
- * @returns {boolean} True if the value is a Date instance.
139
- */
140
- isDate(value) {
141
- return types.isDate(value);
142
- },
143
-
144
- /**
145
- * Checks if a value is a built-in Map instance.
146
- *
147
- * @example
148
- * nodeComfort.Checker.isMap(new Map()); // true
149
- * nodeComfort.Checker.isMap({}); // false
150
- *
151
- * @param {*} value - Value to check.
152
- * @returns {boolean} True if the value is a Map.
153
- */
154
- isMap(value) {
155
- return types.isMap(value);
156
- },
157
-
158
- /**
159
- * Checks if a value is a built-in Set instance.
160
- *
161
- * @example
162
- * nodeComfort.Checker.isSet(new Set()); // true
163
- * nodeComfort.Checker.isSet([]); // false
164
- *
165
- * @param {*} value - Value to check.
166
- * @returns {boolean} True if the value is a Set.
167
- */
168
- isSet(value) {
169
- return types.isSet(value);
170
- },
171
-
172
- /**
173
- * Checks if a value is a native Error instance.
174
- *
175
- * Uses `util.types.isNativeError` to correctly handle errors from other realms.
176
- *
177
- * @example
178
- * nodeComfort.Checker.isError(new Error("x")); // true
179
- * nodeComfort.Checker.isError(new TypeError("x")); // true
180
- * nodeComfort.Checker.isError({ message: "x" }); // false
181
- *
182
- * @param {*} value - Value to check.
183
- * @returns {boolean} True if the value is a native Error.
184
- */
185
- isError(value) {
186
- return types.isNativeError(value);
187
- },
188
- };
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
+
13
+ const { types } = require("node:util");
14
+
15
+ /**
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?
46
+ *
47
+ * @example
48
+ * nc.isArray([1, 2]); // true
49
+ * nc.isArray({ length: 0 }); // false
50
+ *
51
+ * @param {unknown} value
52
+ * @returns {value is any[]}
53
+ */
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 {
602
+ return false;
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;
850
+ }
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,
979
+ };