Skip to content

Commit a3b2dca

Browse files
committed
Update MS function
1 parent 2e31129 commit a3b2dca

File tree

2 files changed

+105
-133
lines changed

2 files changed

+105
-133
lines changed

scripts/library/utils/formatter.js

Lines changed: 51 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -46,95 +46,73 @@ function formatNumber(value) {
4646
return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
4747
}
4848
;
49-
/**
50-
* Convert seconds, minutes, hours, days and week to milliseconds and vice versa
51-
* @param {string | number} value string time support: second, minute, hour, day, week.
52-
* @param {boolean} [compact] Return time string in a compact format
53-
* @returns {string | number | undefined}
54-
* @example MS('2 days') //Output: 172800000
55-
* MS('1d') //Output: 86400000
56-
* MS('10h') //Output: 36000000
57-
* MS('2.5 hrs') //Output: 9000000
58-
* MS('2h') //Output: 7200000
59-
* MS('1m') //Output: 60000
60-
* MS('5s') //Output: 5000
61-
* MS('1y') //Output: 31557600000
62-
* MS('100') //Output: 100
63-
* MS('-3 days') //Output: -259200000
64-
* MS('-1h') //Output: -3600000
65-
* MS('-200') //Output: -200
66-
*
67-
* //Convert from Milliseconds
68-
*
69-
* MS(86400000, { compact: true }); //Output: 1d
70-
* MS(86400000); //Output: 1 day
71-
* MS(172800000, { compact: true }); //Output: 2d
72-
* MS(172800000); //Output: 2 days
73-
*/
74-
function MS(value, { compact } = {}) {
75-
if (typeof value === 'string')
76-
return timeToMs(value);
77-
if (typeof value === 'number')
78-
return msToTime(value, compact ? true : false);
49+
export function MS(value, { compactDuration, fullDuration, avoidDuration } = {}) {
50+
try {
51+
if (typeof value === 'string') {
52+
if (/^\d+$/.test(value))
53+
return Number(value);
54+
const durations = value.match(/-?\d*\.?\d+\s*?(years?|yrs?|weeks?|days?|hours?|hrs?|minutes?|mins?|seconds?|secs?|milliseconds?|msecs?|ms|[smhdwy])/gi);
55+
return durations ? durations.reduce((a, b) => a + toMS(b), 0) : null;
56+
}
57+
;
58+
if (typeof value === 'number')
59+
return toDuration(value, { compactDuration, fullDuration, avoidDuration });
60+
throw new Error('Value is not a string or a number');
61+
}
62+
catch (err) {
63+
const message = isError(err)
64+
? `${err.message}. Value = ${JSON.stringify(value)}`
65+
: 'An unknown error has occured.';
66+
throw new Error(message);
67+
}
68+
;
7969
}
8070
;
8171
/**
82-
*
83-
* @param {string} string Time to ms
84-
* @returns {number}
72+
* Convert Durations to milliseconds
8573
*/
86-
function timeToMs(value) {
87-
if (!/^-?\s?\d*\.?\d*?\s?((years*?|yrs*?)|(weeks*?)|(days*?)|(hours*?|hrs*?)|(minutes*?|mins*?)|(seconds*?|secs*?)|(milliseconds*?|msecs*?|ms)|[smhdwy])$/.test(value))
88-
return;
89-
const number = parseFloat(value.replace(/[^-.0-9]+/g, ''));
90-
if (/\d+(?=\s?(milliseconds?|msecs?|ms))/.test(value))
74+
function toMS(value) {
75+
const number = Number(value.replace(/[^-.0-9]+/g, ''));
76+
value = value.replace(/\s+/g, '');
77+
if (/\d+(?=ms|milliseconds?)/i.test(value))
9178
return number;
92-
else if (/\d+(?=\s?s)/.test(value))
79+
else if (/\d+(?=s)/i.test(value))
9380
return number * 1000;
94-
else if (/\d+(?=\s?m)/.test(value))
81+
else if (/\d+(?=m)/i.test(value))
9582
return number * 60000;
96-
else if (/\d+(?=\s?h)/.test(value))
83+
else if (/\d+(?=h)/i.test(value))
9784
return number * 3.6e+6;
98-
else if (/\d+(?=\s?d)/.test(value))
85+
else if (/\d+(?=d)/i.test(value))
9986
return number * 8.64e+7;
100-
else if (/\d+(?=\s?w)/.test(value))
87+
else if (/\d+(?=w)/i.test(value))
10188
return number * 6.048e+8;
102-
else if (/\d+(?=\s?y)/.test(value))
89+
else if (/\d+(?=y)/i.test(value))
10390
return number * 3.154e+10;
10491
}
10592
;
10693
/**
107-
*
108-
* @param {number} ms Ms to Time
109-
* @param {boolean} [compact] Compact time format
110-
* @returns {string}
94+
* Convert milliseconds to durations
11195
*/
112-
function msToTime(ms, compact) {
113-
let negative = Math.sign(ms) === -1, absMs = Math.abs(ms);
114-
let seconds = absMs / 1000, minutes = absMs / 60000, hours = absMs / 3.6e+6, days = absMs / 8.64e+7, weeks = absMs / 6.048e+8;
115-
if (absMs < 1000)
116-
return plural('ms', 'millisecond', negative, absMs, compact);
117-
else if (seconds < 60)
118-
return plural('s', 'second', negative, seconds, compact);
119-
else if (minutes < 60)
120-
return plural('m', 'minute', negative, minutes, compact);
121-
else if (hours < 24)
122-
return plural('h', 'hour', negative, hours, compact);
123-
else if (days < 7)
124-
return plural('d', 'day', negative, days, compact);
125-
else
126-
return plural('w', 'week', negative, weeks, compact);
96+
function toDuration(value, { compactDuration, fullDuration, avoidDuration } = {}) {
97+
const absMs = Math.abs(value);
98+
const duration = [
99+
{ short: 'd', long: 'day', ms: absMs / 8.64e+7 },
100+
{ short: 'h', long: 'hour', ms: absMs / 3.6e+6 % 24 },
101+
{ short: 'm', long: 'minute', ms: absMs / 60000 % 60 },
102+
{ short: 's', long: 'second', ms: absMs / 1000 % 60 },
103+
{ short: 'ms', long: 'millisecond', ms: absMs % 1000 },
104+
];
105+
const mappedDuration = duration
106+
.filter(obj => obj.ms !== 0 && avoidDuration ? fullDuration && !avoidDuration.map(v => v.toLowerCase()).includes(obj.short) : obj.ms)
107+
.map(obj => `${Math.sign(value) === -1 ? '-' : ''}${compactDuration ? `${Math.floor(obj.ms)}${obj.short}` : `${Math.floor(obj.ms)} ${obj.long}${obj.ms === 1 ? '' : 's'}`}`);
108+
return fullDuration ? mappedDuration.join(compactDuration ? ' ' : ', ') : mappedDuration[0];
127109
}
128110
;
129-
function plural(shortType, type, negative, number, compact) {
130-
number = Math.round(number);
131-
let origNumb = `${negative ? '-' : ''}${number}`;
132-
if (compact)
133-
return `${origNumb}${shortType}`;
134-
if (number > 1)
135-
return `${origNumb} ${type}s`;
136-
else
137-
return `${origNumb} ${type}`;
111+
/**
112+
* A type guard for errors.
113+
*/
114+
function isError(error) {
115+
return typeof error === 'object' && error !== null && 'message' in error;
138116
}
139117
;
140-
export { rainbowText, compressNumber, formatNumber, MS };
118+
export { rainbowText, compressNumber, formatNumber };

src/library/utils/formatter.ts

Lines changed: 54 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { StringValue, compactUnitAnyCase, durationInterface } from '../@types/utils/formatter';
2+
13
/**
24
* Turn text into colored text that supports MCBE
35
* @param {string} text The text you want to format to rainbow colors.
@@ -39,73 +41,65 @@ function formatNumber(value: number): string {
3941
if(typeof value !== 'number') return;
4042
return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
4143
};
44+
45+
export function MS(value: StringValue): number;
46+
export function MS(value: number, { compactDuration, fullDuration }?: { compactDuration?: boolean, fullDuration?: boolean }): string;
47+
export function MS(value: number, { fullDuration, avoidDuration }?: { compactDuration?: boolean, fullDuration: boolean, avoidDuration: Array<compactUnitAnyCase> }): string;
48+
export function MS(value: StringValue | number, { compactDuration, fullDuration, avoidDuration }: { compactDuration?: boolean, fullDuration?: boolean, avoidDuration?: Array<compactUnitAnyCase> } = {}): string | number | undefined {
49+
try {
50+
if(typeof value === 'string') {
51+
if(/^\d+$/.test(value)) return Number(value);
52+
const durations = value.match(/-?\d*\.?\d+\s*?(years?|yrs?|weeks?|days?|hours?|hrs?|minutes?|mins?|seconds?|secs?|milliseconds?|msecs?|ms|[smhdwy])/gi);
53+
return durations ? durations.reduce((a, b) => a + toMS(b), 0) : null;
54+
};
55+
if(typeof value === 'number') return toDuration(value, { compactDuration, fullDuration, avoidDuration });
56+
throw new Error('Value is not a string or a number');
57+
} catch(err) {
58+
const message = isError(err)
59+
? `${err.message}. Value = ${JSON.stringify(value)}`
60+
: 'An unknown error has occured.';
61+
throw new Error(message);
62+
};
63+
};
64+
4265
/**
43-
* Convert seconds, minutes, hours, days and week to milliseconds and vice versa
44-
* @param {string | number} value string time support: second, minute, hour, day, week.
45-
* @param {boolean} [compact] Return time string in a compact format
46-
* @returns {string | number | undefined}
47-
* @example MS('2 days') //Output: 172800000
48-
* MS('1d') //Output: 86400000
49-
* MS('10h') //Output: 36000000
50-
* MS('2.5 hrs') //Output: 9000000
51-
* MS('2h') //Output: 7200000
52-
* MS('1m') //Output: 60000
53-
* MS('5s') //Output: 5000
54-
* MS('1y') //Output: 31557600000
55-
* MS('100') //Output: 100
56-
* MS('-3 days') //Output: -259200000
57-
* MS('-1h') //Output: -3600000
58-
* MS('-200') //Output: -200
59-
*
60-
* //Convert from Milliseconds
61-
*
62-
* MS(86400000, { compact: true }); //Output: 1d
63-
* MS(86400000); //Output: 1 day
64-
* MS(172800000, { compact: true }); //Output: 2d
65-
* MS(172800000); //Output: 2 days
66+
* Convert Durations to milliseconds
6667
*/
67-
function MS(value: string | number, { compact }: { compact?: boolean } = {}): any {
68-
if(typeof value === 'string') return timeToMs(value);
69-
if(typeof value === 'number') return msToTime(value, compact ? true : false);
68+
function toMS(value: string): number | undefined {
69+
const number = Number(value.replace(/[^-.0-9]+/g, ''));
70+
value = value.replace(/\s+/g, '');
71+
if(/\d+(?=ms|milliseconds?)/i.test(value)) return number;
72+
else if(/\d+(?=s)/i.test(value)) return number * 1000;
73+
else if(/\d+(?=m)/i.test(value)) return number * 60000;
74+
else if(/\d+(?=h)/i.test(value)) return number * 3.6e+6;
75+
else if(/\d+(?=d)/i.test(value)) return number * 8.64e+7;
76+
else if(/\d+(?=w)/i.test(value)) return number * 6.048e+8;
77+
else if(/\d+(?=y)/i.test(value)) return number * 3.154e+10;
7078
};
79+
7180
/**
72-
*
73-
* @param {string} string Time to ms
74-
* @returns {number}
81+
* Convert milliseconds to durations
7582
*/
76-
function timeToMs(value: string): number {
77-
if(!/^-?\s?\d*\.?\d*?\s?((years*?|yrs*?)|(weeks*?)|(days*?)|(hours*?|hrs*?)|(minutes*?|mins*?)|(seconds*?|secs*?)|(milliseconds*?|msecs*?|ms)|[smhdwy])$/.test(value)) return;
78-
const number = parseFloat(value.replace(/[^-.0-9]+/g, ''));
79-
if(/\d+(?=\s?(milliseconds?|msecs?|ms))/.test(value)) return number;
80-
else if(/\d+(?=\s?s)/.test(value)) return number * 1000;
81-
else if(/\d+(?=\s?m)/.test(value)) return number * 60000;
82-
else if(/\d+(?=\s?h)/.test(value)) return number * 3.6e+6;
83-
else if(/\d+(?=\s?d)/.test(value)) return number * 8.64e+7;
84-
else if(/\d+(?=\s?w)/.test(value)) return number * 6.048e+8;
85-
else if(/\d+(?=\s?y)/.test(value)) return number * 3.154e+10;
83+
function toDuration(value: number, { compactDuration, fullDuration, avoidDuration }: { compactDuration?: boolean, fullDuration?: boolean, avoidDuration?: Array<compactUnitAnyCase> } = {}): string {
84+
const absMs = Math.abs(value);
85+
const duration: Array<durationInterface> = [
86+
{ short: 'd', long: 'day', ms: absMs / 8.64e+7 },
87+
{ short: 'h', long: 'hour', ms: absMs / 3.6e+6 % 24 },
88+
{ short: 'm', long: 'minute', ms: absMs / 60000 % 60 },
89+
{ short: 's', long: 'second', ms: absMs / 1000 % 60 },
90+
{ short: 'ms', long: 'millisecond', ms: absMs % 1000 },
91+
];
92+
const mappedDuration = duration
93+
.filter(obj => obj.ms !== 0 && avoidDuration ? fullDuration && !avoidDuration.map(v => v.toLowerCase()).includes(obj.short) : obj.ms)
94+
.map(obj => `${Math.sign(value) === -1 ? '-' : ''}${compactDuration ? `${Math.floor(obj.ms)}${obj.short}` : `${Math.floor(obj.ms)} ${obj.long}${obj.ms === 1 ? '' : 's'}`}`);
95+
return fullDuration ? mappedDuration.join(compactDuration ? ' ' : ', ') : mappedDuration[0];
8696
};
97+
8798
/**
88-
*
89-
* @param {number} ms Ms to Time
90-
* @param {boolean} [compact] Compact time format
91-
* @returns {string}
99+
* A type guard for errors.
92100
*/
93-
function msToTime(ms: number, compact?: boolean): string {
94-
let negative = Math.sign(ms) === -1, absMs = Math.abs(ms);
95-
let seconds = absMs / 1000, minutes = absMs / 60000, hours = absMs / 3.6e+6, days = absMs / 8.64e+7, weeks = absMs / 6.048e+8;
96-
if(absMs < 1000) return plural('ms', 'millisecond', negative, absMs, compact);
97-
else if(seconds < 60) return plural('s', 'second', negative, seconds, compact);
98-
else if(minutes < 60) return plural('m', 'minute', negative, minutes, compact);
99-
else if(hours < 24) return plural('h', 'hour', negative, hours, compact);
100-
else if(days < 7) return plural('d', 'day', negative, days, compact);
101-
else return plural('w', 'week', negative, weeks, compact);
102-
};
103-
function plural(shortType: string, type: string, negative: boolean, number: number, compact: boolean): string {
104-
number = Math.round(number);
105-
let origNumb = `${negative ? '-' : ''}${number}`;
106-
if(compact) return `${origNumb}${shortType}`;
107-
if(number > 1) return `${origNumb} ${type}s`;
108-
else return `${origNumb} ${type}`;
101+
function isError(error: unknown): error is Error {
102+
return typeof error === 'object' && error !== null && 'message' in error;
109103
};
110104

111-
export { rainbowText, compressNumber, formatNumber, MS };
105+
export { rainbowText, compressNumber, formatNumber };

0 commit comments

Comments
 (0)