@zelgadis87/utils-core 5.3.5 → 5.3.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/.rollup/index.mjs CHANGED
@@ -1078,6 +1078,20 @@ function randomNumberInInterval(min, max) {
1078
1078
  const randomId = (length) => {
1079
1079
  return Math.random().toString(36).substring(2, length + 2);
1080
1080
  };
1081
+ function randomPick(arr) {
1082
+ return first$1(randomPicks(arr, 1));
1083
+ }
1084
+ function randomPicks(arr, count) {
1085
+ const available = [...arr];
1086
+ const result = [];
1087
+ while (available.length > 0 && count > 0) {
1088
+ const randomIndex = randomNumberInInterval(0, available.length - 1);
1089
+ result.push(available[randomIndex]);
1090
+ available.splice(randomIndex, 1);
1091
+ count--;
1092
+ }
1093
+ return result;
1094
+ }
1081
1095
 
1082
1096
  function dictToEntries(obj) {
1083
1097
  return Object.entries(obj);
@@ -2343,8 +2357,48 @@ function normalizeMonthName(name) {
2343
2357
  // Trim whitespace
2344
2358
  .trim();
2345
2359
  }
2346
- const PATTERN_REGEX = /(M|y|d|D|h|H|m|s|S|G|Z|P|a)+/g;
2347
2360
  const ESCAPE_REGEX = /\\"|"((?:\\"|[^"])*)"/g;
2361
+ /**
2362
+ * Tokenize a date/time pattern by detecting character changes.
2363
+ *
2364
+ * This function uses a character-change detection algorithm to split a pattern into tokens:
2365
+ * 1. Iterates through the pattern character by character
2366
+ * 2. Detects when the character changes (e.g., 'y' → 'M' → 'd')
2367
+ * 3. Creates tokens based on consecutive identical characters
2368
+ * 4. Marks tokens as pattern tokens only if they consist of repeated pattern characters
2369
+ *
2370
+ * This approach works correctly for patterns with or without separators:
2371
+ * - "yyyy-MM-dd" → [{token:"yyyy", type:"y"}, {token:"-", type:null}, {token:"MM", type:"M"}, {token:"-", type:null}, {token:"dd", type:"d"}]
2372
+ * - "yyyyMMdd" → [{token:"yyyy", type:"y"}, {token:"MM", type:"M"}, {token:"dd", type:"d"}]
2373
+ *
2374
+ * @param pattern - The date/time pattern to tokenize
2375
+ * @returns Array of tokens with their types (null for separators/literals, pattern char for pattern tokens)
2376
+ */
2377
+ function tokenizePattern(pattern) {
2378
+ const result = [];
2379
+ let currentToken = '';
2380
+ let currentChar = '';
2381
+ for (const char of pattern) {
2382
+ if (char === currentChar) {
2383
+ // Same character, extend current token
2384
+ currentToken += char;
2385
+ }
2386
+ else {
2387
+ // Character changed, end current token and start new one
2388
+ if (currentToken) {
2389
+ // Mark the token with its character (caller will decide if it's a valid pattern)
2390
+ result.push({ token: currentToken, type: currentChar });
2391
+ }
2392
+ currentToken = char;
2393
+ currentChar = char;
2394
+ }
2395
+ }
2396
+ // Don't forget the last token
2397
+ if (currentToken) {
2398
+ result.push({ token: currentToken, type: currentChar });
2399
+ }
2400
+ return result;
2401
+ }
2348
2402
  // Formatter configuration mapping: token pattern -> configuration with optional extraction rules
2349
2403
  const formatterConfigs = {
2350
2404
  // Year
@@ -2426,11 +2480,16 @@ function formatTimeInstant(instant, pattern, config = {}) {
2426
2480
  if (index % 2 !== 0) {
2427
2481
  return sub;
2428
2482
  }
2429
- return sub.replace(PATTERN_REGEX, (match) => {
2430
- const type = match.charAt(0);
2431
- const length = match.length;
2432
- return formatType(type, length, date, locale, timeZone) || match;
2433
- });
2483
+ // Tokenize the pattern by detecting character changes
2484
+ const tokens = tokenizePattern(sub);
2485
+ // Format each token and join the results
2486
+ return tokens.map(({ token, type }) => {
2487
+ // If type is null or formatting fails, keep token as-is
2488
+ if (!type)
2489
+ return token;
2490
+ const formatted = formatType(type, token.length, date, locale, timeZone);
2491
+ return formatted !== undefined ? formatted : token;
2492
+ }).join('');
2434
2493
  })
2435
2494
  .join('');
2436
2495
  }
