@andrew_l/toolkit 0.2.4 → 0.2.5

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/dist/index.cjs CHANGED
@@ -1,11 +1,11 @@
1
1
  'use strict';
2
2
 
3
- const _get = require('lodash/get');
4
- const _cloneDeep = require('lodash/cloneDeep');
5
- const _cloneDeepWith = require('lodash/cloneDeepWith');
6
- const _defaultsDeep = require('lodash/defaultsDeep');
7
- const _set = require('lodash/set');
8
- const _unset = require('lodash/unset');
3
+ const _get = require('lodash/get.js');
4
+ const _cloneDeep = require('lodash/cloneDeep.js');
5
+ const _cloneDeepWith = require('lodash/cloneDeepWith.js');
6
+ const _defaultsDeep = require('lodash/defaultsDeep.js');
7
+ const _set = require('lodash/set.js');
8
+ const _unset = require('lodash/unset.js');
9
9
 
10
10
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
11
11
 
@@ -248,6 +248,30 @@ function difference(...arrays) {
248
248
  return Array.from(set);
249
249
  }
250
250
 
251
+ function groupBy(array, keyBy, objectMode) {
252
+ const getItemKey = isFunction(keyBy) ? keyBy : (item) => item?.[keyBy];
253
+ let key;
254
+ if (objectMode === true) {
255
+ const result2 = {};
256
+ for (const item of array) {
257
+ key = getItemKey(item);
258
+ result2[key] = result2[key] || [];
259
+ result2[key].push(item);
260
+ }
261
+ return result2;
262
+ }
263
+ const result = /* @__PURE__ */ new Map();
264
+ for (const item of array) {
265
+ key = getItemKey(item);
266
+ if (!result.has(key)) {
267
+ result.set(key, [item]);
268
+ } else {
269
+ result.get(key).push(item);
270
+ }
271
+ }
272
+ return result;
273
+ }
274
+
251
275
  function intersection(...arrays) {
252
276
  if (arrays.length === 0) return [];
253
277
  if (arrays.length === 1) return arrays[0];
@@ -358,6 +382,7 @@ let AssertionError;
358
382
  (r) => r.BrowserAssertionError
359
383
  ) : await import('node:assert').then((r) => r.AssertionError);
360
384
  })();
385
+
361
386
  function ok(value, message) {
362
387
  if (!value) {
363
388
  throw toError$1(
@@ -379,6 +404,11 @@ function equal(actual, expected, message) {
379
404
  });
380
405
  }
381
406
  }
