@zelgadis87/utils-core 5.3.3 → 5.3.4
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.cjs +215 -3
- package/.rollup/index.cjs.map +1 -1
- package/.rollup/index.d.ts +18 -2
- package/.rollup/index.mjs +214 -4
- package/.rollup/index.mjs.map +1 -1
- package/.rollup/tsconfig.tsbuildinfo +1 -1
- package/CHANGELOG.md +7 -1
- package/package.json +2 -2
- package/src/time/TimeInstant.ts +372 -99
package/.rollup/index.mjs
CHANGED
|
@@ -2139,8 +2139,8 @@ class TimeInstant extends TimeBase {
|
|
|
2139
2139
|
return timeInstantBuilder();
|
|
2140
2140
|
}
|
|
2141
2141
|
static fromIso8601(str) {
|
|
2142
|
-
// Regex to capture: YYYY-MM-DDTHH:mm:ss.
|
|
2143
|
-
const iso8601Regex = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})
|
|
2142
|
+
// Regex to capture: YYYY-MM-DDTHH:mm:ss[.sss]Z or YYYY-MM-DDTHH:mm:ss[.sss]±HH:mm
|
|
2143
|
+
const iso8601Regex = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d{3})|)(Z|[+-]\d{2}:\d{2})?$/;
|
|
2144
2144
|
const match = str.match(iso8601Regex);
|
|
2145
2145
|
if (!match) {
|
|
2146
2146
|
throw new Error('Invalid ISO 8601 date format: ' + str);
|
|
@@ -2153,7 +2153,7 @@ class TimeInstant extends TimeBase {
|
|
|
2153
2153
|
const hours = parseInt(hourStr, 10);
|
|
2154
2154
|
const minutes = parseInt(minuteStr, 10);
|
|
2155
2155
|
const seconds = parseInt(secondStr, 10);
|
|
2156
|
-
const milliseconds = parseInt(millisecondStr, 10);
|
|
2156
|
+
const milliseconds = millisecondStr ? parseInt(millisecondStr, 10) : 0;
|
|
2157
2157
|
// Validate each component using standalone validation functions
|
|
2158
2158
|
if (!isValidYear(year))
|
|
2159
2159
|
throw new Error('Invalid year in: ' + str);
|
|
@@ -2589,6 +2589,216 @@ function parseTimeInstantComponents(dateString, pattern, config = {}) {
|
|
|
2589
2589
|
}
|
|
2590
2590
|
return result;
|
|
2591
2591
|
}
|
|
2592
|
+
/**
|
|
2593
|
+
* Parses a date string using only basic patterns that don't require Intl.
|
|
2594
|
+
* This is a safer alternative to parseTimeInstantComponents that works even when Intl is not available.
|
|
2595
|
+
*
|
|
2596
|
+
* @param dateString The date string to parse
|
|
2597
|
+
* @param pattern A basic pattern that doesn't require Intl (strongly typed)
|
|
2598
|
+
* @returns Partial time instant parameters that were parsed from the string
|
|
2599
|
+
* @throws Error if the string doesn't match the pattern or contains invalid values
|
|
2600
|
+
*/
|
|
2601
|
+
function parseTimeInstantBasicComponents(dateString, pattern) {
|
|
2602
|
+
// Check if Intl is available, if so warn the user about the existing function
|
|
2603
|
+
const isIntlAvailable = typeof Intl !== 'undefined' && typeof Intl.DateTimeFormat !== 'undefined';
|
|
2604
|
+
if (isIntlAvailable)
|
|
2605
|
+
console.warn('Intl is available, use parseTimeInstantComponents instead of parseTimeInstantBasicComponents.');
|
|
2606
|
+
const result = {};
|
|
2607
|
+
let patternIndex = 0;
|
|
2608
|
+
let dateStringIndex = 0;
|
|
2609
|
+
// Helper function to check if a character is a pattern token
|
|
2610
|
+
const isPatternChar = (char) => ['y', 'M', 'd', 'H', 'm', 's', 'S'].includes(char);
|
|
2611
|
+
// Token extraction rules dictionary
|
|
2612
|
+
const tokenRules = {
|
|
2613
|
+
'': { maxLength: undefined }, // Default rule
|
|
2614
|
+
'H': {
|
|
2615
|
+
maxLength: 2,
|
|
2616
|
+
validator: (value) => /^\d{1,2}$/.test(value) && parseInt(value, 10) >= 0 && parseInt(value, 10) <= 23,
|
|
2617
|
+
description: 'Hour (0-23, 1-2 digits)'
|
|
2618
|
+
},
|
|
2619
|
+
'HH': {
|
|
2620
|
+
maxLength: 2,
|
|
2621
|
+
validator: (value) => /^\d{2}$/.test(value) && parseInt(value, 10) >= 0 && parseInt(value, 10) <= 23,
|
|
2622
|
+
description: 'Hour (00-23, exactly 2 digits)'
|
|
2623
|
+
},
|
|
2624
|
+
'M': {
|
|
2625
|
+
maxLength: 2,
|
|
2626
|
+
validator: (value) => /^\d{1,2}$/.test(value) && parseInt(value, 10) >= 1 && parseInt(value, 10) <= 12,
|
|
2627
|
+
description: 'Month (1-12, 1-2 digits)'
|
|
2628
|
+
},
|
|
2629
|
+
'MM': {
|
|
2630
|
+
maxLength: 2,
|
|
2631
|
+
validator: (value) => /^\d{2}$/.test(value) && parseInt(value, 10) >= 1 && parseInt(value, 10) <= 12,
|
|
2632
|
+
description: 'Month (01-12, exactly 2 digits)'
|
|
2633
|
+
},
|
|
2634
|
+
'd': {
|
|
2635
|
+
maxLength: 2,
|
|
2636
|
+
validator: (value) => /^\d{1,2}$/.test(value) && parseInt(value, 10) >= 1 && parseInt(value, 10) <= 31,
|
|
2637
|
+
description: 'Day (1-31, 1-2 digits)'
|
|
2638
|
+
},
|
|
2639
|
+
'dd': {
|
|
2640
|
+
maxLength: 2,
|
|
2641
|
+
validator: (value) => /^\d{2}$/.test(value) && parseInt(value, 10) >= 1 && parseInt(value, 10) <= 31,
|
|
2642
|
+
description: 'Day (01-31, exactly 2 digits)'
|
|
2643
|
+
},
|
|
2644
|
+
'm': {
|
|
2645
|
+
maxLength: 2,
|
|
2646
|
+
validator: (value) => /^\d{1,2}$/.test(value) && parseInt(value, 10) >= 0 && parseInt(value, 10) <= 59,
|
|
2647
|
+
description: 'Minutes (0-59, 1-2 digits)'
|
|
2648
|
+
},
|
|
2649
|
+
'mm': {
|
|
2650
|
+
maxLength: 2,
|
|
2651
|
+
validator: (value) => /^\d{2}$/.test(value) && parseInt(value, 10) >= 0 && parseInt(value, 10) <= 59,
|
|
2652
|
+
description: 'Minutes (00-59, exactly 2 digits)'
|
|
2653
|
+
},
|
|
2654
|
+
's': {
|
|
2655
|
+
maxLength: 2,
|
|
2656
|
+
validator: (value) => /^\d{1,2}$/.test(value) && parseInt(value, 10) >= 0 && parseInt(value, 10) <= 59,
|
|
2657
|
+
description: 'Seconds (0-59, 1-2 digits)'
|
|
2658
|
+
},
|
|
2659
|
+
'ss': {
|
|
2660
|
+
maxLength: 2,
|
|
2661
|
+
validator: (value) => /^\d{2}$/.test(value) && parseInt(value, 10) >= 0 && parseInt(value, 10) <= 59,
|
|
2662
|
+
description: 'Seconds (00-59, exactly 2 digits)'
|
|
2663
|
+
},
|
|
2664
|
+
'S': {
|
|
2665
|
+
maxLength: 3,
|
|
2666
|
+
validator: (value) => /^\d{1,3}$/.test(value) && parseInt(value, 10) >= 0 && parseInt(value, 10) <= 999,
|
|
2667
|
+
description: 'Milliseconds (0-999, 1-3 digits)'
|
|
2668
|
+
},
|
|
2669
|
+
'SS': {
|
|
2670
|
+
maxLength: 2,
|
|
2671
|
+
validator: (value) => /^\d{2}$/.test(value) && parseInt(value, 10) >= 0 && parseInt(value, 10) <= 99,
|
|
2672
|
+
description: 'Milliseconds (0-99, exactly 2 digits)'
|
|
2673
|
+
},
|
|
2674
|
+
'SSS': {
|
|
2675
|
+
maxLength: 3,
|
|
2676
|
+
validator: (value) => /^\d{3}$/.test(value) && parseInt(value, 10) >= 0 && parseInt(value, 10) <= 999,
|
|
2677
|
+
description: 'Milliseconds (000-999, exactly 3 digits)'
|
|
2678
|
+
},
|
|
2679
|
+
'y': {
|
|
2680
|
+
maxLength: 4,
|
|
2681
|
+
validator: (value) => /^\d{1,4}$/.test(value) && parseInt(value, 10) >= 0 && parseInt(value, 10) <= 9999,
|
|
2682
|
+
description: 'Year (0-9999, 1-4 digits)'
|
|
2683
|
+
},
|
|
2684
|
+
'yy': {
|
|
2685
|
+
maxLength: 2,
|
|
2686
|
+
validator: (value) => /^\d{2}$/.test(value),
|
|
2687
|
+
description: 'Year (2 digits)'
|
|
2688
|
+
},
|
|
2689
|
+
'yyyy': {
|
|
2690
|
+
maxLength: 4,
|
|
2691
|
+
validator: (value) => /^\d{4}$/.test(value),
|
|
2692
|
+
description: 'Year (4 digits)'
|
|
2693
|
+
}
|
|
2694
|
+
};
|
|
2695
|
+
// Helper function to extract a token value from the date string using token rules
|
|
2696
|
+
const extractValue = (tokenType, tokenLength) => {
|
|
2697
|
+
const tokenKey = tokenType.repeat(tokenLength);
|
|
2698
|
+
const rule = tokenRules[tokenKey] || tokenRules[''];
|
|
2699
|
+
// Extract consecutive digits up to maxLength
|
|
2700
|
+
let endIndex = dateStringIndex;
|
|
2701
|
+
let digitCount = 0;
|
|
2702
|
+
const maxChars = rule.maxLength || tokenLength;
|
|
2703
|
+
while (endIndex < dateString.length && /\d/.test(dateString[endIndex]) && digitCount < maxChars) {
|
|
2704
|
+
endIndex++;
|
|
2705
|
+
digitCount++;
|
|
2706
|
+
}
|
|
2707
|
+
const value = dateString.substring(dateStringIndex, endIndex);
|
|
2708
|
+
dateStringIndex = endIndex;
|
|
2709
|
+
// Validate the extracted value if a validator is provided
|
|
2710
|
+
if (rule.validator && !rule.validator(value)) {
|
|
2711
|
+
// Extract field name from description for better error messages
|
|
2712
|
+
const fieldName = (rule.description || tokenKey).split(' ')[0].toLowerCase();
|
|
2713
|
+
throw new Error(`Invalid ${fieldName} value: "${value}"`);
|
|
2714
|
+
}
|
|
2715
|
+
return value;
|
|
2716
|
+
};
|
|
2717
|
+
// Helper function to parse and validate a numeric value
|
|
2718
|
+
const parseNumericValue = (value, min, max, field) => {
|
|
2719
|
+
const num = parseInt(value, 10);
|
|
2720
|
+
if (isNaN(num) || num < min || num > max)
|
|
2721
|
+
throw new Error(`Invalid ${field} value: ${value}`);
|
|
2722
|
+
return num;
|
|
2723
|
+
};
|
|
2724
|
+
while (patternIndex < pattern.length) {
|
|
2725
|
+
const patternChar = pattern[patternIndex];
|
|
2726
|
+
if (isPatternChar(patternChar)) {
|
|
2727
|
+
// Start of a token - determine its full length
|
|
2728
|
+
let tokenLength = 0;
|
|
2729
|
+
while (patternIndex + tokenLength < pattern.length &&
|
|
2730
|
+
pattern[patternIndex + tokenLength] === patternChar) {
|
|
2731
|
+
tokenLength++;
|
|
2732
|
+
}
|
|
2733
|
+
// Extract and parse the corresponding value from the date string
|
|
2734
|
+
const value = extractValue(patternChar, tokenLength);
|
|
2735
|
+
// Check if we got enough characters for this token (after extraction)
|
|
2736
|
+
if (value.length < tokenLength) {
|
|
2737
|
+
throw new Error(`Date string "${dateString}" does not match pattern "${pattern}"`);
|
|
2738
|
+
}
|
|
2739
|
+
// Debug: log pattern processing (commented out for production)
|
|
2740
|
+
// console.log( `Processing patternChar="${patternChar}" with tokenLength=${tokenLength}, value="${value}"` );
|
|
2741
|
+
switch (patternChar) {
|
|
2742
|
+
case 'y': {
|
|
2743
|
+
if (tokenLength === 2) {
|
|
2744
|
+
// 2-digit year
|
|
2745
|
+
const shortYear = parseNumericValue(value, 0, 99, 'year');
|
|
2746
|
+
result.year = shortYear < 50 ? 2000 + shortYear : 1900 + shortYear;
|
|
2747
|
+
}
|
|
2748
|
+
else {
|
|
2749
|
+
// 4-digit year
|
|
2750
|
+
result.year = parseNumericValue(value, 0, 9999, 'year');
|
|
2751
|
+
}
|
|
2752
|
+
break;
|
|
2753
|
+
}
|
|
2754
|
+
case 'M':
|
|
2755
|
+
result.month = parseNumericValue(value, 1, 12, 'month');
|
|
2756
|
+
break;
|
|
2757
|
+
case 'd':
|
|
2758
|
+
result.date = parseNumericValue(value, 1, 31, 'day');
|
|
2759
|
+
break;
|
|
2760
|
+
case 'H':
|
|
2761
|
+
result.hours = parseNumericValue(value, 0, 23, 'hours');
|
|
2762
|
+
break;
|
|
2763
|
+
case 'm':
|
|
2764
|
+
result.minutes = parseNumericValue(value, 0, 59, 'minutes');
|
|
2765
|
+
break;
|
|
2766
|
+
case 's':
|
|
2767
|
+
result.seconds = parseNumericValue(value, 0, 59, 'seconds');
|
|
2768
|
+
break;
|
|
2769
|
+
case 'S': {
|
|
2770
|
+
let ms = parseInt(value, 10);
|
|
2771
|
+
if (isNaN(ms))
|
|
2772
|
+
throw new Error(`Invalid milliseconds value: ${value}`);
|
|
2773
|
+
// Normalize to milliseconds based on length
|
|
2774
|
+
if (tokenLength === 1)
|
|
2775
|
+
ms *= 100;
|
|
2776
|
+
else if (tokenLength === 2)
|
|
2777
|
+
ms *= 10;
|
|
2778
|
+
result.milliseconds = ms;
|
|
2779
|
+
break;
|
|
2780
|
+
}
|
|
2781
|
+
default:
|
|
2782
|
+
throw new Error(`Unsupported pattern character: ${patternChar}`);
|
|
2783
|
+
}
|
|
2784
|
+
patternIndex += tokenLength;
|
|
2785
|
+
}
|
|
2786
|
+
else {
|
|
2787
|
+
// Non-pattern character (separator like '-', '/', ':', ' ', '.')
|
|
2788
|
+
if (dateStringIndex >= dateString.length ||
|
|
2789
|
+
dateString[dateStringIndex] !== patternChar) {
|
|
2790
|
+
throw new Error(`Date string "${dateString}" does not match pattern "${pattern}"`);
|
|
2791
|
+
}
|
|
2792
|
+
patternIndex++;
|
|
2793
|
+
dateStringIndex++;
|
|
2794
|
+
}
|
|
2795
|
+
}
|
|
2796
|
+
// After processing the entire pattern, check if we consumed the entire date string
|
|
2797
|
+
if (dateStringIndex < dateString.length) {
|
|
2798
|
+
throw new Error(`Date string "${dateString}" does not match pattern "${pattern}"`);
|
|
2799
|
+
}
|
|
2800
|
+
return result;
|
|
2801
|
+
}
|
|
2592
2802
|
|
|
2593
2803
|
const LEVELS = ["trace", "log", "debug", "info", "warn", "error"];
|
|
2594
2804
|
const timestamp = () => TimeInstant.now().format('HH:mm:ss');
|
|
@@ -3263,5 +3473,5 @@ function isUpgradable(obj) {
|
|
|
3263
3473
|
return isDefined(obj) && typeof obj === "object" && VERSION_FIELD in obj && isNumber(obj.$version) && isPositiveNumber(obj.$version);
|
|
3264
3474
|
}
|
|
3265
3475
|
|
|
3266
|
-
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, 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, 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, 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 };
|
|
3476
|
+
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, 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, 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 };
|
|
3267
3477
|
//# sourceMappingURL=index.mjs.map
|