@@ -2458,53 +2517,62 @@ function parseTimeInstantComponents(dateString, pattern, config = {}) {
2458
2517
  if (index % 2 !== 0) {
2459
2518
  return sub.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // Escape special regex chars
2460
2519
  }
2461
- return sub.replace(PATTERN_REGEX, (match) => {
2462
- const type = match.charAt(0);
2463
- tokens.push({ type, length: match.length, position: position++ });
2520
+ // Tokenize the pattern by detecting character changes
2521
+ const patternTokens = tokenizePattern(sub);
2522
+ // Build regex pattern from tokens
2523
+ return patternTokens.map(({ token, type }) => {
2524
+ // Check if this is a valid pattern by looking it up in formatterConfigs
2525
+ const isValidPattern = type && formatterConfigs[token];
2526
+ if (!isValidPattern) {
2527
+ // This is a literal/separator, escape it for regex
2528
+ return token.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
2529
+ }
2530
+ // This is a pattern token, track it and create regex
2531
+ tokens.push({ type, length: token.length, position: position++ });
2464
2532
  // Create appropriate regex for each token type
2465
2533
  switch (type) {
2466
2534
  case 'y':
2467
- return match.length === 2 ? '(\\d{2})' : '(\\d{4})';
2535
+ return token.length === 2 ? '(\\d{2})' : '(\\d{4})';
2468
2536
  case 'M':
2469
- if (match.length === 1)
2537
+ if (token.length === 1)
2470
2538
  return '(\\d{1,2})';
2471
- if (match.length === 2)
2539
+ if (token.length === 2)
2472
2540
  return '(\\d{2})';
2473
- if (match.length === 3)
2541
+ if (token.length === 3)
2474
2542
  return '([A-Za-z.]{1,7})';
2475
2543
  return '([A-Za-z]+)';
2476
2544
  case 'd':
2477
- return match.length === 1 ? '(\\d{1,2})' : '(\\d{2})';
2545
+ return token.length === 1 ? '(\\d{1,2})' : '(\\d{2})';
2478
2546
  case 'H':
2479
2547
  case 'h':
2480
- return match.length === 1 ? '(\\d{1,2})' : '(\\d{2})';
2548
+ return token.length === 1 ? '(\\d{1,2})' : '(\\d{2})';
2481
2549
  case 'm':
2482
2550
  case 's':
2483
- return match.length === 1 ? '(\\d{1,2})' : '(\\d{2})';
2551
+ return token.length === 1 ? '(\\d{1,2})' : '(\\d{2})';
2484
2552
  case 'S':
2485
- return `(\\d{${match.length}})`;
2553
+ return `(\\d{${token.length}})`;
2486
2554
  case 'a':
2487
2555
  return '([aApP][mM])';
2488
2556
  case 'D':
2489
- if (match.length === 1)
2557
+ if (token.length === 1)
2490
2558
  return '([A-Za-z])';
2491
- if (match.length === 2)
2559
+ if (token.length === 2)
2492
2560
  return '([A-Za-z]{3})';
2493
2561
  return '([A-Za-z]+)';
2494
2562
  case 'G':
2495
- if (match.length === 1)
2563
+ if (token.length === 1)
2496
2564
  return '([A-Za-z])';
2497
- if (match.length === 2)
2565
+ if (token.length === 2)
2498
2566
  return '([A-Za-z]{2})';
2499
2567
  return '([A-Za-z\\s]+)';
2500
2568
  case 'Z':
2501
- return match.length === 1 ? '([A-Za-z0-9+\\-:]+)' : '([A-Za-z\\s]+)';
2569
+ return token.length === 1 ? '([A-Za-z0-9+\\-:]+)' : '([A-Za-z\\s]+)';
2502
2570
  case 'P':
2503
2571
  return '([A-Za-z\\s]+)';
2504
2572
  default:
2505
- return match;
2573
+ return token;
2506
2574
  }
2507
- });
2575
+ }).join('');
2508
2576
  }).join('');
2509
2577
  const regex = new RegExp('^' + regexPattern + '$');
2510
2578
  const matches = dateString.match(regex);
@@ -3505,5 +3573,5 @@ function isUpgradable(obj) {
3505
3573
  return isDefined(obj) && typeof obj === "object" && VERSION_FIELD in obj && isNumber(obj.$version) && isPositiveNumber(obj.$version);
3506
3574
  }
3507
3575
 
