nhb-toolbox 4.20.87 → 4.20.89

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/CHANGELOG.md CHANGED
@@ -6,6 +6,15 @@ All notable changes to the package will be documented here.
6
6
 
7
7
  ---
8
8
 
9
+ ## [4.20.89] - 2025-10-12
10
+
11
+ - **Updated** behavior of `fromNow()` `Chronos` method: _excluded_ `week` level and _included_ `millisecond` for consistency. **Refactored** _internal logic_.
12
+
13
+ ## [4.20.88] - 2025-10-11
14
+
15
+ - **Added** new utility `romanToInteger` and its _aliases_ to convert _Roman numerals_ to _Arabic numeric_ representation and **updated** _input validation_ for `convertToRomanNumerals`.
16
+ - **Added** new _utility type_ `Repeat` to repeat literal string, it works like `String.prototype.repeat()` but on _type-level_.
17
+
9
18
  ## [4.20.87] - 2025-10-08
10
19
 
11
20
  - **Added** new _constants_ and _types_ related to _country information_, e.g. _full country name, code, ISO code_ etc.
@@ -14,10 +14,14 @@ const fromNowPlugin = (ChronosClass) => {
14
14
  let years = to.getFullYear() - from.getFullYear();
15
15
  let months = to.getMonth() - from.getMonth();
16
16
  let days = to.getDate() - from.getDate();
17
- let weeks = 0;
18
17
  let hours = to.getHours() - from.getHours();
19
18
  let minutes = to.getMinutes() - from.getMinutes();
20
19
  let seconds = to.getSeconds() - from.getSeconds();
20
+ let milliseconds = to.getMilliseconds() - from.getMilliseconds();
21
+ if (milliseconds < 0) {
22
+ milliseconds += 1000;
23
+ seconds--;
24
+ }
21
25
  if (seconds < 0) {
22
26
  seconds += 60;
23
27
  minutes--;
@@ -30,10 +34,6 @@ const fromNowPlugin = (ChronosClass) => {
30
34
  hours += 24;
31
35
  days--;
32
36
  }
33
- if (level === 'week' || level === 'day') {
34
- weeks = Math.floor(days / 7);
35
- days = days % 7;
36
- }
37
37
  if (days < 0) {
38
38
  const prevMonth = new Date(to.getFullYear(), to.getMonth(), 0);
39
39
  days += prevMonth.getDate();
@@ -43,29 +43,43 @@ const fromNowPlugin = (ChronosClass) => {
43
43
  months += 12;
44
44
  years--;
45
45
  }
46
- const unitOrder = ['year', 'month', 'week', 'day', 'hour', 'minute', 'second'];
46
+ const unitOrder = [
47
+ 'year',
48
+ 'month',
49
+ 'day',
50
+ 'hour',
51
+ 'minute',
52
+ 'second',
53
+ 'millisecond',
54
+ ];
47
55
  const lvlIdx = unitOrder.indexOf(level);
48
56
  const parts = [];
49
- if (lvlIdx >= 0 && years > 0 && lvlIdx >= unitOrder.indexOf('year')) {
50
- parts?.push((0, convert_1.formatUnitWithPlural)(years, 'year'));
57
+ const _pushToParts = (value, unit) => {
58
+ parts.push((0, convert_1.formatUnitWithPlural)(value, unit));
59
+ };
60
+ const _isLevelRequired = (unit) => {
61
+ return lvlIdx >= unitOrder.indexOf(unit);
62
+ };
63
+ if (years > 0) {
64
+ _pushToParts(years, 'year');
51
65
  }
52
- if (lvlIdx >= unitOrder.indexOf('month') && months > 0) {
53
- parts?.push((0, convert_1.formatUnitWithPlural)(months, 'month'));
66
+ if (_isLevelRequired('month') && months > 0) {
67
+ _pushToParts(months, 'month');
54
68
  }
55
- if (lvlIdx >= unitOrder.indexOf('week') && weeks > 0) {
56
- parts?.push((0, convert_1.formatUnitWithPlural)(weeks, 'week'));
69
+ if (_isLevelRequired('day') && days > 0) {
70
+ _pushToParts(days, 'day');
57
71
  }
58
- if (lvlIdx >= unitOrder.indexOf('day') && days > 0) {
59
- parts?.push((0, convert_1.formatUnitWithPlural)(days, 'day'));
72
+ if (_isLevelRequired('hour') && hours > 0) {
73
+ _pushToParts(hours, 'hour');
60
74
  }
61
- if (lvlIdx >= unitOrder.indexOf('hour') && hours > 0) {
62
- parts?.push((0, convert_1.formatUnitWithPlural)(hours, 'hour'));
75
+ if (_isLevelRequired('minute') && minutes > 0) {
76
+ _pushToParts(minutes, 'minute');
63
77
  }
64
- if (lvlIdx >= unitOrder.indexOf('minute') && minutes > 0) {
65
- parts?.push((0, convert_1.formatUnitWithPlural)(minutes, 'minute'));
78
+ if (_isLevelRequired('second') && seconds > 0) {
79
+ _pushToParts(seconds, 'second');
66
80
  }
67
- if (lvlIdx >= unitOrder.indexOf('second') && (seconds > 0 || parts?.length === 0)) {
68
- parts?.push((0, convert_1.formatUnitWithPlural)(seconds, 'second'));
81
+ if (_isLevelRequired('millisecond') && (milliseconds > 0 || parts?.length === 0)) {
82
+ _pushToParts(milliseconds, 'millisecond');
69
83
  }
70
84
  let prefix = '';
71
85
  let suffix = '';
@@ -77,7 +91,7 @@ const fromNowPlugin = (ChronosClass) => {
77
91
  suffix = ' ago';
78
92
  }
79
93
  }
80
- return `${prefix}${parts?.join(' ')}${suffix}`;
94
+ return parts.length ? `${prefix}${parts?.join(' ')}${suffix}` : `0 ${level}`;
81
95
  };
82
96
  };
83
97
  exports.fromNowPlugin = fromNowPlugin;
package/dist/cjs/index.js CHANGED
@@ -1,13 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.sumDigits = exports.roundToDecimal = exports.roundNumber = exports.reverseNumber = exports.getSumOfNumbers = exports.getRandomNumber = exports.getRandomInt = exports.getAverageOfNumbers = exports.getAverage = exports.convertToFixed = exports.convertToDecimal = exports.calculateLCM = exports.calculateLCD = exports.calculateHCF = exports.calculateGCD = exports.calculateAverage = exports.verbalizer = exports.Verbalizer = exports.pluralizer = exports.Pluralizer = exports.wordCount = exports.parseNumbersFromText = exports.levenshteinDistance = exports.getLevenshteinDistance = exports.extractNumbersFromString = exports.extractNumbers = exports.countWordsInString = exports.countWords = exports.slugifyString = exports.reverseString = exports.replaceAllInString = exports.normalizeString = exports.maskString = exports.formatWithPlural = exports.formatUnitWithPlural = exports.formatNumberWithPluralUnit = exports.extractURLs = exports.extractEmails = exports.convertStringCase = exports.isSnakeCase = exports.isPascalCase = exports.isPalindrome = exports.isKebabCase = exports.isEmojiOnly = exports.isCamelCase = exports.generateAnagrams = exports.truncateString = exports.trimString = exports.generateRandomID = exports.capitalizeString = void 0;
4
- exports.findPrimeNumbers = exports.wordToNumber = exports.wordsToNumber = exports.toRomanNumeral = exports.toRoman = exports.numericToRoman = exports.numberToWordsOrdinal = exports.numberToWords = exports.numberToRoman = exports.integerToRoman = exports.convertWordToNumber = exports.convertWordsToNumber = exports.convertToRomanNumerals = exports.convertNumberToWordsOrdinal = exports.convertNumberToWords = exports.cardinalWordsToOrdinal = exports.isPerfectSquare = exports.isPartOfFibonacciSeries = exports.isPartOfFibonacci = exports.isOddNumber = exports.isOdd = exports.isNumberInvalid = exports.isMultiple = exports.isInvalidNumber = exports.isFibonacci = exports.isEvenNumber = exports.isEven = exports.areNumbersInvalid = exports.areInvalidNumbers = exports.getNthFibonacci = exports.getMemoizedFibonacciSeries = exports.getMemoizedFibonacci = exports.getFibonacciSeriesMemo = exports.getFibonacciSeries = exports.getFibonacciNumbers = exports.getFibonacci = exports.generateFibonacci = exports.fibonacciGenerator = exports.calculatePercentage = exports.UnitConverter = exports.Unit = exports.Currency = exports.getDivisors = exports.factorsOf = exports.getFactors = exports.getFactorial = exports.calculateFactorial = exports.factorial = exports.sumOfNumbers = exports.sumNumbers = void 0;
5
- exports.Chronos = exports.isValidUTCOffSet = exports.isValidUTC = exports.isValidTimeString = exports.isValidTime = exports.isLeapYear = exports.isDateLike = exports.greet = exports.getGreeting = exports.generateGreeting = exports.extractSolidColorValues = exports.extractAlphaColorValues = exports.Colour = exports.Color = exports.convertRgbToRgba = exports.convertRgbToHsl = exports.convertRgbToHex = exports.convertRgbaToHsla = exports.convertRgbaToHex8 = exports.convertHslToRgb = exports.convertHslToHex = exports.convertHslaToRgba = exports.convertHslaToHex8 = exports.convertHexToRgb = exports.convertHexToHsl = exports.convertHex8ToRgba = exports.convertHex8ToHsla = exports.convertColorCode = exports.generateRandomHSLColor = exports.generateRandomColorInHexRGB = exports.getColorForInitial = exports.getNumbersInRange = exports.roundToNearestInterval = exports.roundToNearest = exports.roundNumberToNearestInterval = exports.numberToOrdinal = exports.normalizeNumber = exports.getRandomFloat = exports.getRandomDecimal = exports.getOrdinalNumber = exports.getOrdinal = exports.formatCurrency = exports.convertToOrdinal = exports.convertNumberToOrdinal = exports.convertNumberToCurrency = exports.clampNumber = exports.cardinalToOrdinal = exports.isPrimeNumber = exports.isPrime = exports.getPrimeNumbers = void 0;
6
- exports.getDuplicatesFromArray = exports.getDuplicates = exports.findMissingElements = exports.extractMissingElements = exports.extractDuplicatesFromArray = exports.extractDuplicates = exports.createOptionsArray = exports.sortAnArray = exports.Finder = exports.totalDeltaByField = exports.sumFieldDifference = exports.sumByField = exports.groupAndSumByField = exports.groupAndAvgByField = exports.groupAndAverageByField = exports.avgByField = exports.averageByField = exports.shuffleArray = exports.isValidEmptyArray = exports.isInvalidOrEmptyArray = exports.getLastArrayElement = exports.flattenArray = exports.filterArrayOfObjects = exports.minutesToUTCOffset = exports.getTotalMinutesFromUTC = exports.getTotalMinutesFromTime = exports.getTotalMinutes = exports.getTimeStringFromUTC = exports.getTimeFromMinutes = exports.getMinutesFromUTC = exports.getHourMinutesFromMinutes = exports.getCurrentTime = exports.getCurrentDateTime = exports.formatUTCOffset = exports.extractTotalMinutesFromTime = exports.extractTimeStringFromUTC = exports.extractTimeFromUTC = exports.extractMinutesFromUTC = exports.extractHourMinute = exports.convertMinutesToUTCOffset = exports.convertMinutesToTime = exports.convertMinutesToHourMinutes = exports.chronusts = exports.chronusjs = exports.chronus = exports.chronosts = exports.chronosjs = exports.chronos = exports.INTERNALS = exports.Chronus = void 0;
7
- exports.pickObjectFields = exports.pickFieldsByCondition = exports.pickFields = exports.omitObjectFields = exports.omitFields = exports.deleteObjectFields = exports.deleteFields = exports.convertObjectValues = exports.sanitizeData = exports.parseStringifiedObjectValues = exports.parseObjectValues = exports.parseJsonToObject = exports.mergeObjects = exports.mergeAndFlattenObjects = exports.flattenObjectKeyValue = exports.flattenObjectDotNotation = exports.extractUpdatedFields = exports.extractUpdatedAndNewFields = exports.extractNewFields = exports.extractKeysDeep = exports.extractObjectKeysDeep = exports.extractKeys = exports.extractObjectKeys = exports.countObjectFields = exports.cloneObject = exports.isValidFormData = exports.isOriginFileObj = exports.isFileUpload = exports.isFileOrBlob = exports.isFileList = exports.isFileArray = exports.isCustomFileArray = exports.isCustomFile = exports.serializeForm = exports.parseFormData = exports.createFormData = exports.createControlledFormData = exports.convertIntoFormData = exports.naturalSortForString = exports.naturalSort = exports.compareSorter = exports.compareNaturally = exports.splitArrayByProperty = exports.splitArray = exports.rotateArray = exports.removeDuplicatesFromArray = exports.removeDuplicates = exports.moveArrayElement = exports.groupArrayByProperty = exports.getMissingElements = void 0;
8
- exports.isPositiveInteger = exports.isNumber = exports.isNull = exports.isNormalPrimitive = exports.isNonEmptyString = exports.isInteger = exports.isFalsy = exports.isBoolean = exports.isBigInt = exports.Paginator = exports.throttleAction = exports.parsePrimitivesDeep = exports.parseJsonDeep = exports.parseJSON = exports.joinArrayElements = exports.isDeepEqual = exports.getStaticMethodsCount = exports.getStaticMethodNames = exports.getInstanceMethodsCount = exports.getInstanceMethodNames = exports.getClassDetails = exports.deepParsePrimitives = exports.debounceAction = exports.countStaticMethods = exports.countInstanceMethods = exports.convertArrayToString = exports.saveToSessionStorage = exports.saveToLocalStorage = exports.removeFromSessionStorage = exports.removeFromLocalStorage = exports.getFromSessionStorage = exports.getFromLocalStorage = exports.toggleFullScreen = exports.smoothScrollTo = exports.copyToClipboard = exports.updateQueryParam = exports.literalQueryStringToObject = exports.parseQueryStringLiteral = exports.queryStringToObject = exports.parseQueryString = exports.getQueryStringAsObject = exports.getQueryParams = exports.generateQueryParams = exports.formatQueryParams = exports.createQueryParams = exports.removeObjectFields = exports.removeFields = exports.remapObjectFields = exports.remapFields = exports.pickObjectFieldsByCondition = void 0;
9
- exports.isUUID = exports.isURL = exports.isPhoneNumber = exports.isNumericString = exports.isNodeEnvironment = exports.isNodeENV = exports.isNode = exports.isIPAddress = exports.isExpectedNodeENV = exports.isEnvironment = exports.isEmailArray = exports.isEmail = exports.isDateString = exports.isBrowser = exports.isBase64 = exports.httpStatus = exports.HttpStatus = exports.isValidSet = exports.isValidObject = exports.isValidMap = exports.isValidJSON = exports.isValidArray = exports.isSet = exports.isReturningPromise = exports.isRegularExpression = exports.isRegExp = exports.isPromise = exports.isObjectWithKeys = exports.isObjectEmpty = exports.isObject = exports.isNotEmptyObject = exports.isMethodDescriptor = exports.isMethod = exports.isMap = exports.isJSONObject = exports.isJSON = exports.isFunction = exports.isError = exports.isEmptyObjectGuard = exports.isEmptyObject = exports.isDate = exports.isArrayWithLength = exports.isArrayOfType = exports.isArray = exports.doesReturnPromise = exports.isUndefined = exports.isTruthy = exports.isSymbol = exports.isString = exports.isPrimitive = void 0;
10
- exports.isValidURL = exports.isValidEmail = void 0;
3
+ exports.getRandomInt = exports.getFactors = exports.getFactorial = exports.getDivisors = exports.getAverageOfNumbers = exports.getAverage = exports.factorsOf = exports.factorial = exports.convertToFixed = exports.convertToDecimal = exports.calculateLCM = exports.calculateLCD = exports.calculateHCF = exports.calculateGCD = exports.calculateFactorial = exports.calculateAverage = exports.verbalizer = exports.Verbalizer = exports.pluralizer = exports.Pluralizer = exports.wordCount = exports.parseNumbersFromText = exports.levenshteinDistance = exports.getLevenshteinDistance = exports.extractNumbersFromString = exports.extractNumbers = exports.countWordsInString = exports.countWords = exports.slugifyString = exports.reverseString = exports.replaceAllInString = exports.normalizeString = exports.maskString = exports.formatWithPlural = exports.formatUnitWithPlural = exports.formatNumberWithPluralUnit = exports.extractURLs = exports.extractEmails = exports.convertStringCase = exports.isSnakeCase = exports.isPascalCase = exports.isPalindrome = exports.isKebabCase = exports.isEmojiOnly = exports.isCamelCase = exports.generateAnagrams = exports.truncateString = exports.trimString = exports.generateRandomID = exports.capitalizeString = void 0;
4
+ exports.romanToArabic = exports.numericToRoman = exports.numberToWordsOrdinal = exports.numberToWords = exports.numberToRoman = exports.integerToRoman = exports.convertWordToNumber = exports.convertWordsToNumber = exports.convertToRomanNumerals = exports.convertRomanToNumeric = exports.convertRomanToInteger = exports.convertRomanToArabic = exports.convertNumberToWordsOrdinal = exports.convertNumberToWords = exports.cardinalWordsToOrdinal = exports.arabicToRoman = exports.isPerfectSquare = exports.isPartOfFibonacciSeries = exports.isPartOfFibonacci = exports.isOddNumber = exports.isOdd = exports.isNumberInvalid = exports.isMultiple = exports.isInvalidNumber = exports.isFibonacci = exports.isEvenNumber = exports.isEven = exports.areNumbersInvalid = exports.areInvalidNumbers = exports.getNthFibonacci = exports.getMemoizedFibonacciSeries = exports.getMemoizedFibonacci = exports.getFibonacciSeriesMemo = exports.getFibonacciSeries = exports.getFibonacciNumbers = exports.getFibonacci = exports.generateFibonacci = exports.fibonacciGenerator = exports.calculatePercentage = exports.UnitConverter = exports.Unit = exports.Currency = exports.sumOfNumbers = exports.sumNumbers = exports.sumDigits = exports.roundToDecimal = exports.roundNumber = exports.reverseNumber = exports.getSumOfNumbers = exports.getRandomNumber = void 0;
5
+ exports.greet = exports.getGreeting = exports.generateGreeting = exports.extractSolidColorValues = exports.extractAlphaColorValues = exports.Colour = exports.Color = exports.convertRgbToRgba = exports.convertRgbToHsl = exports.convertRgbToHex = exports.convertRgbaToHsla = exports.convertRgbaToHex8 = exports.convertHslToRgb = exports.convertHslToHex = exports.convertHslaToRgba = exports.convertHslaToHex8 = exports.convertHexToRgb = exports.convertHexToHsl = exports.convertHex8ToRgba = exports.convertHex8ToHsla = exports.convertColorCode = exports.generateRandomHSLColor = exports.generateRandomColorInHexRGB = exports.getColorForInitial = exports.getNumbersInRange = exports.roundToNearestInterval = exports.roundToNearest = exports.roundNumberToNearestInterval = exports.numberToOrdinal = exports.normalizeNumber = exports.getRandomFloat = exports.getRandomDecimal = exports.getOrdinalNumber = exports.getOrdinal = exports.formatCurrency = exports.convertToOrdinal = exports.convertNumberToOrdinal = exports.convertNumberToCurrency = exports.clampNumber = exports.cardinalToOrdinal = exports.isPrimeNumber = exports.isPrime = exports.getPrimeNumbers = exports.findPrimeNumbers = exports.wordToNumber = exports.wordsToNumber = exports.toRomanNumeral = exports.toRoman = exports.romanToNumeric = exports.romanToInteger = void 0;
6
+ exports.sortAnArray = exports.Finder = exports.totalDeltaByField = exports.sumFieldDifference = exports.sumByField = exports.groupAndSumByField = exports.groupAndAvgByField = exports.groupAndAverageByField = exports.avgByField = exports.averageByField = exports.shuffleArray = exports.isValidEmptyArray = exports.isInvalidOrEmptyArray = exports.getLastArrayElement = exports.flattenArray = exports.filterArrayOfObjects = exports.minutesToUTCOffset = exports.getTotalMinutesFromUTC = exports.getTotalMinutesFromTime = exports.getTotalMinutes = exports.getTimeStringFromUTC = exports.getTimeFromMinutes = exports.getMinutesFromUTC = exports.getHourMinutesFromMinutes = exports.getCurrentTime = exports.getCurrentDateTime = exports.formatUTCOffset = exports.extractTotalMinutesFromTime = exports.extractTimeStringFromUTC = exports.extractTimeFromUTC = exports.extractMinutesFromUTC = exports.extractHourMinute = exports.convertMinutesToUTCOffset = exports.convertMinutesToTime = exports.convertMinutesToHourMinutes = exports.chronusts = exports.chronusjs = exports.chronus = exports.chronosts = exports.chronosjs = exports.chronos = exports.INTERNALS = exports.Chronus = exports.Chronos = exports.isValidUTCOffSet = exports.isValidUTC = exports.isValidTimeString = exports.isValidTime = exports.isLeapYear = exports.isDateLike = void 0;
7
+ exports.convertObjectValues = exports.sanitizeData = exports.parseStringifiedObjectValues = exports.parseObjectValues = exports.parseJsonToObject = exports.mergeObjects = exports.mergeAndFlattenObjects = exports.flattenObjectKeyValue = exports.flattenObjectDotNotation = exports.extractUpdatedFields = exports.extractUpdatedAndNewFields = exports.extractNewFields = exports.extractObjectKeysDeep = exports.extractObjectKeys = exports.extractKeysDeep = exports.extractKeys = exports.countObjectFields = exports.cloneObject = exports.isValidFormData = exports.isOriginFileObj = exports.isFileUpload = exports.isFileOrBlob = exports.isFileList = exports.isFileArray = exports.isCustomFileArray = exports.isCustomFile = exports.serializeForm = exports.parseFormData = exports.createFormData = exports.createControlledFormData = exports.convertIntoFormData = exports.naturalSortForString = exports.naturalSort = exports.compareSorter = exports.compareNaturally = exports.splitArrayByProperty = exports.splitArray = exports.rotateArray = exports.removeDuplicatesFromArray = exports.removeDuplicates = exports.moveArrayElement = exports.groupArrayByProperty = exports.getMissingElements = exports.getDuplicatesFromArray = exports.getDuplicates = exports.findMissingElements = exports.extractMissingElements = exports.extractDuplicatesFromArray = exports.extractDuplicates = exports.createOptionsArray = void 0;
8
+ exports.isBoolean = exports.isBigInt = exports.Paginator = exports.throttleAction = exports.parsePrimitivesDeep = exports.parseJsonDeep = exports.parseJSON = exports.joinArrayElements = exports.isDeepEqual = exports.getStaticMethodsCount = exports.getStaticMethodNames = exports.getInstanceMethodsCount = exports.getInstanceMethodNames = exports.getClassDetails = exports.deepParsePrimitives = exports.debounceAction = exports.countStaticMethods = exports.countInstanceMethods = exports.convertArrayToString = exports.saveToSessionStorage = exports.saveToLocalStorage = exports.removeFromSessionStorage = exports.removeFromLocalStorage = exports.getFromSessionStorage = exports.getFromLocalStorage = exports.toggleFullScreen = exports.smoothScrollTo = exports.copyToClipboard = exports.updateQueryParam = exports.queryStringToObject = exports.parseQueryStringLiteral = exports.parseQueryString = exports.literalQueryStringToObject = exports.getQueryStringAsObject = exports.getQueryParams = exports.generateQueryParams = exports.formatQueryParams = exports.createQueryParams = exports.removeObjectFields = exports.removeFields = exports.remapObjectFields = exports.remapFields = exports.pickObjectFieldsByCondition = exports.pickObjectFields = exports.pickFieldsByCondition = exports.pickFields = exports.omitObjectFields = exports.omitFields = exports.deleteObjectFields = exports.deleteFields = void 0;
9
+ exports.isIPAddress = exports.isExpectedNodeENV = exports.isEnvironment = exports.isEmailArray = exports.isEmail = exports.isDateString = exports.isBrowser = exports.isBase64 = exports.httpStatus = exports.HttpStatus = exports.isValidSet = exports.isValidObject = exports.isValidMap = exports.isValidJSON = exports.isValidArray = exports.isSet = exports.isReturningPromise = exports.isRegularExpression = exports.isRegExp = exports.isPromise = exports.isObjectWithKeys = exports.isObjectEmpty = exports.isObject = exports.isNotEmptyObject = exports.isMethodDescriptor = exports.isMethod = exports.isMap = exports.isJSONObject = exports.isJSON = exports.isFunction = exports.isError = exports.isEmptyObjectGuard = exports.isEmptyObject = exports.isDate = exports.isArrayWithLength = exports.isArrayOfType = exports.isArray = exports.doesReturnPromise = exports.isUndefined = exports.isTruthy = exports.isSymbol = exports.isString = exports.isPrimitive = exports.isPositiveInteger = exports.isNumber = exports.isNull = exports.isNormalPrimitive = exports.isNonEmptyString = exports.isInteger = exports.isFalsy = void 0;
10
+ exports.isValidURL = exports.isValidEmail = exports.isUUID = exports.isURL = exports.isPhoneNumber = exports.isNumericString = exports.isNodeEnvironment = exports.isNodeENV = exports.isNode = void 0;
11
11
  var basics_1 = require("./string/basics");
12
12
  Object.defineProperty(exports, "capitalizeString", { enumerable: true, get: function () { return basics_1.capitalizeString; } });
13
13
  Object.defineProperty(exports, "generateRandomID", { enumerable: true, get: function () { return basics_1.generateRandomID; } });
@@ -52,14 +52,20 @@ Object.defineProperty(exports, "Verbalizer", { enumerable: true, get: function (
52
52
  Object.defineProperty(exports, "verbalizer", { enumerable: true, get: function () { return Verbalizer_1.verbalizer; } });
53
53
  var basics_2 = require("./number/basics");
54
54
  Object.defineProperty(exports, "calculateAverage", { enumerable: true, get: function () { return basics_2.getAverage; } });
55
+ Object.defineProperty(exports, "calculateFactorial", { enumerable: true, get: function () { return basics_2.factorial; } });
55
56
  Object.defineProperty(exports, "calculateGCD", { enumerable: true, get: function () { return basics_2.calculateHCF; } });
56
57
  Object.defineProperty(exports, "calculateHCF", { enumerable: true, get: function () { return basics_2.calculateHCF; } });
57
58
  Object.defineProperty(exports, "calculateLCD", { enumerable: true, get: function () { return basics_2.calculateLCM; } });
58
59
  Object.defineProperty(exports, "calculateLCM", { enumerable: true, get: function () { return basics_2.calculateLCM; } });
59
60
  Object.defineProperty(exports, "convertToDecimal", { enumerable: true, get: function () { return basics_2.convertToDecimal; } });
60
61
  Object.defineProperty(exports, "convertToFixed", { enumerable: true, get: function () { return basics_2.convertToDecimal; } });
62
+ Object.defineProperty(exports, "factorial", { enumerable: true, get: function () { return basics_2.factorial; } });
63
+ Object.defineProperty(exports, "factorsOf", { enumerable: true, get: function () { return basics_2.getFactors; } });
61
64
  Object.defineProperty(exports, "getAverage", { enumerable: true, get: function () { return basics_2.getAverage; } });
62
65
  Object.defineProperty(exports, "getAverageOfNumbers", { enumerable: true, get: function () { return basics_2.getAverage; } });
66
+ Object.defineProperty(exports, "getDivisors", { enumerable: true, get: function () { return basics_2.getFactors; } });
67
+ Object.defineProperty(exports, "getFactorial", { enumerable: true, get: function () { return basics_2.factorial; } });
68
+ Object.defineProperty(exports, "getFactors", { enumerable: true, get: function () { return basics_2.getFactors; } });
63
69
  Object.defineProperty(exports, "getRandomInt", { enumerable: true, get: function () { return basics_2.getRandomNumber; } });
64
70
  Object.defineProperty(exports, "getRandomNumber", { enumerable: true, get: function () { return basics_2.getRandomNumber; } });
65
71
  Object.defineProperty(exports, "getSumOfNumbers", { enumerable: true, get: function () { return basics_2.sumNumbers; } });
@@ -69,12 +75,6 @@ Object.defineProperty(exports, "roundToDecimal", { enumerable: true, get: functi
69
75
  Object.defineProperty(exports, "sumDigits", { enumerable: true, get: function () { return basics_2.sumDigits; } });
70
76
  Object.defineProperty(exports, "sumNumbers", { enumerable: true, get: function () { return basics_2.sumNumbers; } });
71
77
  Object.defineProperty(exports, "sumOfNumbers", { enumerable: true, get: function () { return basics_2.sumNumbers; } });
72
- Object.defineProperty(exports, "factorial", { enumerable: true, get: function () { return basics_2.factorial; } });
73
- Object.defineProperty(exports, "calculateFactorial", { enumerable: true, get: function () { return basics_2.factorial; } });
74
- Object.defineProperty(exports, "getFactorial", { enumerable: true, get: function () { return basics_2.factorial; } });
75
- Object.defineProperty(exports, "getFactors", { enumerable: true, get: function () { return basics_2.getFactors; } });
76
- Object.defineProperty(exports, "factorsOf", { enumerable: true, get: function () { return basics_2.getFactors; } });
77
- Object.defineProperty(exports, "getDivisors", { enumerable: true, get: function () { return basics_2.getFactors; } });
78
78
  var Currency_1 = require("./number/Currency");
79
79
  Object.defineProperty(exports, "Currency", { enumerable: true, get: function () { return Currency_1.Currency; } });
80
80
  var Unit_1 = require("./number/Unit");
@@ -107,9 +107,13 @@ Object.defineProperty(exports, "isPartOfFibonacci", { enumerable: true, get: fun
107
107
  Object.defineProperty(exports, "isPartOfFibonacciSeries", { enumerable: true, get: function () { return guards_2.isFibonacci; } });
108
108
  Object.defineProperty(exports, "isPerfectSquare", { enumerable: true, get: function () { return guards_2.isPerfectSquare; } });
109
109
  var convert_2 = require("./number/convert");
110
+ Object.defineProperty(exports, "arabicToRoman", { enumerable: true, get: function () { return convert_2.convertToRomanNumerals; } });
110
111
  Object.defineProperty(exports, "cardinalWordsToOrdinal", { enumerable: true, get: function () { return convert_2.numberToWordsOrdinal; } });
111
112
  Object.defineProperty(exports, "convertNumberToWords", { enumerable: true, get: function () { return convert_2.numberToWords; } });
112
113
  Object.defineProperty(exports, "convertNumberToWordsOrdinal", { enumerable: true, get: function () { return convert_2.numberToWordsOrdinal; } });
114
+ Object.defineProperty(exports, "convertRomanToArabic", { enumerable: true, get: function () { return convert_2.romanToInteger; } });
115
+ Object.defineProperty(exports, "convertRomanToInteger", { enumerable: true, get: function () { return convert_2.romanToInteger; } });
116
+ Object.defineProperty(exports, "convertRomanToNumeric", { enumerable: true, get: function () { return convert_2.romanToInteger; } });
113
117
  Object.defineProperty(exports, "convertToRomanNumerals", { enumerable: true, get: function () { return convert_2.convertToRomanNumerals; } });
114
118
  Object.defineProperty(exports, "convertWordsToNumber", { enumerable: true, get: function () { return convert_2.wordsToNumber; } });
115
119
  Object.defineProperty(exports, "convertWordToNumber", { enumerable: true, get: function () { return convert_2.wordsToNumber; } });
@@ -118,6 +122,9 @@ Object.defineProperty(exports, "numberToRoman", { enumerable: true, get: functio
118
122
  Object.defineProperty(exports, "numberToWords", { enumerable: true, get: function () { return convert_2.numberToWords; } });
119
123
  Object.defineProperty(exports, "numberToWordsOrdinal", { enumerable: true, get: function () { return convert_2.numberToWordsOrdinal; } });
120
124
  Object.defineProperty(exports, "numericToRoman", { enumerable: true, get: function () { return convert_2.convertToRomanNumerals; } });
125
+ Object.defineProperty(exports, "romanToArabic", { enumerable: true, get: function () { return convert_2.romanToInteger; } });
126
+ Object.defineProperty(exports, "romanToInteger", { enumerable: true, get: function () { return convert_2.romanToInteger; } });
127
+ Object.defineProperty(exports, "romanToNumeric", { enumerable: true, get: function () { return convert_2.romanToInteger; } });
121
128
  Object.defineProperty(exports, "toRoman", { enumerable: true, get: function () { return convert_2.convertToRomanNumerals; } });
122
129
  Object.defineProperty(exports, "toRomanNumeral", { enumerable: true, get: function () { return convert_2.convertToRomanNumerals; } });
123
130
  Object.defineProperty(exports, "wordsToNumber", { enumerable: true, get: function () { return convert_2.wordsToNumber; } });
@@ -274,10 +281,10 @@ Object.defineProperty(exports, "isValidFormData", { enumerable: true, get: funct
274
281
  var basics_4 = require("./object/basics");
275
282
  Object.defineProperty(exports, "cloneObject", { enumerable: true, get: function () { return basics_4.cloneObject; } });
276
283
  Object.defineProperty(exports, "countObjectFields", { enumerable: true, get: function () { return basics_4.countObjectFields; } });
277
- Object.defineProperty(exports, "extractObjectKeys", { enumerable: true, get: function () { return basics_4.extractObjectKeys; } });
278
284
  Object.defineProperty(exports, "extractKeys", { enumerable: true, get: function () { return basics_4.extractObjectKeys; } });
279
- Object.defineProperty(exports, "extractObjectKeysDeep", { enumerable: true, get: function () { return basics_4.extractObjectKeysDeep; } });
280
285
  Object.defineProperty(exports, "extractKeysDeep", { enumerable: true, get: function () { return basics_4.extractObjectKeysDeep; } });
286
+ Object.defineProperty(exports, "extractObjectKeys", { enumerable: true, get: function () { return basics_4.extractObjectKeys; } });
287
+ Object.defineProperty(exports, "extractObjectKeysDeep", { enumerable: true, get: function () { return basics_4.extractObjectKeysDeep; } });
281
288
  var objectify_1 = require("./object/objectify");
282
289
  Object.defineProperty(exports, "extractNewFields", { enumerable: true, get: function () { return objectify_1.extractNewFields; } });
283
290
  Object.defineProperty(exports, "extractUpdatedAndNewFields", { enumerable: true, get: function () { return objectify_1.extractUpdatedAndNewFields; } });
@@ -311,10 +318,10 @@ Object.defineProperty(exports, "formatQueryParams", { enumerable: true, get: fun
311
318
  Object.defineProperty(exports, "generateQueryParams", { enumerable: true, get: function () { return query_1.generateQueryParams; } });
312
319
  Object.defineProperty(exports, "getQueryParams", { enumerable: true, get: function () { return query_1.getQueryParams; } });
313
320
  Object.defineProperty(exports, "getQueryStringAsObject", { enumerable: true, get: function () { return query_1.parseQueryString; } });
321
+ Object.defineProperty(exports, "literalQueryStringToObject", { enumerable: true, get: function () { return query_1.parseQueryStringLiteral; } });
314
322
  Object.defineProperty(exports, "parseQueryString", { enumerable: true, get: function () { return query_1.parseQueryString; } });
315
- Object.defineProperty(exports, "queryStringToObject", { enumerable: true, get: function () { return query_1.parseQueryString; } });
316
323
  Object.defineProperty(exports, "parseQueryStringLiteral", { enumerable: true, get: function () { return query_1.parseQueryStringLiteral; } });
317
- Object.defineProperty(exports, "literalQueryStringToObject", { enumerable: true, get: function () { return query_1.parseQueryStringLiteral; } });
324
+ Object.defineProperty(exports, "queryStringToObject", { enumerable: true, get: function () { return query_1.parseQueryString; } });
318
325
  Object.defineProperty(exports, "updateQueryParam", { enumerable: true, get: function () { return query_1.updateQueryParam; } });
319
326
  var utils_4 = require("./dom/utils");
320
327
  Object.defineProperty(exports, "copyToClipboard", { enumerable: true, get: function () { return utils_4.copyToClipboard; } });
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.convertToRomanNumerals = void 0;
3
+ exports.romanToInteger = exports.convertToRomanNumerals = void 0;
4
4
  exports.numberToWords = numberToWords;
5
5
  exports.numberToWordsOrdinal = numberToWordsOrdinal;
6
6
  exports.wordsToNumber = wordsToNumber;
@@ -8,6 +8,7 @@ const primitives_1 = require("../guards/primitives");
8
8
  const specials_1 = require("../guards/specials");
9
9
  const constants_1 = require("./constants");
10
10
  const helpers_1 = require("./helpers");
11
+ const utilities_1 = require("./utilities");
11
12
  function numberToWords(num) {
12
13
  let number = Math.trunc(Number(num));
13
14
  if (!Number.isFinite(number) || isNaN(number)) {
@@ -34,10 +35,11 @@ function numberToWords(num) {
34
35
  const finalResult = result.trim().replace(/\s+/g, ' ');
35
36
  return isNegative ? `minus ${finalResult}` : finalResult;
36
37
  }
37
- const convertToRomanNumerals = (num) => {
38
- let number = Number(num);
39
- if (number <= 0 || number >= 4000)
38
+ const convertToRomanNumerals = (value) => {
39
+ let num = (0, utilities_1.normalizeNumber)(value);
40
+ if (!num || num <= 0 || num >= 4000) {
40
41
  throw new RangeError('Number must be between 1 and 3999');
42
+ }
41
43
  const romanMap = [
42
44
  [1000, 'M'],
43
45
  [900, 'CM'],
@@ -55,14 +57,53 @@ const convertToRomanNumerals = (num) => {
55
57
  ];
56
58
  let result = '';
57
59
  for (const [value, numeral] of romanMap) {
58
- while (number >= value) {
60
+ while (num >= value) {
59
61
  result += numeral;
60
- number -= value;
62
+ num -= value;
61
63
  }
62
64
  }
63
65
  return result;
64
66
  };
65
67
  exports.convertToRomanNumerals = convertToRomanNumerals;
68
+ const romanToInteger = (roman) => {
69
+ const romanMap = {
70
+ I: 1,
71
+ V: 5,
72
+ X: 10,
73
+ L: 50,
74
+ C: 100,
75
+ D: 500,
76
+ M: 1000,
77
+ };
78
+ if (!(0, primitives_1.isNonEmptyString)(roman) || !roman?.trim()) {
79
+ throw new TypeError('Input must be a non-empty string');
80
+ }
81
+ const upperRoman = roman?.toUpperCase()?.trim();
82
+ let total = 0;
83
+ let prevValue = 0;
84
+ for (let i = upperRoman.length - 1; i >= 0; i--) {
85
+ const char = upperRoman[i];
86
+ const value = romanMap[char];
87
+ if (!value) {
88
+ throw new Error(`Invalid Roman numeral character: '${char}'`);
89
+ }
90
+ if (value < prevValue) {
91
+ total -= value;
92
+ }
93
+ else {
94
+ total += value;
95
+ prevValue = value;
96
+ }
97
+ }
98
+ if (total <= 0 || total >= 4000) {
99
+ throw new RangeError('Resulting number must be between 1 and 3999');
100
+ }
101
+ if ((0, exports.convertToRomanNumerals)(total) !== upperRoman) {
102
+ throw new Error('Invalid or malformed Roman numeral!');
103
+ }
104
+ return total;
105
+ };
106
+ exports.romanToInteger = romanToInteger;
66
107
  function numberToWordsOrdinal(number) {
67
108
  const TEEN_OR_HUNDRED = /(teen|hundred|thousand|(m|b|tr|quadr)illion)$/;
68
109
  const UNDER_TEEN = /(zero|one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve)$/;
@@ -396,7 +396,7 @@ export declare class Chronos {
396
396
  * @param baseDate Optional base date to compare with.
397
397
  */
398
398
  calendar(baseDate?: ChronosInput): string;
399
- /** @instance Returns a short human-readable string like "2h ago", "in 5m" */
399
+ /** @instance Returns a short human-readable string like "2h ago", "in 5m". From `year` to `second`. */
400
400
  fromNowShort(): string;
401
401
  /**
402
402
  * @instance Sets the date to the Monday of the specified ISO week number within the current year.
@@ -294,7 +294,7 @@ export declare const TIME_ZONES: Readonly<{
294
294
  readonly PETT: number;
295
295
  }>;
296
296
  /** List of time-zone labels against their corresponding utc values as array of objects */
297
- export declare const TIME_ZONE_LABELS: Readonly<Record<"UTC+00:15" | "UTC+00:30" | "UTC+00:45" | "UTC+00:00" | "UTC+07:15" | "UTC+07:30" | "UTC+07:45" | "UTC+07:00" | "UTC+01:15" | "UTC+01:30" | "UTC+01:45" | "UTC+01:00" | "UTC+02:15" | "UTC+02:30" | "UTC+02:45" | "UTC+02:00" | "UTC+09:15" | "UTC+09:30" | "UTC+09:45" | "UTC+09:00" | "UTC+05:15" | "UTC+05:30" | "UTC+05:45" | "UTC+05:00" | "UTC+03:15" | "UTC+03:30" | "UTC+03:45" | "UTC+03:00" | "UTC+04:15" | "UTC+04:30" | "UTC+04:45" | "UTC+04:00" | "UTC+06:15" | "UTC+06:30" | "UTC+06:45" | "UTC+06:00" | "UTC+08:15" | "UTC+08:30" | "UTC+08:45" | "UTC+08:00" | "UTC+10:15" | "UTC+10:30" | "UTC+10:45" | "UTC+10:00" | "UTC+11:15" | "UTC+11:30" | "UTC+11:45" | "UTC+11:00" | "UTC+12:15" | "UTC+12:30" | "UTC+12:45" | "UTC+12:00" | "UTC+13:15" | "UTC+13:30" | "UTC+13:45" | "UTC+13:00" | "UTC+14:15" | "UTC+14:30" | "UTC+14:45" | "UTC+14:00" | "UTC-00:15" | "UTC-00:30" | "UTC-00:45" | "UTC-00:00" | "UTC-07:15" | "UTC-07:30" | "UTC-07:45" | "UTC-07:00" | "UTC-01:15" | "UTC-01:30" | "UTC-01:45" | "UTC-01:00" | "UTC-02:15" | "UTC-02:30" | "UTC-02:45" | "UTC-02:00" | "UTC-09:15" | "UTC-09:30" | "UTC-09:45" | "UTC-09:00" | "UTC-05:15" | "UTC-05:30" | "UTC-05:45" | "UTC-05:00" | "UTC-03:15" | "UTC-03:30" | "UTC-03:45" | "UTC-03:00" | "UTC-04:15" | "UTC-04:30" | "UTC-04:45" | "UTC-04:00" | "UTC-06:15" | "UTC-06:30" | "UTC-06:45" | "UTC-06:00" | "UTC-08:15" | "UTC-08:30" | "UTC-08:45" | "UTC-08:00" | "UTC-10:15" | "UTC-10:30" | "UTC-10:45" | "UTC-10:00" | "UTC-11:15" | "UTC-11:30" | "UTC-11:45" | "UTC-11:00" | "UTC-12:15" | "UTC-12:30" | "UTC-12:45" | "UTC-12:00" | "UTC-13:15" | "UTC-13:30" | "UTC-13:45" | "UTC-13:00" | "UTC-14:15" | "UTC-14:30" | "UTC-14:45" | "UTC-14:00", string>>;
297
+ export declare const TIME_ZONE_LABELS: Readonly<Record<"UTC+00:15" | "UTC+00:30" | "UTC+00:45" | "UTC+00:00" | "UTC+01:15" | "UTC+01:30" | "UTC+01:45" | "UTC+01:00" | "UTC+07:15" | "UTC+07:30" | "UTC+07:45" | "UTC+07:00" | "UTC+05:15" | "UTC+05:30" | "UTC+05:45" | "UTC+05:00" | "UTC+02:15" | "UTC+02:30" | "UTC+02:45" | "UTC+02:00" | "UTC+03:15" | "UTC+03:30" | "UTC+03:45" | "UTC+03:00" | "UTC+04:15" | "UTC+04:30" | "UTC+04:45" | "UTC+04:00" | "UTC+06:15" | "UTC+06:30" | "UTC+06:45" | "UTC+06:00" | "UTC+08:15" | "UTC+08:30" | "UTC+08:45" | "UTC+08:00" | "UTC+09:15" | "UTC+09:30" | "UTC+09:45" | "UTC+09:00" | "UTC+10:15" | "UTC+10:30" | "UTC+10:45" | "UTC+10:00" | "UTC+11:15" | "UTC+11:30" | "UTC+11:45" | "UTC+11:00" | "UTC+12:15" | "UTC+12:30" | "UTC+12:45" | "UTC+12:00" | "UTC+13:15" | "UTC+13:30" | "UTC+13:45" | "UTC+13:00" | "UTC+14:15" | "UTC+14:30" | "UTC+14:45" | "UTC+14:00" | "UTC-00:15" | "UTC-00:30" | "UTC-00:45" | "UTC-00:00" | "UTC-01:15" | "UTC-01:30" | "UTC-01:45" | "UTC-01:00" | "UTC-07:15" | "UTC-07:30" | "UTC-07:45" | "UTC-07:00" | "UTC-05:15" | "UTC-05:30" | "UTC-05:45" | "UTC-05:00" | "UTC-02:15" | "UTC-02:30" | "UTC-02:45" | "UTC-02:00" | "UTC-03:15" | "UTC-03:30" | "UTC-03:45" | "UTC-03:00" | "UTC-04:15" | "UTC-04:30" | "UTC-04:45" | "UTC-04:00" | "UTC-06:15" | "UTC-06:30" | "UTC-06:45" | "UTC-06:00" | "UTC-08:15" | "UTC-08:30" | "UTC-08:45" | "UTC-08:00" | "UTC-09:15" | "UTC-09:30" | "UTC-09:45" | "UTC-09:00" | "UTC-10:15" | "UTC-10:30" | "UTC-10:45" | "UTC-10:00" | "UTC-11:15" | "UTC-11:30" | "UTC-11:45" | "UTC-11:00" | "UTC-12:15" | "UTC-12:30" | "UTC-12:45" | "UTC-12:00" | "UTC-13:15" | "UTC-13:30" | "UTC-13:45" | "UTC-13:00" | "UTC-14:15" | "UTC-14:30" | "UTC-14:45" | "UTC-14:00", string>>;
298
298
  /** Ranges for day parts. */
299
299
  export declare const DEFAULT_RANGES: Readonly<Record<DayPart, [ClockHour, ClockHour]>>;
300
300
  /** Western Zodiac Signs */
@@ -1,4 +1,4 @@
1
- import type { ChronosInput, TimeUnit } from '../types';
1
+ import type { ChronosInput, FromNowUnit } from '../types';
2
2
  type MainChronos = typeof import('../Chronos').Chronos;
3
3
  declare module '../Chronos' {
4
4
  interface Chronos {
@@ -9,8 +9,12 @@ declare module '../Chronos' {
9
9
  * @param withSuffixPrefix If `true`, adds `"in"` or `"ago"` depending on whether the time is in the future or past. Defaults to `true`.
10
10
  * @param time An optional time value to compare with (`string`, `number`, `Date`, or `Chronos` instance). Defaults to `now`.
11
11
  * @returns The difference as a human-readable string, e.g., `2 years 1 month 9 days 18 hours 56 minutes ago`.
12
+ *
13
+ * @remarks
14
+ * - This method calculates the **elapsed time difference** (exclusive of the end day), consistent with libraries like `Day.js` and `Luxon`.
15
+ * - If you need an *inclusive calendar-style* difference (counting both start and end days), add one day manually to the result.
12
16
  */
13
- fromNow(level: Exclude<TimeUnit, 'millisecond'>, withSuffixPrefix: boolean, time?: ChronosInput): string;
17
+ fromNow(level?: FromNowUnit, withSuffixPrefix?: boolean, time?: ChronosInput): string;
14
18
  }
15
19
  }
16
20
  /** * Plugin to inject `fromNow` method */
@@ -47,7 +47,10 @@ export interface GreetingConfigs {
47
47
  /** Default greeting message if no period matches. */
48
48
  defaultMessage?: string;
49
49
  }
50
+ /** Name of time unit from year to millisecond */
50
51
  export type TimeUnit = 'year' | 'month' | 'day' | 'week' | 'hour' | 'minute' | 'second' | 'millisecond';
52
+ /** Name of time unit from `year` to `millisecond`, except `week` */
53
+ export type FromNowUnit = Exclude<TimeUnit, 'week'>;
51
54
  /** Year in either 4 or 2 digits format */
52
55
  export type Year = (typeof YEAR_FORMATS)[number];
53
56
  /** Month in either 1 or 2 digits or 3 letters or full word format */
@@ -21,13 +21,13 @@ export { extractEmails, extractURLs, formatUnitWithPlural as formatNumberWithPlu
21
21
  export { countWords, countWords as countWordsInString, extractNumbersFromString as extractNumbers, extractNumbersFromString, getLevenshteinDistance, getLevenshteinDistance as levenshteinDistance, extractNumbersFromString as parseNumbersFromText, countWords as wordCount, } from './string/utilities';
22
22
  export { Pluralizer, pluralizer } from './pluralize/Pluralizer';
23
23
  export { Verbalizer, verbalizer } from './verbalizer/Verbalizer';
24
- export { getAverage as calculateAverage, calculateHCF as calculateGCD, calculateHCF, calculateLCM as calculateLCD, calculateLCM, convertToDecimal, convertToDecimal as convertToFixed, getAverage, getAverage as getAverageOfNumbers, getRandomNumber as getRandomInt, getRandomNumber, sumNumbers as getSumOfNumbers, reverseNumber, roundNumber, roundNumber as roundToDecimal, sumDigits, sumNumbers, sumNumbers as sumOfNumbers, factorial, factorial as calculateFactorial, factorial as getFactorial, getFactors, getFactors as factorsOf, getFactors as getDivisors, } from './number/basics';
24
+ export { getAverage as calculateAverage, factorial as calculateFactorial, calculateHCF as calculateGCD, calculateHCF, calculateLCM as calculateLCD, calculateLCM, convertToDecimal, convertToDecimal as convertToFixed, factorial, getFactors as factorsOf, getAverage, getAverage as getAverageOfNumbers, getFactors as getDivisors, factorial as getFactorial, getFactors, getRandomNumber as getRandomInt, getRandomNumber, sumNumbers as getSumOfNumbers, reverseNumber, roundNumber, roundNumber as roundToDecimal, sumDigits, sumNumbers, sumNumbers as sumOfNumbers, } from './number/basics';
25
25
  export { Currency } from './number/Currency';
26
26
  export { Unit, Unit as UnitConverter } from './number/Unit';
27
27
  export { calculatePercentage } from './number/percent';
28
28
  export { fibonacciGenerator, fibonacciGenerator as generateFibonacci, getFibonacciSeries as getFibonacci, getFibonacciSeries as getFibonacciNumbers, getFibonacciSeries, getFibonacciSeriesMemo, getFibonacciSeriesMemo as getMemoizedFibonacci, getFibonacciSeriesMemo as getMemoizedFibonacciSeries, getNthFibonacci, } from './number/fibonacci';
29
29
  export { areInvalidNumbers, areInvalidNumbers as areNumbersInvalid, isEven, isEven as isEvenNumber, isFibonacci, areInvalidNumbers as isInvalidNumber, isMultiple, areInvalidNumbers as isNumberInvalid, isOdd, isOdd as isOddNumber, isFibonacci as isPartOfFibonacci, isFibonacci as isPartOfFibonacciSeries, isPerfectSquare, } from './number/guards';
30
- export { numberToWordsOrdinal as cardinalWordsToOrdinal, numberToWords as convertNumberToWords, numberToWordsOrdinal as convertNumberToWordsOrdinal, convertToRomanNumerals, wordsToNumber as convertWordsToNumber, wordsToNumber as convertWordToNumber, convertToRomanNumerals as integerToRoman, convertToRomanNumerals as numberToRoman, numberToWords, numberToWordsOrdinal, convertToRomanNumerals as numericToRoman, convertToRomanNumerals as toRoman, convertToRomanNumerals as toRomanNumeral, wordsToNumber, wordsToNumber as wordToNumber, } from './number/convert';
30
+ export { convertToRomanNumerals as arabicToRoman, numberToWordsOrdinal as cardinalWordsToOrdinal, numberToWords as convertNumberToWords, numberToWordsOrdinal as convertNumberToWordsOrdinal, romanToInteger as convertRomanToArabic, romanToInteger as convertRomanToInteger, romanToInteger as convertRomanToNumeric, convertToRomanNumerals, wordsToNumber as convertWordsToNumber, wordsToNumber as convertWordToNumber, convertToRomanNumerals as integerToRoman, convertToRomanNumerals as numberToRoman, numberToWords, numberToWordsOrdinal, convertToRomanNumerals as numericToRoman, romanToInteger as romanToArabic, romanToInteger, romanToInteger as romanToNumeric, convertToRomanNumerals as toRoman, convertToRomanNumerals as toRomanNumeral, wordsToNumber, wordsToNumber as wordToNumber, } from './number/convert';
31
31
  export { findPrimeNumbers, findPrimeNumbers as getPrimeNumbers, isPrime, isPrime as isPrimeNumber, } from './number/prime';
32
32
  export { getOrdinal as cardinalToOrdinal, clampNumber, formatCurrency as convertNumberToCurrency, getOrdinal as convertNumberToOrdinal, getOrdinal as convertToOrdinal, formatCurrency, getOrdinal, getOrdinal as getOrdinalNumber, getRandomFloat as getRandomDecimal, getRandomFloat, normalizeNumber, getOrdinal as numberToOrdinal, roundToNearest as roundNumberToNearestInterval, roundToNearest, roundToNearest as roundToNearestInterval, } from './number/utilities';
33
33
  export { getNumbersInRange } from './number/range';
@@ -51,11 +51,11 @@ export { naturalSort as compareNaturally, naturalSort as compareSorter, naturalS
51
51
  export { createControlledFormData as convertIntoFormData, createControlledFormData, createControlledFormData as createFormData, } from './form/convert';
52
52
  export { parseFormData, serializeForm } from './form/transform';
53
53
  export { isCustomFile, isCustomFileArray, isFileArray, isFileList, isFileOrBlob, isFileUpload, isOriginFileObj, isValidFormData, } from './form/guards';
54
- export { cloneObject, countObjectFields, extractObjectKeys, extractObjectKeys as extractKeys, extractObjectKeysDeep, extractObjectKeysDeep as extractKeysDeep, } from './object/basics';
54
+ export { cloneObject, countObjectFields, extractObjectKeys as extractKeys, extractObjectKeysDeep as extractKeysDeep, extractObjectKeys, extractObjectKeysDeep, } from './object/basics';
55
55
  export { extractNewFields, extractUpdatedAndNewFields, extractUpdatedFields, flattenObjectDotNotation, flattenObjectKeyValue, mergeAndFlattenObjects, mergeObjects, parseJsonToObject, } from './object/objectify';
56
56
  export { parseObjectValues, parseObjectValues as parseStringifiedObjectValues, sanitizeData, } from './object/sanitize';
57
57
  export { convertObjectValues, deleteFields, deleteFields as deleteObjectFields, deleteFields as omitFields, deleteFields as omitObjectFields, pickFields, pickObjectFieldsByCondition as pickFieldsByCondition, pickFields as pickObjectFields, pickObjectFieldsByCondition, remapFields, remapFields as remapObjectFields, deleteFields as removeFields, deleteFields as removeObjectFields, } from './object/convert';
58
- export { generateQueryParams as createQueryParams, generateQueryParams as formatQueryParams, generateQueryParams, getQueryParams, parseQueryString as getQueryStringAsObject, parseQueryString, parseQueryString as queryStringToObject, parseQueryStringLiteral, parseQueryStringLiteral as literalQueryStringToObject, updateQueryParam, } from './dom/query';
58
+ export { generateQueryParams as createQueryParams, generateQueryParams as formatQueryParams, generateQueryParams, getQueryParams, parseQueryString as getQueryStringAsObject, parseQueryStringLiteral as literalQueryStringToObject, parseQueryString, parseQueryStringLiteral, parseQueryString as queryStringToObject, updateQueryParam, } from './dom/query';
59
59
  export { copyToClipboard, smoothScrollTo, toggleFullScreen } from './dom/utils';
60
60
  export { getFromLocalStorage, getFromSessionStorage, removeFromLocalStorage, removeFromSessionStorage, saveToLocalStorage, saveToSessionStorage, } from './dom/storage';
61
61
  export { convertArrayToString, countInstanceMethods, countStaticMethods, debounceAction, deepParsePrimitives, getClassDetails, getInstanceMethodNames, countInstanceMethods as getInstanceMethodsCount, getStaticMethodNames, countStaticMethods as getStaticMethodsCount, isDeepEqual, convertArrayToString as joinArrayElements, parseJSON, parseJSON as parseJsonDeep, deepParsePrimitives as parsePrimitivesDeep, throttleAction, } from './utils/index';
@@ -1,4 +1,5 @@
1
1
  import type { Numeric } from '../types/index';
2
+ import type { RomanNumeral, RomanNumeralCap } from './types';
2
3
  /**
3
4
  * * Converts a numeric value into its corresponding English word representation.
4
5
  * @warning ***Supports numeric values up to `10e19` or `10^20` (one hundred quintillion).***
@@ -9,12 +10,22 @@ import type { Numeric } from '../types/index';
9
10
  export declare function numberToWords(num: Numeric): string;
10
11
  /**
11
12
  * * Converts a number to a Roman numeral.
12
- * @param num - The number to convert. Number must be `between 1 and 3999`.
13
+ * @param value - The number to convert. Number must be `between 1 and 3999`.
13
14
  * @returns The Roman numeral representation.
14
15
  *
15
16
  * @example convertToRomanNumerals(29) → "XXIX"
16
17
  */
17
- export declare const convertToRomanNumerals: (num: Numeric) => string;
18
+ export declare const convertToRomanNumerals: (value: Numeric) => RomanNumeralCap;
19
+ /**
20
+ * * Converts a Roman numeral to its Arabic numeric representation.
21
+ * @param roman - The Roman numeral to convert. Case-insensitive but must represent a valid Roman numeral (I–MMMCMXCIX) otherwise throws error.
22
+ * @returns The numeric (Arabic) representation.
23
+ *
24
+ * @example
25
+ * romanToInteger("XXIX") → 29
26
+ * romanToInteger("mmxxv") → 2025
27
+ */
28
+ export declare const romanToInteger: (roman: RomanNumeral) => number;
18
29
  /**
19
30
  * * Converts a number, numeric string, or cardinal word string into its ordinal word representation.
20
31
  *
@@ -1,3 +1,4 @@
1
+ import type { LooseLiteral, Repeat } from '../utils/types';
1
2
  import type { CURRENCY_CODES, CURRENCY_LOCALES, LOCALE_CODES, PREFIX_MULTIPLIERS, SUPPORTED_CURRENCIES, UNITS } from './constants';
2
3
  import type { Unit } from './Unit';
3
4
  /** Enumerate & Enumerate Internal: builds a union of all numbers from 0 to N - 1 */
@@ -165,4 +166,60 @@ export type UnitKey = keyof typeof UNITS;
165
166
  export type UnitLabel = (typeof UNITS)[UnitKey];
166
167
  /** - Prefixes for SI units */
167
168
  export type SIPrefix = keyof typeof PREFIX_MULTIPLIERS;
169
+ /**
170
+ * * Roman numeral base letters (upper-case only).
171
+ *
172
+ * Includes:
173
+ * - `I` → 1
174
+ * - `V` → 5
175
+ * - `X` → 10
176
+ * - `L` → 50
177
+ * - `C` → 100
178
+ * - `D` → 500
179
+ * - `M` → 1000
180
+ */
181
+ export type $RomanBase = 'I' | 'V' | 'X' | 'L' | 'C' | 'D' | 'M';
182
+ /**
183
+ * * Represents repeated Roman numeral sequences (1–5 characters long), enabling IntelliSense autocompletion for sequential Roman characters.
184
+ *
185
+ * - Suggests Roman base letters after each character.
186
+ * - Supports up to 5-character combinations for performance.
187
+ * - Does **not** validate Roman numeral correctness (e.g., `VVVV` is allowed).
188
+ *
189
+ * @example
190
+ * ```ts
191
+ * // ✅ Valid according to type (even if not a real Roman numeral)
192
+ * const a: $RomanRepeated = 'MMXII';
193
+ * const b: $RomanRepeated = 'VVVV';
194
+ * ```
195
+ *
196
+ * @remarks
197
+ * **Limitations:**
198
+ * - Only supports up to **5-character** combinations (`Repeat<$RomanBase, 5>`) using {@link Repeat}.
199
+ * - Increasing beyond 5 leads to TypeScript recursion/union complexity issues.
200
+ * - Designed purely for **editor IntelliSense**, not runtime validation.
201
+ */
202
+ export type $RomanNumeralCap = $RomanBase | Repeat<$RomanBase, 2> | Repeat<$RomanBase, 3> | Repeat<$RomanBase, 4> | Repeat<$RomanBase, 5>;
203
+ /** * Represents repeated Roman numeral sequences (1–5 characters long) in uppercase letters and any string */
204
+ export type RomanNumeralCap = Uppercase<LooseLiteral<$RomanNumeralCap>>;
205
+ /**
206
+ * * Comprehensive Roman numeral string type.
207
+ *
208
+ * Includes both upper and lowercase Roman letters, with support for loose
209
+ * literal fallbacks (via {@link LooseLiteral}) to accept arbitrary strings
210
+ * while still providing IntelliSense suggestions for known Roman combinations.
211
+ *
212
+ * @example
213
+ * ```ts
214
+ * const a: RomanNumeral = 'xiv'; // ✅ IntelliSense suggests Roman letters
215
+ * const b: RomanNumeral = 'MMX'; // ✅ Supported
216
+ * const c: RomanNumeral = 'xyz'; // ⚠️ Allowed only via LooseLiteral fallback
217
+ * ```
218
+ *
219
+ * @remarks
220
+ * - Combines {@link $RomanNumeralCap} and its lowercase variants.
221
+ * - The {@link LooseLiteral} wrapper allows non-literal strings (e.g., variables) without losing IntelliSense for literals.
222
+ * - Does not enforce valid Roman numeral formation.
223
+ */
224
+ export type RomanNumeral = LooseLiteral<$RomanNumeralCap | Lowercase<$RomanNumeralCap>>;
168
225
  export {};
@@ -580,4 +580,24 @@ export type Tuple<T> = [T] extends [never] ? [] : $UnionToTuple<T>;
580
580
  export type $Expand<T> = T extends infer O ? {
581
581
  [K in keyof O]: O[K];
582
582
  } : T;
583
+ /**
584
+ * Recursively join the string S for each element in the tuple A.
585
+ * Returns an empty string for an empty tuple.
586
+ */
587
+ export type $JoinRepeat<S extends string, A extends unknown[]> = A extends [unknown, ...infer Rest] ? `${S}${$JoinRepeat<S, Rest>}` : '';
588
+ /**
589
+ * * Repeat string `S`, `N` times.
590
+ *
591
+ * @example
592
+ * ```ts
593
+ * type L10 = Repeat<'l', 10>; // "llllllllll"
594
+ *
595
+ * type AB3 = Repeat<'a' | 'b', 3>; // "aab" | "aaa" | "aba" | "abb" | "bab" | "baa" | "bba" | "bbb"
596
+ * ```
597
+ *
598
+ * **Limitations:**
599
+ * - `N` must be a literal number.
600
+ * - If `S` is a union (e.g. 'a'|'b'), the resulting union grows exponentially with N.
601
+ */
602
+ export type Repeat<S extends string, N extends number> = $JoinRepeat<S, $BuildTuple<N>>;
583
603
  export {};
@@ -11,10 +11,14 @@ export const fromNowPlugin = (ChronosClass) => {
11
11
  let years = to.getFullYear() - from.getFullYear();
12
12
  let months = to.getMonth() - from.getMonth();
13
13
  let days = to.getDate() - from.getDate();
14
- let weeks = 0;
15
14
  let hours = to.getHours() - from.getHours();
16
15
  let minutes = to.getMinutes() - from.getMinutes();
17
16
  let seconds = to.getSeconds() - from.getSeconds();
17
+ let milliseconds = to.getMilliseconds() - from.getMilliseconds();
18
+ if (milliseconds < 0) {
19
+ milliseconds += 1000;
20
+ seconds--;
21
+ }
18
22
  if (seconds < 0) {
19
23
  seconds += 60;
20
24
  minutes--;
@@ -27,10 +31,6 @@ export const fromNowPlugin = (ChronosClass) => {
27
31
  hours += 24;
28
32
  days--;
29
33
  }
30
- if (level === 'week' || level === 'day') {
31
- weeks = Math.floor(days / 7);
32
- days = days % 7;
33
- }
34
34
  if (days < 0) {
35
35
  const prevMonth = new Date(to.getFullYear(), to.getMonth(), 0);
36
36
  days += prevMonth.getDate();
@@ -40,29 +40,43 @@ export const fromNowPlugin = (ChronosClass) => {
40
40
  months += 12;
41
41
  years--;
42
42
  }
43
- const unitOrder = ['year', 'month', 'week', 'day', 'hour', 'minute', 'second'];
43
+ const unitOrder = [
44
+ 'year',
45
+ 'month',
46
+ 'day',
47
+ 'hour',
48
+ 'minute',
49
+ 'second',
50
+ 'millisecond',
51
+ ];
44
52
  const lvlIdx = unitOrder.indexOf(level);
45
53
  const parts = [];
46
- if (lvlIdx >= 0 && years > 0 && lvlIdx >= unitOrder.indexOf('year')) {
47
- parts?.push(formatUnitWithPlural(years, 'year'));
54
+ const _pushToParts = (value, unit) => {
55
+ parts.push(formatUnitWithPlural(value, unit));
56
+ };
57
+ const _isLevelRequired = (unit) => {
58
+ return lvlIdx >= unitOrder.indexOf(unit);
59
+ };
60
+ if (years > 0) {
61
+ _pushToParts(years, 'year');
48
62
  }
49
- if (lvlIdx >= unitOrder.indexOf('month') && months > 0) {
50
- parts?.push(formatUnitWithPlural(months, 'month'));
63
+ if (_isLevelRequired('month') && months > 0) {
64
+ _pushToParts(months, 'month');
51
65
  }
52
- if (lvlIdx >= unitOrder.indexOf('week') && weeks > 0) {
53
- parts?.push(formatUnitWithPlural(weeks, 'week'));
66
+ if (_isLevelRequired('day') && days > 0) {
67
+ _pushToParts(days, 'day');
54
68
  }
55
- if (lvlIdx >= unitOrder.indexOf('day') && days > 0) {
56
- parts?.push(formatUnitWithPlural(days, 'day'));
69
+ if (_isLevelRequired('hour') && hours > 0) {
70
+ _pushToParts(hours, 'hour');
57
71
  }
58
- if (lvlIdx >= unitOrder.indexOf('hour') && hours > 0) {
59
- parts?.push(formatUnitWithPlural(hours, 'hour'));
72
+ if (_isLevelRequired('minute') && minutes > 0) {
73
+ _pushToParts(minutes, 'minute');
60
74
  }
61
- if (lvlIdx >= unitOrder.indexOf('minute') && minutes > 0) {
62
- parts?.push(formatUnitWithPlural(minutes, 'minute'));
75
+ if (_isLevelRequired('second') && seconds > 0) {
76
+ _pushToParts(seconds, 'second');
63
77
  }
64
- if (lvlIdx >= unitOrder.indexOf('second') && (seconds > 0 || parts?.length === 0)) {
65
- parts?.push(formatUnitWithPlural(seconds, 'second'));
78
+ if (_isLevelRequired('millisecond') && (milliseconds > 0 || parts?.length === 0)) {
79
+ _pushToParts(milliseconds, 'millisecond');
66
80
  }
67
81
  let prefix = '';
68
82
  let suffix = '';
@@ -74,6 +88,6 @@ export const fromNowPlugin = (ChronosClass) => {
74
88
  suffix = ' ago';
75
89
  }
76
90
  }
77
- return `${prefix}${parts?.join(' ')}${suffix}`;
91
+ return parts.length ? `${prefix}${parts?.join(' ')}${suffix}` : `0 ${level}`;
78
92
  };
79
93
  };
package/dist/esm/index.js CHANGED
@@ -6,13 +6,13 @@ export { extractEmails, extractURLs, formatUnitWithPlural as formatNumberWithPlu
6
6
  export { countWords, countWords as countWordsInString, extractNumbersFromString as extractNumbers, extractNumbersFromString, getLevenshteinDistance, getLevenshteinDistance as levenshteinDistance, extractNumbersFromString as parseNumbersFromText, countWords as wordCount, } from './string/utilities.js';
7
7
  export { Pluralizer, pluralizer } from './pluralize/Pluralizer.js';
8
8
  export { Verbalizer, verbalizer } from './verbalizer/Verbalizer.js';
9
- export { getAverage as calculateAverage, calculateHCF as calculateGCD, calculateHCF, calculateLCM as calculateLCD, calculateLCM, convertToDecimal, convertToDecimal as convertToFixed, getAverage, getAverage as getAverageOfNumbers, getRandomNumber as getRandomInt, getRandomNumber, sumNumbers as getSumOfNumbers, reverseNumber, roundNumber, roundNumber as roundToDecimal, sumDigits, sumNumbers, sumNumbers as sumOfNumbers, factorial, factorial as calculateFactorial, factorial as getFactorial, getFactors, getFactors as factorsOf, getFactors as getDivisors, } from './number/basics.js';
9
+ export { getAverage as calculateAverage, factorial as calculateFactorial, calculateHCF as calculateGCD, calculateHCF, calculateLCM as calculateLCD, calculateLCM, convertToDecimal, convertToDecimal as convertToFixed, factorial, getFactors as factorsOf, getAverage, getAverage as getAverageOfNumbers, getFactors as getDivisors, factorial as getFactorial, getFactors, getRandomNumber as getRandomInt, getRandomNumber, sumNumbers as getSumOfNumbers, reverseNumber, roundNumber, roundNumber as roundToDecimal, sumDigits, sumNumbers, sumNumbers as sumOfNumbers, } from './number/basics.js';
10
10
  export { Currency } from './number/Currency.js';
11
11
  export { Unit, Unit as UnitConverter } from './number/Unit.js';
12
12
  export { calculatePercentage } from './number/percent.js';
13
13
  export { fibonacciGenerator, fibonacciGenerator as generateFibonacci, getFibonacciSeries as getFibonacci, getFibonacciSeries as getFibonacciNumbers, getFibonacciSeries, getFibonacciSeriesMemo, getFibonacciSeriesMemo as getMemoizedFibonacci, getFibonacciSeriesMemo as getMemoizedFibonacciSeries, getNthFibonacci, } from './number/fibonacci.js';
14
14
  export { areInvalidNumbers, areInvalidNumbers as areNumbersInvalid, isEven, isEven as isEvenNumber, isFibonacci, areInvalidNumbers as isInvalidNumber, isMultiple, areInvalidNumbers as isNumberInvalid, isOdd, isOdd as isOddNumber, isFibonacci as isPartOfFibonacci, isFibonacci as isPartOfFibonacciSeries, isPerfectSquare, } from './number/guards.js';
15
- export { numberToWordsOrdinal as cardinalWordsToOrdinal, numberToWords as convertNumberToWords, numberToWordsOrdinal as convertNumberToWordsOrdinal, convertToRomanNumerals, wordsToNumber as convertWordsToNumber, wordsToNumber as convertWordToNumber, convertToRomanNumerals as integerToRoman, convertToRomanNumerals as numberToRoman, numberToWords, numberToWordsOrdinal, convertToRomanNumerals as numericToRoman, convertToRomanNumerals as toRoman, convertToRomanNumerals as toRomanNumeral, wordsToNumber, wordsToNumber as wordToNumber, } from './number/convert.js';
15
+ export { convertToRomanNumerals as arabicToRoman, numberToWordsOrdinal as cardinalWordsToOrdinal, numberToWords as convertNumberToWords, numberToWordsOrdinal as convertNumberToWordsOrdinal, romanToInteger as convertRomanToArabic, romanToInteger as convertRomanToInteger, romanToInteger as convertRomanToNumeric, convertToRomanNumerals, wordsToNumber as convertWordsToNumber, wordsToNumber as convertWordToNumber, convertToRomanNumerals as integerToRoman, convertToRomanNumerals as numberToRoman, numberToWords, numberToWordsOrdinal, convertToRomanNumerals as numericToRoman, romanToInteger as romanToArabic, romanToInteger, romanToInteger as romanToNumeric, convertToRomanNumerals as toRoman, convertToRomanNumerals as toRomanNumeral, wordsToNumber, wordsToNumber as wordToNumber, } from './number/convert.js';
16
16
  export { findPrimeNumbers, findPrimeNumbers as getPrimeNumbers, isPrime, isPrime as isPrimeNumber, } from './number/prime.js';
17
17
  export { getOrdinal as cardinalToOrdinal, clampNumber, formatCurrency as convertNumberToCurrency, getOrdinal as convertNumberToOrdinal, getOrdinal as convertToOrdinal, formatCurrency, getOrdinal, getOrdinal as getOrdinalNumber, getRandomFloat as getRandomDecimal, getRandomFloat, normalizeNumber, getOrdinal as numberToOrdinal, roundToNearest as roundNumberToNearestInterval, roundToNearest, roundToNearest as roundToNearestInterval, } from './number/utilities.js';
18
18
  export { getNumbersInRange } from './number/range.js';
@@ -36,11 +36,11 @@ export { naturalSort as compareNaturally, naturalSort as compareSorter, naturalS
36
36
  export { createControlledFormData as convertIntoFormData, createControlledFormData, createControlledFormData as createFormData, } from './form/convert.js';
37
37
  export { parseFormData, serializeForm } from './form/transform.js';
38
38
  export { isCustomFile, isCustomFileArray, isFileArray, isFileList, isFileOrBlob, isFileUpload, isOriginFileObj, isValidFormData, } from './form/guards.js';
39
- export { cloneObject, countObjectFields, extractObjectKeys, extractObjectKeys as extractKeys, extractObjectKeysDeep, extractObjectKeysDeep as extractKeysDeep, } from './object/basics.js';
39
+ export { cloneObject, countObjectFields, extractObjectKeys as extractKeys, extractObjectKeysDeep as extractKeysDeep, extractObjectKeys, extractObjectKeysDeep, } from './object/basics.js';
40
40
  export { extractNewFields, extractUpdatedAndNewFields, extractUpdatedFields, flattenObjectDotNotation, flattenObjectKeyValue, mergeAndFlattenObjects, mergeObjects, parseJsonToObject, } from './object/objectify.js';
41
41
  export { parseObjectValues, parseObjectValues as parseStringifiedObjectValues, sanitizeData, } from './object/sanitize.js';
42
42
  export { convertObjectValues, deleteFields, deleteFields as deleteObjectFields, deleteFields as omitFields, deleteFields as omitObjectFields, pickFields, pickObjectFieldsByCondition as pickFieldsByCondition, pickFields as pickObjectFields, pickObjectFieldsByCondition, remapFields, remapFields as remapObjectFields, deleteFields as removeFields, deleteFields as removeObjectFields, } from './object/convert.js';
43
- export { generateQueryParams as createQueryParams, generateQueryParams as formatQueryParams, generateQueryParams, getQueryParams, parseQueryString as getQueryStringAsObject, parseQueryString, parseQueryString as queryStringToObject, parseQueryStringLiteral, parseQueryStringLiteral as literalQueryStringToObject, updateQueryParam, } from './dom/query.js';
43
+ export { generateQueryParams as createQueryParams, generateQueryParams as formatQueryParams, generateQueryParams, getQueryParams, parseQueryString as getQueryStringAsObject, parseQueryStringLiteral as literalQueryStringToObject, parseQueryString, parseQueryStringLiteral, parseQueryString as queryStringToObject, updateQueryParam, } from './dom/query.js';
44
44
  export { copyToClipboard, smoothScrollTo, toggleFullScreen } from './dom/utils.js';
45
45
  export { getFromLocalStorage, getFromSessionStorage, removeFromLocalStorage, removeFromSessionStorage, saveToLocalStorage, saveToSessionStorage, } from './dom/storage.js';
46
46
  export { convertArrayToString, countInstanceMethods, countStaticMethods, debounceAction, deepParsePrimitives, getClassDetails, getInstanceMethodNames, countInstanceMethods as getInstanceMethodsCount, getStaticMethodNames, countStaticMethods as getStaticMethodsCount, isDeepEqual, convertArrayToString as joinArrayElements, parseJSON, parseJSON as parseJsonDeep, deepParsePrimitives as parsePrimitivesDeep, throttleAction, } from './utils/index.js';
@@ -1,7 +1,8 @@
1
- import { isNumber } from '../guards/primitives.js';
1
+ import { isNonEmptyString, isNumber } from '../guards/primitives.js';
2
2
  import { isNumericString } from '../guards/specials.js';
3
3
  import { ONES, ORDINAL_TO_CARDINAL, ORDINAL_UNDER_TEEN, TEENS, TENS, THOUSANDS, } from './constants.js';
4
4
  import { _convertLessThanThousand } from './helpers.js';
5
+ import { normalizeNumber } from './utilities.js';
5
6
  export function numberToWords(num) {
6
7
  let number = Math.trunc(Number(num));
7
8
  if (!Number.isFinite(number) || isNaN(number)) {
@@ -28,10 +29,11 @@ export function numberToWords(num) {
28
29
  const finalResult = result.trim().replace(/\s+/g, ' ');
29
30
  return isNegative ? `minus ${finalResult}` : finalResult;
30
31
  }
31
- export const convertToRomanNumerals = (num) => {
32
- let number = Number(num);
33
- if (number <= 0 || number >= 4000)
32
+ export const convertToRomanNumerals = (value) => {
33
+ let num = normalizeNumber(value);
34
+ if (!num || num <= 0 || num >= 4000) {
34
35
  throw new RangeError('Number must be between 1 and 3999');
36
+ }
35
37
  const romanMap = [
36
38
  [1000, 'M'],
37
39
  [900, 'CM'],
@@ -49,13 +51,51 @@ export const convertToRomanNumerals = (num) => {
49
51
  ];
50
52
  let result = '';
51
53
  for (const [value, numeral] of romanMap) {
52
- while (number >= value) {
54
+ while (num >= value) {
53
55
  result += numeral;
54
- number -= value;
56
+ num -= value;
55
57
  }
56
58
  }
57
59
  return result;
58
60
  };
61
+ export const romanToInteger = (roman) => {
62
+ const romanMap = {
63
+ I: 1,
64
+ V: 5,
65
+ X: 10,
66
+ L: 50,
67
+ C: 100,
68
+ D: 500,
69
+ M: 1000,
70
+ };
71
+ if (!isNonEmptyString(roman) || !roman?.trim()) {
72
+ throw new TypeError('Input must be a non-empty string');
73
+ }
74
+ const upperRoman = roman?.toUpperCase()?.trim();
75
+ let total = 0;
76
+ let prevValue = 0;
77
+ for (let i = upperRoman.length - 1; i >= 0; i--) {
78
+ const char = upperRoman[i];
79
+ const value = romanMap[char];
80
+ if (!value) {
81
+ throw new Error(`Invalid Roman numeral character: '${char}'`);
82
+ }
83
+ if (value < prevValue) {
84
+ total -= value;
85
+ }
86
+ else {
87
+ total += value;
88
+ prevValue = value;
89
+ }
90
+ }
91
+ if (total <= 0 || total >= 4000) {
92
+ throw new RangeError('Resulting number must be between 1 and 3999');
93
+ }
94
+ if (convertToRomanNumerals(total) !== upperRoman) {
95
+ throw new Error('Invalid or malformed Roman numeral!');
96
+ }
97
+ return total;
98
+ };
59
99
  export function numberToWordsOrdinal(number) {
60
100
  const TEEN_OR_HUNDRED = /(teen|hundred|thousand|(m|b|tr|quadr)illion)$/;
61
101
  const UNDER_TEEN = /(zero|one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve)$/;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nhb-toolbox",
3
- "version": "4.20.87",
3
+ "version": "4.20.89",
4
4
  "description": "A versatile collection of smart, efficient, and reusable utility functions, classes and types for everyday development needs.",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",