@ix-xs/node-comfort 1.1.3 → 1.2.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/src/Checker.js CHANGED
@@ -1,188 +1,547 @@
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
+ const { types } = require("node:util");
2
+
3
+ /**
4
+ * Runtime type-checking helper.
5
+ *
6
+ * Every method is a small boolean guard that works on any input value.
7
+ * The goal is to replace the noisy, error-prone `typeof` / `instanceof`
8
+ * checks you write over and over with a single, readable call.
9
+ */
10
+ module.exports = {
11
+ /**
12
+ * Checks if a value is a real Array.
13
+ *
14
+ * @example
15
+ * nodeComfort.isArray([1, 2, 3]); // true
16
+ * nodeComfort.isArray("not array"); // false
17
+ *
18
+ * @param {*} value - Value to check.
19
+ * @returns {boolean} True if the value is an Array.
20
+ */
21
+ isArray(value) {
22
+ return Array.isArray(value);
23
+ },
24
+
25
+ /**
26
+ * Checks if a value is a number (excluding NaN).
27
+ *
28
+ * @example
29
+ * nodeComfort.isNumber(42); // true
30
+ * nodeComfort.isNumber(NaN); // false
31
+ * nodeComfort.isNumber("42"); // false
32
+ *
33
+ * @param {*} value - Value to check.
34
+ * @returns {boolean} True if the value is a finite number or Infinity/-Infinity.
35
+ */
36
+ isNumber(value) {
37
+ return typeof value === "number" && !Number.isNaN(value);
38
+ },
39
+
40
+ /**
41
+ * Checks if a value is a finite number (excludes NaN, Infinity and -Infinity).
42
+ *
43
+ * @example
44
+ * nodeComfort.isFinite(42); // true
45
+ * nodeComfort.isFinite(Infinity); // false
46
+ *
47
+ * @param {*} value - Value to check.
48
+ * @returns {boolean} True if the value is a finite number.
49
+ */
50
+ isFinite(value) {
51
+ return typeof value === "number" && Number.isFinite(value);
52
+ },
53
+
54
+ /**
55
+ * Checks if a value is a safe integer.
56
+ *
57
+ * @example
58
+ * nodeComfort.isInteger(42); // true
59
+ * nodeComfort.isInteger(4.2); // false
60
+ *
61
+ * @param {*} value - Value to check.
62
+ * @returns {boolean} True if the value is an integer.
63
+ */
64
+ isInteger(value) {
65
+ return Number.isInteger(value);
66
+ },
67
+
68
+ /**
69
+ * Checks if a value is a floating-point number (a finite non-integer number).
70
+ *
71
+ * @example
72
+ * nodeComfort.isFloat(4.2); // true
73
+ * nodeComfort.isFloat(4); // false
74
+ *
75
+ * @param {*} value - Value to check.
76
+ * @returns {boolean} True if the value is a non-integer finite number.
77
+ */
78
+ isFloat(value) {
79
+ return typeof value === "number" && Number.isFinite(value) && !Number.isInteger(value);
80
+ },
81
+
82
+ /**
83
+ * Checks if a value is a function.
84
+ *
85
+ * @example
86
+ * nodeComfort.isFunction(() => {}); // true
87
+ * nodeComfort.isFunction(class {}); // true
88
+ * nodeComfort.isFunction("fn"); // false
89
+ *
90
+ * @param {*} value - Value to check.
91
+ * @returns {boolean} True if the value is a function.
92
+ */
93
+ isFunction(value) {
94
+ return typeof value === "function";
95
+ },
96
+
97
+ /**
98
+ * Checks if a value is an async function (declared with `async`).
99
+ *
100
+ * @example
101
+ * nodeComfort.isAsyncFunction(async () => {}); // true
102
+ * nodeComfort.isAsyncFunction(() => {}); // false
103
+ *
104
+ * @param {*} value - Value to check.
105
+ * @returns {boolean} True if the value is an async function.
106
+ */
107
+ isAsyncFunction(value) {
108
+ return types.isAsyncFunction(value);
109
+ },
110
+
111
+ /**
112
+ * Checks if a value is a non-null object.
113
+ *
114
+ * Note: Arrays, Maps, Sets, Dates, etc. are also considered objects here.
115
+ *
116
+ * @example
117
+ * nodeComfort.isObject({}); // true
118
+ * nodeComfort.isObject([]); // true
119
+ * nodeComfort.isObject(null); // false
120
+ * nodeComfort.isObject("str"); // false
121
+ *
122
+ * @param {*} value - Value to check.
123
+ * @returns {boolean} True if the value is a non-null object.
124
+ */
125
+ isObject(value) {
126
+ return typeof value === "object" && value !== null;
127
+ },
128
+
129
+ /**
130
+ * Checks if a value is a plain object (created via `{}` or `new Object()`).
131
+ *
132
+ * Unlike {@link isObject}, this excludes arrays, Maps, Dates, class instances, etc.
133
+ *
134
+ * @example
135
+ * nodeComfort.isPlainObject({ a: 1 }); // true
136
+ * nodeComfort.isPlainObject([]); // false
137
+ * nodeComfort.isPlainObject(new Date()); // false
138
+ *
139
+ * @param {*} value - Value to check.
140
+ * @returns {boolean} True if the value is a plain object.
141
+ */
142
+ isPlainObject(value) {
143
+ if (typeof value !== "object" || value === null) return false;
144
+ const proto = Object.getPrototypeOf(value);
145
+ return proto === null || proto === Object.prototype;
146
+ },
147
+
148
+ /**
149
+ * Checks if a value is a boolean.
150
+ *
151
+ * @example
152
+ * nodeComfort.isBoolean(true); // true
153
+ * nodeComfort.isBoolean(false); // true
154
+ * nodeComfort.isBoolean(0); // false
155
+ *
156
+ * @param {*} value - Value to check.
157
+ * @returns {boolean} True if the value is a boolean.
158
+ */
159
+ isBoolean(value) {
160
+ return typeof value === "boolean";
161
+ },
162
+
163
+ /**
164
+ * Checks if a value is a string.
165
+ *
166
+ * @example
167
+ * nodeComfort.isString("hello"); // true
168
+ * nodeComfort.isString(123); // false
169
+ *
170
+ * @param {*} value - Value to check.
171
+ * @returns {boolean} True if the value is a string.
172
+ */
173
+ isString(value) {
174
+ return typeof value === "string";
175
+ },
176
+
177
+ /**
178
+ * Checks if a value is a symbol.
179
+ *
180
+ * @example
181
+ * nodeComfort.isSymbol(Symbol("x")); // true
182
+ *
183
+ * @param {*} value - Value to check.
184
+ * @returns {boolean} True if the value is a symbol.
185
+ */
186
+ isSymbol(value) {
187
+ return typeof value === "symbol";
188
+ },
189
+
190
+ /**
191
+ * Checks if a value is a BigInt.
192
+ *
193
+ * @example
194
+ * nodeComfort.isBigInt(10n); // true
195
+ * nodeComfort.isBigInt(10); // false
196
+ *
197
+ * @param {*} value - Value to check.
198
+ * @returns {boolean} True if the value is a BigInt.
199
+ */
200
+ isBigInt(value) {
201
+ return typeof value === "bigint";
202
+ },
203
+
204
+ /**
205
+ * Checks if a value is exactly undefined.
206
+ *
207
+ * @example
208
+ * nodeComfort.isUndefined(undefined); // true
209
+ * nodeComfort.isUndefined(null); // false
210
+ *
211
+ * @param {*} value - Value to check.
212
+ * @returns {boolean} True if the value is undefined.
213
+ */
214
+ isUndefined(value) {
215
+ return typeof value === "undefined";
216
+ },
217
+
218
+ /**
219
+ * Checks if a value is exactly null.
220
+ *
221
+ * @example
222
+ * nodeComfort.isNull(null); // true
223
+ * nodeComfort.isNull(undefined); // false
224
+ *
225
+ * @param {*} value - Value to check.
226
+ * @returns {boolean} True if the value is null.
227
+ */
228
+ isNull(value) {
229
+ return value === null;
230
+ },
231
+
232
+ /**
233
+ * Checks if a value is `null` or `undefined`.
234
+ *
235
+ * @example
236
+ * nodeComfort.isNil(null); // true
237
+ * nodeComfort.isNil(undefined); // true
238
+ * nodeComfort.isNil(0); // false
239
+ *
240
+ * @param {*} value - Value to check.
241
+ * @returns {boolean} True if the value is null or undefined.
242
+ */
243
+ isNil(value) {
244
+ return value === null || value === undefined;
245
+ },
246
+
247
+ /**
248
+ * Checks if a value is a primitive (string, number, boolean, symbol, bigint, null or undefined).
249
+ *
250
+ * @example
251
+ * nodeComfort.isPrimitive(42); // true
252
+ * nodeComfort.isPrimitive({}); // false
253
+ *
254
+ * @param {*} value - Value to check.
255
+ * @returns {boolean} True if the value is a primitive.
256
+ */
257
+ isPrimitive(value) {
258
+ return value === null || (typeof value !== "object" && typeof value !== "function");
259
+ },
260
+
261
+ /**
262
+ * Checks if a value is a Promise (or a thenable object).
263
+ *
264
+ * @example
265
+ * nodeComfort.isPromise(Promise.resolve()); // true
266
+ * nodeComfort.isPromise({ then() {} }); // true
267
+ * nodeComfort.isPromise(42); // false
268
+ *
269
+ * @param {*} value - Value to check.
270
+ * @returns {boolean} True if the value is a Promise or thenable.
271
+ */
272
+ isPromise(value) {
273
+ return (
274
+ types.isPromise(value) ||
275
+ (value !== null &&
276
+ (typeof value === "object" || typeof value === "function") &&
277
+ typeof value.then === "function")
278
+ );
279
+ },
280
+
281
+ /**
282
+ * Checks if a value is a RegExp instance.
283
+ *
284
+ * @example
285
+ * nodeComfort.isRegExp(/a/); // true
286
+ * nodeComfort.isRegExp("a"); // false
287
+ *
288
+ * @param {*} value - Value to check.
289
+ * @returns {boolean} True if the value is a RegExp.
290
+ */
291
+ isRegExp(value) {
292
+ return types.isRegExp(value);
293
+ },
294
+
295
+ /**
296
+ * Checks if a value is a built-in Date instance.
297
+ *
298
+ * Uses `util.types.isDate` under the hood to handle cross-realm Dates.
299
+ *
300
+ * @example
301
+ * nodeComfort.isDate(new Date()); // true
302
+ * nodeComfort.isDate("2024-01-01"); // false
303
+ *
304
+ * @param {*} value - Value to check.
305
+ * @returns {boolean} True if the value is a Date instance.
306
+ */
307
+ isDate(value) {
308
+ return types.isDate(value);
309
+ },
310
+
311
+ /**
312
+ * Checks if a value is a **valid** Date (a Date instance that is not `Invalid Date`).
313
+ *
314
+ * @example
315
+ * nodeComfort.isValidDate(new Date()); // true
316
+ * nodeComfort.isValidDate(new Date("nope")); // false
317
+ *
318
+ * @param {*} value - Value to check.
319
+ * @returns {boolean} True if the value is a valid Date.
320
+ */
321
+ isValidDate(value) {
322
+ return types.isDate(value) && !Number.isNaN(value.getTime());
323
+ },
324
+
325
+ /**
326
+ * Checks if a value is a built-in Map instance.
327
+ *
328
+ * @example
329
+ * nodeComfort.isMap(new Map()); // true
330
+ * nodeComfort.isMap({}); // false
331
+ *
332
+ * @param {*} value - Value to check.
333
+ * @returns {boolean} True if the value is a Map.
334
+ */
335
+ isMap(value) {
336
+ return types.isMap(value);
337
+ },
338
+
339
+ /**
340
+ * Checks if a value is a built-in Set instance.
341
+ *
342
+ * @example
343
+ * nodeComfort.isSet(new Set()); // true
344
+ * nodeComfort.isSet([]); // false
345
+ *
346
+ * @param {*} value - Value to check.
347
+ * @returns {boolean} True if the value is a Set.
348
+ */
349
+ isSet(value) {
350
+ return types.isSet(value);
351
+ },
352
+
353
+ /**
354
+ * Checks if a value is a WeakMap instance.
355
+ *
356
+ * @param {*} value - Value to check.
357
+ * @returns {boolean} True if the value is a WeakMap.
358
+ */
359
+ isWeakMap(value) {
360
+ return types.isWeakMap(value);
361
+ },
362
+
363
+ /**
364
+ * Checks if a value is a WeakSet instance.
365
+ *
366
+ * @param {*} value - Value to check.
367
+ * @returns {boolean} True if the value is a WeakSet.
368
+ */
369
+ isWeakSet(value) {
370
+ return types.isWeakSet(value);
371
+ },
372
+
373
+ /**
374
+ * Checks if a value is an iterable (has a `Symbol.iterator`).
375
+ *
376
+ * Strings, arrays, Maps, Sets and generators are iterable.
377
+ *
378
+ * @example
379
+ * nodeComfort.isIterable([1, 2]); // true
380
+ * nodeComfort.isIterable("hi"); // true
381
+ * nodeComfort.isIterable({}); // false
382
+ *
383
+ * @param {*} value - Value to check.
384
+ * @returns {boolean} True if the value is iterable.
385
+ */
386
+ isIterable(value) {
387
+ return value != null && typeof value[Symbol.iterator] === "function";
388
+ },
389
+
390
+ /**
391
+ * Checks if a value is a Node.js Buffer.
392
+ *
393
+ * @param {*} value - Value to check.
394
+ * @returns {boolean} True if the value is a Buffer.
395
+ */
396
+ isBuffer(value) {
397
+ return Buffer.isBuffer(value);
398
+ },
399
+
400
+ /**
401
+ * Checks if a value is any TypedArray (Uint8Array, Float64Array, etc.).
402
+ *
403
+ * @param {*} value - Value to check.
404
+ * @returns {boolean} True if the value is a TypedArray.
405
+ */
406
+ isTypedArray(value) {
407
+ return types.isTypedArray(value);
408
+ },
409
+
410
+ /**
411
+ * Checks if a value is a native Error instance.
412
+ *
413
+ * Uses `util.types.isNativeError` to correctly handle errors from other realms.
414
+ *
415
+ * @example
416
+ * nodeComfort.isError(new Error("x")); // true
417
+ * nodeComfort.isError(new TypeError("x")); // true
418
+ * nodeComfort.isError({ message: "x" }); // false
419
+ *
420
+ * @param {*} value - Value to check.
421
+ * @returns {boolean} True if the value is a native Error.
422
+ */
423
+ isError(value) {
424
+ return types.isNativeError(value);
425
+ },
426
+
427
+ /**
428
+ * Checks if a value is "empty".
429
+ *
430
+ * Emptiness rules:
431
+ * - `null` / `undefined` -> empty
432
+ * - string / array -> empty when `length === 0`
433
+ * - Map / Set -> empty when `size === 0`
434
+ * - plain object -> empty when it has no own enumerable keys
435
+ * - anything else (numbers, booleans, functions, ...) -> never empty
436
+ *
437
+ * @example
438
+ * nodeComfort.isEmpty(""); // true
439
+ * nodeComfort.isEmpty([]); // true
440
+ * nodeComfort.isEmpty({}); // true
441
+ * nodeComfort.isEmpty(new Map()); // true
442
+ * nodeComfort.isEmpty("x"); // false
443
+ * nodeComfort.isEmpty(0); // false
444
+ *
445
+ * @param {*} value - Value to check.
446
+ * @returns {boolean} True if the value is considered empty.
447
+ */
448
+ isEmpty(value) {
449
+ if (value === null || value === undefined) return true;
450
+ if (typeof value === "string" || Array.isArray(value)) return value.length === 0;
451
+ if (types.isMap(value) || types.isSet(value)) return value.size === 0;
452
+ if (typeof value === "object") return Object.keys(value).length === 0;
453
+ return false;
454
+ },
455
+
456
+ /**
457
+ * Checks if a string is a valid, well-formed email address.
458
+ *
459
+ * This is a pragmatic check (not a full RFC 5322 parser) that covers the
460
+ * vast majority of real-world addresses.
461
+ *
462
+ * @example
463
+ * nodeComfort.isEmail("john@example.com"); // true
464
+ * nodeComfort.isEmail("nope"); // false
465
+ *
466
+ * @param {*} value - Value to check.
467
+ * @returns {boolean} True if the value looks like an email address.
468
+ */
469
+ isEmail(value) {
470
+ if (typeof value !== "string") return false;
471
+ return /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(value);
472
+ },
473
+
474
+ /**
475
+ * Checks if a string is a valid HTTP(S) URL.
476
+ *
477
+ * @example
478
+ * nodeComfort.isURL("https://example.com"); // true
479
+ * nodeComfort.isURL("ftp://example.com"); // false (not http/https)
480
+ *
481
+ * @param {*} value - Value to check.
482
+ * @param {{ protocols?: string[] }} [options] - Allowed protocols (default: http, https).
483
+ * @returns {boolean} True if the value is a valid URL with an allowed protocol.
484
+ */
485
+ isURL(value, options = {}) {
486
+ if (typeof value !== "string") return false;
487
+ const protocols = options.protocols ?? ["http:", "https:"];
488
+ try {
489
+ const url = new URL(value);
490
+ return protocols.includes(url.protocol);
491
+ } catch {
492
+ return false;
493
+ }
494
+ },
495
+
496
+ /**
497
+ * Checks if a string is a valid UUID (versions 1-5, any variant).
498
+ *
499
+ * @example
500
+ * nodeComfort.isUUID("123e4567-e89b-12d3-a456-426614174000"); // true
501
+ *
502
+ * @param {*} value - Value to check.
503
+ * @returns {boolean} True if the value is a UUID.
504
+ */
505
+ isUUID(value) {
506
+ if (typeof value !== "string") return false;
507
+ return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
508
+ },
509
+
510
+ /**
511
+ * Checks if a string is valid, parseable JSON.
512
+ *
513
+ * @example
514
+ * nodeComfort.isJSON('{"a":1}'); // true
515
+ * nodeComfort.isJSON("{a:1}"); // false
516
+ *
517
+ * @param {*} value - Value to check.
518
+ * @returns {boolean} True if the value is a JSON-parseable string.
519
+ */
520
+ isJSON(value) {
521
+ if (typeof value !== "string") return false;
522
+ try {
523
+ JSON.parse(value);
524
+ return true;
525
+ } catch {
526
+ return false;
527
+ }
528
+ },
529
+
530
+ /**
531
+ * Checks if a value is numeric • a number, or a string that fully represents one.
532
+ *
533
+ * @example
534
+ * nodeComfort.isNumeric(42); // true
535
+ * nodeComfort.isNumeric("42"); // true
536
+ * nodeComfort.isNumeric("4.2e3"); // true
537
+ * nodeComfort.isNumeric("4px"); // false
538
+ *
539
+ * @param {*} value - Value to check.
540
+ * @returns {boolean} True if the value is numeric.
541
+ */
542
+ isNumeric(value) {
543
+ if (typeof value === "number") return Number.isFinite(value);
544
+ if (typeof value !== "string" || value.trim() === "") return false;
545
+ return Number.isFinite(Number(value));
546
+ },
547
+ };