@andrew_l/toolkit 0.2.4 → 0.2.7

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.d.ts CHANGED
@@ -114,23 +114,6 @@ declare function chunkSeries(list: number[], step?: number): number[][];
114
114
  */
115
115
  declare function difference<T>(...arrays: readonly T[][]): T[];
116
116
 
117
- /**
118
- * Returns the intersection of arrays.
119
- *
120
- * This function takes arrays and returns a new array containing the elements that are
121
- * present in all arrays.
122
- *
123
- * @template T - The type of elements in the array.
124
- * @returns {T[]} A new array containing the elements that are present in both arrays.
125
- *
126
- * @example
127
- * const array1 = [1, 2, 3, 4, 5];
128
- * const array2 = [3, 4, 5, 6, 7];
129
- * const result = intersection(array1, array2);
130
- * // result will be [3, 4, 5] since these elements are in both arrays.
131
- */
132
- declare function intersection<T>(...arrays: readonly T[][]): T[];
133
-
134
117
  type MaybePropertyKey<T> = T extends object
135
118
  ? keyof T | PropertyKey
136
119
  : PropertyKey;
@@ -149,6 +132,28 @@ type IsPropertyKey<T, V, L> = T extends object
149
132
  : L
150
133
  : PropertyKeyLiteralToType<L>;
151
134
 
135
+ declare function groupBy<T, K extends MaybePropertyKey<T>>(array: readonly T[], keyBy: K, objectMode?: false): Map<IsPropertyKey<T, K, K>, T[]>;
136
+ declare function groupBy<T, K>(array: readonly T[], keyBy: (item: T) => K, objectMode?: false): Map<K, T[]>;
137
+ declare function groupBy<T, K extends MaybePropertyKey<T>>(array: readonly T[], keyBy: K, objectMode: true): Record<K, T[]>;
138
+ declare function groupBy<T, K extends PropertyKey>(array: readonly T[], keyBy: (item: T) => K, objectMode: true): Record<K, T[]>;
139
+
140
+ /**
141
+ * Returns the intersection of arrays.
142
+ *
143
+ * This function takes arrays and returns a new array containing the elements that are
144
+ * present in all arrays.
145
+ *
146
+ * @template T - The type of elements in the array.
147
+ * @returns {T[]} A new array containing the elements that are present in both arrays.
148
+ *
149
+ * @example
150
+ * const array1 = [1, 2, 3, 4, 5];
151
+ * const array2 = [3, 4, 5, 6, 7];
152
+ * const result = intersection(array1, array2);
153
+ * // result will be [3, 4, 5] since these elements are in both arrays.
154
+ */
155
+ declare function intersection<T>(...arrays: readonly T[][]): T[];
156
+
152
157
  /**
153
158
  * Maps each element of an array based on a provided key.
154
159
  *
@@ -316,13 +321,45 @@ declare function uniq<T extends any[]>(value: T): T;
316
321
  */
317
322
  declare function uniqBy<T>(array: T[], comparator: ((value: T) => any) | PropertyKey): T[];
318
323
 
324
+ type WrrItem<T> = {
325
+ item: T;
326
+ weight?: number;
327
+ };
328
+ /**
329
+ * Creates a function that returns a weighted round-robin item from the provided array.
330
+ *
331
+ * The input array should contain objects with an `item` property and a `weight` property.
332
+ * The `weight` determines the relative likelihood of selecting an item.
333
+ * Items with higher weights will appear more frequently in the selection.
334
+ *
335
+ * If the `weight` property is missing or falsy, it defaults to `1`.
336
+ * An empty array will result in a function that always returns `undefined`.
337
+ *
338
+ * @example
339
+ * const getItem = weightedRoundRobin([
340
+ * { item: 'a', weight: 2 },
341
+ * { item: 'b', weight: 3 },
342
+ * { item: 'c' },
343
+ * ]);
344
+ *
345
+ * console.log(getItem()); // 'a', 'b', or 'c'
346
+ *
347
+ * @group Array
348
+ */
349
+ declare function weightedRoundRobin<T = unknown>(arr: WrrItem<T>[]): () => T;
350
+
319
351
  declare function ok(value: unknown, message?: string | Error): asserts value;
320
352
  declare function equal<T>(actual: unknown, expected: T, message?: string | Error): asserts actual is T;
353
+ declare function empty(value: unknown, message?: string | Error): asserts value;
321
354
  declare function object(value: unknown, message?: string | Error): asserts value is object;
322
355
  declare function string(value: unknown, message?: string | Error): asserts value is string;
323
356
  declare function boolean(value: unknown, message?: string | Error): asserts value is boolean;
324
357
  declare function notEmptyString(value: unknown, message?: string | Error): asserts value is string;
325
358
  declare function number(value: unknown, message?: string | Error): asserts value is number;