3508
- export { Cached, DataUpgrader, Deferred, DeferredCanceledError, ErrorCannotInstantiatePresentOptionalWithEmptyValue, ErrorGetEmptyOptional, ErrorSetEmptyOptional, Lazy, LazyAsync, LazyDictionary, Logger, NEVER, NonExhaustiveSwitchError, Operation, Optional, PredicateBuilder, RandomTimeDuration, RateThrottler, Semaphore, Sorter, StringParts, TimeDuration, TimeFrequency, TimeInstant, TimeRange, TimeUnit, TimeoutError, alwaysFalse, alwaysTrue, and, arrayGet, arrayIncludes, asError, asPromise, average, averageBy, awaitAtMost, capitalizeWord, clamp, clampInt0_100, constant, constantFalse, constantNull, constantOne, constantTrue, constantUndefined, constantZero, cssDeclarationRulesDictionaryToCss, decrement, decrementBy, delayPromise, dictToEntries, dictToList, divideBy, ellipsis, ensureArray, ensureDefined, ensureNegativeNumber, ensureNonNegativeNumber, ensureNonPositiveNumber, ensurePositiveNumber, ensureReadableArray, entriesToDict, entriesToEntries, entriesToList, extendArray, extendArrayWith, fill, fillWith, filterMap, filterMapReduce, filterWithTypePredicate, findInArray, findIndexInArray, first$1 as first, flatMapTruthys, getCauseMessageFromError, getCauseStackFromError, getMessageFromError, getStackFromError, groupByBoolean, groupByBooleanWith, groupByNumber, groupByNumberWith, groupByString, groupByStringWith, groupBySymbol, groupBySymbolWith, hashCode, head, identity, ifDefined, ifNullOrUndefined, iff, includes, increment, incrementBy, indexByNumber, indexByNumberWith, indexByString, indexByStringWith, indexBySymbol, indexBySymbolWith, indexByWith, isAllowedTimeDuration, isArray, isDefined, isEmpty, isError, isFalse, isFunction, isNegativeNumber, isNullOrUndefined, isNullOrUndefinedOrEmpty, isNumber, isPositiveNumber, isString, isTimeInstant, isTrue, isUpgradable, isZero, jsonCloneDeep, last$1 as last, listToDict, mapDefined, mapEntries, mapFirstTruthy, mapTruthys, max, maxBy, min, minBy, multiplyBy, noop, not, omitFromJsonObject, or, pad, padLeft, padRight, parseJson, parseTimeInstantBasicComponents, parseTimeInstantComponents, partition, pick, pipedInvoke, pipedInvokeFromArray, pluralize, promiseSequence, randomId, randomNumberInInterval, range, repeat, reverse$1 as reverse, round, roundAwayFromZero, roundToLower, roundToNearest, roundToUpper, roundTowardsZero, shallowArrayEquals, shallowRecordEquals, sortedArray, splitWords, stringToNumber, stringifyJson, sum, sumBy, tail, throttle, throwIfNullOrUndefined, transformCssDictionary, tryToParseJson, tryToParseNumber, uniq, uniqBy, uniqByKey, unzip, upsert, withTryCatch, withTryCatchAsync, wrapWithString, xor, zip };
3576
+ export { Cached, DataUpgrader, Deferred, DeferredCanceledError, ErrorCannotInstantiatePresentOptionalWithEmptyValue, ErrorGetEmptyOptional, ErrorSetEmptyOptional, Lazy, LazyAsync, LazyDictionary, Logger, NEVER, NonExhaustiveSwitchError, Operation, Optional, PredicateBuilder, RandomTimeDuration, RateThrottler, Semaphore, Sorter, StringParts, TimeDuration, TimeFrequency, TimeInstant, TimeRange, TimeUnit, TimeoutError, alwaysFalse, alwaysTrue, and, arrayGet, arrayIncludes, asError, asPromise, average, averageBy, awaitAtMost, capitalizeWord, clamp, clampInt0_100, constant, constantFalse, constantNull, constantOne, constantTrue, constantUndefined, constantZero, cssDeclarationRulesDictionaryToCss, decrement, decrementBy, delayPromise, dictToEntries, dictToList, divideBy, ellipsis, ensureArray, ensureDefined, ensureNegativeNumber, ensureNonNegativeNumber, ensureNonPositiveNumber, ensurePositiveNumber, ensureReadableArray, entriesToDict, entriesToEntries, entriesToList, extendArray, extendArrayWith, fill, fillWith, filterMap, filterMapReduce, filterWithTypePredicate, findInArray, findIndexInArray, first$1 as first, flatMapTruthys, getCauseMessageFromError, getCauseStackFromError, getMessageFromError, getStackFromError, groupByBoolean, groupByBooleanWith, groupByNumber, groupByNumberWith, groupByString, groupByStringWith, groupBySymbol, groupBySymbolWith, hashCode, head, identity, ifDefined, ifNullOrUndefined, iff, includes, increment, incrementBy, indexByNumber, indexByNumberWith, indexByString, indexByStringWith, indexBySymbol, indexBySymbolWith, indexByWith, isAllowedTimeDuration, isArray, isDefined, isEmpty, isError, isFalse, isFunction, isNegativeNumber, isNullOrUndefined, isNullOrUndefinedOrEmpty, isNumber, isPositiveNumber, isString, isTimeInstant, isTrue, isUpgradable, isZero, jsonCloneDeep, last$1 as last, listToDict, mapDefined, mapEntries, mapFirstTruthy, mapTruthys, max, maxBy, min, minBy, multiplyBy, noop, not, omitFromJsonObject, or, pad, padLeft, padRight, parseJson, parseTimeInstantBasicComponents, parseTimeInstantComponents, partition, pick, pipedInvoke, pipedInvokeFromArray, pluralize, promiseSequence, randomId, randomNumberInInterval, randomPick, randomPicks, range, repeat, reverse$1 as reverse, round, roundAwayFromZero, roundToLower, roundToNearest, roundToUpper, roundTowardsZero, shallowArrayEquals, shallowRecordEquals, sortedArray, splitWords, stringToNumber, stringifyJson, sum, sumBy, tail, throttle, throwIfNullOrUndefined, transformCssDictionary, tryToParseJson, tryToParseNumber, uniq, uniqBy, uniqByKey, unzip, upsert, withTryCatch, withTryCatchAsync, wrapWithString, xor, zip };
3509
3577
  //# sourceMappingURL=index.mjs.map