407
+ function empty$1(value, message) {
408
+ if (isEmpty(value)) {
409
+ throw toError$1(empty$1, value, message, "Expected not empty value.");
410
+ }
411
+ }
382
412
  function object(value, message) {
383
413
  if (!isObject(value)) {
384
414
  throw toError$1(object, value, message, "Expected object value.");
@@ -409,6 +439,36 @@ function number$1(value, message) {
409
439
  throw toError$1(number$1, value, message, "Expected number value.");
410
440
  }
411
441
  }
442
+ function date(value, message) {
443
+ if (!isDate(value)) {
444
+ throw toError$1(date, value, message, "Expected date value.");
445
+ }
446
+ }
447
+ function fn(value, message) {
448
+ if (!isNumber(value)) {
449
+ throw toError$1(fn, value, message, "Expected function value.");
450
+ }
451
+ }
452
+ function greaterThan(value, target, message) {
453
+ if (!isNumber(value) || value < target) {
454
+ throw toError$1(
455
+ greaterThan,
456
+ value,
457
+ message,
458
+ "Expected number value greater then " + target + "."
459
+ );
460
+ }
461
+ }
462
+ function lessThan(value, target, message) {
463
+ if (!isNumber(value) || value > target) {
464
+ throw toError$1(
465
+ lessThan,
466
+ value,
467
+ message,
468
+ "Expected number value less then " + target + "."
469
+ );
470
+ }
471
+ }
412
472
  function array(value, message) {
413
473
  if (!Array.isArray(value)) {
414
474
  throw toError$1(array, value, message, "Expected array value.");
@@ -442,7 +502,12 @@ const assert = {
442
502
  arrayNumbers: arrayNumbers,
443
503
  arrayStrings: arrayStrings,
444
504
  boolean: boolean,
505
+ date: date,
506
+ empty: empty$1,
445
507
  equal: equal,
508
+ fn: fn,
509
+ greaterThan: greaterThan,
510
+ lessThan: lessThan,
446
511
  notEmptyString: notEmptyString,
447
512
  number: number$1,
448
513
  object: object,
@@ -450,6 +515,53 @@ const assert = {
450
515
  string: string
451
516
  };
452
517
 
518
+ function weightedRoundRobin(arr) {
519
+ ok(arr.length > 0, "Array must contain at least one item.");
520
+ const instance = new WeightedRoundRobin(
521
+ arr.map((v) => ({
522
+ item: v.item,
523
+ weight: Math.min(v.weight ?? 1, 1)
524
+ }))
525
+ );
526
+ return () => instance.nextItem();
527
+ }
528
+ const gcd = (a, b) => !b ? a : gcd(b, a % b);
529
+ class WeightedRoundRobin {
530
+ constructor(items) {
531
+ this.items = items;
532
+ this.maxWeight = this._calculateMaxWeight();
533
+ this.gcdWeight = this._calculateGCD();
534
+ }
535
+ currentIndex = -1;
536
+ currentWeight = 0;
537
+ maxWeight;
538
+ gcdWeight;
539
+ _calculateGCD() {
540
+ return this.items.reduce(
541
+ (acc, curr) => gcd(acc, curr.weight),
542
+ this.items[0].weight
543
+ );
544
+ }
545
+ _calculateMaxWeight() {
546
+ return Math.max(...this.items.map((s) => s.weight));
547
+ }
548
+ nextItem() {
549
+ const n = this.items.length;
550
+ while (true) {
551
+ this.currentIndex = (this.currentIndex + 1) % n;
552
+ if (this.currentIndex === 0) {
553
+ this.currentWeight -= this.gcdWeight;
554
+ if (this.currentWeight <= 0) {
555
+ this.currentWeight = this.maxWeight;
556
+ }
557
+ }
558
+ if (this.items[this.currentIndex].weight >= this.currentWeight) {
559
+ return this.items[this.currentIndex].item;
560
+ }
561
+ }
562
+ }
563
+ }
564
+
453
565
  class Base64Encoding {
454
566
  alphabet;
455
567
  padding;
@@ -658,13 +770,12 @@ const def = (obj, key, value, writable = false) => {
658
770
  const rndCharacters = "abcdefghijklmnopqrstuvwxyz0123456789";
659
771
  const charactersLength = rndCharacters.length;
660
772
  function randomString(length) {
661
- let result = "";
662
- for (let i = 0; i < length; i++) {
663
- result += rndCharacters.charAt(
664
- Math.floor(Math.random() * charactersLength)
665
- );
773
+ let str = "";
774
+ let num = isNumber(length) ? Math.max(0, length) : 0;
775
+ while (num--) {
776
+ str += rndCharacters[charactersLength * Math.random() | 0];
666
777
  }
667
- return result;
778
+ return str;
668
779
  }
669
780
 
670
781
  const objectKeys = /* @__PURE__ */ new WeakMap();
@@ -1457,27 +1568,57 @@ function flatten(obj, {
1457
1568
  isObjectCompare = isObject
1458
1569
  } = {}) {
1459
1570
  const result = {};
1460
- const processed = /* @__PURE__ */ new WeakSet();
1461
- const handle = (node, prefix, initial) => {
1462
- if (processed.has(node)) return;
1463
- if (isObjectCompare(node)) {
1464
- processed.add(node);
1465
- prefix = prefix && !initial ? `${prefix}${separator}` : prefix;
1466
- for (const [key, value] of Object.entries(node)) {
1467
- handle(value, `${prefix}${key}`);
1468
- }
1571
+ const seen = /* @__PURE__ */ new WeakSet();
1572
+ if (isObjectCompare(obj)) {
1573
+ iter(
1574
+ result,
1575
+ seen,
1576
+ isObjectCompare,
1577
+ separator,
1578
+ withArrays,
1579
+ obj,
1580
+ initialPrefix,
1581
+ true
1582
+ );
1583
+ }
1584
+ return result;
1585
+ }
1586
+ function iter(output, seen, isObjectCompare, separator, withArrays, val, key, initial) {
1587
+ if (seen.has(val)) return;
1588
+ let k, pfx = key && !initial ? key + separator : key;
1589
+ if (Array.isArray(val)) {
1590
+ seen.add(val);
1591
+ if (!withArrays) {
1592
+ output[key] = val;
1469
1593
  return;
1470
1594
  }
1471
- if (Array.isArray(node) && withArrays) {
1472
- processed.add(node);
1473
- prefix = prefix && !initial ? `${prefix}${separator}` : prefix;
1474
- node.forEach((value, idx) => handle(value, `${prefix}${idx}`));
1475
- return;
1595
+ for (k = 0; k < val.length; k++) {
1596
+ iter(
1597
+ output,
1598
+ seen,
1599
+ isObjectCompare,
1600
+ separator,
1601
+ withArrays,
1602
+ val[k],
1603
+ pfx + k
1604
+ );
1476
1605
  }
1477
- result[prefix] = node;
1478
- };
1479
- handle(obj, initialPrefix, true);
1480
- return result;
1606
+ } else if (isObjectCompare(val)) {
1607
+ seen.add(val);
1608
+ for (k in val) {
1609
+ iter(
1610
+ output,
1611
+ seen,
1612
+ isObjectCompare,
1613
+ separator,
1614
+ withArrays,
1615
+ val[k],
1616
+ pfx + k
1617
+ );
1618
+ }
1619
+ } else {
1620
+ output[key] = val;
1621
+ }
1481
1622
  }
1482
1623
 
1483
1624
  function has(value, keys) {
@@ -1558,12 +1699,40 @@ const toMap = (obj) => {
1558
1699
  return map;
1559
1700
  };
1560
1701
 
1561
- function unflatten(obj, separator = "_") {
1562
- const result = {};
1563
- Object.keys(obj).forEach((path) => {
1564
- set(result, path.split(separator), obj[path]);
1565
- });
1566
- return result;
1702
+ const badKeys = Object.freeze(
1703
+ /* @__PURE__ */ new Set(["constructor", "__proto__", "prototype"])
1704
+ );
1705
+ function unflatten(input, separator = "_") {
1706
+ if (!isObject(input)) {
1707
+ return {};
1708
+ }
1709
+ let arr, tmp, output;
1710
+ let i = 0, k, key;
1711
+ for (k in input) {
1712
+ tmp = output;
1713
+ arr = k.split(separator);
1714
+ for (i = 0; i < arr.length; ) {
1715
+ key = arr[i++];
1716
+ if (tmp == null) {
1717
+ tmp = empty(+key);
1718
+ output = output || tmp;
1719
+ }
1720
+ if (badKeys.has(key)) break;
1721
+ if (i < arr.length) {
1722
+ if (key in tmp) {
1723
+ tmp = tmp[key];
1724
+ } else {
1725
+ tmp = tmp[key] = empty(+arr[i]);
1726
+ }
1727
+ } else {
1728
+ tmp[key] = input[k];
1729
+ }
1730
+ }
1731
+ }
1732
+ return output;
1733
+ }
1734
+ function empty(key) {
1735
+ return key === key ? [] : {};
1567
1736
  }
1568
1737
 
1569
1738
  const unset = _unset__default;
@@ -3188,7 +3357,7 @@ function getFileExtension(name, withDot = true) {
3188
3357
  return null;
3189
3358
  }
3190
3359
  const ext = name.split(".").at(-1)?.split("?")?.at(0);
3191
- return ext ? withDot ? ext : `.${ext}` : null;
3360
+ return ext ? withDot ? `.${ext}` : ext : null;
3192
3361
  }
3193
3362
 
3194
3363
  const DEF_PROTOCOLS = ["http://", "https://"];
@@ -3206,7 +3375,21 @@ function getFileName(value) {
3206
3375
  if (!ext) {
3207
3376
  return value;
3208
3377
  }
3209
- return value.slice(0, -ext.length - 1);
3378
+ return value.slice(0, -ext.length);
3379
+ }
3380
+
3381
+ function getMostSpecificPaths(keys) {
3382
+ keys = [...keys].sort();
3383
+ const result = [];
3384
+ for (let i = 0; i < keys.length; i++) {
3385
+ const currentPath = keys[i];
3386
+ const nextPath = keys[i + 1];
3387
+ if (currentPath === nextPath) continue;
3388
+ if (!nextPath || !nextPath.startsWith(currentPath + ".")) {
3389
+ result.push(currentPath);
3390
+ }
3391
+ }
3392
+ return result;
3210
3393
  }
3211
3394
 
3212
3395
  function humanFileSize(bytes, digits = 1, withSpace = true) {
@@ -4325,9 +4508,11 @@ exports.get = get;
4325
4508
  exports.getFileExtension = getFileExtension;
4326
4509
  exports.getFileName = getFileName;
4327
4510
  exports.getInitials = getInitials;
4511
+ exports.getMostSpecificPaths = getMostSpecificPaths;
4328
4512
  exports.getRandomInt = getRandomInt;
4329
4513
  exports.getRandomTime = getRandomTime;
4330
4514
  exports.getWords = getWords;
4515
+ exports.groupBy = groupBy;
4331
4516
  exports.has = has;
4332
4517
  exports.hasOwn = hasOwn;
4333
4518
  exports.hasProtocol = hasProtocol;
@@ -4431,6 +4616,7 @@ exports.uniq = uniq;
4431
4616
  exports.uniqBy = uniqBy;
4432
4617
  exports.unset = unset;
4433
4618
  exports.weeksInYear = weeksInYear;
4619
+ exports.weightedRoundRobin = weightedRoundRobin;
4434
4620
  exports.withCache = withCache;
4435
4621
  exports.withCacheBucket = withCacheBucket;
4436
4622
  exports.withCacheBucketBatch = withCacheBucketBatch;