359
+ declare function date(value: unknown, message?: string | Error): asserts value is Date;
360
+ declare function fn(value: unknown, message?: string | Error): asserts value is Function;
361
+ declare function greaterThan(value: unknown, target: number, message?: string | Error): asserts value is number;
362
+ declare function lessThan(value: unknown, target: number, message?: string | Error): asserts value is number;
326
363
  /**
327
364
  * @param {unknown} value
328
365
  * @param {string | Error} [message]
@@ -336,14 +373,19 @@ declare const assert_array: typeof array;
336
373
  declare const assert_arrayNumbers: typeof arrayNumbers;
337
374
  declare const assert_arrayStrings: typeof arrayStrings;
338
375
  declare const assert_boolean: typeof boolean;
376
+ declare const assert_date: typeof date;
377
+ declare const assert_empty: typeof empty;
339
378
  declare const assert_equal: typeof equal;
379
+ declare const assert_fn: typeof fn;
380
+ declare const assert_greaterThan: typeof greaterThan;
381
+ declare const assert_lessThan: typeof lessThan;
340
382
  declare const assert_notEmptyString: typeof notEmptyString;
341
383
  declare const assert_number: typeof number;
342
384
  declare const assert_object: typeof object;
343
385
  declare const assert_ok: typeof ok;
344
386
  declare const assert_string: typeof string;
345
387
  declare namespace assert {
346
- export { assert_array as array, assert_arrayNumbers as arrayNumbers, assert_arrayStrings as arrayStrings, assert_boolean as boolean, assert_equal as equal, assert_notEmptyString as notEmptyString, assert_number as number, assert_object as object, assert_ok as ok, assert_string as string };
388
+ export { assert_array as array, assert_arrayNumbers as arrayNumbers, assert_arrayStrings as arrayStrings, assert_boolean as boolean, assert_date as date, assert_empty as empty, assert_equal as equal, assert_fn as fn, assert_greaterThan as greaterThan, assert_lessThan as lessThan, assert_notEmptyString as notEmptyString, assert_number as number, assert_object as object, assert_ok as ok, assert_string as string };
347
389
  }
348
390
 
349
391
  type Base64ToBytesOptions = {
@@ -695,9 +737,17 @@ type FunctionArgs<Args extends any[] = any[], Return = void> = (
695
737
  ...args: Args
696
738
  ) => Return;
697
739
 
698
- type DeepPartial<T> = T extends object
699
- ? { [P in keyof T]?: DeepPartial<T[P]> }
700
- : T;
740
+ type DeepPartial<T> = T extends Date
741
+ ? T
742
+ : T extends object
743
+ ? { [P in keyof T]?: DeepPartial<T[P]> }
744
+ : T;
745
+
746
+ type DeepReadonly<T> = T extends unknown[]
747
+ ? Readonly<T>
748
+ : T extends object
749
+ ? Readonly<{ [P in keyof T]: DeepReadonly<T[P]> }>
750
+ : Readonly<T>;
701
751
 
702
752
  type AnyFunction = (...args: any[]) => any;
703
753
 
@@ -2531,7 +2581,12 @@ declare function isSuccess<T extends ExecResult>(value: T): value is ExecResultT
2531
2581
  declare function isSkip<T extends ExecResult>(value: T): value is ExecResultToSkip<T>;
2532
2582
 
2533
2583
  /**
2534
- * Extracts file extension from filename or url link
2584
+ * Extract file extension from string
2585
+ *
2586
+ * @example
2587
+ * getFileExtension('Andrew L - CV.pdf'); // 'pdf'
2588
+ *
2589
+ * @group Files
2535
2590
  */
2536
2591
  declare function getFileExtension(name: string, withDot?: boolean): string | null;
2537
2592
 
@@ -2545,6 +2600,28 @@ declare function getFileExtension(name: string, withDot?: boolean): string | nul
2545
2600
  */
2546
2601
  declare function getFileName(value: string): string | null;
2547
2602
 
2603
+ /**
2604
+ * Filters an array of paths to retain only the most specific (deepest) paths,
2605
+ * removing any path that is a prefix of another path.
2606
+ *
2607
+ * @param {string[]} keys - An array of dot-separated string paths.
2608
+ * @returns {string[]} - A new array containing only the most specific paths.
2609
+ *
2610
+ * @example
2611
+ * const inputPaths = [
2612
+ * 'profile',
2613
+ * 'profile.basic',
2614
+ * 'profile.basic.fullName',
2615
+ * 'profile.updatedAt'
2616
+ * ];
2617
+ *
2618
+ * const result = getMostSpecificPaths(inputPaths);
2619
+ * console.log(result); // ['profile.basic.fullName', 'profile.updatedAt']
2620
+ *
2621
+ * @group Files
2622
+ */
2623
+ declare function getMostSpecificPaths(keys: string[]): string[];
2624
+
2548
2625
  /**
2549
2626
  * Converts bytes amount into human readably string
2550
2627
  *
@@ -2715,6 +2792,12 @@ declare function isPromise<T = void>(value: any): value is Promise<T>;
2715
2792
  */
2716
2793
  declare const isPrimitive: (value: unknown) => value is Primitive;
2717
2794
 
2795
+ type LogLevel = Exclude<keyof Logger, 'extend'>;
2796
+ /**
2797
+ * Set global log level.
2798
+ * @group Utility Functions
2799
+ */
2800
+ declare const loggerSetLevel: (level: LogLevel) => void;
2718
2801
  /**
2719
2802
  * Create pretty simple `console.log` wrapper interface.
2720
2803
  *
@@ -3520,6 +3603,7 @@ interface FlattenOptions {
3520
3603
  * // { 'root-user-name': 'Jane', 'root-user-profile-age': 30 }
3521
3604
  *
3522
3605
  * @group Object
3606
+ * @author lukeed
3523
3607
  */
3524
3608
  declare function flatten(obj: Record<string, unknown>, { separator, initialPrefix, withArrays, isObjectCompare, }?: FlattenOptions): Record<string, unknown>;
3525
3609
 
