@lowentry/utils 0.1.1

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/LeTypes.js ADDED
@@ -0,0 +1,76 @@
1
+ export const ISSET = (value) => (typeof value !== 'undefined') && (value !== null);
2
+
3
+ export const IS_ARRAY = (value) => Array.isArray(value);
4
+ export const ARRAY = (value) => IS_ARRAY(value) ? value : ((typeof value !== 'undefined') ? [value] : []);
5
+
6
+ export const IS_OBJECT = (value) => (typeof value === 'object') && (value !== null) && !Array.isArray(value);
7
+ export const OBJECT = (value) => IS_OBJECT(value) ? value : {};
8
+
9
+ export const STRING = (value) => ISSET(value) ? ('' + value) : '';
10
+ export const STRING_ANY = (...values) =>
11
+ {
12
+ for(let value of values)
13
+ {
14
+ if(ISSET(value))
15
+ {
16
+ return '' + value;
17
+ }
18
+ }
19
+ return '';
20
+ };
21
+
22
+ export const INT = (value) => Math.round(FLOAT(value));
23
+ export const INT_ANY = (...values) => Math.round(FLOAT_ANY(...values));
24
+
25
+ export const FLOAT = (value) =>
26
+ {
27
+ const v = +value;
28
+ if(!isNaN(v))
29
+ {
30
+ return v;
31
+ }
32
+ return 0;
33
+ };
34
+ export const FLOAT_ANY = (...values) =>
35
+ {
36
+ for(let value of values)
37
+ {
38
+ if(value !== null)
39
+ {
40
+ const v = +value;
41
+ if(!isNaN(v))
42
+ {
43
+ return v;
44
+ }
45
+ }
46
+ }
47
+ return 0;
48
+ };
49
+
50
+ export const INT_LAX = (value) => Math.round(FLOAT_LAX(value));
51
+ export const INT_LAX_ANY = (...values) => Math.round(FLOAT_LAX_ANY(...values));
52
+
53
+ export const FLOAT_LAX = (value) =>
54
+ {
55
+ const v = parseFloat(value);
56
+ if(!isNaN(v))
57
+ {
58
+ return v;
59
+ }
60
+ return 0;
61
+ };
62
+ export const FLOAT_LAX_ANY = (...values) =>
63
+ {
64
+ for(let value of values)
65
+ {
66
+ if(value !== null)
67
+ {
68
+ const v = parseFloat(value);
69
+ if(!isNaN(v))
70
+ {
71
+ return v;
72
+ }
73
+ }
74
+ }
75
+ return 0;
76
+ };
package/LeUtils.js ADDED
@@ -0,0 +1,890 @@
1
+ import FastDeepEqual from 'fast-deep-equal';
2
+ import {ISSET, IS_OBJECT, STRING, INT, FLOAT, FLOAT_ANY, INT_LAX} from './LeTypes.js';
3
+
4
+
5
+ export const LeUtils = {
6
+ equals:FastDeepEqual,
7
+
8
+ getCleanErrorMessage:
9
+ (error) =>
10
+ {
11
+ const message = STRING(((typeof error === 'string') ? error : (error.message ?? JSON.stringify(error))));
12
+ const messageParts = message.split('threw an error:');
13
+ return messageParts[messageParts.length - 1].trim();
14
+ },
15
+
16
+ /** expects a version string like "1.2.3" or "1.2.3 r0" **/
17
+ parseVersionString:
18
+ (versionString) =>
19
+ {
20
+ if(IS_OBJECT(versionString) && ISSET(versionString?.major) && ISSET(versionString?.minor) && ISSET(versionString?.patch))
21
+ {
22
+ return versionString;
23
+ }
24
+
25
+ versionString = STRING(versionString).trim();
26
+ const partsVersion = versionString.split(' ')[0].split('-')[0].split('.');
27
+ const major = INT_LAX(partsVersion[0]);
28
+ const minor = INT_LAX(partsVersion[1]);
29
+ const patch = INT_LAX(partsVersion[2]);
30
+
31
+ const THIS = {
32
+ major:major,
33
+ minor:minor,
34
+ patch:patch,
35
+
36
+ toString:
37
+ () => major + '.' + minor + '.' + patch,
38
+
39
+ equals:
40
+ (otherVersion) =>
41
+ {
42
+ otherVersion = LeUtils.parseVersionString(otherVersion);
43
+ return (major === otherVersion.major) && (minor === otherVersion.minor) && (patch === otherVersion.patch);
44
+ },
45
+
46
+ largerThan:
47
+ (otherVersion) =>
48
+ {
49
+ otherVersion = LeUtils.parseVersionString(otherVersion);
50
+
51
+ if(major > otherVersion.major)
52
+ {
53
+ return true;
54
+ }
55
+ if(major < otherVersion.major)
56
+ {
57
+ return false;
58
+ }
59
+
60
+ if(minor > otherVersion.minor)
61
+ {
62
+ return true;
63
+ }
64
+ if(minor < otherVersion.minor)
65
+ {
66
+ return false;
67
+ }
68
+
69
+ return (patch > otherVersion.patch);
70
+ },
71
+
72
+ largerThanOrEquals:
73
+ (otherVersion) =>
74
+ {
75
+ otherVersion = LeUtils.parseVersionString(otherVersion);
76
+
77
+ if(major > otherVersion.major)
78
+ {
79
+ return true;
80
+ }
81
+ if(major < otherVersion.major)
82
+ {
83
+ return false;
84
+ }
85
+
86
+ if(minor > otherVersion.minor)
87
+ {
88
+ return true;
89
+ }
90
+ if(minor < otherVersion.minor)
91
+ {
92
+ return false;
93
+ }
94
+
95
+ return (patch >= otherVersion.patch);
96
+ },
97
+
98
+ smallerThan:
99
+ (otherVersion) => !THIS.largerThanOrEquals(otherVersion),
100
+
101
+ smallerThanOrEquals:
102
+ (otherVersion) => !THIS.largerThan(otherVersion),
103
+ };
104
+ return THIS;
105
+ },
106
+
107
+ contains:
108
+ (array, value) =>
109
+ {
110
+ if(!array)
111
+ {
112
+ return false;
113
+ }
114
+ let result = false;
115
+ value = STRING(value);
116
+ LeUtils.each(array, (val) =>
117
+ {
118
+ if(STRING(val) === value)
119
+ {
120
+ result = true;
121
+ return false;
122
+ }
123
+ });
124
+ return result;
125
+ },
126
+
127
+ containsCaseInsensitive:
128
+ (array, value) =>
129
+ {
130
+ if(!array)
131
+ {
132
+ return false;
133
+ }
134
+ let result = false;
135
+ value = STRING(value).toLowerCase();
136
+ LeUtils.each(array, (val) =>
137
+ {
138
+ if(STRING(val).toLowerCase() === value)
139
+ {
140
+ result = true;
141
+ return false;
142
+ }
143
+ });
144
+ return result;
145
+ },
146
+
147
+ each:
148
+ (elements, callback, optionalSkipHasOwnPropertyCheck = false) =>
149
+ {
150
+ if((elements !== null) && (typeof elements !== 'undefined'))
151
+ {
152
+ if(Array.isArray(elements))
153
+ {
154
+ for(let index = 0; index < elements.length; index++)
155
+ {
156
+ if(callback.call(elements[index], elements[index], index) === false)
157
+ {
158
+ break;
159
+ }
160
+ }
161
+ }
162
+ else if((typeof elements === 'object') || (typeof elements === 'function'))
163
+ {
164
+ for(let index in elements)
165
+ {
166
+ if((optionalSkipHasOwnPropertyCheck === true) || Object.prototype.hasOwnProperty.call(elements, index))
167
+ {
168
+ if(callback.call(elements[index], elements[index], index) === false)
169
+ {
170
+ break;
171
+ }
172
+ }
173
+ }
174
+ }
175
+ else
176
+ {
177
+ console.warn('Executed LeUtils.each() on an invalid type: [' + (typeof elements) + ']', elements);
178
+ }
179
+ }
180
+ return elements;
181
+ },
182
+
183
+ filter:
184
+ (elements, callback, optionalSkipHasOwnPropertyCheck = false) =>
185
+ {
186
+ if((elements !== null) && (typeof elements !== 'undefined'))
187
+ {
188
+ if(Array.isArray(elements))
189
+ {
190
+ let result = [];
191
+ for(let index = 0; index < elements.length; index++)
192
+ {
193
+ if(callback.call(elements[index], elements[index], index) !== false)
194
+ {
195
+ result.push(elements[index]);
196
+ }
197
+ }
198
+ return result;
199
+ }
200
+ else if((typeof elements === 'object') || (typeof elements === 'function'))
201
+ {
202
+ let result = {};
203
+ for(let index in elements)
204
+ {
205
+ if((optionalSkipHasOwnPropertyCheck === true) || Object.prototype.hasOwnProperty.call(elements, index))
206
+ {
207
+ if(callback.call(elements[index], elements[index], index) !== false)
208
+ {
209
+ result[index] = elements[index];
210
+ }
211
+ }
212
+ }
213
+ return result;
214
+ }
215
+ else
216
+ {
217
+ console.warn('Executed LeUtils.filter() on an invalid type: [' + (typeof elements) + ']', elements);
218
+ }
219
+ }
220
+ return elements;
221
+ },
222
+
223
+ map:
224
+ (elements, callback, optionalSkipHasOwnPropertyCheck = false) =>
225
+ {
226
+ if((elements !== null) && (typeof elements !== 'undefined'))
227
+ {
228
+ if(Array.isArray(elements))
229
+ {
230
+ let result = [];
231
+ for(let index = 0; index < elements.length; index++)
232
+ {
233
+ result[index] = callback.call(elements[index], elements[index], index);
234
+ }
235
+ return result;
236
+ }
237
+ else if((typeof elements === 'object') || (typeof elements === 'function'))
238
+ {
239
+ let result = {};
240
+ for(let index in elements)
241
+ {
242
+ if((optionalSkipHasOwnPropertyCheck === true) || Object.prototype.hasOwnProperty.call(elements, index))
243
+ {
244
+ result[index] = callback.call(elements[index], elements[index], index);
245
+ }
246
+ }
247
+ return result;
248
+ }
249
+ else
250
+ {
251
+ console.warn('Executed LeUtils.map() on an invalid type: [' + (typeof elements) + ']', elements);
252
+ }
253
+ }
254
+ return elements;
255
+ },
256
+
257
+ mapToArray:
258
+ (elements, callback, optionalSkipHasOwnPropertyCheck = false) =>
259
+ {
260
+ let result = [];
261
+ if((elements !== null) && (typeof elements !== 'undefined'))
262
+ {
263
+ if(Array.isArray(elements))
264
+ {
265
+ for(let index = 0; index < elements.length; index++)
266
+ {
267
+ result.push(callback.call(elements[index], elements[index], index));
268
+ }
269
+ }
270
+ else if((typeof elements === 'object') || (typeof elements === 'function'))
271
+ {
272
+ for(let index in elements)
273
+ {
274
+ if((optionalSkipHasOwnPropertyCheck === true) || Object.prototype.hasOwnProperty.call(elements, index))
275
+ {
276
+ result.push(callback.call(elements[index], elements[index], index));
277
+ }
278
+ }
279
+ }
280
+ else
281
+ {
282
+ console.warn('Executed LeUtils.mapToArray() on an invalid type: [' + (typeof elements) + ']', elements);
283
+ }
284
+ }
285
+ return result;
286
+ },
287
+
288
+ mapToArraySorted:
289
+ (elements, comparator, callback, optionalSkipHasOwnPropertyCheck = false) =>
290
+ {
291
+ const keys = LeUtils.sortKeys(elements, comparator, optionalSkipHasOwnPropertyCheck);
292
+ let result = [];
293
+ for(let i = 0; i < keys.length; i++)
294
+ {
295
+ result.push(callback.call(elements[keys[i]], elements[keys[i]], keys[i]));
296
+ }
297
+ return result;
298
+ },
299
+
300
+ sortKeys:
301
+ (elements, comparator, optionalSkipHasOwnPropertyCheck = false) =>
302
+ {
303
+ let keys = [];
304
+ if((elements !== null) && (typeof elements !== 'undefined'))
305
+ {
306
+ if(Array.isArray(elements))
307
+ {
308
+ for(let index = 0; index < elements.length; index++)
309
+ {
310
+ keys.push(index);
311
+ }
312
+ }
313
+ else if((typeof elements === 'object') || (typeof elements === 'function'))
314
+ {
315
+ for(let index in elements)
316
+ {
317
+ if((optionalSkipHasOwnPropertyCheck === true) || Object.prototype.hasOwnProperty.call(elements, index))
318
+ {
319
+ keys.push(index);
320
+ }
321
+ }
322
+ }
323
+ else
324
+ {
325
+ console.warn('Executed LeUtils.sortKeys() on an invalid type: [' + (typeof elements) + ']', elements);
326
+ }
327
+ }
328
+ keys.sort((a, b) => comparator(elements[a], elements[b]));
329
+ return keys;
330
+ },
331
+
332
+ compare:
333
+ (a, b) =>
334
+ {
335
+ if(a < b)
336
+ {
337
+ return -1;
338
+ }
339
+ if(a > b)
340
+ {
341
+ return 1;
342
+ }
343
+ return 0;
344
+ },
345
+
346
+ compareNumbers:
347
+ (a, b) => a - b,
348
+
349
+ compareNumericStrings:
350
+ (a, b) =>
351
+ {
352
+ a = STRING(a).trim();
353
+ b = STRING(b).trim();
354
+ if(a.length === b.length)
355
+ {
356
+ return (a < b) ? -1 : ((a > b) ? 1 : 0);
357
+ }
358
+ return (a.length < b.length) ? -1 : 1;
359
+ },
360
+
361
+ isEmptyObject:
362
+ (obj) =>
363
+ {
364
+ // noinspection LoopStatementThatDoesntLoopJS
365
+ for(let name in obj)
366
+ {
367
+ return false;
368
+ }
369
+ return true;
370
+ },
371
+
372
+ getObjectFieldsCount:
373
+ (obj) =>
374
+ {
375
+ let count = 0;
376
+ for(let name in obj)
377
+ {
378
+ count++;
379
+ }
380
+ return count;
381
+ },
382
+
383
+ flattenArray:
384
+ (() =>
385
+ {
386
+ const flattenArrayRecursive = (result, array) =>
387
+ {
388
+ if(!Array.isArray(array))
389
+ {
390
+ result.push(array);
391
+ return;
392
+ }
393
+ array.forEach((entry) =>
394
+ {
395
+ flattenArrayRecursive(result, entry);
396
+ });
397
+ };
398
+
399
+ return (array) =>
400
+ {
401
+ if(!Array.isArray(array))
402
+ {
403
+ return [array];
404
+ }
405
+ let result = [];
406
+ array.forEach((entry) =>
407
+ {
408
+ flattenArrayRecursive(result, entry);
409
+ });
410
+ return result;
411
+ };
412
+ })(),
413
+
414
+ isGeneratorFunction:
415
+ (() =>
416
+ {
417
+ const GeneratorFunction = function* ()
418
+ {
419
+ }.constructor;
420
+
421
+ const AsyncGeneratorFunction = async function* ()
422
+ {
423
+ }.constructor;
424
+
425
+ const RegularFunction = function()
426
+ {
427
+ }.constructor;
428
+
429
+ const PossibleGeneratorFunctionNames = Array.from(new Set(['GeneratorFunction', 'AsyncFunction', 'AsyncGeneratorFunction', GeneratorFunction.name, GeneratorFunction.displayName, AsyncGeneratorFunction.name, AsyncGeneratorFunction.displayName])).filter(function(element)
430
+ {
431
+ return (element && (element !== RegularFunction.name) && (element !== RegularFunction.displayName));
432
+ });
433
+
434
+ return (func) =>
435
+ {
436
+ if(!func)
437
+ {
438
+ return false;
439
+ }
440
+ const constructor = func.constructor;
441
+ if(!constructor)
442
+ {
443
+ return false;
444
+ }
445
+ return ((constructor.name && PossibleGeneratorFunctionNames.includes(constructor.name)) || (constructor.displayName && PossibleGeneratorFunctionNames.includes(constructor.displayName)));
446
+ };
447
+ })(),
448
+
449
+ setInterval:
450
+ (callback, intervalMs, fireImmediately) =>
451
+ {
452
+ intervalMs = FLOAT_ANY(intervalMs, 1000);
453
+
454
+ if(fireImmediately)
455
+ {
456
+ try
457
+ {
458
+ callback(0);
459
+ }
460
+ catch(e)
461
+ {
462
+ console.error(e);
463
+ }
464
+ }
465
+
466
+ let lastTime = performance.now();
467
+ let handler = setInterval(() =>
468
+ {
469
+ let currentTime = performance.now();
470
+ try
471
+ {
472
+ callback((currentTime - lastTime) / 1000);
473
+ }
474
+ catch(e)
475
+ {
476
+ console.error(e);
477
+ }
478
+ lastTime = currentTime;
479
+ }, intervalMs);
480
+
481
+ return {
482
+ remove:
483
+ () =>
484
+ {
485
+ if(handler !== null)
486
+ {
487
+ clearInterval(handler);
488
+ handler = null;
489
+ }
490
+ },
491
+ };
492
+ },
493
+
494
+ setAnimationFrameInterval:
495
+ (callback, intervalFrames, fireImmediately) =>
496
+ {
497
+ intervalFrames = INT(intervalFrames);
498
+
499
+ if(fireImmediately)
500
+ {
501
+ try
502
+ {
503
+ callback(0);
504
+ }
505
+ catch(e)
506
+ {
507
+ console.error(e);
508
+ }
509
+ }
510
+
511
+ let run = true;
512
+ let requestAnimationFrameId = null;
513
+ let lastTime = performance.now();
514
+ let frames = intervalFrames;
515
+ const tick = () =>
516
+ {
517
+ if(run)
518
+ {
519
+ if(frames <= 0)
520
+ {
521
+ let currentTime = performance.now();
522
+ try
523
+ {
524
+ callback((currentTime - lastTime) / 1000);
525
+ }
526
+ catch(e)
527
+ {
528
+ console.error(e);
529
+ }
530
+ lastTime = currentTime;
531
+ frames = intervalFrames;
532
+ }
533
+ frames--;
534
+
535
+ if(run)
536
+ {
537
+ requestAnimationFrameId = window?.requestAnimationFrame(tick);
538
+ }
539
+ }
540
+ };
541
+ window?.requestAnimationFrame(tick);
542
+
543
+ return {
544
+ remove:
545
+ () =>
546
+ {
547
+ run = false;
548
+ if(requestAnimationFrameId !== null)
549
+ {
550
+ cancelAnimationFrame(requestAnimationFrameId);
551
+ requestAnimationFrameId = null;
552
+ }
553
+ },
554
+ };
555
+ },
556
+
557
+ setAnimationFrameTimeout:
558
+ (callback, frames) =>
559
+ {
560
+ frames = INT(frames);
561
+
562
+ let run = true;
563
+ let requestAnimationFrameId = null;
564
+ const tick = () =>
565
+ {
566
+ if(run)
567
+ {
568
+ if(frames <= 0)
569
+ {
570
+ run = false;
571
+ requestAnimationFrameId = null;
572
+ try
573
+ {
574
+ callback();
575
+ }
576
+ catch(e)
577
+ {
578
+ console.error(e);
579
+ }
580
+ return;
581
+ }
582
+ frames--;
583
+ requestAnimationFrameId = window?.requestAnimationFrame(tick);
584
+ }
585
+ };
586
+ tick();
587
+
588
+ return {
589
+ remove:
590
+ () =>
591
+ {
592
+ run = false;
593
+ if(requestAnimationFrameId !== null)
594
+ {
595
+ cancelAnimationFrame(requestAnimationFrameId);
596
+ requestAnimationFrameId = null;
597
+ }
598
+ },
599
+ };
600
+ },
601
+
602
+ capitalize:
603
+ (string) =>
604
+ {
605
+ string = STRING(string).trim();
606
+ if(string.length <= 0)
607
+ {
608
+ return string;
609
+ }
610
+ return string.charAt(0).toUpperCase() + string.slice(1);
611
+ },
612
+
613
+ stopPropagation:
614
+ (callback) =>
615
+ {
616
+ return (event) =>
617
+ {
618
+ event.stopPropagation();
619
+ if(typeof callback !== 'undefined')
620
+ {
621
+ callback();
622
+ }
623
+ };
624
+ },
625
+
626
+ /**
627
+ * Returns true if the user is on a smartphone device (mobile).
628
+ * Will return false if the user is on a tablet or on a desktop.
629
+ *
630
+ * In short:
631
+ * - Mobile: True
632
+ * - Tablet: False
633
+ * - Desktop: False
634
+ */
635
+ platformIsMobile:
636
+ () =>
637
+ {
638
+ // noinspection JSDeprecatedSymbols, JSUnresolvedReference
639
+ /** navigator.userAgentData.mobile doesn't return the correct value on some platforms, so this is a work-around, code from: http://detectmobilebrowsers.com **/
640
+ const a = STRING(window?.navigator?.userAgent || window?.navigator?.vendor || window?.opera || '');
641
+ const b = a.substring(0, 4);
642
+ return !!(
643
+ /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series([46])0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i
644
+ .test(a) ||
645
+ /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br([ev])w|bumb|bw-([nu])|c55\/|capi|ccwa|cdm-|cell|chtm|cldc|cmd-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc-s|devi|dica|dmob|do([cp])o|ds(12|-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly([-_])|g1 u|g560|gene|gf-5|g-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd-([mpt])|hei-|hi(pt|ta)|hp( i|ip)|hs-c|ht(c([- _agpst])|tp)|hu(aw|tc)|i-(20|go|ma)|i230|iac([ \-/])|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja([tv])a|jbro|jemu|jigs|kddi|keji|kgt([ /])|klon|kpt |kwc-|kyo([ck])|le(no|xi)|lg( g|\/([klu])|50|54|-[a-w])|libw|lynx|m1-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t([- ov])|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30([02])|n50([025])|n7(0([01])|10)|ne(([cm])-|on|tf|wf|wg|wt)|nok([6i])|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan([adt])|pdxg|pg(13|-([1-8]|c))|phil|pire|pl(ay|uc)|pn-2|po(ck|rt|se)|prox|psio|pt-g|qa-a|qc(07|12|21|32|60|-[2-7]|i-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h-|oo|p-)|sdk\/|se(c([-01])|47|mc|nd|ri)|sgh-|shar|sie([-m])|sk-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h-|v-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl-|tdg-|tel([im])|tim-|t-mo|to(pl|sh)|ts(70|m-|m3|m5)|tx-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c([- ])|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas-|your|zeto|zte-/i
646
+ .test(b)
647
+ );
648
+ },
649
+
650
+ /**
651
+ * Returns true if the user has a cursor (mouse, touchpad, etc).
652
+ * In this context, a cursor is defined as an input device that can hover over elements without necessarily interacting with them.
653
+ */
654
+ platformHasCursor:
655
+ () =>
656
+ {
657
+ return !LeUtils.platformIsMobile() && !window?.matchMedia('(any-hover: none)')?.matches;
658
+ },
659
+
660
+ promiseTimeout:
661
+ (timeoutMs) =>
662
+ {
663
+ timeoutMs = FLOAT(timeoutMs);
664
+ if(timeoutMs <= 0)
665
+ {
666
+ return new Promise(resolve => resolve());
667
+ }
668
+ return new Promise(resolve => setTimeout(resolve, timeoutMs));
669
+ },
670
+
671
+ endsWithAny:
672
+ (string, endingCharsStringOrArray) =>
673
+ {
674
+ string = STRING(string);
675
+ let endingCharsArray;
676
+ if(Array.isArray(endingCharsStringOrArray))
677
+ {
678
+ endingCharsArray = endingCharsStringOrArray;
679
+ }
680
+ else
681
+ {
682
+ endingCharsArray = STRING(endingCharsStringOrArray).split('');
683
+ }
684
+ let result = false;
685
+ LeUtils.each(endingCharsArray, (chars) =>
686
+ {
687
+ if(string.endsWith(STRING(chars)))
688
+ {
689
+ result = true;
690
+ return false;
691
+ }
692
+ });
693
+ return result;
694
+ },
695
+
696
+ startsWithAny:
697
+ (string, startingCharsStringOrArray) =>
698
+ {
699
+ string = STRING(string);
700
+ let startingCharsArray;
701
+ if(Array.isArray(startingCharsStringOrArray))
702
+ {
703
+ startingCharsArray = startingCharsStringOrArray;
704
+ }
705
+ else
706
+ {
707
+ startingCharsArray = STRING(startingCharsStringOrArray).split('');
708
+ }
709
+ let result = false;
710
+ LeUtils.each(startingCharsArray, (chars) =>
711
+ {
712
+ if(string.startsWith(STRING(chars)))
713
+ {
714
+ result = true;
715
+ return false;
716
+ }
717
+ });
718
+ return result;
719
+ },
720
+
721
+ trimEnd:
722
+ (string, trimCharsStringOrArray) =>
723
+ {
724
+ string = STRING(string);
725
+ let endingCharsArray;
726
+ if(Array.isArray(trimCharsStringOrArray))
727
+ {
728
+ endingCharsArray = trimCharsStringOrArray;
729
+ }
730
+ else
731
+ {
732
+ endingCharsArray = STRING(trimCharsStringOrArray).split('');
733
+ }
734
+ const trimChars = (chars) =>
735
+ {
736
+ chars = STRING(chars);
737
+ if(string.endsWith(chars))
738
+ {
739
+ string = string.substring(0, string.length - chars.length);
740
+ run = true;
741
+ }
742
+ };
743
+ let run = true;
744
+ while(run)
745
+ {
746
+ run = false;
747
+ LeUtils.each(endingCharsArray, trimChars);
748
+ }
749
+ return string;
750
+ },
751
+
752
+ trimStart:
753
+ (string, trimCharsStringOrArray) =>
754
+ {
755
+ string = STRING(string);
756
+ let startingCharsArray;
757
+ if(Array.isArray(trimCharsStringOrArray))
758
+ {
759
+ startingCharsArray = trimCharsStringOrArray;
760
+ }
761
+ else
762
+ {
763
+ startingCharsArray = STRING(trimCharsStringOrArray).split('');
764
+ }
765
+ const trimChars = (chars) =>
766
+ {
767
+ chars = STRING(chars);
768
+ if(string.startsWith(chars))
769
+ {
770
+ string = string.substring(chars.length);
771
+ run = true;
772
+ }
773
+ };
774
+ let run = true;
775
+ while(run)
776
+ {
777
+ run = false;
778
+ LeUtils.each(startingCharsArray, trimChars);
779
+ }
780
+ return string;
781
+ },
782
+
783
+ trim:
784
+ (string, trimCharsStringOrArray) => LeUtils.trimEnd(LeUtils.trimStart(string, trimCharsStringOrArray), trimCharsStringOrArray),
785
+
786
+ cleanupSentence:
787
+ (sentence) =>
788
+ {
789
+ sentence = LeUtils.trimEnd(STRING(sentence).trim(), '.: \r\n\t');
790
+ sentence += (LeUtils.endsWithAny(sentence, '!?;') ? '' : '.');
791
+ return sentence;
792
+ },
793
+
794
+ increaseNumericStringByOne:
795
+ (string) =>
796
+ {
797
+ if(typeof string !== 'string')
798
+ {
799
+ string = '' + string;
800
+ for(let i = string.length - 1; i >= 0; i--)
801
+ {
802
+ const c = string.charAt(i);
803
+ if((c < '0') || (c > '9'))
804
+ {
805
+ return '1';
806
+ }
807
+ }
808
+ }
809
+ if(string === '')
810
+ {
811
+ return '1';
812
+ }
813
+ for(let i = string.length - 1; i >= 0; i--)
814
+ {
815
+ let c = string.charAt(i);
816
+ if((c < '0') || (c > '9'))
817
+ {
818
+ return '1';
819
+ }
820
+ if(c < '9')
821
+ {
822
+ c++;
823
+ string = string.substring(0, i) + c + string.substring(i + 1);// string[i] = (char + 1);
824
+ break;
825
+ }
826
+ string = string.substring(0, i) + '0' + string.substring(i + 1);// string[i] = '0';
827
+ }
828
+ if(string.charAt(0) === '0')
829
+ {
830
+ string = '1' + string;
831
+ }
832
+ return string;
833
+ },
834
+
835
+ uniqueId:
836
+ (() =>
837
+ {
838
+ let previousUniqueIdsTime = null;
839
+ let previousUniqueIds = {};
840
+
841
+ const generateUniqueId = () =>
842
+ {
843
+ let now;
844
+ try
845
+ {
846
+ // noinspection JSDeprecatedSymbols
847
+ now = (performance.timeOrigin || performance.timing.navigationStart) + performance.now();
848
+ if(typeof now !== 'number')
849
+ {
850
+ throw new Error();
851
+ }
852
+ }
853
+ catch(e)
854
+ {
855
+ now = (Date.now ? Date.now() : (new Date()).getTime());
856
+ }
857
+
858
+ return {
859
+ time:now,
860
+ id: (now + '_' + (Math.random() + '').substring(2)).replace(/\D/g, '_'),
861
+ };
862
+ };
863
+
864
+ return () =>
865
+ {
866
+ while(true)
867
+ {
868
+ const result = generateUniqueId();
869
+ if(previousUniqueIdsTime !== result.time)
870
+ {
871
+ previousUniqueIdsTime = result.time;
872
+ previousUniqueIds = {[result.id]:true};
873
+ return result.id;
874
+ }
875
+ else if(previousUniqueIds[result.id] !== true)
876
+ {
877
+ previousUniqueIds[result.id] = true;
878
+ return result.id;
879
+ }
880
+ }
881
+ };
882
+ })(),
883
+
884
+ getEmptyImageSrc:
885
+ () =>
886
+ {
887
+ // noinspection SpellCheckingInspection
888
+ return 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
889
+ },
890
+ };
package/README.md ADDED
@@ -0,0 +1,24 @@
1
+ # @lowentry/utils
2
+
3
+ Provides utilities for general JavaScript development.
4
+
5
+
6
+ ## Description
7
+
8
+ This plugin will add utility functions and classes to make it easier to use JavaScript.
9
+
10
+ Think about things such as:
11
+
12
+ - looping through arrays and objects indiscriminately
13
+ - ensuring that a value is a certain type
14
+ - generating unique IDs
15
+ - trimming certain characters from the start and/or end of a string
16
+ - etc.
17
+
18
+ It's basically just a collection of utilities that are shared between LowEntry projects and plugins.
19
+ This is done primarily to keep them all in one place, preventing code duplication, and to also make it easier to start new projects which typically need utilities such as these.
20
+
21
+
22
+ ## Final words
23
+
24
+ I hope this plugin will be useful to you. If you have any questions or suggestions, feel free to contact me at [LowEntry.com](https://lowentry.com/).
@@ -0,0 +1,19 @@
1
+ image: node:lts
2
+
3
+ pipelines:
4
+ default:
5
+ - step:
6
+ name: Build and Test
7
+ script:
8
+ - npm install
9
+ - npm test
10
+ - step:
11
+ name: Publish
12
+ deployment: production
13
+ script:
14
+ - npm version patch -m "Upgrade to %s [skip ci]"
15
+ - git push && git push --tags
16
+ - pipe: atlassian/npm-publish:1.1.0
17
+ variables:
18
+ NPM_TOKEN: $NPM_TOKEN
19
+ EXTRA_ARGS: "--access public"
package/index.js ADDED
@@ -0,0 +1,4 @@
1
+ import {LeUtils} from './LeUtils.js';
2
+ import {ISSET, IS_ARRAY, ARRAY, IS_OBJECT, OBJECT, STRING, STRING_ANY, INT, INT_ANY, FLOAT, FLOAT_ANY, INT_LAX, INT_LAX_ANY, FLOAT_LAX, FLOAT_LAX_ANY} from './LeTypes.js';
3
+
4
+ export {LeUtils, ISSET, IS_ARRAY, ARRAY, IS_OBJECT, OBJECT, STRING, STRING_ANY, INT, INT_ANY, FLOAT, FLOAT_ANY, INT_LAX, INT_LAX_ANY, FLOAT_LAX, FLOAT_LAX_ANY};
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "@lowentry/utils",
3
+ "version": "0.1.1",
4
+ "private": false,
5
+ "type": "module",
6
+ "description": "Provides utilities for general JavaScript development.",
7
+ "author": "Low Entry",
8
+ "license": "MIT",
9
+ "keywords": [
10
+ "plugin",
11
+ "utility",
12
+ "utilities"
13
+ ],
14
+ "homepage": "https://bitbucket.org/lowentry/plugin_javascript_leutils/src",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://bitbucket.org/lowentry/plugin_javascript_leutils/src"
18
+ },
19
+ "scripts": {
20
+ "test": "node --check index.js"
21
+ },
22
+ "dependencies": {
23
+ "fast-deep-equal": "^3"
24
+ }
25
+ }