@qrvey/utils 1.3.1 → 1.3.2
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/README.md +1 -1
- package/dist/cjs/dates/helpers/isValidDateObject.d.ts +6 -0
- package/dist/cjs/dates/helpers/isValidDateObject.js +12 -0
- package/dist/cjs/dates/range/getDateRange.js +10 -3
- package/dist/cjs/filters/helpers/common/mergeFilters.js +2 -2
- package/dist/cjs/format/definition.d.ts +62 -0
- package/dist/cjs/format/definition.js +18 -1
- package/dist/cjs/format/duration/addDurationFormat.d.ts +13 -0
- package/dist/cjs/format/duration/addDurationFormat.js +20 -0
- package/dist/cjs/format/duration/durationFormatter.d.ts +79 -0
- package/dist/cjs/format/duration/durationFormatter.js +156 -0
- package/dist/cjs/format/duration/index.d.ts +2 -0
- package/dist/cjs/format/duration/index.js +18 -0
- package/dist/cjs/format/index.d.ts +1 -0
- package/dist/cjs/format/index.js +1 -0
- package/dist/dates/helpers/isValidDateObject.d.ts +6 -0
- package/dist/dates/helpers/isValidDateObject.js +8 -0
- package/dist/dates/range/getDateRange.js +10 -3
- package/dist/filters/helpers/common/mergeFilters.js +2 -2
- package/dist/format/definition.d.ts +62 -0
- package/dist/format/definition.js +17 -0
- package/dist/format/duration/addDurationFormat.d.ts +13 -0
- package/dist/format/duration/addDurationFormat.js +16 -0
- package/dist/format/duration/durationFormatter.d.ts +79 -0
- package/dist/format/duration/durationFormatter.js +152 -0
- package/dist/format/duration/index.d.ts +2 -0
- package/dist/format/duration/index.js +2 -0
- package/dist/format/index.d.ts +1 -0
- package/dist/format/index.js +1 -0
- package/package.json +1 -1
- package/src/dates/helpers/isValidDateObject.ts +9 -0
- package/src/dates/range/getDateRange.ts +13 -3
- package/src/filters/helpers/common/mergeFilters.ts +2 -2
- package/src/format/definition.ts +19 -0
- package/src/format/duration/addDurationFormat.ts +17 -0
- package/src/format/duration/durationFormatter.ts +169 -0
- package/src/format/duration/index.ts +2 -0
- package/src/format/index.ts +1 -0
- package/test/format/addDurationFormat.test.js +39 -0
- package/test/format/addDurationFormatWithLocale.test.js +11 -0
- package/test/format/durationFormatterClass.test.js +45 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export declare class DurationFormatter {
|
|
2
|
+
private options;
|
|
3
|
+
private parts;
|
|
4
|
+
private valueFormatter;
|
|
5
|
+
private numberFactor;
|
|
6
|
+
private template;
|
|
7
|
+
private numberFormatOptions;
|
|
8
|
+
/**
|
|
9
|
+
* The constructor function takes in a template string and an options object. It then sets the
|
|
10
|
+
* options object to the default options object if no options object is passed in. It then parses
|
|
11
|
+
* the template string and sets the parts to the parsed template string. It then tries to set the
|
|
12
|
+
* valueFormatter to a new Intl.NumberFormat object with the locale and fractionDigits options. If
|
|
13
|
+
* it fails, it sets the valueFormatter to a new Intl.NumberFormat object with the default locale
|
|
14
|
+
* and fractionDigits options. It then sets the numberFactor to the duration parts object with the
|
|
15
|
+
* name of the unit option. If it can't find the unit option, it sets the numberFactor to 1
|
|
16
|
+
* @param [template] - The template string that will be used to format the duration.
|
|
17
|
+
* @param options - This is an object that contains the following properties: unit, locale and fractionDigits
|
|
18
|
+
*/
|
|
19
|
+
constructor(options: {
|
|
20
|
+
template: string;
|
|
21
|
+
options?: {
|
|
22
|
+
unit?: string;
|
|
23
|
+
locale?: string;
|
|
24
|
+
fractionDigits?: number;
|
|
25
|
+
};
|
|
26
|
+
intlNumberFormat?: Intl.NumberFormat;
|
|
27
|
+
});
|
|
28
|
+
private setOptions;
|
|
29
|
+
/**
|
|
30
|
+
* It sets the locale formatter for the number.
|
|
31
|
+
*/
|
|
32
|
+
private setLocaleFormatter;
|
|
33
|
+
/**
|
|
34
|
+
* It returns a new instance of the Intl.NumberFormat class, which is a built-in JavaScript class
|
|
35
|
+
* that formats numbers
|
|
36
|
+
* @param {string | string[]} locale - string | string[]
|
|
37
|
+
* @returns A new instance of the Intl.NumberFormat class.
|
|
38
|
+
*/
|
|
39
|
+
private getNewNumberFormat;
|
|
40
|
+
/**
|
|
41
|
+
* It takes a template string and sets the parts property to the result of calling the
|
|
42
|
+
* parseFormatTemplate function with the template string as an argument
|
|
43
|
+
* @param {string} template - The format template string.
|
|
44
|
+
*/
|
|
45
|
+
private setParts;
|
|
46
|
+
/**
|
|
47
|
+
* It replaces the H and D characters in the template with h and d respectively
|
|
48
|
+
* @param {string} template - The template string to be used for the date format.
|
|
49
|
+
* @returns The template string with all instances of H replaced with h and all instances of D
|
|
50
|
+
* replaced with d.
|
|
51
|
+
*/
|
|
52
|
+
private matchFormatsReplace;
|
|
53
|
+
/**
|
|
54
|
+
* It sets the numberFactor to the value of the duration part that matches the unit.
|
|
55
|
+
*/
|
|
56
|
+
private setNumberFactor;
|
|
57
|
+
/**
|
|
58
|
+
* It takes a string, splits it into an array of strings, then maps each string to a config object,
|
|
59
|
+
* then filters out any falsy values, then reverses the array
|
|
60
|
+
* @param {string} template - string - the template string that we want to parse
|
|
61
|
+
* @returns An array of objects that have the order and the name of the part of the duration.
|
|
62
|
+
*/
|
|
63
|
+
private parseFormatTemplate;
|
|
64
|
+
/**
|
|
65
|
+
* It takes a number, multiplies it by a factor, then uses the parts array to calculate the number
|
|
66
|
+
* of each part in the number, then uses the template to format the number
|
|
67
|
+
* @param {number} number - The number of milliseconds to format.
|
|
68
|
+
* @returns The template string with the values replaced.
|
|
69
|
+
*/
|
|
70
|
+
format(number: number): string;
|
|
71
|
+
/**
|
|
72
|
+
* It takes a dictionary of values and a list of keys, and returns a formatted string
|
|
73
|
+
* @param parts - { [x: string]: any; }
|
|
74
|
+
* @param {string | (string | number)[]} part - This is the part of the date that we're
|
|
75
|
+
* formatting.
|
|
76
|
+
* @returns The value of the part of the date that is being formatted.
|
|
77
|
+
*/
|
|
78
|
+
private formatValue;
|
|
79
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { isEmpty } from "../../general/mix/isEmpty";
|
|
2
|
+
import { DEFAULT_OPTIONS, DURATION_PARTS, PARTS_REGEX } from "../definition";
|
|
3
|
+
/* It takes a template string and a number of milliseconds and returns a string that is formatted to
|
|
4
|
+
the user's preference
|
|
5
|
+
this class is based on moment format:
|
|
6
|
+
years: Y or y
|
|
7
|
+
months: M
|
|
8
|
+
weeks: W or w
|
|
9
|
+
days: D or d
|
|
10
|
+
hours: H or h
|
|
11
|
+
minutes: m
|
|
12
|
+
seconds: s
|
|
13
|
+
ms: S
|
|
14
|
+
*/
|
|
15
|
+
export class DurationFormatter {
|
|
16
|
+
/**
|
|
17
|
+
* The constructor function takes in a template string and an options object. It then sets the
|
|
18
|
+
* options object to the default options object if no options object is passed in. It then parses
|
|
19
|
+
* the template string and sets the parts to the parsed template string. It then tries to set the
|
|
20
|
+
* valueFormatter to a new Intl.NumberFormat object with the locale and fractionDigits options. If
|
|
21
|
+
* it fails, it sets the valueFormatter to a new Intl.NumberFormat object with the default locale
|
|
22
|
+
* and fractionDigits options. It then sets the numberFactor to the duration parts object with the
|
|
23
|
+
* name of the unit option. If it can't find the unit option, it sets the numberFactor to 1
|
|
24
|
+
* @param [template] - The template string that will be used to format the duration.
|
|
25
|
+
* @param options - This is an object that contains the following properties: unit, locale and fractionDigits
|
|
26
|
+
*/
|
|
27
|
+
constructor(options) {
|
|
28
|
+
this.numberFormatOptions = {
|
|
29
|
+
minimumFractionDigits: DEFAULT_OPTIONS.fractionDigits,
|
|
30
|
+
maximumFractionDigits: DEFAULT_OPTIONS.fractionDigits
|
|
31
|
+
};
|
|
32
|
+
this.setOptions(options.options);
|
|
33
|
+
this.setParts(options.template);
|
|
34
|
+
this.setLocaleFormatter(options.intlNumberFormat);
|
|
35
|
+
this.setNumberFactor();
|
|
36
|
+
}
|
|
37
|
+
setOptions(options) {
|
|
38
|
+
this.options = Object.assign(Object.assign({}, DEFAULT_OPTIONS), options);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* It sets the locale formatter for the number.
|
|
42
|
+
*/
|
|
43
|
+
setLocaleFormatter(intlNumberFormat) {
|
|
44
|
+
try {
|
|
45
|
+
if (intlNumberFormat) {
|
|
46
|
+
console.log(intlNumberFormat.resolvedOptions());
|
|
47
|
+
this.valueFormatter = intlNumberFormat;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
this.valueFormatter = this.getNewNumberFormat(this.options.locale);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch (e) {
|
|
54
|
+
if (intlNumberFormat) {
|
|
55
|
+
this.valueFormatter = intlNumberFormat;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
this.valueFormatter = this.getNewNumberFormat(DEFAULT_OPTIONS.locale);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* It returns a new instance of the Intl.NumberFormat class, which is a built-in JavaScript class
|
|
64
|
+
* that formats numbers
|
|
65
|
+
* @param {string | string[]} locale - string | string[]
|
|
66
|
+
* @returns A new instance of the Intl.NumberFormat class.
|
|
67
|
+
*/
|
|
68
|
+
getNewNumberFormat(locale) {
|
|
69
|
+
return new Intl.NumberFormat(locale, this.numberFormatOptions);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* It takes a template string and sets the parts property to the result of calling the
|
|
73
|
+
* parseFormatTemplate function with the template string as an argument
|
|
74
|
+
* @param {string} template - The format template string.
|
|
75
|
+
*/
|
|
76
|
+
setParts(template) {
|
|
77
|
+
this.template = this.matchFormatsReplace(template);
|
|
78
|
+
this.parts = this.parseFormatTemplate(template);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* It replaces the H and D characters in the template with h and d respectively
|
|
82
|
+
* @param {string} template - The template string to be used for the date format.
|
|
83
|
+
* @returns The template string with all instances of H replaced with h and all instances of D
|
|
84
|
+
* replaced with d.
|
|
85
|
+
*/
|
|
86
|
+
matchFormatsReplace(template) {
|
|
87
|
+
return isEmpty(template) ? template : template.replace(/H/g, 'h');
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* It sets the numberFactor to the value of the duration part that matches the unit.
|
|
91
|
+
*/
|
|
92
|
+
setNumberFactor() {
|
|
93
|
+
var _a;
|
|
94
|
+
this.numberFactor = ((_a = Object.values(DURATION_PARTS).find((d) => d.name === this.options.unit)) === null || _a === void 0 ? void 0 : _a.ms) || 1;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* It takes a string, splits it into an array of strings, then maps each string to a config object,
|
|
98
|
+
* then filters out any falsy values, then reverses the array
|
|
99
|
+
* @param {string} template - string - the template string that we want to parse
|
|
100
|
+
* @returns An array of objects that have the order and the name of the part of the duration.
|
|
101
|
+
*/
|
|
102
|
+
parseFormatTemplate(template) {
|
|
103
|
+
this.template = isEmpty(template) ? '' : template;
|
|
104
|
+
return (this.template.match(PARTS_REGEX) || [])
|
|
105
|
+
.reduce((store, part) => {
|
|
106
|
+
const config = DURATION_PARTS[part[0]];
|
|
107
|
+
if (config)
|
|
108
|
+
store[config.order] = config;
|
|
109
|
+
return store;
|
|
110
|
+
}, [])
|
|
111
|
+
.filter(Boolean)
|
|
112
|
+
.reverse();
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* It takes a number, multiplies it by a factor, then uses the parts array to calculate the number
|
|
116
|
+
* of each part in the number, then uses the template to format the number
|
|
117
|
+
* @param {number} number - The number of milliseconds to format.
|
|
118
|
+
* @returns The template string with the values replaced.
|
|
119
|
+
*/
|
|
120
|
+
format(number) {
|
|
121
|
+
if (number === null)
|
|
122
|
+
return null;
|
|
123
|
+
if (number === undefined || this.template === undefined || isNaN(number))
|
|
124
|
+
return undefined;
|
|
125
|
+
if (isEmpty(number))
|
|
126
|
+
return "";
|
|
127
|
+
number *= this.numberFactor;
|
|
128
|
+
const durationParts = this.parts.reduce((store, part) => {
|
|
129
|
+
store[part.symbol] = number / part.ms;
|
|
130
|
+
number %= part.ms;
|
|
131
|
+
return store;
|
|
132
|
+
}, {});
|
|
133
|
+
if (!Number.isInteger(number))
|
|
134
|
+
return number === null ? null : this.valueFormatter.format(number).padStart(this.parts.length, "0");
|
|
135
|
+
if (isEmpty(this.template))
|
|
136
|
+
return this.valueFormatter.format(number).padStart(this.parts.length, "0");
|
|
137
|
+
return this.template.replace(PARTS_REGEX, (match, $1) => {
|
|
138
|
+
return $1 || this.formatValue(durationParts, match);
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* It takes a dictionary of values and a list of keys, and returns a formatted string
|
|
143
|
+
* @param parts - { [x: string]: any; }
|
|
144
|
+
* @param {string | (string | number)[]} part - This is the part of the date that we're
|
|
145
|
+
* formatting.
|
|
146
|
+
* @returns The value of the part of the date that is being formatted.
|
|
147
|
+
*/
|
|
148
|
+
formatValue(parts, part) {
|
|
149
|
+
const value = parts[part[0]];
|
|
150
|
+
return this.valueFormatter.format(value).padStart(part.length, "0");
|
|
151
|
+
}
|
|
152
|
+
}
|
package/dist/format/index.d.ts
CHANGED
package/dist/format/index.js
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* If the date is a valid Date object, return true, otherwise return false.
|
|
4
|
+
* @param {Date} date - The date object to check.
|
|
5
|
+
* @returns A boolean value.
|
|
6
|
+
*/
|
|
7
|
+
export function isValidDateObject(date: Date): boolean {
|
|
8
|
+
return date instanceof Date && !isNaN(date.getTime());
|
|
9
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { capitalize } from "../../general/string/capitalize";
|
|
2
2
|
import { isTokenLabel } from "../../tokens/isTokenLabel";
|
|
3
|
+
import { isValidDateObject } from "../helpers/isValidDateObject";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Get date range object from a string date value
|
|
@@ -107,9 +108,18 @@ function getStringTimeRange(value: string, dateGroupLabel: string) {
|
|
|
107
108
|
}
|
|
108
109
|
}
|
|
109
110
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* It takes a Date object as an argument and returns a string in the format of MM/DD/YYYY
|
|
114
|
+
* @param {Date} dt - Date - The date object to convert to a string
|
|
115
|
+
* @returns A string in the format of MM/DD/YYYY
|
|
116
|
+
*/
|
|
117
|
+
function getStringDate(dt: Date):string {
|
|
118
|
+
if(isValidDateObject(dt)){
|
|
119
|
+
return `${('0' + (dt.getMonth() + 1)).slice(-2)}/${('0' + dt.getDate()).slice(-2)}/${dt.getFullYear()}`;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return '01/01/0000';
|
|
113
123
|
}
|
|
114
124
|
|
|
115
125
|
function getYearRange(value: string) {
|
|
@@ -52,7 +52,7 @@ function mergeScopes(scopes1: IFSScope[] = [], scopes2: IFSScope[] = [], setting
|
|
|
52
52
|
const scope2Index = scopes2.findIndex(scope2 => resolveScopeConditions(scope2, { scope: scope1.scope, scopeid: scope1.scopeid }));
|
|
53
53
|
if (scope2Index > -1) {
|
|
54
54
|
scope1 = {
|
|
55
|
-
...
|
|
55
|
+
...scopes2[scope2Index],
|
|
56
56
|
datasets: mergeDatasets(scope1.datasets, scopes2[scope2Index].datasets, settings)
|
|
57
57
|
};
|
|
58
58
|
scopes2.splice(scope2Index, 1);
|
|
@@ -77,7 +77,7 @@ function mergeDatasets(datasets1: IFSDataset[] = [], datasets2: IFSDataset[] = [
|
|
|
77
77
|
const dataset2Index = datasets2.findIndex(dataset2 => resolveDatasetConditions(dataset2, { qrveyid: dataset1.qrveyid, linkid: dataset1.linkid }));
|
|
78
78
|
if (dataset2Index > -1) {
|
|
79
79
|
dataset1 = {
|
|
80
|
-
...
|
|
80
|
+
...datasets2[dataset2Index],
|
|
81
81
|
filters: mergeFilterss(dataset1.filters, datasets2[dataset2Index].filters, settings)
|
|
82
82
|
};
|
|
83
83
|
datasets2.splice(dataset2Index, 1);
|
package/src/format/definition.ts
CHANGED
|
@@ -105,3 +105,22 @@ export const LANG_DEFAULT = 'en-US';
|
|
|
105
105
|
export const CURRENCY_DEFAULT = { text: '$ (USD)', label: 'USD' };
|
|
106
106
|
export const DATETIME_OPTIONS = { year: 'numeric', month: 'numeric', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric' };
|
|
107
107
|
|
|
108
|
+
export const PARTS_REGEX = /\[([^\]]+)]|Y{1,2}|M{1,2}|W{1,2}|D{1,2}|h{1,2}|H{1,2}|m{1,2}|s{1,2}|S{1,3}/g;
|
|
109
|
+
|
|
110
|
+
export const DURATION_PARTS = {
|
|
111
|
+
S: { order: 1, symbol: "S", name: "milliseconds", ms: 1 },
|
|
112
|
+
s: { order: 2, symbol: "s", name: "seconds", ms: 1000 },
|
|
113
|
+
m: { order: 3, symbol: "m", name: "minutes", ms: 1000 * 60 },
|
|
114
|
+
h: { order: 4, symbol: "h", name: "hours", ms: 1000 * 60 * 60 },
|
|
115
|
+
H: { order: 5, symbol: "H", name: "hours", ms: 1000 * 60 * 60 },
|
|
116
|
+
D: { order: 6, symbol: "D", name: "days", ms: 1000 * 60 * 60 * 24 },
|
|
117
|
+
W: { order: 7, symbol: "W", name: "weeks", ms: 1000 * 60 * 60 * 24 * 7 },
|
|
118
|
+
M: { order: 8, symbol: "M", name: "months", ms: 1000 * 60 * 60 * 24 * 30 },
|
|
119
|
+
Y: { order: 9, symbol: "Y", name: "years", ms: 1000 * 60 * 60 * 24 * 365 },
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export const DEFAULT_OPTIONS = {
|
|
123
|
+
unit: "seconds",
|
|
124
|
+
locale: "en-EN",
|
|
125
|
+
fractionDigits: 0
|
|
126
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { DurationFormatter } from "./durationFormatter";
|
|
2
|
+
|
|
3
|
+
/**[TODO: The decimals dots are not working correctly, we need to reviewing (fractionDigits)]
|
|
4
|
+
* "Convert a number of seconds to a human readable string."
|
|
5
|
+
*
|
|
6
|
+
* `addDurationFormat` is a function that takes a number, a format, an optional locale, and an optional
|
|
7
|
+
* number of fraction digits, and returns a string
|
|
8
|
+
* @param {number} number - The number of milliseconds to format.
|
|
9
|
+
* @param {string} format - The format string.
|
|
10
|
+
* @param {string} [locale] - The locale to use for formatting. If not specified, the default locale is
|
|
11
|
+
* used.
|
|
12
|
+
* @param {number} [fractionDigits] - The number of digits to show after the decimal point.
|
|
13
|
+
* @returns A string
|
|
14
|
+
*/
|
|
15
|
+
export function addDurationFormat(number: number, format: string, locale?: string, fractionDigits?: number): string {
|
|
16
|
+
return new DurationFormatter( { template: format, options: { locale: locale, fractionDigits: fractionDigits } }).format(number);
|
|
17
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { isEmpty } from "../../general/mix/isEmpty";
|
|
2
|
+
import { DEFAULT_OPTIONS, DURATION_PARTS, PARTS_REGEX } from "../definition";
|
|
3
|
+
|
|
4
|
+
/* It takes a template string and a number of milliseconds and returns a string that is formatted to
|
|
5
|
+
the user's preference
|
|
6
|
+
this class is based on moment format:
|
|
7
|
+
years: Y or y
|
|
8
|
+
months: M
|
|
9
|
+
weeks: W or w
|
|
10
|
+
days: D or d
|
|
11
|
+
hours: H or h
|
|
12
|
+
minutes: m
|
|
13
|
+
seconds: s
|
|
14
|
+
ms: S
|
|
15
|
+
*/
|
|
16
|
+
export class DurationFormatter {
|
|
17
|
+
|
|
18
|
+
private options: { unit?: string; locale?: string; fractionDigits?: number; };
|
|
19
|
+
private parts: any;
|
|
20
|
+
private valueFormatter: Intl.NumberFormat;
|
|
21
|
+
private numberFactor: number;
|
|
22
|
+
private template: string;
|
|
23
|
+
private numberFormatOptions = {
|
|
24
|
+
minimumFractionDigits: DEFAULT_OPTIONS.fractionDigits,
|
|
25
|
+
maximumFractionDigits: DEFAULT_OPTIONS.fractionDigits
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The constructor function takes in a template string and an options object. It then sets the
|
|
30
|
+
* options object to the default options object if no options object is passed in. It then parses
|
|
31
|
+
* the template string and sets the parts to the parsed template string. It then tries to set the
|
|
32
|
+
* valueFormatter to a new Intl.NumberFormat object with the locale and fractionDigits options. If
|
|
33
|
+
* it fails, it sets the valueFormatter to a new Intl.NumberFormat object with the default locale
|
|
34
|
+
* and fractionDigits options. It then sets the numberFactor to the duration parts object with the
|
|
35
|
+
* name of the unit option. If it can't find the unit option, it sets the numberFactor to 1
|
|
36
|
+
* @param [template] - The template string that will be used to format the duration.
|
|
37
|
+
* @param options - This is an object that contains the following properties: unit, locale and fractionDigits
|
|
38
|
+
*/
|
|
39
|
+
constructor(options:{ template: string, options?: { unit?: string; locale?: string; fractionDigits?: number; }, intlNumberFormat?: Intl.NumberFormat }) {
|
|
40
|
+
this.setOptions(options.options);
|
|
41
|
+
this.setParts(options.template);
|
|
42
|
+
this.setLocaleFormatter(options.intlNumberFormat);
|
|
43
|
+
this.setNumberFactor();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private setOptions(options: { unit?: string; locale?: string; fractionDigits?: number; }){
|
|
47
|
+
this.options = { ...DEFAULT_OPTIONS, ...options };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* It sets the locale formatter for the number.
|
|
52
|
+
*/
|
|
53
|
+
private setLocaleFormatter(intlNumberFormat: Intl.NumberFormat){
|
|
54
|
+
|
|
55
|
+
try{
|
|
56
|
+
if(intlNumberFormat){
|
|
57
|
+
console.log(intlNumberFormat.resolvedOptions());
|
|
58
|
+
this.valueFormatter = intlNumberFormat;
|
|
59
|
+
}else{
|
|
60
|
+
this.valueFormatter = this.getNewNumberFormat(this.options.locale);
|
|
61
|
+
}
|
|
62
|
+
}catch(e){
|
|
63
|
+
if(intlNumberFormat){
|
|
64
|
+
this.valueFormatter = intlNumberFormat;
|
|
65
|
+
}else{
|
|
66
|
+
this.valueFormatter = this.getNewNumberFormat(DEFAULT_OPTIONS.locale);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* It returns a new instance of the Intl.NumberFormat class, which is a built-in JavaScript class
|
|
74
|
+
* that formats numbers
|
|
75
|
+
* @param {string | string[]} locale - string | string[]
|
|
76
|
+
* @returns A new instance of the Intl.NumberFormat class.
|
|
77
|
+
*/
|
|
78
|
+
private getNewNumberFormat(locale: string | string[]){
|
|
79
|
+
return new Intl.NumberFormat(locale, this.numberFormatOptions);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* It takes a template string and sets the parts property to the result of calling the
|
|
84
|
+
* parseFormatTemplate function with the template string as an argument
|
|
85
|
+
* @param {string} template - The format template string.
|
|
86
|
+
*/
|
|
87
|
+
private setParts(template: string){
|
|
88
|
+
this.template = this.matchFormatsReplace(template);
|
|
89
|
+
this.parts = this.parseFormatTemplate(template);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* It replaces the H and D characters in the template with h and d respectively
|
|
94
|
+
* @param {string} template - The template string to be used for the date format.
|
|
95
|
+
* @returns The template string with all instances of H replaced with h and all instances of D
|
|
96
|
+
* replaced with d.
|
|
97
|
+
*/
|
|
98
|
+
private matchFormatsReplace(template: string){
|
|
99
|
+
return isEmpty(template) ? template: template.replace(/H/g, 'h');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* It sets the numberFactor to the value of the duration part that matches the unit.
|
|
104
|
+
*/
|
|
105
|
+
private setNumberFactor(){
|
|
106
|
+
this.numberFactor = Object.values(DURATION_PARTS).find((d) => d.name === this.options.unit)?.ms || 1;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* It takes a string, splits it into an array of strings, then maps each string to a config object,
|
|
111
|
+
* then filters out any falsy values, then reverses the array
|
|
112
|
+
* @param {string} template - string - the template string that we want to parse
|
|
113
|
+
* @returns An array of objects that have the order and the name of the part of the duration.
|
|
114
|
+
*/
|
|
115
|
+
private parseFormatTemplate(template: string) {
|
|
116
|
+
this.template = isEmpty(template)? '': template;
|
|
117
|
+
return (this.template.match(PARTS_REGEX) || [])
|
|
118
|
+
.reduce((store, part) => {
|
|
119
|
+
const config = DURATION_PARTS[part[0]];
|
|
120
|
+
if (config) store[config.order] = config;
|
|
121
|
+
return store;
|
|
122
|
+
}, [])
|
|
123
|
+
.filter(Boolean)
|
|
124
|
+
.reverse();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* It takes a number, multiplies it by a factor, then uses the parts array to calculate the number
|
|
131
|
+
* of each part in the number, then uses the template to format the number
|
|
132
|
+
* @param {number} number - The number of milliseconds to format.
|
|
133
|
+
* @returns The template string with the values replaced.
|
|
134
|
+
*/
|
|
135
|
+
public format(number: number): string {
|
|
136
|
+
if(number === null) return null;
|
|
137
|
+
if(number === undefined || this.template === undefined || isNaN(number)) return undefined;
|
|
138
|
+
if(isEmpty(number)) return "";
|
|
139
|
+
|
|
140
|
+
number *= this.numberFactor;
|
|
141
|
+
|
|
142
|
+
const durationParts = this.parts.reduce((store, part) => {
|
|
143
|
+
store[part.symbol] = number / part.ms;
|
|
144
|
+
number %= part.ms;
|
|
145
|
+
return store;
|
|
146
|
+
}, {});
|
|
147
|
+
|
|
148
|
+
if(!Number.isInteger(number)) return number === null? null: this.valueFormatter.format(number).padStart(this.parts.length, "0");
|
|
149
|
+
if(isEmpty(this.template)) return this.valueFormatter.format(number).padStart(this.parts.length, "0");
|
|
150
|
+
|
|
151
|
+
return this.template.replace(PARTS_REGEX, (match, $1) => {
|
|
152
|
+
return $1 || this.formatValue(durationParts, match);
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* It takes a dictionary of values and a list of keys, and returns a formatted string
|
|
160
|
+
* @param parts - { [x: string]: any; }
|
|
161
|
+
* @param {string | (string | number)[]} part - This is the part of the date that we're
|
|
162
|
+
* formatting.
|
|
163
|
+
* @returns The value of the part of the date that is being formatted.
|
|
164
|
+
*/
|
|
165
|
+
private formatValue(parts: { [x: string]: any; }, part: string | (string | number)[]): string {
|
|
166
|
+
const value = parts[part[0]];
|
|
167
|
+
return this.valueFormatter.format(value).padStart(part.length, "0");
|
|
168
|
+
}
|
|
169
|
+
}
|
package/src/format/index.ts
CHANGED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const { addDurationFormat } = require('../../dist/cjs');
|
|
2
|
+
|
|
3
|
+
describe('Validating the duration format function', function () {
|
|
4
|
+
const seconds = 105243;
|
|
5
|
+
|
|
6
|
+
test("validating addDurationFormat function", () => {
|
|
7
|
+
let value = addDurationFormat(seconds, "HH:mm")
|
|
8
|
+
expect(value).toEqual("29:14");
|
|
9
|
+
|
|
10
|
+
const text = 'seconds';
|
|
11
|
+
value = addDurationFormat(text, "HH:mm");
|
|
12
|
+
expect(value).toEqual(undefined);
|
|
13
|
+
|
|
14
|
+
value = addDurationFormat(null, "HH:mm")
|
|
15
|
+
expect(value).toBeNull();
|
|
16
|
+
|
|
17
|
+
value = addDurationFormat("", "HH:mm")
|
|
18
|
+
expect(value).toEqual("");
|
|
19
|
+
|
|
20
|
+
value = addDurationFormat(seconds, "")
|
|
21
|
+
expect(value).toEqual("105,243,000");
|
|
22
|
+
|
|
23
|
+
value = addDurationFormat(seconds, "TEXTO")
|
|
24
|
+
expect(value).toEqual("TEXTO");
|
|
25
|
+
|
|
26
|
+
value = addDurationFormat(seconds, null)
|
|
27
|
+
expect(value).toEqual("105,243,000");
|
|
28
|
+
|
|
29
|
+
value = addDurationFormat(seconds, undefined)
|
|
30
|
+
expect(value).toEqual("105,243,000");
|
|
31
|
+
|
|
32
|
+
value = addDurationFormat(undefined, undefined)
|
|
33
|
+
expect(value).toEqual(undefined);
|
|
34
|
+
|
|
35
|
+
value = addDurationFormat(null, null)
|
|
36
|
+
expect(value).toEqual(null);
|
|
37
|
+
|
|
38
|
+
})
|
|
39
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const { addDurationFormat } = require('../../dist/cjs');
|
|
2
|
+
|
|
3
|
+
describe('Validating the duration format function', function () {
|
|
4
|
+
const seconds = 105243;
|
|
5
|
+
|
|
6
|
+
test('Duration Format With Locale', function () {
|
|
7
|
+
value = addDurationFormat(seconds, "ss",'pl')
|
|
8
|
+
expect(value).toEqual("105\xa0243");
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const { DurationFormatter } = require('../../dist/cjs');
|
|
2
|
+
|
|
3
|
+
describe('Validating the duration format function', function () {
|
|
4
|
+
const seconds = 105243;
|
|
5
|
+
|
|
6
|
+
test('Duration Format', function () {
|
|
7
|
+
|
|
8
|
+
const intNumberFormat = new Intl.NumberFormat('en', {
|
|
9
|
+
maximumFractionDigits: 0
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
let duration = new DurationFormatter({template: 'D[d] HH[h] mm[m] ss[s]', intlNumberFormat: intNumberFormat});
|
|
13
|
+
value = duration.format(seconds);
|
|
14
|
+
expect(value).toEqual("1d 05h 14m 03s");
|
|
15
|
+
|
|
16
|
+
duration = new DurationFormatter({template: 'HH:mm:ss', intlNumberFormat: intNumberFormat});
|
|
17
|
+
value = duration.format(seconds);
|
|
18
|
+
expect(value).toEqual("29:14:03");
|
|
19
|
+
|
|
20
|
+
duration = new DurationFormatter({template: 'HH:mm', intlNumberFormat: intNumberFormat});
|
|
21
|
+
value = duration.format(seconds);
|
|
22
|
+
expect(value).toEqual("29:14");
|
|
23
|
+
|
|
24
|
+
duration = new DurationFormatter({template: 'HH', intlNumberFormat: intNumberFormat});
|
|
25
|
+
value = duration.format(seconds);
|
|
26
|
+
expect(value).toEqual("29");
|
|
27
|
+
|
|
28
|
+
duration = new DurationFormatter({template: 'mm', intlNumberFormat: intNumberFormat});
|
|
29
|
+
value = duration.format(seconds);
|
|
30
|
+
expect(value).toEqual("1,754");
|
|
31
|
+
|
|
32
|
+
duration = new DurationFormatter({template: 'ss', intlNumberFormat: intNumberFormat});
|
|
33
|
+
value = duration.format(seconds);
|
|
34
|
+
expect(value).toEqual("105,243");
|
|
35
|
+
|
|
36
|
+
duration = new DurationFormatter({template: 'SSS', intlNumberFormat: intNumberFormat});
|
|
37
|
+
value = duration.format(seconds);
|
|
38
|
+
expect(value).toEqual("105,243,000");
|
|
39
|
+
|
|
40
|
+
duration = new DurationFormatter({template: '', intlNumberFormat: intNumberFormat});
|
|
41
|
+
value = duration.format(seconds);
|
|
42
|
+
expect(value).toEqual("105,243,000");
|
|
43
|
+
|
|
44
|
+
});
|
|
45
|
+
});
|