@@ -3738,8 +3822,9 @@ declare const toMap: <T extends object>(obj: T) => Map<keyof T, T[keyof T]>;
3738
3822
  * // }
3739
3823
  *
3740
3824
  * @group Object
3825
+ * @author lukeed
3741
3826
  */
3742
- declare function unflatten(obj: object, separator?: string): {};
3827
+ declare function unflatten(input: object, separator?: string): any;
3743
3828
 
3744
3829
  /**
3745
3830
  * Same as `set` but unset by dot notation
@@ -4910,4 +4995,4 @@ declare function wrapText(value: string, maxLength?: number): string;
4910
4995
  */
4911
4996
  declare function toError<T>(value: T, unknownMessage?: string): T extends Error ? T : Error;
4912
4997
 
4913
- export { type AnyFunction, AppError, type ArgumentsType, type Arrayable, AsyncIterableQueue, type Awaitable, type Base64ToBytesOptions, BrowserAssertionError, type BytesToBase64Options, CancellablePromise, type CatchErrorResult, Color, type ColorChannels, ColorParser, type Data, type DateObject, type DateObjectInput, type DeepPartial, type Defer, instance as EJSON, EJSONStream, type EJSONStreamOptions, type EJSONStreamOptionsWithPayload, type EnvParser, type ExecResult, type ExecResultToSkip, type ExecResultToSuccess, type ExecSkip, type ExecSuccess, FindMean, FixedMap, FixedWeakMap, type Fn, type FormatMoney, type FormatNumber, type FunctionArgs, type GenericObject, type IfAny, type IsAny, type LiteralUnion, type Logger, LruCache, type Nothing, type OverwriteWith, type Prettify, type Primitive, type PromisifyFn, Queue, type RandomizerOptions, type RetryOnErrorConfig, type SelectOptionItem, type SelectOptions, type SimpleDefaultEventMap, SimpleEventEmitter, type SimpleEventMap, _default as TWEMOJI_REGEX, type ThemeConfig, TimeBucket, type TimeBucketOptions, type TimeObject, type TimeObjectInput, TimeSpan, type TimeSpanUnit, type TimeString, type TimeValue, type TimestampMsInput, type TypeOf, type TypeOfMap, type ValuesOfObject, type WithCache, type WithCacheBucketBatchOptions, type WithCacheBucketOptions, type WithCacheFixedOptions, type WithCacheLruOptions, type WithCacheOptions, type WithCachePointer, type WithCacheResult, type WithCacheStorage, type WithCustomizer, type WithCustomizerFactory, type WithCustomizerValue, alpha, arrayable, assert, asyncFilter, asyncFind, asyncForEach, asyncMap, avg, base64ToBytes, bigIntBytes, bigIntFromBytes, blendColors, buildCssColor, bytesToBase64, cache, cacheBucket, cacheFixed, cacheLRU, camelCase, capitalize, captureStackTrace, catchError, channelsToHSL, channelsToHex, channelsToRGB, checkBitmask, chunk, chunkSeries, clamp, cleanEmpty, cleanObject, colorToChannels, compareBytes, concatenateBytes, contrastRatio, convertToUnit, crc32, createCustomizer, createCustomizerFactory, createDateObject, createDeepCloneWith, createEJSON, createEJSONStream, createEnvParser, createRandomizer, createSecureCustomizer, createTimeObject, createTimeSpan, createWithCache, cssVariable, dateInDays, dateInSeconds, deepAssign, deepClone, deepCloneWith, deepDefaults, deepFreeze, def, defer, delay, difference, dropCache, env, escapeHtml, escapeNumeric, escapeRegExp, fastIdle, fastIdlePromise, fastRaf, findMean, flagsToMap, flatten, formatMoney, formatNumber, get, getFileExtension, getFileName, getInitials, getRandomInt, getRandomTime, getWords, has, hasOwn, hasProtocol, hex, hexToChannels, hmToSeconds, hslToChannels, humanFileSize, humanize, interpolateColor, intersection, isBigInt, isBoolean, isCached, isClient, isColorChannels, isCustomizerFactory, isDate, isDateObject, isDef, isEmpty, isEqual, isError, isFunction, isInfinity, isMap, isNullOrUndefined, isNumber, isObject, isOneEmoji, isPlainObject, isPrimitive, isPromise, isSet, isSkip, isString, isSuccess, isSymbol, isTimeObject, isTimeString, isTimeValue, isValidWeekDay, isWeakMap, isWeakSet, isWithCache, isoToFlagEmoji, kebabCase, keyBy, logger, lowerCase, luminance, maskingEmail, maskingPhone, maskingWords, nextTickIteration, noop, objectId, omit, omitPrefixed, orderBy, parseAllNumbers, parseAlpha, parsePercentage, percentOf, pick, pickPrefixed, qs, rafPromise, randomString, removeVS16s, retryOnError, rgbToChannels, round2digits, secondsToHm, set, shuffle, snakeCase, sprintf, startCase, strAssign, sum, timeFromMinutes, timeStringify, timeToMinutes, timeout, timestamp, timestampMs, timestampToDate, tintedTextColor, toError, toMap, truncate, typeOf, uint16ToUint8, uint32ToUint8, uint8ToUint16, uint8ToUint32, unflatten, union, uniq, uniqBy, unset, weeksInYear, withCache, withCacheBucket, withCacheBucketBatch, withCacheFixed, withCacheLRU, withDeepClone, withPointerCache, wrapText };
4998
+ export { type AnyFunction, AppError, type ArgumentsType, type Arrayable, AsyncIterableQueue, type Awaitable, type Base64ToBytesOptions, BrowserAssertionError, type BytesToBase64Options, CancellablePromise, type CatchErrorResult, Color, type ColorChannels, ColorParser, type Data, type DateObject, type DateObjectInput, type DeepPartial, type DeepReadonly, type Defer, instance as EJSON, EJSONStream, type EJSONStreamOptions, type EJSONStreamOptionsWithPayload, type EnvParser, type ExecResult, type ExecResultToSkip, type ExecResultToSuccess, type ExecSkip, type ExecSuccess, FindMean, FixedMap, FixedWeakMap, type Fn, type FormatMoney, type FormatNumber, type FunctionArgs, type GenericObject, type IfAny, type IsAny, type LiteralUnion, type Logger, LruCache, type Nothing, type OverwriteWith, type Prettify, type Primitive, type PromisifyFn, Queue, type RandomizerOptions, type RetryOnErrorConfig, type SelectOptionItem, type SelectOptions, type SimpleDefaultEventMap, SimpleEventEmitter, type SimpleEventMap, _default as TWEMOJI_REGEX, type ThemeConfig, TimeBucket, type TimeBucketOptions, type TimeObject, type TimeObjectInput, TimeSpan, type TimeSpanUnit, type TimeString, type TimeValue, type TimestampMsInput, type TypeOf, type TypeOfMap, type ValuesOfObject, type WithCache, type WithCacheBucketBatchOptions, type WithCacheBucketOptions, type WithCacheFixedOptions, type WithCacheLruOptions, type WithCacheOptions, type WithCachePointer, type WithCacheResult, type WithCacheStorage, type WithCustomizer, type WithCustomizerFactory, type WithCustomizerValue, type WrrItem, alpha, arrayable, assert, asyncFilter, asyncFind, asyncForEach, asyncMap, avg, base64ToBytes, bigIntBytes, bigIntFromBytes, blendColors, buildCssColor, bytesToBase64, cache, cacheBucket, cacheFixed, cacheLRU, camelCase, capitalize, captureStackTrace, catchError, channelsToHSL, channelsToHex, channelsToRGB, checkBitmask, chunk, chunkSeries, clamp, cleanEmpty, cleanObject, colorToChannels, compareBytes, concatenateBytes, contrastRatio, convertToUnit, crc32, createCustomizer, createCustomizerFactory, createDateObject, createDeepCloneWith, createEJSON, createEJSONStream, createEnvParser, createRandomizer, createSecureCustomizer, createTimeObject, createTimeSpan, createWithCache, cssVariable, dateInDays, dateInSeconds, deepAssign, deepClone, deepCloneWith, deepDefaults, deepFreeze, def, defer, delay, difference, dropCache, env, escapeHtml, escapeNumeric, escapeRegExp, fastIdle, fastIdlePromise, fastRaf, findMean, flagsToMap, flatten, formatMoney, formatNumber, get, getFileExtension, getFileName, getInitials, getMostSpecificPaths, getRandomInt, getRandomTime, getWords, groupBy, has, hasOwn, hasProtocol, hex, hexToChannels, hmToSeconds, hslToChannels, humanFileSize, humanize, interpolateColor, intersection, isBigInt, isBoolean, isCached, isClient, isColorChannels, isCustomizerFactory, isDate, isDateObject, isDef, isEmpty, isEqual, isError, isFunction, isInfinity, isMap, isNullOrUndefined, isNumber, isObject, isOneEmoji, isPlainObject, isPrimitive, isPromise, isSet, isSkip, isString, isSuccess, isSymbol, isTimeObject, isTimeString, isTimeValue, isValidWeekDay, isWeakMap, isWeakSet, isWithCache, isoToFlagEmoji, kebabCase, keyBy, logger, loggerSetLevel, lowerCase, luminance, maskingEmail, maskingPhone, maskingWords, nextTickIteration, noop, objectId, omit, omitPrefixed, orderBy, parseAllNumbers, parseAlpha, parsePercentage, percentOf, pick, pickPrefixed, qs, rafPromise, randomString, removeVS16s, retryOnError, rgbToChannels, round2digits, secondsToHm, set, shuffle, snakeCase, sprintf, startCase, strAssign, sum, timeFromMinutes, timeStringify, timeToMinutes, timeout, timestamp, timestampMs, timestampToDate, tintedTextColor, toError, toMap, truncate, typeOf, uint16ToUint8, uint32ToUint8, uint8ToUint16, uint8ToUint32, unflatten, union, uniq, uniqBy, unset, weeksInYear, weightedRoundRobin, withCache, withCacheBucket, withCacheBucketBatch, withCacheFixed, withCacheLRU, withDeepClone, withPointerCache, wrapText };
package/dist/index.mjs CHANGED
@@ -1,9 +1,9 @@
1
- import _get from 'lodash/get';
2
- import _cloneDeep from 'lodash/cloneDeep';
3
- import _cloneDeepWith from 'lodash/cloneDeepWith';
4
- import _defaultsDeep from 'lodash/defaultsDeep';
5
- import _set from 'lodash/set';
6
- import _unset from 'lodash/unset';
1
+ import _get from 'lodash/get.js';
2
+ import _cloneDeep from 'lodash/cloneDeep.js';
3
+ import _cloneDeepWith from 'lodash/cloneDeepWith.js';
4
+ import _defaultsDeep from 'lodash/defaultsDeep.js';
5
+ import _set from 'lodash/set.js';
6
+ import _unset from 'lodash/unset.js';
7
7
 
