jsfunx 1.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/LICENSE +20 -0
- package/README.md +256 -0
- package/jsfunx.cjs +1641 -0
- package/jsfunx.mjs +1646 -0
- package/package.json +32 -0
package/jsfunx.mjs
ADDED
|
@@ -0,0 +1,1646 @@
|
|
|
1
|
+
/*
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Khiat Mohammed Abderrezzak
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
Author: Khiat Mohammed Abderrezzak <khiat.dev@gmail.com>
|
|
24
|
+
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
// JavaScript utility functions for cleaner, more readable code
|
|
28
|
+
|
|
29
|
+
import { argv } from "process";
|
|
30
|
+
|
|
31
|
+
import { basename } from "path";
|
|
32
|
+
|
|
33
|
+
import { fileURLToPath } from "url";
|
|
34
|
+
|
|
35
|
+
/** @type {string} */
|
|
36
|
+
|
|
37
|
+
export const and = "and";
|
|
38
|
+
|
|
39
|
+
/** @type {string} */
|
|
40
|
+
|
|
41
|
+
export const or = "or";
|
|
42
|
+
|
|
43
|
+
/** @type {string} */
|
|
44
|
+
|
|
45
|
+
export const bigint = "bigint";
|
|
46
|
+
|
|
47
|
+
/** @type {string} */
|
|
48
|
+
|
|
49
|
+
export const func = "function";
|
|
50
|
+
|
|
51
|
+
/** @type {string} */
|
|
52
|
+
|
|
53
|
+
export const number = "number";
|
|
54
|
+
|
|
55
|
+
/** @type {string} */
|
|
56
|
+
|
|
57
|
+
export const object = "object";
|
|
58
|
+
|
|
59
|
+
/** @type {string} */
|
|
60
|
+
|
|
61
|
+
export const string = "string";
|
|
62
|
+
|
|
63
|
+
/** @type {string} */
|
|
64
|
+
|
|
65
|
+
export const symbol = "symbol";
|
|
66
|
+
|
|
67
|
+
/** @type {string} */
|
|
68
|
+
|
|
69
|
+
export const boolean = "boolean";
|
|
70
|
+
|
|
71
|
+
/** @type {string} */
|
|
72
|
+
|
|
73
|
+
export const undef = "undefined";
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Compares a value or a list of values against a given type (or list of types),
|
|
77
|
+
* similar to using `typeof x === y`, but in a more flexible and readable way.
|
|
78
|
+
*
|
|
79
|
+
* Supports single values or arrays, and can combine results using logical
|
|
80
|
+
* operators like `"and"` or `"or"`.
|
|
81
|
+
*
|
|
82
|
+
* @param {* | Array<*>} data - The value or array of values to check.
|
|
83
|
+
* @param {* | Array<*>} dataType - The expected type or array of expected types.
|
|
84
|
+
* @param {"and" | "or"} logic - Logic mode: `"and"` requires all matches, `"or"` allows any match.
|
|
85
|
+
* @param {boolean} match - Whether to compare type names strictly or loosely.
|
|
86
|
+
* @param {boolean} strict - If `true`, enforces strict comparison rules.
|
|
87
|
+
* @returns {boolean} `true` if the data matches the expected type(s) according to the given logic, otherwise `false`.
|
|
88
|
+
*/
|
|
89
|
+
|
|
90
|
+
function checkType(data, dataType, logic, match, strict) {
|
|
91
|
+
// if data or dataType is Array must be nested Array
|
|
92
|
+
|
|
93
|
+
if (!(dataType instanceof Array)) {
|
|
94
|
+
if (!(data instanceof Array)) {
|
|
95
|
+
return typeof data === dataType;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (logic === and) {
|
|
99
|
+
for (let dt of data) {
|
|
100
|
+
// 1 step directly in all cases
|
|
101
|
+
|
|
102
|
+
if (!(typeof dt === dataType)) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// or using recursion (one to one)
|
|
107
|
+
// 2 steps
|
|
108
|
+
|
|
109
|
+
// if (!checkType(dt, dataType, logic, match, strict)) {
|
|
110
|
+
// return false;
|
|
111
|
+
// }
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (logic === or) {
|
|
118
|
+
for (let dt of data) {
|
|
119
|
+
// 1 step directly in all cases
|
|
120
|
+
|
|
121
|
+
if (typeof dt === dataType) {
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// or using recursion (one to one)
|
|
126
|
+
// 2 steps
|
|
127
|
+
|
|
128
|
+
// if (checkType(dt, dataType, logic, match, strict)) {
|
|
129
|
+
// return true;
|
|
130
|
+
// }
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
throw new TypeError("logic type undefined !");
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (!(data instanceof Array)) {
|
|
140
|
+
for (let dtype of dataType) {
|
|
141
|
+
// 1 step directly in all cases
|
|
142
|
+
|
|
143
|
+
if (typeof data === dtype) {
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// or using recursion if (one to one) enabled
|
|
148
|
+
// 2 steps
|
|
149
|
+
|
|
150
|
+
// if (checkType(data, dtype, logic, match, strict)) {
|
|
151
|
+
// return true;
|
|
152
|
+
// }
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (!match) {
|
|
159
|
+
if (logic === and) {
|
|
160
|
+
outerLoop: for (let dt of data) {
|
|
161
|
+
for (let dtype of dataType) {
|
|
162
|
+
if (typeof dt === dtype) {
|
|
163
|
+
continue outerLoop;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return true;
|
|
171
|
+
|
|
172
|
+
// or like this handling each case individually using recursion
|
|
173
|
+
|
|
174
|
+
// checking relationship type in this case (one to many)
|
|
175
|
+
|
|
176
|
+
// if (data.length < 2) {
|
|
177
|
+
// // [x], [y, z] => x, [y, z] (one to many)
|
|
178
|
+
|
|
179
|
+
// // we can call isType(data[0], dataType) in place of
|
|
180
|
+
// // checkType(data[0], dataType, logic, match, strict) but take
|
|
181
|
+
// // one step plus
|
|
182
|
+
|
|
183
|
+
// // 2 steps (one to one)
|
|
184
|
+
// if (!checkType(data[0], dataType, logic, match, strict)) {
|
|
185
|
+
// return false;
|
|
186
|
+
// }
|
|
187
|
+
|
|
188
|
+
// return true;
|
|
189
|
+
|
|
190
|
+
// // 1 step directly using (one to one)
|
|
191
|
+
|
|
192
|
+
// // for (let dtype of dataType) {
|
|
193
|
+
// // if (checkType(data[0], dtype, logic, match, strict)) {
|
|
194
|
+
// // return true;
|
|
195
|
+
// // }
|
|
196
|
+
|
|
197
|
+
// // // the same as this
|
|
198
|
+
|
|
199
|
+
// // // if (typeof data[0] === dtype) {
|
|
200
|
+
// // // return true;
|
|
201
|
+
// // // }
|
|
202
|
+
// // }
|
|
203
|
+
|
|
204
|
+
// // return false;
|
|
205
|
+
// }
|
|
206
|
+
|
|
207
|
+
// checking relationship type in this case (many to one)
|
|
208
|
+
|
|
209
|
+
// if (dataType.length < 2) {
|
|
210
|
+
// // [x, y], [z] => [x, y], z (many to one)
|
|
211
|
+
|
|
212
|
+
// // we can call isType(data, dataType[0]) in place of
|
|
213
|
+
// // checkType(data, dataType[0], logic, match, strict) but take
|
|
214
|
+
// // one step plus
|
|
215
|
+
|
|
216
|
+
// // 2 steps (one to one)
|
|
217
|
+
|
|
218
|
+
// if (!checkType(data, dataType[0], logic, match, strict)) {
|
|
219
|
+
// return false;
|
|
220
|
+
// }
|
|
221
|
+
|
|
222
|
+
// // 1 step directly (one to one)
|
|
223
|
+
|
|
224
|
+
// // for (let dt of data) {
|
|
225
|
+
// // if (!checkType(dt, dataType[0], logic, match, strict)) {
|
|
226
|
+
// // return false;
|
|
227
|
+
// // }
|
|
228
|
+
|
|
229
|
+
// // // the same as this
|
|
230
|
+
|
|
231
|
+
// // // if (!(typeof dt === dataType[0])) {
|
|
232
|
+
// // // return false;
|
|
233
|
+
// // // }
|
|
234
|
+
// // }
|
|
235
|
+
|
|
236
|
+
// // shared return
|
|
237
|
+
|
|
238
|
+
// return true;
|
|
239
|
+
// }
|
|
240
|
+
|
|
241
|
+
// checking relationship type in this case (many to many)
|
|
242
|
+
|
|
243
|
+
// we can embeds this in recursive (one to many) with the condition
|
|
244
|
+
// if (data.length < 2 || (data.length > 1 && dataType.length > 1)){
|
|
245
|
+
// with adding a for loop for any number of data at least one
|
|
246
|
+
// and replacing data[0] with dt from the loop and remove the next
|
|
247
|
+
// condition if (dataType.length < 2) {} because it's the last one no
|
|
248
|
+
// more conditions after it run the nested condition directly
|
|
249
|
+
// and set just one global true in the last of the two logics
|
|
250
|
+
|
|
251
|
+
// for (let dt of data) {
|
|
252
|
+
// // [w, x], [y, z] => w, [y, z]
|
|
253
|
+
// // [w, x], [y, z] => x, [y, z]
|
|
254
|
+
// // (one to many) 1 step directly
|
|
255
|
+
|
|
256
|
+
// // we can call isType(dt, dataType) in place of
|
|
257
|
+
// // checkType(dt, dataType, logic, match, strict) but take
|
|
258
|
+
// // one step plus
|
|
259
|
+
|
|
260
|
+
// if (!checkType(dt, dataType, logic, match, strict)) {
|
|
261
|
+
// return false;
|
|
262
|
+
// }
|
|
263
|
+
// }
|
|
264
|
+
|
|
265
|
+
// return true;
|
|
266
|
+
|
|
267
|
+
// checking relationship type in this case (many to many)
|
|
268
|
+
|
|
269
|
+
// for (let dt of data) {
|
|
270
|
+
// // [w, x], [y, z] => [w], [y, z]
|
|
271
|
+
// // [w, x], [y, z] => [x], [y, z]
|
|
272
|
+
// // (one to many) 2 steps
|
|
273
|
+
|
|
274
|
+
// // we can call isType([dt], dataType, match) in place of
|
|
275
|
+
// // checkType([dt], dataType, logic, match, strict) but take
|
|
276
|
+
// // one step plus
|
|
277
|
+
|
|
278
|
+
// if (!checkType([dt], dataType, logic, match, strict)) {
|
|
279
|
+
// return false;
|
|
280
|
+
// }
|
|
281
|
+
// }
|
|
282
|
+
|
|
283
|
+
// return true;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (logic === or) {
|
|
287
|
+
for (let dt of data) {
|
|
288
|
+
for (let dtype of dataType) {
|
|
289
|
+
if (typeof dt === dtype) {
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
return false;
|
|
295
|
+
|
|
296
|
+
// or like this handling each case individually using recursion
|
|
297
|
+
|
|
298
|
+
// checking relationship type in this case (one to many)
|
|
299
|
+
|
|
300
|
+
// if (data.length < 2) {
|
|
301
|
+
// // [x], [y, z] => x, [y, z] (one to many)
|
|
302
|
+
|
|
303
|
+
// // we can call isType(data[0], dataType, logic) in place of
|
|
304
|
+
// // checkType(data[0], dataType, logic, match, strict) but take
|
|
305
|
+
// // one step plus
|
|
306
|
+
|
|
307
|
+
// // 2 steps (one to one)
|
|
308
|
+
|
|
309
|
+
// if (checkType(data[0], dataType, logic, match, strict)) {
|
|
310
|
+
// return true;
|
|
311
|
+
// }
|
|
312
|
+
|
|
313
|
+
// // 1 step directly using (one to one)
|
|
314
|
+
|
|
315
|
+
// // for (let dtype of dataType) {
|
|
316
|
+
// // if (checkType(data[0], dtype, logic, match, strict)) {
|
|
317
|
+
// // return true;
|
|
318
|
+
// // }
|
|
319
|
+
|
|
320
|
+
// // // the same as this
|
|
321
|
+
|
|
322
|
+
// // // if (typeof data[0] === dtype) {
|
|
323
|
+
// // // return true;
|
|
324
|
+
// // // }
|
|
325
|
+
// // }
|
|
326
|
+
|
|
327
|
+
// // shared return
|
|
328
|
+
|
|
329
|
+
// return false;
|
|
330
|
+
// }
|
|
331
|
+
|
|
332
|
+
// checking relationship type in this case (many to one)
|
|
333
|
+
|
|
334
|
+
// if (dataType.length < 2) {
|
|
335
|
+
// // [x, y], [z] => [x, y], z (many to one)
|
|
336
|
+
|
|
337
|
+
// // we can call isType(data, dataType[0], logic) in place of
|
|
338
|
+
// // checkType(data, dataType[0], logic, match, strict) but take
|
|
339
|
+
// // one step plus
|
|
340
|
+
|
|
341
|
+
// // 2 steps (one to one)
|
|
342
|
+
|
|
343
|
+
// if (checkType(data, dataType[0], logic, match, strict)) {
|
|
344
|
+
// return true;
|
|
345
|
+
// }
|
|
346
|
+
|
|
347
|
+
// // 1 step directly using (one to one)
|
|
348
|
+
|
|
349
|
+
// // for (let dt of data) {
|
|
350
|
+
// // if (checkType(dt, dataType[0], logic, match, strict)) {
|
|
351
|
+
// // return true;
|
|
352
|
+
// // }
|
|
353
|
+
|
|
354
|
+
// // // the same as this
|
|
355
|
+
|
|
356
|
+
// // if (typeof dt === dataType[0]) {
|
|
357
|
+
// // return true;
|
|
358
|
+
// // }
|
|
359
|
+
// // }
|
|
360
|
+
|
|
361
|
+
// // shared return
|
|
362
|
+
|
|
363
|
+
// return false;
|
|
364
|
+
// }
|
|
365
|
+
|
|
366
|
+
// checking relationship type in this case (many to many)
|
|
367
|
+
|
|
368
|
+
// we can embeds this in recursive (one to many) with the condition
|
|
369
|
+
// if (data.length < 2 || (data.length > 1 && dataType.length > 1)){
|
|
370
|
+
// with adding a for loop for any number of data at least one
|
|
371
|
+
// and replacing data[0] with dt from the loop and remove the next
|
|
372
|
+
// condition if (dataType.length < 2) {} because it's the last one no
|
|
373
|
+
// more conditions after it run the nested condition directly
|
|
374
|
+
// and set just one global true in the last of the two logics
|
|
375
|
+
|
|
376
|
+
// for (let dt of data) {
|
|
377
|
+
// // [w, x], [y, z] => w, [y, z]
|
|
378
|
+
// // [w, x], [y, z] => x, [y, z]
|
|
379
|
+
// // (one to many) 1 step directly & 2 steps if (one to one)
|
|
380
|
+
|
|
381
|
+
// // we can call isType(dt, dataType, logic) in place of
|
|
382
|
+
// // checkType(dt, dataType, logic, match, strict) but take
|
|
383
|
+
// // one step plus
|
|
384
|
+
|
|
385
|
+
// if (checkType(dt, dataType, logic, match, strict)) {
|
|
386
|
+
// return true;
|
|
387
|
+
// }
|
|
388
|
+
// }
|
|
389
|
+
|
|
390
|
+
// return false;
|
|
391
|
+
|
|
392
|
+
// checking relationship type in this case (many to many)
|
|
393
|
+
|
|
394
|
+
// for (let dtype of dataType) {
|
|
395
|
+
// // [w, x], [y, z] => [w, x], y
|
|
396
|
+
// // [w, x], [y, z] => [w, x], z
|
|
397
|
+
// // (many to one) 1 step directly & 2 steps (one to one)
|
|
398
|
+
|
|
399
|
+
// // we can call isType(data, dtype, logic) in place of
|
|
400
|
+
// // checkType(data, dtype, logic, match, strict) but take
|
|
401
|
+
// // one step plus
|
|
402
|
+
|
|
403
|
+
// if (checkType(data, dtype, logic, match, strict)) {
|
|
404
|
+
// return true;
|
|
405
|
+
// }
|
|
406
|
+
// }
|
|
407
|
+
|
|
408
|
+
// return false;
|
|
409
|
+
|
|
410
|
+
// checking relationship type in this case (many to many)
|
|
411
|
+
|
|
412
|
+
// for (let dt of data) {
|
|
413
|
+
// // [w, x], [y, z] => [w], [y, z]
|
|
414
|
+
// // [w, x], [y, z] => [x], [y, z]
|
|
415
|
+
// // (one to many) 2 steps & 3 steps (one to one)
|
|
416
|
+
|
|
417
|
+
// // we can call isType([dt], dataType, logic, match) in place of
|
|
418
|
+
// // checkType([dt], dataType, logic, match, strict) but take
|
|
419
|
+
// // one step plus
|
|
420
|
+
|
|
421
|
+
// if (checkType([dt], dataType, logic, match, strict)) {
|
|
422
|
+
// return true;
|
|
423
|
+
// }
|
|
424
|
+
// }
|
|
425
|
+
|
|
426
|
+
// return false;
|
|
427
|
+
|
|
428
|
+
// checking relationship type in this case (many to many)
|
|
429
|
+
|
|
430
|
+
// for (let dtype of dataType) {
|
|
431
|
+
// // [w, x], [y, z] => [w, x], [y]
|
|
432
|
+
// // [w, x], [y, z] => [w, x], [z]
|
|
433
|
+
// // (many to one) 2 steps & 3 steps (one to one)
|
|
434
|
+
|
|
435
|
+
// // we can call isType(data, [dtype], logic, match) in place of
|
|
436
|
+
// // checkType(data, [dtype], logic, match, strict) but take
|
|
437
|
+
// // one step plus
|
|
438
|
+
|
|
439
|
+
// if (checkType(data, [dtype], logic, match, strict)) {
|
|
440
|
+
// return true;
|
|
441
|
+
// }
|
|
442
|
+
// }
|
|
443
|
+
|
|
444
|
+
// return false;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
throw new TypeError("logic type undefined !");
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
if (data.length !== dataType.length) {
|
|
451
|
+
if (strict) {
|
|
452
|
+
throw new TypeError(
|
|
453
|
+
"length of array of dataTypes must match number of data"
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/** @type {number} */
|
|
458
|
+
|
|
459
|
+
let min;
|
|
460
|
+
|
|
461
|
+
if (data.length < dataType.length) {
|
|
462
|
+
min = data.length;
|
|
463
|
+
} else {
|
|
464
|
+
min = dataType.length;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
if (logic === and) {
|
|
468
|
+
for (let i = 0; i < min; ++i) {
|
|
469
|
+
// 1 step directly in all cases
|
|
470
|
+
|
|
471
|
+
if (!(typeof data[i] === dataType[i])) {
|
|
472
|
+
return false;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// or using recursion (one to one)
|
|
476
|
+
// 2 steps
|
|
477
|
+
|
|
478
|
+
// if (!checkType(data[i], dataType[i], logic, match, strict)) {
|
|
479
|
+
// return false;
|
|
480
|
+
// }
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// shared return
|
|
484
|
+
|
|
485
|
+
return true;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
if (logic === or) {
|
|
489
|
+
for (let i = 0; i < min; ++i) {
|
|
490
|
+
// 1 step directly in all cases
|
|
491
|
+
|
|
492
|
+
if (typeof data[i] === dataType[i]) {
|
|
493
|
+
return true;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// or using recursion (one to one)
|
|
497
|
+
// 2 steps
|
|
498
|
+
|
|
499
|
+
// if (checkType(data[i], dataType[i], logic, match, strict)) {
|
|
500
|
+
// return true;
|
|
501
|
+
// }
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// shared return
|
|
505
|
+
|
|
506
|
+
return false;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
throw new TypeError("logic type undefined !");
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
if (logic === and) {
|
|
513
|
+
for (let i = 0; i < data.length; ++i) {
|
|
514
|
+
// 1 step directly in all cases
|
|
515
|
+
|
|
516
|
+
if (!(typeof data[i] === dataType[i])) {
|
|
517
|
+
return false;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// or using recursion (one to one)
|
|
521
|
+
// 2 steps
|
|
522
|
+
|
|
523
|
+
// if (!checkType(data[i], dataType[i], logic, match, strict)) {
|
|
524
|
+
// return false;
|
|
525
|
+
// }
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// shared return
|
|
529
|
+
|
|
530
|
+
return true;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
if (logic === or) {
|
|
534
|
+
for (let i = 0; i < data.length; ++i) {
|
|
535
|
+
// 1 step directly in all cases
|
|
536
|
+
|
|
537
|
+
if (typeof data[i] === dataType[i]) {
|
|
538
|
+
return true;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// or using recursion (one to one)
|
|
542
|
+
// 2 steps
|
|
543
|
+
|
|
544
|
+
// if (checkType(data[i], dataType[i], logic, match, strict)) {
|
|
545
|
+
// return true;
|
|
546
|
+
// }
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// shared return
|
|
550
|
+
|
|
551
|
+
return false;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
throw new TypeError("logic type undefined !");
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
/**
|
|
558
|
+
* Checks whether one or more objects are instances of a given class (or classes),
|
|
559
|
+
* similar to using the `instanceof` operator — but extended to handle arrays
|
|
560
|
+
* and multiple constructors with logical control.
|
|
561
|
+
*
|
|
562
|
+
* Works like a plural form of `instanceof`, allowing you to check several objects
|
|
563
|
+
* against one or more classes, using `"and"` or `"or"` logic.
|
|
564
|
+
*
|
|
565
|
+
* @template T - The instance type returned by the constructor(s).
|
|
566
|
+
* @param {* | Array<*>} objs - The object or array of objects to test.
|
|
567
|
+
* @param {(new (...args: any[]) => T) | Array<new (...args: any[]) => T>} type - The constructor or list of constructors to test against.
|
|
568
|
+
* @param {"and" | "or"} logic - Logic mode: `"and"` requires all matches, `"or"` allows any match.
|
|
569
|
+
* @param {boolean} match - Whether to compare classes names strictly or loosely.
|
|
570
|
+
* @param {boolean} strict - If `true`, enables strict comparison behavior.
|
|
571
|
+
* @returns {boolean} `true` if the provided object(s) match the given type(s) according to the chosen logic, otherwise `false`.
|
|
572
|
+
*/
|
|
573
|
+
|
|
574
|
+
function isinstances(objs, type, logic, match, strict) {
|
|
575
|
+
if (!(type instanceof Array)) {
|
|
576
|
+
// uncomment (return objs instanceof type)
|
|
577
|
+
// to enable the 1/4 of (one to one)
|
|
578
|
+
|
|
579
|
+
if (!(objs instanceof Array)) {
|
|
580
|
+
// return objs instanceof type;
|
|
581
|
+
|
|
582
|
+
throw new TypeError(
|
|
583
|
+
`instancesof expected at least : 2 objects as first argument 'objs' or 2 types as second argument 'type', got 1`
|
|
584
|
+
);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// remove this (if) condition to enable the 1/4 of (one to one)
|
|
588
|
+
|
|
589
|
+
if (objs.length < 2) {
|
|
590
|
+
throw new TypeError(
|
|
591
|
+
`instancesof expected at least 2 objects as first argument 'objs', got 1`
|
|
592
|
+
);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
if (logic === and) {
|
|
596
|
+
for (let obj of objs) {
|
|
597
|
+
// 1 step directly in all cases
|
|
598
|
+
|
|
599
|
+
try {
|
|
600
|
+
if (!(obj instanceof type)) {
|
|
601
|
+
return false;
|
|
602
|
+
}
|
|
603
|
+
} catch (error) {
|
|
604
|
+
throw new TypeError(
|
|
605
|
+
"second argument of 'instancesof' is not a type/class or array of types/classes"
|
|
606
|
+
);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// or using recursion if (one to one) enabled
|
|
610
|
+
// 2 steps
|
|
611
|
+
|
|
612
|
+
// if (!isinstances(obj, type, logic, match, strict)) {
|
|
613
|
+
// return false;
|
|
614
|
+
// }
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
return true;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
if (logic === or) {
|
|
621
|
+
for (let obj of objs) {
|
|
622
|
+
// 1 step directly in all cases
|
|
623
|
+
|
|
624
|
+
try {
|
|
625
|
+
if (obj instanceof type) {
|
|
626
|
+
return true;
|
|
627
|
+
}
|
|
628
|
+
} catch (error) {
|
|
629
|
+
throw new TypeError(
|
|
630
|
+
"second argument of 'instancesof' is not a type/class or array of types/classes"
|
|
631
|
+
);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// or using recursion if (one to one) enabled
|
|
635
|
+
// 2 steps
|
|
636
|
+
|
|
637
|
+
// if (isinstances(obj, type, logic, match, strict)) {
|
|
638
|
+
// return true;
|
|
639
|
+
// }
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
return false;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
throw new TypeError("logic type undefined !");
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
if (!(objs instanceof Array)) {
|
|
649
|
+
// remove this (if) condition to enable the 1/4 of (one to one)
|
|
650
|
+
|
|
651
|
+
if (type.length < 2) {
|
|
652
|
+
throw new TypeError(
|
|
653
|
+
`instancesof expected at least 2 types as second argument 'type', got 1`
|
|
654
|
+
);
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
for (let dt of type) {
|
|
658
|
+
// 1 step directly in all cases
|
|
659
|
+
|
|
660
|
+
try {
|
|
661
|
+
if (objs instanceof dt) {
|
|
662
|
+
return true;
|
|
663
|
+
}
|
|
664
|
+
} catch (error) {
|
|
665
|
+
throw new TypeError(
|
|
666
|
+
"second argument of 'instancesof' is not a type/class or array of types/classes"
|
|
667
|
+
);
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
// or using recursion if (one to one) enabled
|
|
671
|
+
// 2 steps
|
|
672
|
+
|
|
673
|
+
// if (isinstances(objs, dt, logic, match, strict)) {
|
|
674
|
+
// return true;
|
|
675
|
+
// }
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
return false;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// remove this (if) to enable 1/4 of (one to one)
|
|
682
|
+
|
|
683
|
+
if (objs.length < 2 && type.length < 2) {
|
|
684
|
+
throw new TypeError(
|
|
685
|
+
`instancesof expected at least : 2 objects as first argument 'objs' or 2 types as second argument 'type', got 1`
|
|
686
|
+
);
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
if (!match) {
|
|
690
|
+
if (logic === and) {
|
|
691
|
+
outerLoop: for (let obj of objs) {
|
|
692
|
+
for (let dt of type) {
|
|
693
|
+
try {
|
|
694
|
+
if (obj instanceof dt) {
|
|
695
|
+
continue outerLoop;
|
|
696
|
+
}
|
|
697
|
+
} catch (error) {
|
|
698
|
+
throw new TypeError(
|
|
699
|
+
"second argument of 'instancesof' is not a type/class or array of types/classes"
|
|
700
|
+
);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
return false;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
return true;
|
|
708
|
+
|
|
709
|
+
// or like this handling each case individually using recursion
|
|
710
|
+
|
|
711
|
+
// checking relationship type in this case (one to many)
|
|
712
|
+
|
|
713
|
+
// if (objs.length < 2) {
|
|
714
|
+
// // [x], [y, z] => x, [y, z] (one to many)
|
|
715
|
+
|
|
716
|
+
// // we can call instancesof(objs[0], type) in place of
|
|
717
|
+
// // isinstances(objs[0], type, logic, match, strict) but take
|
|
718
|
+
// // one step plus
|
|
719
|
+
|
|
720
|
+
// // 2 steps if (one to one) enabled
|
|
721
|
+
// if (!isinstances(objs[0], type, logic, match, strict)) {
|
|
722
|
+
// return false;
|
|
723
|
+
// }
|
|
724
|
+
|
|
725
|
+
// return true;
|
|
726
|
+
|
|
727
|
+
// // 1 step directly using (one to one) if enabled
|
|
728
|
+
|
|
729
|
+
// // for (let dt of type) {
|
|
730
|
+
// // if (isinstances(objs[0], dt, logic, match, strict)) {
|
|
731
|
+
// // return true;
|
|
732
|
+
// // }
|
|
733
|
+
|
|
734
|
+
// // // the same as this
|
|
735
|
+
|
|
736
|
+
// // // if (objs[0] instanceof dt) {
|
|
737
|
+
// // // return true;
|
|
738
|
+
// // // }
|
|
739
|
+
// // }
|
|
740
|
+
|
|
741
|
+
// // return false;
|
|
742
|
+
// }
|
|
743
|
+
|
|
744
|
+
// checking relationship type in this case (many to one)
|
|
745
|
+
|
|
746
|
+
// if (type.length < 2) {
|
|
747
|
+
// // [x, y], [z] => [x, y], z (many to one)
|
|
748
|
+
|
|
749
|
+
// // we can call instancesof(objs, type[0]) in place of
|
|
750
|
+
// // isinstances(objs, type[0], logic, match, strict) but take
|
|
751
|
+
// // one step plus
|
|
752
|
+
|
|
753
|
+
// // 2 steps if (one to one) enabled
|
|
754
|
+
|
|
755
|
+
// if (!isinstances(objs, type[0], logic, match, strict)) {
|
|
756
|
+
// return false;
|
|
757
|
+
// }
|
|
758
|
+
|
|
759
|
+
// // 1 step directly using (one to one) if enabled
|
|
760
|
+
|
|
761
|
+
// // for (let obj of objs) {
|
|
762
|
+
// // if (!isinstances(obj, type[0], logic, match, strict)) {
|
|
763
|
+
// // return false;
|
|
764
|
+
// // }
|
|
765
|
+
|
|
766
|
+
// // // the same as this
|
|
767
|
+
|
|
768
|
+
// // // if (!(obj instanceof type[0])) {
|
|
769
|
+
// // // return false;
|
|
770
|
+
// // // }
|
|
771
|
+
// // }
|
|
772
|
+
|
|
773
|
+
// // shared return
|
|
774
|
+
|
|
775
|
+
// return true;
|
|
776
|
+
// }
|
|
777
|
+
|
|
778
|
+
// checking relationship type in this case (many to many)
|
|
779
|
+
|
|
780
|
+
// we can embeds this in recursive (one to many) with the condition
|
|
781
|
+
// if (objs.length < 2 || (objs.length > 1 && type.length > 1)){
|
|
782
|
+
// with adding a for loop for any number of objs at least one
|
|
783
|
+
// and replacing objs[0] with obj from the loop and remove the next
|
|
784
|
+
// condition if (type.length < 2) {} because it's the last one no
|
|
785
|
+
// more conditions after it run the nested condition directly
|
|
786
|
+
// and set just one global true in the last of the two logics
|
|
787
|
+
|
|
788
|
+
// for (let obj of objs) {
|
|
789
|
+
// // [w, x], [y, z] => w, [y, z]
|
|
790
|
+
// // [w, x], [y, z] => x, [y, z]
|
|
791
|
+
// // (one to many) (1 step directly)
|
|
792
|
+
|
|
793
|
+
// // we can call instancesof(obj, type) in place of
|
|
794
|
+
// // isinstances(obj, type, logic, match, strict) but take
|
|
795
|
+
// // one step plus
|
|
796
|
+
|
|
797
|
+
// if (!isinstances(obj, type, logic, match, strict)) {
|
|
798
|
+
// return false;
|
|
799
|
+
// }
|
|
800
|
+
// }
|
|
801
|
+
|
|
802
|
+
// return true;
|
|
803
|
+
|
|
804
|
+
// checking relationship type in this case (many to many)
|
|
805
|
+
|
|
806
|
+
// for (let obj of objs) {
|
|
807
|
+
// // [w, x], [y, z] => [w], [y, z]
|
|
808
|
+
// // [w, x], [y, z] => [x], [y, z]
|
|
809
|
+
// // (one to many) (2 steps)
|
|
810
|
+
|
|
811
|
+
// // we can call instancesof([obj], type, match) in place of
|
|
812
|
+
// // isinstances([obj], type, logic, match, strict) but take
|
|
813
|
+
// // one step plus
|
|
814
|
+
|
|
815
|
+
// if (!isinstances([obj], type, logic, match, strict)) {
|
|
816
|
+
// return false;
|
|
817
|
+
// }
|
|
818
|
+
// }
|
|
819
|
+
|
|
820
|
+
// return true;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
if (logic === or) {
|
|
824
|
+
for (let obj of objs) {
|
|
825
|
+
for (let dt of type) {
|
|
826
|
+
try {
|
|
827
|
+
if (obj instanceof dt) {
|
|
828
|
+
return true;
|
|
829
|
+
}
|
|
830
|
+
} catch (error) {
|
|
831
|
+
throw new TypeError(
|
|
832
|
+
"second argument of 'instancesof' is not a type/class or array of types/classes"
|
|
833
|
+
);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
return false;
|
|
838
|
+
|
|
839
|
+
// or like this handling each case individually using recursion
|
|
840
|
+
|
|
841
|
+
// checking relationship type in this case (one to many)
|
|
842
|
+
|
|
843
|
+
// if (objs.length < 2) {
|
|
844
|
+
// // [x], [y, z] => x, [y, z] (one to many)
|
|
845
|
+
|
|
846
|
+
// // we can call instancesof(objs[0], type, logic) in place of
|
|
847
|
+
// // isinstances(objs[0], type, logic, match, strict) but take
|
|
848
|
+
// // one step plus
|
|
849
|
+
|
|
850
|
+
// // 2 steps if (one to one) enabled
|
|
851
|
+
|
|
852
|
+
// if (isinstances(objs[0], type, logic, match, strict)) {
|
|
853
|
+
// return true;
|
|
854
|
+
// }
|
|
855
|
+
|
|
856
|
+
// // // 1 step directly using (one to one) if enabled
|
|
857
|
+
|
|
858
|
+
// // for (let dt of type) {
|
|
859
|
+
// // if (isinstances(objs[0], dt, logic, match, strict)) {
|
|
860
|
+
// // return true;
|
|
861
|
+
// // }
|
|
862
|
+
|
|
863
|
+
// // // the same as this
|
|
864
|
+
|
|
865
|
+
// // // if (objs[0] instanceof dt) {
|
|
866
|
+
// // // return true;
|
|
867
|
+
// // // }
|
|
868
|
+
// // }
|
|
869
|
+
|
|
870
|
+
// // shared return
|
|
871
|
+
|
|
872
|
+
// return false;
|
|
873
|
+
// }
|
|
874
|
+
|
|
875
|
+
// checking relationship type in this case (many to one)
|
|
876
|
+
|
|
877
|
+
// if (type.length < 2) {
|
|
878
|
+
// // [x, y], [z] => [x, y], z (many to one)
|
|
879
|
+
|
|
880
|
+
// // we can call instancesof(objs, type[0], logic) in place of
|
|
881
|
+
// // isinstances(objs, type[0], logic, match, strict) but take
|
|
882
|
+
// // one step plus
|
|
883
|
+
|
|
884
|
+
// // 2 steps if (one to one) enabled
|
|
885
|
+
|
|
886
|
+
// if (isinstances(objs, type[0], logic, match, strict)) {
|
|
887
|
+
// return true;
|
|
888
|
+
// }
|
|
889
|
+
|
|
890
|
+
// // // 1 step directly using (one to one) if enabled
|
|
891
|
+
|
|
892
|
+
// // for (let obj of objs) {
|
|
893
|
+
// // if (isinstances(obj, type[0], logic, match, strict)) {
|
|
894
|
+
// // return true;
|
|
895
|
+
// // }
|
|
896
|
+
|
|
897
|
+
// // // the same as this
|
|
898
|
+
|
|
899
|
+
// // // if (obj instanceof type[0]) {
|
|
900
|
+
// // // return true;
|
|
901
|
+
// // // }
|
|
902
|
+
// // }
|
|
903
|
+
|
|
904
|
+
// // shared return
|
|
905
|
+
|
|
906
|
+
// return false;
|
|
907
|
+
// }
|
|
908
|
+
|
|
909
|
+
// checking relationship type in this case (many to many)
|
|
910
|
+
|
|
911
|
+
// we can embeds this in recursive (one to many) with the condition
|
|
912
|
+
// if (objs.length < 2 || (objs.length > 1 && type.length > 1)){
|
|
913
|
+
// with adding a for loop for any number of objs at least one
|
|
914
|
+
// and replacing objs[0] with obj from the loop and remove the next
|
|
915
|
+
// condition if (type.length < 2) {} because it's the last one no
|
|
916
|
+
// more conditions after it run the nested condition directly
|
|
917
|
+
// and set just one global true in the last of the two logics
|
|
918
|
+
|
|
919
|
+
// for (let obj of objs) {
|
|
920
|
+
// // [w, x], [y, z] => w, [y, z]
|
|
921
|
+
// // [w, x], [y, z] => x, [y, z]
|
|
922
|
+
// // (one to many) (1 step directly) & (2 steps if (one to one) enabled)
|
|
923
|
+
|
|
924
|
+
// // we can call instancesof(obj, type, logic) in place of
|
|
925
|
+
// // isinstances(obj, type, logic, match, strict) but take
|
|
926
|
+
// // one step plus
|
|
927
|
+
|
|
928
|
+
// if (isinstances(obj, type, logic, match, strict)) {
|
|
929
|
+
// return true;
|
|
930
|
+
// }
|
|
931
|
+
// }
|
|
932
|
+
|
|
933
|
+
// return false;
|
|
934
|
+
|
|
935
|
+
// checking relationship type in this case (many to many)
|
|
936
|
+
|
|
937
|
+
// for (let dt of type) {
|
|
938
|
+
// // [w, x], [y, z] => [w, x], y
|
|
939
|
+
// // [w, x], [y, z] => [w, x], z
|
|
940
|
+
// // (many to one) (1 step directly) & (2 steps if (one to one) enabled)
|
|
941
|
+
|
|
942
|
+
// // we can call instancesof(objs, dt, logic) in place of
|
|
943
|
+
// // isinstances(objs, dt, logic, match, strict) but take
|
|
944
|
+
// // one step plus
|
|
945
|
+
|
|
946
|
+
// if (isinstances(objs, dt, logic, match, strict)) {
|
|
947
|
+
// return true;
|
|
948
|
+
// }
|
|
949
|
+
// }
|
|
950
|
+
|
|
951
|
+
// return false;
|
|
952
|
+
|
|
953
|
+
// checking relationship type in this case (many to many)
|
|
954
|
+
|
|
955
|
+
// for (let obj of objs) {
|
|
956
|
+
// // [w, x], [y, z] => [w], [y, z]
|
|
957
|
+
// // [w, x], [y, z] => [x], [y, z]
|
|
958
|
+
// // (one to many) (2 steps) & (3 steps if (one to one) enabled)
|
|
959
|
+
|
|
960
|
+
// // we can call instancesof([obj], type, logic, match) in place of
|
|
961
|
+
// // isinstances([obj], type, logic, match, strict) but take
|
|
962
|
+
// // one step plus
|
|
963
|
+
|
|
964
|
+
// if (isinstances([obj], type, logic, match, strict)) {
|
|
965
|
+
// return true;
|
|
966
|
+
// }
|
|
967
|
+
// }
|
|
968
|
+
|
|
969
|
+
// return false;
|
|
970
|
+
|
|
971
|
+
// checking relationship type in this case (many to many)
|
|
972
|
+
|
|
973
|
+
// for (let dt of type) {
|
|
974
|
+
// // [w, x], [y, z] => [w, x], [y]
|
|
975
|
+
// // [w, x], [y, z] => [w, x], [z]
|
|
976
|
+
// // (many to one) (2 steps) & (3 steps if (one to one) enabled)
|
|
977
|
+
|
|
978
|
+
// // we can call instancesof(objs, [dt], logic, match) in place of
|
|
979
|
+
// // isinstances(objs, [dt], logic, match, strict) but take
|
|
980
|
+
// // one step plus
|
|
981
|
+
|
|
982
|
+
// if (isinstances(objs, [dt], logic, match, strict)) {
|
|
983
|
+
// return true;
|
|
984
|
+
// }
|
|
985
|
+
// }
|
|
986
|
+
|
|
987
|
+
// return false;
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
throw new TypeError("logic type undefined !");
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
if (objs.length !== type.length) {
|
|
994
|
+
if (strict) {
|
|
995
|
+
throw new TypeError(
|
|
996
|
+
"length of array of types must match number of objects"
|
|
997
|
+
);
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
/** @type {number} */
|
|
1001
|
+
|
|
1002
|
+
let min;
|
|
1003
|
+
|
|
1004
|
+
if (objs.length < type.length) {
|
|
1005
|
+
min = objs.length;
|
|
1006
|
+
} else {
|
|
1007
|
+
min = type.length;
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
if (logic === and) {
|
|
1011
|
+
for (let i = 0; i < min; ++i) {
|
|
1012
|
+
// 1 step directly in all cases
|
|
1013
|
+
|
|
1014
|
+
try {
|
|
1015
|
+
if (!(objs[i] instanceof type[i])) {
|
|
1016
|
+
return false;
|
|
1017
|
+
}
|
|
1018
|
+
} catch (error) {
|
|
1019
|
+
throw new TypeError(
|
|
1020
|
+
"second argument of 'instancesof' is not a type/class or array of types/classes"
|
|
1021
|
+
);
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
// or using recursion if (one to one) enabled
|
|
1025
|
+
// 2 steps
|
|
1026
|
+
|
|
1027
|
+
// if (!isinstances(objs[i], type[i], logic, match, strict)) {
|
|
1028
|
+
// return false;
|
|
1029
|
+
// }
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
// shared return
|
|
1033
|
+
|
|
1034
|
+
return true;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
if (logic === or) {
|
|
1038
|
+
for (let i = 0; i < min; ++i) {
|
|
1039
|
+
// 1 step directly in all cases
|
|
1040
|
+
|
|
1041
|
+
try {
|
|
1042
|
+
if (objs[i] instanceof type[i]) {
|
|
1043
|
+
return true;
|
|
1044
|
+
}
|
|
1045
|
+
} catch (error) {
|
|
1046
|
+
throw new TypeError(
|
|
1047
|
+
"second argument of 'instancesof' is not a type/class or array of types/classes"
|
|
1048
|
+
);
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
// or using recursion if (one to one) enabled
|
|
1052
|
+
// 2 steps
|
|
1053
|
+
|
|
1054
|
+
// if (isinstances(objs[i], type[i], logic, match, strict)) {
|
|
1055
|
+
// return true;
|
|
1056
|
+
// }
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
// shared return
|
|
1060
|
+
|
|
1061
|
+
return false;
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
throw new TypeError("logic type undefined !");
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
if (logic === and) {
|
|
1068
|
+
for (let i = 0; i < objs.length; ++i) {
|
|
1069
|
+
// 1 step directly in all cases
|
|
1070
|
+
|
|
1071
|
+
try {
|
|
1072
|
+
if (!(objs[i] instanceof type[i])) {
|
|
1073
|
+
return false;
|
|
1074
|
+
}
|
|
1075
|
+
} catch (error) {
|
|
1076
|
+
throw new TypeError(
|
|
1077
|
+
"second argument of 'instancesof' is not a type/class or array of types/classes"
|
|
1078
|
+
);
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
// or using recursion if (one to one) enabled
|
|
1082
|
+
// 2 steps
|
|
1083
|
+
|
|
1084
|
+
// if (!isinstances(objs[i], type[i], logic, match, strict)) {
|
|
1085
|
+
// return false;
|
|
1086
|
+
// }
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
// shared return
|
|
1090
|
+
|
|
1091
|
+
return true;
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
if (logic === or) {
|
|
1095
|
+
for (let i = 0; i < objs.length; ++i) {
|
|
1096
|
+
// 1 step directly in all cases
|
|
1097
|
+
|
|
1098
|
+
try {
|
|
1099
|
+
if (objs[i] instanceof type[i]) {
|
|
1100
|
+
return true;
|
|
1101
|
+
}
|
|
1102
|
+
} catch (error) {
|
|
1103
|
+
throw new TypeError(
|
|
1104
|
+
"second argument of 'instancesof' is not a type/class or array of types/classes"
|
|
1105
|
+
);
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
// or using recursion if (one to one) enabled
|
|
1109
|
+
// 2 steps
|
|
1110
|
+
|
|
1111
|
+
// if (isinstances(objs[i], type[i], logic, match, strict)) {
|
|
1112
|
+
// return true;
|
|
1113
|
+
// }
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
// shared return
|
|
1117
|
+
|
|
1118
|
+
return false;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
throw new TypeError("logic type undefined !");
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
/**
|
|
1125
|
+
* Checks whether one or more objects are instances of a given class (or classes),
|
|
1126
|
+
* similar to using the `instanceof` operator — but extended to handle arrays
|
|
1127
|
+
* and multiple constructors with logical control.
|
|
1128
|
+
*
|
|
1129
|
+
* Works like a plural form of `instanceof`, allowing you to check several objects
|
|
1130
|
+
* against one or more classes, using `"and"` or `"or"` logic.
|
|
1131
|
+
*
|
|
1132
|
+
* @template T - The instance type returned by the constructor(s).
|
|
1133
|
+
* @param {*|Array<*>} objs - The object or array of objects to test.
|
|
1134
|
+
* @param {(new (...args: any[]) => T) | Array<new (...args: any[]) => T>} type - The constructor or list of constructors to test against.
|
|
1135
|
+
* @param {"and" | "or" | boolean} logic_or_match - Logic mode: `"and"` requires all matches, `"or"` allows any match.
|
|
1136
|
+
* @param {boolean} match_or_strict - Whether to compare classes names strictly or loosely.
|
|
1137
|
+
* @param {boolean} strict - If `true`, enables strict comparison behavior.
|
|
1138
|
+
* @returns {boolean} `true` if the provided object(s) match the given type(s) according to the chosen logic, otherwise `false`.
|
|
1139
|
+
*/
|
|
1140
|
+
|
|
1141
|
+
export function instancesof(
|
|
1142
|
+
objs,
|
|
1143
|
+
type,
|
|
1144
|
+
logic_or_match = and,
|
|
1145
|
+
match_or_strict = true,
|
|
1146
|
+
strict = true
|
|
1147
|
+
) {
|
|
1148
|
+
/** @type {number} */
|
|
1149
|
+
|
|
1150
|
+
let len = arguments.length;
|
|
1151
|
+
|
|
1152
|
+
if (len < 2) {
|
|
1153
|
+
throw new TypeError(
|
|
1154
|
+
len == 1
|
|
1155
|
+
? "instancesof() missing 1 required arguments: 'type'"
|
|
1156
|
+
: "instancesof() missing 2 required arguments: 'objs' and 'type'"
|
|
1157
|
+
);
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
if (len > 5) {
|
|
1161
|
+
throw new TypeError(
|
|
1162
|
+
`instancesof() takes 5 positional arguments but ${len} were given`
|
|
1163
|
+
);
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
if (len === 3) {
|
|
1167
|
+
switch (arguments[2]) {
|
|
1168
|
+
case true:
|
|
1169
|
+
case false:
|
|
1170
|
+
return isinstances(objs, type, and, logic_or_match, strict);
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
if (len === 4) {
|
|
1175
|
+
switch (arguments[3]) {
|
|
1176
|
+
case true:
|
|
1177
|
+
case false:
|
|
1178
|
+
break;
|
|
1179
|
+
default:
|
|
1180
|
+
throw new TypeError("forth argument must be true or false");
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
switch (arguments[2]) {
|
|
1184
|
+
case true:
|
|
1185
|
+
case false:
|
|
1186
|
+
return isinstances(objs, type, and, logic_or_match, match_or_strict);
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
return isinstances(objs, type, logic_or_match, match_or_strict, strict);
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
/**
|
|
1194
|
+
* Compares a value or a list of values against a given type (or list of types),
|
|
1195
|
+
* similar to using `typeof x === y`, but in a more flexible and readable way.
|
|
1196
|
+
*
|
|
1197
|
+
* Supports single values or arrays, and can combine results using logical
|
|
1198
|
+
* operators like `"and"` or `"or"`.
|
|
1199
|
+
*
|
|
1200
|
+
* @param {* | Array<*>} data - The value or array of values to check.
|
|
1201
|
+
* @param {* | Array<*>} dataType - The expected type or array of expected types.
|
|
1202
|
+
* @param {"and" | "or" | boolean} logic_or_match - Logic mode: `"and"` requires all matches, `"or"` allows any match.
|
|
1203
|
+
* @param {boolean} match_or_strict - Whether to compare type names strictly or loosely.
|
|
1204
|
+
* @param {boolean} strict - If `true`, enforces strict comparison rules.
|
|
1205
|
+
* @returns {boolean} `true` if the data matches the expected type(s) according to the given logic, otherwise `false`.
|
|
1206
|
+
*/
|
|
1207
|
+
|
|
1208
|
+
export function isType(
|
|
1209
|
+
data,
|
|
1210
|
+
dataType,
|
|
1211
|
+
logic_or_match = and,
|
|
1212
|
+
match_or_strict = true,
|
|
1213
|
+
strict = true
|
|
1214
|
+
) {
|
|
1215
|
+
/** @type {number} */
|
|
1216
|
+
|
|
1217
|
+
let len = arguments.length;
|
|
1218
|
+
|
|
1219
|
+
if (len < 2) {
|
|
1220
|
+
throw new TypeError(
|
|
1221
|
+
len == 1
|
|
1222
|
+
? "isType() missing 1 required arguments: 'dataType'"
|
|
1223
|
+
: "isType() missing 2 required arguments: 'data' and 'dataType'"
|
|
1224
|
+
);
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
if (len > 5) {
|
|
1228
|
+
throw new TypeError(
|
|
1229
|
+
`isType() takes 5 positional arguments but ${len} were given`
|
|
1230
|
+
);
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
if (len === 3) {
|
|
1234
|
+
switch (arguments[2]) {
|
|
1235
|
+
case true:
|
|
1236
|
+
case false:
|
|
1237
|
+
return checkType(data, dataType, and, logic_or_match, strict);
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
if (len === 4) {
|
|
1242
|
+
switch (arguments[3]) {
|
|
1243
|
+
case true:
|
|
1244
|
+
case false:
|
|
1245
|
+
break;
|
|
1246
|
+
default:
|
|
1247
|
+
throw new TypeError("forth argument must be true or false");
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
switch (arguments[2]) {
|
|
1251
|
+
case true:
|
|
1252
|
+
case false:
|
|
1253
|
+
return checkType(data, dataType, and, logic_or_match, match_or_strict);
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
return checkType(data, dataType, logic_or_match, match_or_strict, strict);
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
/**
|
|
1261
|
+
* Checks whether all provided values have the same length.
|
|
1262
|
+
* Each value must have a numeric `length` property (e.g., arrays, strings, typed arrays, etc.).
|
|
1263
|
+
*
|
|
1264
|
+
* If all lengths are equal, returns a tuple containing that length and `true`.
|
|
1265
|
+
* Otherwise, returns a tuple containing an array of all detected lengths and `false`.
|
|
1266
|
+
*
|
|
1267
|
+
* @param {...{length: number}} objs - The values to compare by their length property.
|
|
1268
|
+
* @returns {[number | number[], boolean]} A tuple:
|
|
1269
|
+
* - `[length, true]` if all values have the same length.
|
|
1270
|
+
* - `[lengths, false]` if the lengths differ.
|
|
1271
|
+
*/
|
|
1272
|
+
|
|
1273
|
+
export function lengths(...objs) {
|
|
1274
|
+
// use not(objs) to enable all cases including one argument only
|
|
1275
|
+
|
|
1276
|
+
if (objs.length < 2) {
|
|
1277
|
+
throw new TypeError(
|
|
1278
|
+
`lengths() takes at least two arguments (${objs.length} given)`
|
|
1279
|
+
);
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
/** @type {Array<number>} */
|
|
1283
|
+
|
|
1284
|
+
let lens = [objs[0].length];
|
|
1285
|
+
|
|
1286
|
+
/** @type {boolean} */
|
|
1287
|
+
|
|
1288
|
+
let equal = true;
|
|
1289
|
+
|
|
1290
|
+
/** @type {number} */
|
|
1291
|
+
|
|
1292
|
+
let len;
|
|
1293
|
+
|
|
1294
|
+
for (let i = 1; i < objs.length; ++i) {
|
|
1295
|
+
len = objs[i].length;
|
|
1296
|
+
|
|
1297
|
+
lens.push(len);
|
|
1298
|
+
|
|
1299
|
+
if (!equal) {
|
|
1300
|
+
continue;
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
if (len !== lens[i - 1]) {
|
|
1304
|
+
equal = false;
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
if (equal) {
|
|
1309
|
+
return [lens[0], equal];
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
return [lens, equal];
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
/**
|
|
1316
|
+
* Evaluates the truthiness of a given value.
|
|
1317
|
+
* Works like the logical NOT operator (`!`), returning `true` if the value is falsy and `false` if it is truthy.
|
|
1318
|
+
*
|
|
1319
|
+
* @param {*} obj - The value to evaluate.
|
|
1320
|
+
* @returns {boolean} `true` if the value is falsy, otherwise `false`.
|
|
1321
|
+
*/
|
|
1322
|
+
|
|
1323
|
+
export function not(obj) {
|
|
1324
|
+
if (arguments.length === 0) {
|
|
1325
|
+
throw new TypeError("not() takes exactly one argument (0 given)");
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
if (obj instanceof Boolean) {
|
|
1329
|
+
return obj == false;
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
return obj?.length === 0 || !obj; // handling the object case
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
/**
|
|
1336
|
+
* Checks whether all provided values are of the same type.
|
|
1337
|
+
* Similar to the `typeof` operator but supports multiple inputs.
|
|
1338
|
+
*
|
|
1339
|
+
* If all values share the same type, returns a tuple containing that type as a string and `true`.
|
|
1340
|
+
* Otherwise, returns a tuple containing an array of the detected types and `false`.
|
|
1341
|
+
*
|
|
1342
|
+
* @param {...*} objs - The values to check.
|
|
1343
|
+
* @returns {[string | string[], boolean]} A tuple:
|
|
1344
|
+
* - `[type, true]` if all values are of the same type.
|
|
1345
|
+
* - `[types, false]` if values have mixed types.
|
|
1346
|
+
*/
|
|
1347
|
+
|
|
1348
|
+
export function typesof(...objs) {
|
|
1349
|
+
// use not(objs) to enable all cases including one argument only
|
|
1350
|
+
|
|
1351
|
+
if (objs.length < 2) {
|
|
1352
|
+
throw new TypeError(
|
|
1353
|
+
`typesof() takes at least two arguments (${objs.length} given)`
|
|
1354
|
+
);
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
/** @type {Array<string>} */
|
|
1358
|
+
|
|
1359
|
+
let types = [typeof objs[0]];
|
|
1360
|
+
|
|
1361
|
+
/** @type {boolean} */
|
|
1362
|
+
|
|
1363
|
+
let equal = true;
|
|
1364
|
+
|
|
1365
|
+
/** @type {string} */
|
|
1366
|
+
|
|
1367
|
+
let type;
|
|
1368
|
+
|
|
1369
|
+
for (let i = 1; i < objs.length; ++i) {
|
|
1370
|
+
type = typeof objs[i];
|
|
1371
|
+
|
|
1372
|
+
types.push(type);
|
|
1373
|
+
|
|
1374
|
+
if (!equal) {
|
|
1375
|
+
continue;
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
if (type !== types[i - 1]) {
|
|
1379
|
+
equal = false;
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
if (equal) {
|
|
1384
|
+
return [types[0], equal];
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
return [types, equal];
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
/**
|
|
1391
|
+
* Evaluates the truthiness of a given value.
|
|
1392
|
+
* Works like the logical NOT operator (`!`), returning `true` if the value is falsy and `false` if it is truthy.
|
|
1393
|
+
*
|
|
1394
|
+
* @param {*} obj - The value to evaluate.
|
|
1395
|
+
* @returns {boolean} `true` if the value is falsy, otherwise `false`.
|
|
1396
|
+
*/
|
|
1397
|
+
|
|
1398
|
+
export function $(obj) {
|
|
1399
|
+
return not(obj);
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
function main() {
|
|
1403
|
+
console.log("----------instancesof----------");
|
|
1404
|
+
|
|
1405
|
+
/** @type {Number} */
|
|
1406
|
+
|
|
1407
|
+
let a = new Number(3);
|
|
1408
|
+
|
|
1409
|
+
/** @type {Number} */
|
|
1410
|
+
|
|
1411
|
+
let b = new Number(7);
|
|
1412
|
+
|
|
1413
|
+
/** @type {String} */
|
|
1414
|
+
|
|
1415
|
+
let c = new String("test");
|
|
1416
|
+
|
|
1417
|
+
// one to one (disabled)
|
|
1418
|
+
|
|
1419
|
+
// console.log(instancesof(a, Number)); // true
|
|
1420
|
+
// console.log(instancesof(a, [Number])); // true
|
|
1421
|
+
// console.log(instancesof([a], Number)); // true
|
|
1422
|
+
|
|
1423
|
+
// match=true and strict=true (default)
|
|
1424
|
+
// console.log(instancesof([a], [Number])); // true
|
|
1425
|
+
|
|
1426
|
+
// match=false and strict=true
|
|
1427
|
+
// but when match=false strict don't matter True or False
|
|
1428
|
+
// console.log(instancesof([a], [Number], false)); // true
|
|
1429
|
+
|
|
1430
|
+
// one to many
|
|
1431
|
+
|
|
1432
|
+
console.log(instancesof(a, [Number, String], false)); // true
|
|
1433
|
+
console.log(instancesof([a], [Number, String], false)); // true
|
|
1434
|
+
|
|
1435
|
+
// match=true and strict=false
|
|
1436
|
+
// in this case take just Number with x the second type ignored
|
|
1437
|
+
console.log(instancesof(a, [Number, String], true, false)); // true
|
|
1438
|
+
|
|
1439
|
+
console.log(instancesof([a], [Number, String], true, false)); // true
|
|
1440
|
+
|
|
1441
|
+
// many to one
|
|
1442
|
+
|
|
1443
|
+
// AND
|
|
1444
|
+
|
|
1445
|
+
console.log(instancesof([a, b], Number)); // true
|
|
1446
|
+
console.log(instancesof([a, b], [Number], false)); // true
|
|
1447
|
+
|
|
1448
|
+
// OR
|
|
1449
|
+
|
|
1450
|
+
console.log(instancesof([b, c], Number, or)); // true
|
|
1451
|
+
console.log(instancesof([b, c], [Number], or, false)); // true
|
|
1452
|
+
|
|
1453
|
+
// many to many
|
|
1454
|
+
|
|
1455
|
+
// AND
|
|
1456
|
+
|
|
1457
|
+
console.log(instancesof([a, b], [Number, String], false)); // true
|
|
1458
|
+
|
|
1459
|
+
// OR
|
|
1460
|
+
|
|
1461
|
+
console.log(instancesof([b, c], [Number, Boolean], or, false)); // true
|
|
1462
|
+
|
|
1463
|
+
// pattern matching
|
|
1464
|
+
|
|
1465
|
+
// AND
|
|
1466
|
+
|
|
1467
|
+
console.log(instancesof([a, b], [Number, Number])); // true
|
|
1468
|
+
|
|
1469
|
+
console.log(instancesof([a, b], [Number, Number, String], true, false)); // true
|
|
1470
|
+
|
|
1471
|
+
// OR
|
|
1472
|
+
|
|
1473
|
+
console.log(instancesof([b, c], [Number, Boolean], or)); // true
|
|
1474
|
+
|
|
1475
|
+
console.log(instancesof([b, c], [Number, Boolean, String], or, true, false)); // true
|
|
1476
|
+
|
|
1477
|
+
console.log("------------isType------------");
|
|
1478
|
+
|
|
1479
|
+
/** @type {number} */
|
|
1480
|
+
|
|
1481
|
+
let x = 3; // or Number(3)
|
|
1482
|
+
|
|
1483
|
+
/** @type {number} */
|
|
1484
|
+
|
|
1485
|
+
let y = 7; // or Number(7)
|
|
1486
|
+
|
|
1487
|
+
/** @type {number} */
|
|
1488
|
+
|
|
1489
|
+
let z = "test"; // or String("test")
|
|
1490
|
+
|
|
1491
|
+
// one to one
|
|
1492
|
+
|
|
1493
|
+
console.log(isType(x, number)); // true
|
|
1494
|
+
console.log(isType(x, [number])); // true
|
|
1495
|
+
console.log(isType([x], number)); // true
|
|
1496
|
+
|
|
1497
|
+
// match=true and strict=true (default)
|
|
1498
|
+
console.log(isType([x], [number])); // true
|
|
1499
|
+
|
|
1500
|
+
// match=false and strict=true
|
|
1501
|
+
// but when match=false strict don't matter True or False
|
|
1502
|
+
console.log(isType([x], [number], false)); // true
|
|
1503
|
+
|
|
1504
|
+
// one to many
|
|
1505
|
+
|
|
1506
|
+
console.log(isType(x, [number, string], false)); // true
|
|
1507
|
+
console.log(isType([x], [number, string], false)); // true
|
|
1508
|
+
|
|
1509
|
+
// match=true and strict=false
|
|
1510
|
+
// in this case take just Number with x the second type ignored
|
|
1511
|
+
console.log(isType(x, [number, string], true, false)); // true
|
|
1512
|
+
|
|
1513
|
+
console.log(isType([x], [number, string], true, false)); // true
|
|
1514
|
+
|
|
1515
|
+
// many to one
|
|
1516
|
+
|
|
1517
|
+
// AND
|
|
1518
|
+
|
|
1519
|
+
console.log(isType([x, y], number)); // true
|
|
1520
|
+
console.log(isType([x, y], [number], false)); // true
|
|
1521
|
+
|
|
1522
|
+
// OR
|
|
1523
|
+
|
|
1524
|
+
console.log(isType([y, z], number, or)); // true
|
|
1525
|
+
console.log(isType([y, z], [number], or, false)); // true
|
|
1526
|
+
|
|
1527
|
+
// many to many
|
|
1528
|
+
|
|
1529
|
+
// AND
|
|
1530
|
+
|
|
1531
|
+
console.log(isType([x, y], [number, string], false)); // true
|
|
1532
|
+
|
|
1533
|
+
// OR
|
|
1534
|
+
|
|
1535
|
+
console.log(isType([y, z], [number, boolean], or, false)); // true
|
|
1536
|
+
|
|
1537
|
+
// pattern matching
|
|
1538
|
+
|
|
1539
|
+
// AND
|
|
1540
|
+
|
|
1541
|
+
console.log(isType([x, y], [number, number])); // true
|
|
1542
|
+
|
|
1543
|
+
console.log(isType([x, y], [number, number, string], true, false)); // true
|
|
1544
|
+
|
|
1545
|
+
// OR
|
|
1546
|
+
|
|
1547
|
+
console.log(isType([y, z], [number, boolean], or)); // true
|
|
1548
|
+
|
|
1549
|
+
console.log(isType([y, z], [number, boolean, string], or, true, false)); // true
|
|
1550
|
+
|
|
1551
|
+
console.log("-----------lengths-----------");
|
|
1552
|
+
|
|
1553
|
+
// // use .length directly in this case is the best practice
|
|
1554
|
+
// // one arg (disabled)
|
|
1555
|
+
|
|
1556
|
+
// console.log(lengths([1, 2, 3])); // [ 3, true ]
|
|
1557
|
+
|
|
1558
|
+
// two args +
|
|
1559
|
+
|
|
1560
|
+
console.log(lengths([1, 2, 3], [1, 2, 3])); // [ 3, true ]
|
|
1561
|
+
console.log(lengths([1, 2, 3], "hello")); // [ [3, 5], false ]
|
|
1562
|
+
|
|
1563
|
+
console.log("--------------!--------------");
|
|
1564
|
+
|
|
1565
|
+
console.log(!"test"); // false
|
|
1566
|
+
console.log(!1); // false
|
|
1567
|
+
console.log(!true); // false
|
|
1568
|
+
console.log(!""); // true
|
|
1569
|
+
console.log(!0); // true
|
|
1570
|
+
console.log(!false); // true
|
|
1571
|
+
console.log(!null); // true
|
|
1572
|
+
console.log(!undefined); // true
|
|
1573
|
+
|
|
1574
|
+
// using (!) these is false because objects in JS always true
|
|
1575
|
+
console.log(![]); // new Array()
|
|
1576
|
+
console.log(!new Boolean(""));
|
|
1577
|
+
console.log(!new Boolean(0));
|
|
1578
|
+
console.log(!new Boolean(false));
|
|
1579
|
+
console.log(!new Boolean(null));
|
|
1580
|
+
console.log(!new Boolean(undefined));
|
|
1581
|
+
|
|
1582
|
+
console.log("-------------not-------------");
|
|
1583
|
+
|
|
1584
|
+
console.log(not("test")); // false
|
|
1585
|
+
console.log(not(1)); // false
|
|
1586
|
+
console.log(not(true)); // false
|
|
1587
|
+
console.log(not("")); // true
|
|
1588
|
+
console.log(not(0)); // true
|
|
1589
|
+
console.log(not(false)); // true
|
|
1590
|
+
console.log(not(null)); // true
|
|
1591
|
+
console.log(not(undefined)); // true
|
|
1592
|
+
|
|
1593
|
+
// using (not) these is true because is empty/falsy values
|
|
1594
|
+
console.log(not([])); // new Array()
|
|
1595
|
+
console.log(not(new Boolean("")));
|
|
1596
|
+
console.log(not(new Boolean(0)));
|
|
1597
|
+
console.log(not(new Boolean(false)));
|
|
1598
|
+
console.log(not(new Boolean(null)));
|
|
1599
|
+
console.log(not(new Boolean(undefined)));
|
|
1600
|
+
|
|
1601
|
+
// you can use $() in place of not() (syntactic sugar)
|
|
1602
|
+
|
|
1603
|
+
console.log("-----------typesof-----------");
|
|
1604
|
+
|
|
1605
|
+
// // use typeof directly in this case is the best practice
|
|
1606
|
+
// // one arg (disabled)
|
|
1607
|
+
|
|
1608
|
+
// console.log(typesof(1)); // [ number, true ]
|
|
1609
|
+
|
|
1610
|
+
// two args +
|
|
1611
|
+
|
|
1612
|
+
console.log(typesof(1, 2)); // [ number, true ]
|
|
1613
|
+
console.log(typesof(1, "hi")); // [ [number, string], false ]
|
|
1614
|
+
|
|
1615
|
+
console.log("------------------------------");
|
|
1616
|
+
|
|
1617
|
+
console.log("51 tests passed");
|
|
1618
|
+
|
|
1619
|
+
console.log("7 tests are commented");
|
|
1620
|
+
|
|
1621
|
+
console.log("total tests : 58");
|
|
1622
|
+
|
|
1623
|
+
console.log("============ jsfunx ============");
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1626
|
+
/**
|
|
1627
|
+
* The name of the main script file that was executed.
|
|
1628
|
+
* Derived from the second CLI argument (`process.argv[1]`).
|
|
1629
|
+
*
|
|
1630
|
+
* @type {string}
|
|
1631
|
+
*/
|
|
1632
|
+
|
|
1633
|
+
const mainFile = basename(argv[1]);
|
|
1634
|
+
|
|
1635
|
+
/**
|
|
1636
|
+
* The name of the currently running module file.
|
|
1637
|
+
* Computed from the current module URL using `fileURLToPath(import.meta.url)`.
|
|
1638
|
+
*
|
|
1639
|
+
* @type {string}
|
|
1640
|
+
*/
|
|
1641
|
+
|
|
1642
|
+
const currentFile = basename(fileURLToPath(import.meta.url));
|
|
1643
|
+
|
|
1644
|
+
if (currentFile === mainFile) {
|
|
1645
|
+
main(); // testing
|
|
1646
|
+
}
|