8
8
  const isClient = typeof globalThis?.window !== "undefined";
9
9
  const isDef = (val) => typeof val !== "undefined";
@@ -237,6 +237,30 @@ function difference(...arrays) {
237
237
  return Array.from(set);
238
238
  }
239
239
 
240
+ function groupBy(array, keyBy, objectMode) {
241
+ const getItemKey = isFunction(keyBy) ? keyBy : (item) => item?.[keyBy];
242
+ let key;
243
+ if (objectMode === true) {
244
+ const result2 = {};
245
+ for (const item of array) {
246
+ key = getItemKey(item);
247
+ result2[key] = result2[key] || [];
248
+ result2[key].push(item);
249
+ }
250
+ return result2;
251
+ }
252
+ const result = /* @__PURE__ */ new Map();
253
+ for (const item of array) {
254
+ key = getItemKey(item);
255
+ if (!result.has(key)) {
256
+ result.set(key, [item]);
257
+ } else {
258
+ result.get(key).push(item);
259
+ }
260
+ }
261
+ return result;
262
+ }
263
+
240
264
  function intersection(...arrays) {
241
265
  if (arrays.length === 0) return [];
242
266
  if (arrays.length === 1) return arrays[0];
@@ -347,6 +371,7 @@ let AssertionError;
347
371
  (r) => r.BrowserAssertionError
348
372
  ) : await import('node:assert').then((r) => r.AssertionError);
349
373
  })();
374
+
350
375
  function ok(value, message) {
351
376
  if (!value) {
352
377
  throw toError$1(
@@ -368,6 +393,11 @@ function equal(actual, expected, message) {
368
393
  });
369
394
  }
370
395
  }
396
+ function empty$1(value, message) {
397
+ if (isEmpty(value)) {
398
+ throw toError$1(empty$1, value, message, "Expected not empty value.");
399
+ }
400
+ }
371
401
  function object(value, message) {
372
402
  if (!isObject(value)) {
373
403
  throw toError$1(object, value, message, "Expected object value.");
@@ -398,6 +428,36 @@ function number$1(value, message) {
398
428
  throw toError$1(number$1, value, message, "Expected number value.");
399
429
  }
400
430
  }
431
+ function date(value, message) {
432
+ if (!isDate(value)) {
433
+ throw toError$1(date, value, message, "Expected date value.");
434
+ }
435
+ }
436
+ function fn(value, message) {
437
+ if (!isNumber(value)) {
438
+ throw toError$1(fn, value, message, "Expected function value.");
439
+ }
440
+ }
441
+ function greaterThan(value, target, message) {
442
+ if (!isNumber(value) || value < target) {
443
+ throw toError$1(
444
+ greaterThan,
445
+ value,
446
+ message,
447
+ "Expected number value greater then " + target + "."
448
+ );
449
+ }
450
+ }
451
+ function lessThan(value, target, message) {
452
+ if (!isNumber(value) || value > target) {
453
+ throw toError$1(
454
+ lessThan,
455
+ value,
456
+ message,
457
+ "Expected number value less then " + target + "."
458
+ );
459
+ }
460
+ }
401
461
  function array(value, message) {
402
462
  if (!Array.isArray(value)) {
403
463
  throw toError$1(array, value, message, "Expected array value.");
@@ -431,7 +491,12 @@ const assert = {
431
491
  arrayNumbers: arrayNumbers,
432
492
  arrayStrings: arrayStrings,
433
493
  boolean: boolean,
494
+ date: date,
495
+ empty: empty$1,
434
496
  equal: equal,
497
+ fn: fn,
498
+ greaterThan: greaterThan,
499
+ lessThan: lessThan,
435
500
  notEmptyString: notEmptyString,
436
501
  number: number$1,
437
502
  object: object,
@@ -439,6 +504,53 @@ const assert = {
439
504
  string: string
440
505
  };
441
506
 
507
+ function weightedRoundRobin(arr) {
508
+ ok(arr.length > 0, "Array must contain at least one item.");
509
+ const instance = new WeightedRoundRobin(
510
+ arr.map((v) => ({
511
+ item: v.item,
512
+ weight: Math.min(v.weight ?? 1, 1)
513
+ }))
514
+ );
515
+ return () => instance.nextItem();
516
+ }
517
+ const gcd = (a, b) => !b ? a : gcd(b, a % b);
518
+ class WeightedRoundRobin {
519
+ constructor(items) {
520
+ this.items = items;
521
+ this.maxWeight = this._calculateMaxWeight();
522
+ this.gcdWeight = this._calculateGCD();
523
+ }
524
+ currentIndex = -1;
525
+ currentWeight = 0;
526
+ maxWeight;
527
+ gcdWeight;
528
+ _calculateGCD() {
529
+ return this.items.reduce(
530
+ (acc, curr) => gcd(acc, curr.weight),
531
+ this.items[0].weight
532
+ );
533
+ }
534
+ _calculateMaxWeight() {
535
+ return Math.max(...this.items.map((s) => s.weight));
536
+ }
537
+ nextItem() {
538
+ const n = this.items.length;
539
+ while (true) {
540
+ this.currentIndex = (this.currentIndex + 1) % n;
541
+ if (this.currentIndex === 0) {
542
+ this.currentWeight -= this.gcdWeight;
543
+ if (this.currentWeight <= 0) {
544
+ this.currentWeight = this.maxWeight;
545
+ }
546
+ }
547
+ if (this.items[this.currentIndex].weight >= this.currentWeight) {
548
+ return this.items[this.currentIndex].item;
549
+ }
550
+ }
551
+ }
552
+ }
553
+
442
554
  class Base64Encoding {
443
555
  alphabet;
444
556
  padding;
@@ -647,13 +759,12 @@ const def = (obj, key, value, writable = false) => {
647
759
  const rndCharacters = "abcdefghijklmnopqrstuvwxyz0123456789";
648
760
  const charactersLength = rndCharacters.length;
649
761
  function randomString(length) {
650
- let result = "";
651
- for (let i = 0; i < length; i++) {
652
- result += rndCharacters.charAt(
653
- Math.floor(Math.random() * charactersLength)
654
- );
762
+ let str = "";
763
+ let num = isNumber(length) ? Math.max(0, length) : 0;
764
+ while (num--) {
765
+ str += rndCharacters[charactersLength * Math.random() | 0];
655
766
  }
656
- return result;
767
+ return str;
657
768
  }
658
769
 
659
770
  const objectKeys = /* @__PURE__ */ new WeakMap();
@@ -1446,27 +1557,57 @@ function flatten(obj, {
1446
1557
  isObjectCompare = isObject
1447
1558
  } = {}) {
1448
1559
  const result = {};
1449
- const processed = /* @__PURE__ */ new WeakSet();
1450
- const handle = (node, prefix, initial) => {
1451
- if (processed.has(node)) return;
1452
- if (isObjectCompare(node)) {
1453
- processed.add(node);
1454
- prefix = prefix && !initial ? `${prefix}${separator}` : prefix;
1455
- for (const [key, value] of Object.entries(node)) {
1456
- handle(value, `${prefix}${key}`);
1457
- }
1560
+ const seen = /* @__PURE__ */ new WeakSet();
1561
+ if (isObjectCompare(obj)) {
1562
+ iter(
1563
+ result,
1564
+ seen,
1565
+ isObjectCompare,
1566
+ separator,
1567
+ withArrays,
1568
+ obj,
1569
+ initialPrefix,
1570
+ true
1571
+ );
1572
+ }
1573
+ return result;
1574
+ }
1575
+ function iter(output, seen, isObjectCompare, separator, withArrays, val, key, initial) {
1576
+ if (seen.has(val)) return;
1577
+ let k, pfx = key && !initial ? key + separator : key;
1578
+ if (Array.isArray(val)) {
1579
+ seen.add(val);
1580
+ if (!withArrays) {
1581
+ output[key] = val;
1458
1582
  return;
1459
1583
  }
1460
- if (Array.isArray(node) && withArrays) {
1461
- processed.add(node);
1462
- prefix = prefix && !initial ? `${prefix}${separator}` : prefix;
1463
- node.forEach((value, idx) => handle(value, `${prefix}${idx}`));
1464
- return;
1584
+ for (k = 0; k < val.length; k++) {
1585
+ iter(
1586
+ output,
1587
+ seen,
1588
+ isObjectCompare,
1589
+ separator,
1590
+ withArrays,
1591
+ val[k],
1592
+ pfx + k
1593
+ );
1465
1594
  }
1466
- result[prefix] = node;
1467
- };
1468
- handle(obj, initialPrefix, true);
1469
- return result;
1595
+ } else if (isObjectCompare(val)) {
1596
+ seen.add(val);
1597
+ for (k in val) {
1598
+ iter(
1599
+ output,
1600
+ seen,
1601
+ isObjectCompare,
1602
+ separator,
1603
+ withArrays,
1604
+ val[k],
1605
+ pfx + k
1606
+ );
1607
+ }
1608
+ } else {
1609
+ output[key] = val;
1610
+ }
1470
1611
  }
1471
1612
 
1472
1613
  function has(value, keys) {
@@ -1547,12 +1688,40 @@ const toMap = (obj) => {
1547
1688
  return map;
1548
1689
  };
1549
1690
 
1550
- function unflatten(obj, separator = "_") {
1551
- const result = {};
1552
- Object.keys(obj).forEach((path) => {
1553
- set(result, path.split(separator), obj[path]);
1554
- });
1555
- return result;
1691
+ const badKeys = Object.freeze(
1692
+ /* @__PURE__ */ new Set(["constructor", "__proto__", "prototype"])
1693
+ );
1694
+ function unflatten(input, separator = "_") {
1695
+ if (!isObject(input)) {
1696
+ return {};
1697
+ }
1698
+ let arr, tmp, output;
1699
+ let i = 0, k, key;
1700
+ for (k in input) {
1701
+ tmp = output;
1702
+ arr = k.split(separator);
1703
+ for (i = 0; i < arr.length; ) {
1704
+ key = arr[i++];
1705
+ if (tmp == null) {
1706
+ tmp = empty(+key);
1707
+ output = output || tmp;
1708
+ }
1709
+ if (badKeys.has(key)) break;
1710
+ if (i < arr.length) {
1711
+ if (key in tmp) {
1712
+ tmp = tmp[key];
1713
+ } else {
1714
+ tmp = tmp[key] = empty(+arr[i]);
1715
+ }
1716
+ } else {
1717
+ tmp[key] = input[k];
1718
+ }
1719
+ }
1720
+ }
1721
+ return output;
1722
+ }
1723
+ function empty(key) {
1724
+ return key === key ? [] : {};
1556
1725
  }
1557
1726
 
1558
1727
  const unset = _unset;
@@ -3177,7 +3346,7 @@ function getFileExtension(name, withDot = true) {
3177
3346
  return null;
3178
3347
  }
3179
3348
  const ext = name.split(".").at(-1)?.split("?")?.at(0);
3180
- return ext ? withDot ? ext : `.${ext}` : null;
3349
+ return ext ? withDot ? `.${ext}` : ext : null;
3181
3350
  }
3182
3351
 
3183
3352
  const DEF_PROTOCOLS = ["http://", "https://"];
@@ -3195,7 +3364,21 @@ function getFileName(value) {
3195
3364
  if (!ext) {
3196
3365
  return value;
3197
3366
  }
3198
- return value.slice(0, -ext.length - 1);
3367
+ return value.slice(0, -ext.length);
3368
+ }
3369
+
3370
+ function getMostSpecificPaths(keys) {
3371
+ keys = [...keys].sort();
3372
+ const result = [];
3373
+ for (let i = 0; i < keys.length; i++) {
3374
+ const currentPath = keys[i];
3375
+ const nextPath = keys[i + 1];
3376
+ if (currentPath === nextPath) continue;
3377
+ if (!nextPath || !nextPath.startsWith(currentPath + ".")) {
3378
+ result.push(currentPath);
3379
+ }
3380
+ }
3381
+ return result;
3199
3382
  }
3200
3383
 
3201
3384
  function humanFileSize(bytes, digits = 1, withSpace = true) {
@@ -3297,19 +3480,37 @@ function tryStringify(o) {
3297
3480
  }
3298
3481
  }
3299
3482
 
3300
- const IS_DEV = env.isDevelopment || env.bool("DEV", false);
3483
+ const LEVEL_NUM = {
3484
+ debug: 0,
3485
+ log: 1,
3486
+ info: 2,
3487
+ warn: 3,
3488
+ error: 4
3489
+ };
3490
+ let currentLogLevel = LEVEL_NUM.log;
3491
+ const loggerSetLevel = (level) => {
3492
+ number$1(LEVEL_NUM[level], `Invalid log level: ${level}`);
3493
+ currentLogLevel = LEVEL_NUM[level];
3494
+ };
3301
3495
  const logger = (...baseArgs) => {
3496
+ if (isString(baseArgs[0]?.url)) {
3497
+ baseArgs[0] = baseArgs[0]?.url;
3498
+ }
3302
3499
  if (typeof baseArgs[0] === "string" && baseArgs[0][0] !== "[") {
3303
3500
  baseArgs[0] = `[${baseArgs[0].split("/").at(-1).split("?", 1)[0]}]`;
3304
3501
  }
3305
3502
  const writeLog = (level, ...[pattern, ...args]) => {
3503
+ const levelNum = LEVEL_NUM[level];
3504
+ if (levelNum < currentLogLevel) {
3505
+ return;
3506
+ }
3306
3507
  if (!isString(pattern)) {
3307
3508
  console[level](...baseArgs, pattern, ...args);
3308
3509
  return;
3309
3510
  }
3310
3511
  const unusedArgs = [];
3311
3512
  const formatted = sprintf(pattern, args, unusedArgs);
3312
- console[level](...baseArgs, ...formatted, ...unusedArgs);
3513
+ console[level](...baseArgs, formatted, ...unusedArgs);
3313
3514
  };
3314
3515
  const log = writeLog.bind(null, "log");
3315
3516
  const info = writeLog.bind(null, "info");
@@ -3327,9 +3528,6 @@ const logger = (...baseArgs) => {
3327
3528
  debug,
3328
3529
  extend
3329
3530
  };
3330
- Object.defineProperty(instance, "debug", {
3331
- get: () => IS_DEV ? debug : noop
3332
- });
3333
3531
  return instance;
3334
3532
  };
3335
3533
 
@@ -4220,5 +4418,5 @@ function wrapText(value, maxLength = 30) {
4220
4418
  return value;
4221
4419
  }
4222
4420
 
4223
- export { AppError, AsyncIterableQueue, BrowserAssertionError, CancellablePromise, ColorParser, instance as EJSON, EJSONStream, FindMean, FixedMap, FixedWeakMap, LruCache, Queue, SimpleEventEmitter, TWEMOJI_REGEX, TimeBucket, TimeSpan, alpha, arrayable, assert, asyncFilter, asyncFind, asyncForEach, asyncMap, avg, base64ToBytes, bigIntBytes, bigIntFromBytes, blendColors, buildCssColor, bytesToBase64, cache, cacheBucket, cacheFixed, cacheLRU, camelCase, capitalize, captureStackTrace, catchError, channelsToHSL, channelsToHex, channelsToRGB, checkBitmask, chunk, chunkSeries, clamp, cleanEmpty, cleanObject, colorToChannels, compareBytes, concatenateBytes, contrastRatio, convertToUnit, crc32, createCustomizer, createCustomizerFactory, createDateObject, createDeepCloneWith, createEJSON, createEJSONStream, createEnvParser, createRandomizer, createSecureCustomizer, createTimeObject, createTimeSpan, createWithCache, cssVariable, dateInDays, dateInSeconds, deepAssign, deepClone, deepCloneWith, deepDefaults, deepFreeze, def, defer, delay, difference, dropCache, env, escapeHtml, escapeNumeric, escapeRegExp, fastIdle, fastIdlePromise, fastRaf, findMean, flagsToMap, flatten, formatMoney, formatNumber, get, getFileExtension, getFileName, getInitials, getRandomInt, getRandomTime, getWords, has, hasOwn, hasProtocol, hex, hexToChannels, hmToSeconds, hslToChannels, humanFileSize, humanize, interpolateColor, intersection, isBigInt, isBoolean, isCached, isClient, isColorChannels, isCustomizerFactory, isDate, isDateObject, isDef, isEmpty, isEqual, isError, isFunction, isInfinity, isMap, isNullOrUndefined, isNumber, isObject, isOneEmoji, isPlainObject, isPrimitive, isPromise, isSet, isSkip, isString, isSuccess, isSymbol, isTimeObject, isTimeString, isTimeValue, isValidWeekDay, isWeakMap, isWeakSet, isWithCache, isoToFlagEmoji, kebabCase, keyBy, logger, lowerCase, luminance, maskingEmail, maskingPhone, maskingWords, nextTickIteration, noop, objectId, omit, omitPrefixed, orderBy, parseAllNumbers, parseAlpha, parsePercentage, percentOf, pick, pickPrefixed, qs, rafPromise, randomString, removeVS16s, retryOnError, rgbToChannels, round2digits, secondsToHm, set, shuffle, snakeCase, sprintf, startCase, strAssign, sum, timeFromMinutes, timeStringify, timeToMinutes, timeout, timestamp, timestampMs, timestampToDate, tintedTextColor, toError, toMap, truncate, typeOf, uint16ToUint8, uint32ToUint8, uint8ToUint16, uint8ToUint32, unflatten, union, uniq, uniqBy, unset, weeksInYear, withCache, withCacheBucket, withCacheBucketBatch, withCacheFixed, withCacheLRU, withDeepClone, withPointerCache, wrapText };
4421
+ export { AppError, AsyncIterableQueue, BrowserAssertionError, CancellablePromise, ColorParser, instance as EJSON, EJSONStream, FindMean, FixedMap, FixedWeakMap, LruCache, Queue, SimpleEventEmitter, TWEMOJI_REGEX, TimeBucket, TimeSpan, alpha, arrayable, assert, asyncFilter, asyncFind, asyncForEach, asyncMap, avg, base64ToBytes, bigIntBytes, bigIntFromBytes, blendColors, buildCssColor, bytesToBase64, cache, cacheBucket, cacheFixed, cacheLRU, camelCase, capitalize, captureStackTrace, catchError, channelsToHSL, channelsToHex, channelsToRGB, checkBitmask, chunk, chunkSeries, clamp, cleanEmpty, cleanObject, colorToChannels, compareBytes, concatenateBytes, contrastRatio, convertToUnit, crc32, createCustomizer, createCustomizerFactory, createDateObject, createDeepCloneWith, createEJSON, createEJSONStream, createEnvParser, createRandomizer, createSecureCustomizer, createTimeObject, createTimeSpan, createWithCache, cssVariable, dateInDays, dateInSeconds, deepAssign, deepClone, deepCloneWith, deepDefaults, deepFreeze, def, defer, delay, difference, dropCache, env, escapeHtml, escapeNumeric, escapeRegExp, fastIdle, fastIdlePromise, fastRaf, findMean, flagsToMap, flatten, formatMoney, formatNumber, get, getFileExtension, getFileName, getInitials, getMostSpecificPaths, getRandomInt, getRandomTime, getWords, groupBy, has, hasOwn, hasProtocol, hex, hexToChannels, hmToSeconds, hslToChannels, humanFileSize, humanize, interpolateColor, intersection, isBigInt, isBoolean, isCached, isClient, isColorChannels, isCustomizerFactory, isDate, isDateObject, isDef, isEmpty, isEqual, isError, isFunction, isInfinity, isMap, isNullOrUndefined, isNumber, isObject, isOneEmoji, isPlainObject, isPrimitive, isPromise, isSet, isSkip, isString, isSuccess, isSymbol, isTimeObject, isTimeString, isTimeValue, isValidWeekDay, isWeakMap, isWeakSet, isWithCache, isoToFlagEmoji, kebabCase, keyBy, logger, loggerSetLevel, lowerCase, luminance, maskingEmail, maskingPhone, maskingWords, nextTickIteration, noop, objectId, omit, omitPrefixed, orderBy, parseAllNumbers, parseAlpha, parsePercentage, percentOf, pick, pickPrefixed, qs, rafPromise, randomString, removeVS16s, retryOnError, rgbToChannels, round2digits, secondsToHm, set, shuffle, snakeCase, sprintf, startCase, strAssign, sum, timeFromMinutes, timeStringify, timeToMinutes, timeout, timestamp, timestampMs, timestampToDate, tintedTextColor, toError, toMap, truncate, typeOf, uint16ToUint8, uint32ToUint8, uint8ToUint16, uint8ToUint32, unflatten, union, uniq, uniqBy, unset, weeksInYear, weightedRoundRobin, withCache, withCacheBucket, withCacheBucketBatch, withCacheFixed, withCacheLRU, withDeepClone, withPointerCache, wrapText };
4224
4422
  //# sourceMappingURL=index.mjs.map