@villedemontreal/general-utils 5.17.1 → 5.17.3
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/dist/config/configs.d.ts +16 -0
- package/dist/config/configs.js +38 -0
- package/dist/config/configs.js.map +1 -0
- package/dist/scripts/index.d.ts +2 -0
- package/dist/scripts/index.js +14 -0
- package/dist/scripts/index.js.map +1 -0
- package/dist/scripts/lint.d.ts +6 -0
- package/dist/scripts/lint.js +31 -0
- package/dist/scripts/lint.js.map +1 -0
- package/dist/scripts/lintFix.d.ts +6 -0
- package/dist/scripts/lintFix.js +40 -0
- package/dist/scripts/lintFix.js.map +1 -0
- package/dist/src/apiError.d.ts +3 -3
- package/dist/src/apiError.js +3 -3
- package/dist/src/apiError.js.map +1 -1
- package/dist/src/apiError.test.js +57 -48
- package/dist/src/apiError.test.js.map +1 -1
- package/dist/src/apiErrorBuilder.d.ts +1 -1
- package/dist/src/apiErrorBuilder.js +2 -2
- package/dist/src/apiErrorBuilder.js.map +1 -1
- package/dist/src/collectionUtils.js +2 -2
- package/dist/src/collectionUtils.js.map +1 -1
- package/dist/src/collectionUtils.test.js +12 -4
- package/dist/src/collectionUtils.test.js.map +1 -1
- package/dist/src/config/constants.d.ts +1 -1
- package/dist/src/config/constants.js.map +1 -1
- package/dist/src/config/globalConstants.d.ts +1 -1
- package/dist/src/config/globalConstants.js +7 -7
- package/dist/src/config/globalConstants.js.map +1 -1
- package/dist/src/dateUtils.js +6 -2
- package/dist/src/dateUtils.js.map +1 -1
- package/dist/src/dateUtils.test.js +31 -16
- package/dist/src/dateUtils.test.js.map +1 -1
- package/dist/src/pagination.d.ts +1 -1
- package/dist/src/pagination.js +1 -1
- package/dist/src/pagination.js.map +1 -1
- package/dist/src/pagination.test.js +14 -5
- package/dist/src/pagination.test.js.map +1 -1
- package/dist/src/stringUtils.js +4 -1
- package/dist/src/stringUtils.js.map +1 -1
- package/dist/src/stringUtils.test.js.map +1 -1
- package/dist/src/timer.js.map +1 -1
- package/dist/src/timer.test.js +47 -32
- package/dist/src/timer.test.js.map +1 -1
- package/dist/src/utils.d.ts +1 -1
- package/dist/src/utils.js +118 -97
- package/dist/src/utils.js.map +1 -1
- package/dist/src/utils.test.js +219 -196
- package/dist/src/utils.test.js.map +1 -1
- package/dist/tests-resources/exec/execTest.js +11 -2
- package/dist/tests-resources/exec/execTest.js.map +1 -1
- package/package.json +8 -5
- package/src/apiError.test.ts +57 -27
- package/src/apiError.ts +5 -5
- package/src/apiErrorBuilder.ts +21 -12
- package/src/collectionUtils.test.ts +13 -5
- package/src/collectionUtils.ts +11 -7
- package/src/config/constants.ts +1 -1
- package/src/config/globalConstants.ts +8 -8
- package/src/dateUtils.test.ts +40 -20
- package/src/dateUtils.ts +25 -11
- package/src/logLevel.ts +1 -1
- package/src/orderBy.ts +1 -1
- package/src/pagination.test.ts +3 -3
- package/src/pagination.ts +1 -1
- package/src/stringUtils.test.ts +16 -6
- package/src/stringUtils.ts +7 -2
- package/src/timer.test.ts +3 -3
- package/src/timer.ts +1 -1
- package/src/utils.test.ts +64 -47
- package/src/utils.ts +14 -11
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
isMatching,
|
|
11
11
|
removeEmptyValues,
|
|
12
12
|
removeMissingValues,
|
|
13
|
-
toDictionary
|
|
13
|
+
toDictionary,
|
|
14
14
|
} from './collectionUtils';
|
|
15
15
|
|
|
16
16
|
export const EMPTY_STRING = '';
|
|
@@ -29,7 +29,15 @@ Object.freeze(EMPTY_MAP);
|
|
|
29
29
|
const EMPTY_SET = new Set<any>();
|
|
30
30
|
Object.freeze(EMPTY_SET);
|
|
31
31
|
|
|
32
|
-
export const EMPTY_VALUES = [
|
|
32
|
+
export const EMPTY_VALUES = [
|
|
33
|
+
undefined,
|
|
34
|
+
null,
|
|
35
|
+
EMPTY_STRING,
|
|
36
|
+
EMPTY_ARRAY,
|
|
37
|
+
EMPTY_OBJECT,
|
|
38
|
+
EMPTY_MAP,
|
|
39
|
+
EMPTY_SET,
|
|
40
|
+
];
|
|
33
41
|
Object.freeze(EMPTY_VALUES);
|
|
34
42
|
|
|
35
43
|
const EMPTY_VALUES_MAP = toDictionary(EMPTY_VALUES, getValueDescriptionWithType);
|
|
@@ -58,7 +66,7 @@ export const NOT_EMPTY_VALUES = [
|
|
|
58
66
|
new Error(),
|
|
59
67
|
Number(123),
|
|
60
68
|
NOT_EMPTY_MAP,
|
|
61
|
-
NOT_EMPTY_SET
|
|
69
|
+
NOT_EMPTY_SET,
|
|
62
70
|
];
|
|
63
71
|
Object.freeze(NOT_EMPTY_VALUES);
|
|
64
72
|
|
|
@@ -73,12 +81,12 @@ Object.freeze(NOT_MISSING_VALUES_MAP);
|
|
|
73
81
|
|
|
74
82
|
describe('Collection Utility', () => {
|
|
75
83
|
describe('#isEmpty', () => {
|
|
76
|
-
EMPTY_VALUES.forEach(value => {
|
|
84
|
+
EMPTY_VALUES.forEach((value) => {
|
|
77
85
|
it(`should return \`true\` for ${getValueDescriptionWithType(value)}`, () => {
|
|
78
86
|
assert.isTrue(isEmpty(value));
|
|
79
87
|
});
|
|
80
88
|
});
|
|
81
|
-
NOT_EMPTY_VALUES.forEach(value => {
|
|
89
|
+
NOT_EMPTY_VALUES.forEach((value) => {
|
|
82
90
|
it(`should return \`false\` for ${getValueDescriptionWithType(value)}`, () => {
|
|
83
91
|
assert.isFalse(isEmpty(value));
|
|
84
92
|
});
|
package/src/collectionUtils.ts
CHANGED
|
@@ -33,7 +33,8 @@ export const getCartesianProduct = (...vectors: any[]): any[] =>
|
|
|
33
33
|
// Rationale: Lodash's `#isEmpty` only deals with collections...
|
|
34
34
|
export function isEmpty(value: any) {
|
|
35
35
|
// Easy cases:
|
|
36
|
-
let result: boolean | undefined =
|
|
36
|
+
let result: boolean | undefined =
|
|
37
|
+
value === undefined || value === null || value === '' || undefined;
|
|
37
38
|
|
|
38
39
|
const valueType = typeof value;
|
|
39
40
|
|
|
@@ -78,7 +79,7 @@ export function isCollection(value: any) {
|
|
|
78
79
|
* @see #isEmpty
|
|
79
80
|
*/
|
|
80
81
|
export function removeEmptyValues<C extends any | any[]>(collection: C): C {
|
|
81
|
-
return filter(collection, value => !isEmpty(value));
|
|
82
|
+
return filter(collection, (value) => !isEmpty(value));
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
/**
|
|
@@ -90,7 +91,7 @@ export function removeEmptyValues<C extends any | any[]>(collection: C): C {
|
|
|
90
91
|
* @param collection Collection from which to remove the missing values.
|
|
91
92
|
*/
|
|
92
93
|
export function removeMissingValues<C extends any | any[]>(collection: C): C {
|
|
93
|
-
return filter(collection, value => !_.isNil(value));
|
|
94
|
+
return filter(collection, (value) => !_.isNil(value));
|
|
94
95
|
}
|
|
95
96
|
|
|
96
97
|
/**
|
|
@@ -98,7 +99,10 @@ export function removeMissingValues<C extends any | any[]>(collection: C): C {
|
|
|
98
99
|
*
|
|
99
100
|
* @param collection Collection from which to filter the values.
|
|
100
101
|
*/
|
|
101
|
-
export function filter<C extends any | any[]>(
|
|
102
|
+
export function filter<C extends any | any[]>(
|
|
103
|
+
collection: C,
|
|
104
|
+
predicate: (value: any) => boolean,
|
|
105
|
+
): C {
|
|
102
106
|
let result: any = collection;
|
|
103
107
|
|
|
104
108
|
if (!_.isNil(predicate)) {
|
|
@@ -120,7 +124,7 @@ export function filter<C extends any | any[]>(collection: C, predicate: (value:
|
|
|
120
124
|
*/
|
|
121
125
|
export function toDictionary<T, C extends T[]>(
|
|
122
126
|
collection: C,
|
|
123
|
-
mapper: (value: T, index: number) => string = (value: T, index: number) => String(index)
|
|
127
|
+
mapper: (value: T, index: number) => string = (value: T, index: number) => String(index),
|
|
124
128
|
): { [key: string]: T } {
|
|
125
129
|
return _.reduce(
|
|
126
130
|
collection,
|
|
@@ -129,7 +133,7 @@ export function toDictionary<T, C extends T[]>(
|
|
|
129
133
|
accumulator[key] = value;
|
|
130
134
|
return accumulator;
|
|
131
135
|
},
|
|
132
|
-
{}
|
|
136
|
+
{},
|
|
133
137
|
);
|
|
134
138
|
}
|
|
135
139
|
|
|
@@ -175,7 +179,7 @@ export function isCompatible(model: any, expectedModel: any, keyFilter?: string[
|
|
|
175
179
|
const _expectedModel: any = {};
|
|
176
180
|
const compatibilityRules: CompatibilityRuleSet = {};
|
|
177
181
|
|
|
178
|
-
let isCompatibleRulesEmpty
|
|
182
|
+
let isCompatibleRulesEmpty = true;
|
|
179
183
|
_.forEach(expectedModel, (value, key) => {
|
|
180
184
|
if (isEmpty(keyFilter) || (keyFilter && keyFilter.indexOf(key) > -1)) {
|
|
181
185
|
if (typeof value !== 'function') {
|
package/src/config/constants.ts
CHANGED
|
@@ -13,7 +13,7 @@ export class GlobalConstants {
|
|
|
13
13
|
return {
|
|
14
14
|
API: '/api',
|
|
15
15
|
DOCUMENTATION: '/documentation',
|
|
16
|
-
DIAGNOSTICS: '/diagnostics'
|
|
16
|
+
DIAGNOSTICS: '/diagnostics',
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -35,7 +35,7 @@ export class GlobalConstants {
|
|
|
35
35
|
/**
|
|
36
36
|
* "production" seems to be the standard Node label, not "prod".
|
|
37
37
|
*/
|
|
38
|
-
PROD: 'production'
|
|
38
|
+
PROD: 'production',
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
41
|
|
|
@@ -57,9 +57,9 @@ export class GlobalConstants {
|
|
|
57
57
|
NOT_IMPLEMENTED: 'notImplemented',
|
|
58
58
|
UNAUTHORIZED: 'unauthorized',
|
|
59
59
|
UNPROCESSABLE_ENTITY: 'unprocessableEntity',
|
|
60
|
-
FORBIDDEN: 'forbidden'
|
|
61
|
-
}
|
|
62
|
-
}
|
|
60
|
+
FORBIDDEN: 'forbidden',
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
63
|
};
|
|
64
64
|
}
|
|
65
65
|
|
|
@@ -76,7 +76,7 @@ export class GlobalConstants {
|
|
|
76
76
|
*/
|
|
77
77
|
ENV_TYPE: 'NODE_ENV',
|
|
78
78
|
|
|
79
|
-
NODE_APP_INSTANCE: 'NODE_APP_INSTANCE'
|
|
79
|
+
NODE_APP_INSTANCE: 'NODE_APP_INSTANCE',
|
|
80
80
|
};
|
|
81
81
|
}
|
|
82
82
|
|
|
@@ -90,7 +90,7 @@ export class GlobalConstants {
|
|
|
90
90
|
* in an API.
|
|
91
91
|
* This allows local configs to be picked.
|
|
92
92
|
*/
|
|
93
|
-
TESTS: 'tests'
|
|
93
|
+
TESTS: 'tests',
|
|
94
94
|
};
|
|
95
95
|
}
|
|
96
96
|
|
|
@@ -102,4 +102,4 @@ export class GlobalConstants {
|
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
export
|
|
105
|
+
export const globalConstants: GlobalConstants = new GlobalConstants();
|
package/src/dateUtils.test.ts
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
ISO_DATE_PATTERN,
|
|
17
17
|
isValidIso8601Date,
|
|
18
18
|
parseDate,
|
|
19
|
-
startOfDay
|
|
19
|
+
startOfDay,
|
|
20
20
|
} from './dateUtils';
|
|
21
21
|
|
|
22
22
|
const VALID_DATE_UTC_REPRESENTATION = '2018-07-31T12:34:56.789Z';
|
|
@@ -40,10 +40,10 @@ describe('Date Utility', () => {
|
|
|
40
40
|
});
|
|
41
41
|
|
|
42
42
|
describe('#isDateCompatible', () => {
|
|
43
|
-
const dateRepr
|
|
43
|
+
const dateRepr = '2018-09-12T21:45:12.243Z';
|
|
44
44
|
const dateValues = [dateRepr, new Date(dateRepr), moment(dateRepr)];
|
|
45
45
|
|
|
46
|
-
getCartesianProduct(dateValues, dateValues).forEach(dateParameters => {
|
|
46
|
+
getCartesianProduct(dateValues, dateValues).forEach((dateParameters) => {
|
|
47
47
|
const parameter1 = dateParameters[0];
|
|
48
48
|
const parameter2 = dateParameters[1];
|
|
49
49
|
const parameter1TypeName = parameter1.constructor.name;
|
|
@@ -59,13 +59,13 @@ describe('Date Utility', () => {
|
|
|
59
59
|
const date2Repr = '2018-09-12T21:45:12.243Z';
|
|
60
60
|
const date2Values = [date2Repr, new Date(date2Repr), moment(date2Repr)];
|
|
61
61
|
|
|
62
|
-
getCartesianProduct(date1Values, date2Values).forEach(dateRangeParameter => {
|
|
62
|
+
getCartesianProduct(date1Values, date2Values).forEach((dateRangeParameter) => {
|
|
63
63
|
const dateRangeLowBoundary = dateRangeParameter[0];
|
|
64
64
|
const dateRangeHighBoundary = dateRangeParameter[1];
|
|
65
65
|
const dateRangeLowBoundaryTypeName = dateRangeLowBoundary.constructor.name;
|
|
66
66
|
const dateRangeHighBoundaryTypeName = dateRangeHighBoundary.constructor.name;
|
|
67
67
|
|
|
68
|
-
dateValues.forEach(dateValue => {
|
|
68
|
+
dateValues.forEach((dateValue) => {
|
|
69
69
|
const dateValueParameterType = dateValue.constructor.name;
|
|
70
70
|
|
|
71
71
|
it(`should support \`${dateValueParameterType}\` & [\`${dateRangeLowBoundaryTypeName}\`:\`${dateRangeHighBoundaryTypeName}\`] parameters`, () => {
|
|
@@ -75,18 +75,33 @@ describe('Date Utility', () => {
|
|
|
75
75
|
});
|
|
76
76
|
});
|
|
77
77
|
|
|
78
|
-
const INVALID_DATE_VALUES = [
|
|
79
|
-
|
|
78
|
+
const INVALID_DATE_VALUES = [
|
|
79
|
+
undefined,
|
|
80
|
+
null,
|
|
81
|
+
true,
|
|
82
|
+
false,
|
|
83
|
+
123,
|
|
84
|
+
NaN,
|
|
85
|
+
'pouet',
|
|
86
|
+
_.noop,
|
|
87
|
+
/^$/,
|
|
88
|
+
{},
|
|
89
|
+
[],
|
|
90
|
+
];
|
|
91
|
+
const VALID_DATE_VALUES = [
|
|
92
|
+
new Date(2018, 7, 31, 23, 59, 59, 999),
|
|
93
|
+
new Date(2019, 0, 1, 0, 0, 0, 0),
|
|
94
|
+
];
|
|
80
95
|
|
|
81
96
|
describe('#isDate', () => {
|
|
82
|
-
INVALID_DATE_VALUES.forEach(value => {
|
|
97
|
+
INVALID_DATE_VALUES.forEach((value) => {
|
|
83
98
|
const valueDescription = getValueDescriptionWithType(value);
|
|
84
99
|
it(`should return \`false\` for ${valueDescription}`, () => {
|
|
85
100
|
assert.isFalse(utils.isValidDate(value));
|
|
86
101
|
});
|
|
87
102
|
});
|
|
88
103
|
|
|
89
|
-
VALID_DATE_VALUES.forEach(value => {
|
|
104
|
+
VALID_DATE_VALUES.forEach((value) => {
|
|
90
105
|
const valueDescription = getValueDescription(value);
|
|
91
106
|
it(`should return \`true\` for ${valueDescription}`, () => {
|
|
92
107
|
assert.isTrue(utils.isValidDate(value));
|
|
@@ -97,22 +112,24 @@ describe('Date Utility', () => {
|
|
|
97
112
|
const INVALID_DATE_RANGE_VALUES = getCartesianProduct(INVALID_DATE_VALUES, INVALID_DATE_VALUES);
|
|
98
113
|
const VALID_DATE_RANGE_VALUES = getCartesianProduct(VALID_DATE_VALUES, VALID_DATE_VALUES);
|
|
99
114
|
// Append open ranges in valid date range values:
|
|
100
|
-
VALID_DATE_VALUES.forEach(date => {
|
|
115
|
+
VALID_DATE_VALUES.forEach((date) => {
|
|
101
116
|
VALID_DATE_RANGE_VALUES.push([date, null]);
|
|
102
117
|
VALID_DATE_RANGE_VALUES.push([null, date]);
|
|
103
118
|
});
|
|
104
119
|
// Append 3-value items into the invalid date range values:
|
|
105
|
-
VALID_DATE_RANGE_VALUES.forEach(dateRange =>
|
|
120
|
+
VALID_DATE_RANGE_VALUES.forEach((dateRange) =>
|
|
121
|
+
INVALID_DATE_RANGE_VALUES.push(dateRange.concat(null)),
|
|
122
|
+
);
|
|
106
123
|
|
|
107
124
|
describe('#isDateRange', () => {
|
|
108
125
|
INVALID_DATE_RANGE_VALUES.forEach((value: any[]) => {
|
|
109
|
-
const valueDescription = value.map(item => getValueDescriptionWithType(item));
|
|
126
|
+
const valueDescription = value.map((item) => getValueDescriptionWithType(item));
|
|
110
127
|
it(`should return \`false\` for [${valueDescription}]`, () => {
|
|
111
128
|
assert.isFalse(isDateRange(value));
|
|
112
129
|
});
|
|
113
130
|
});
|
|
114
131
|
|
|
115
|
-
VALID_DATE_RANGE_VALUES.forEach(value => {
|
|
132
|
+
VALID_DATE_RANGE_VALUES.forEach((value) => {
|
|
116
133
|
const valueDescription = getValueDescription(value);
|
|
117
134
|
it(`should return \`true\` for ${valueDescription}`, () => {
|
|
118
135
|
assert.isTrue(isDateRange(value));
|
|
@@ -125,7 +142,7 @@ describe('Date Utility', () => {
|
|
|
125
142
|
const expectations = {
|
|
126
143
|
'2018-12-07T12:34:56.789': new Date(Date.UTC(2018, 11, 7, 12, 34, 56, 789)),
|
|
127
144
|
'20181207T123456.789': new Date(Date.UTC(2018, 11, 7, 12, 34, 56, 789)),
|
|
128
|
-
'2018-12-07': new Date(Date.UTC(2018, 11, 7, 0, 0, 0, 0))
|
|
145
|
+
'2018-12-07': new Date(Date.UTC(2018, 11, 7, 0, 0, 0, 0)),
|
|
129
146
|
};
|
|
130
147
|
_.forEach(expectations, (expectedResult, value) => {
|
|
131
148
|
const valueDescription = getValueDescription(value);
|
|
@@ -135,10 +152,10 @@ describe('Date Utility', () => {
|
|
|
135
152
|
});
|
|
136
153
|
|
|
137
154
|
const expectedlyFailingValues = [null, undefined, 'true', 'false', '???'];
|
|
138
|
-
expectedlyFailingValues.forEach(value => {
|
|
155
|
+
expectedlyFailingValues.forEach((value) => {
|
|
139
156
|
const valueDescription = getValueDescription(value);
|
|
140
157
|
it(`should fail with ${valueDescription}`, () => {
|
|
141
|
-
let failed
|
|
158
|
+
let failed = false;
|
|
142
159
|
try {
|
|
143
160
|
getSafeDate(value);
|
|
144
161
|
} catch (error) {
|
|
@@ -170,7 +187,10 @@ describe('Date Utility', () => {
|
|
|
170
187
|
describe('#parseDate', () => {
|
|
171
188
|
it('should parse date representations properly', () => {
|
|
172
189
|
assert.deepStrictEqual(parseDate(VALID_DATE_UTC_REPRESENTATION), VALID_DATE);
|
|
173
|
-
assert.deepStrictEqual(
|
|
190
|
+
assert.deepStrictEqual(
|
|
191
|
+
parseDate(VALID_DATE_UTC_REPRESENTATION, DEFAULT_DATE_FORMAT),
|
|
192
|
+
VALID_DATE,
|
|
193
|
+
);
|
|
174
194
|
|
|
175
195
|
const FUNKY_FORMAT = 'YYYY/MM/DD@HH:mm:ss.SSS';
|
|
176
196
|
let result: Date = parseDate('2018/07/31@12:34:56.789', [FUNKY_FORMAT]);
|
|
@@ -199,7 +219,7 @@ describe('Date Utility', () => {
|
|
|
199
219
|
'20180731 123456,789-1011': ['20180731', '', '123456', '', '789', '-1011'],
|
|
200
220
|
'20180731T123456,789+10:11': ['20180731', '', '123456', '', '789', '+10:11'],
|
|
201
221
|
'20180731 12:34:56,789-1011': ['20180731', '', '12:34:56', ':', '789', '-1011'],
|
|
202
|
-
'2018-07-31 12:34:56.789Z': ['2018-07-31', '-', '12:34:56', ':', '789', 'Z']
|
|
222
|
+
'2018-07-31 12:34:56.789Z': ['2018-07-31', '-', '12:34:56', ':', '789', 'Z'],
|
|
203
223
|
};
|
|
204
224
|
_.forEach(expectations, (expectation, value) => {
|
|
205
225
|
it(`should match « ${value} »`, () => {
|
|
@@ -229,9 +249,9 @@ describe('Date Utility', () => {
|
|
|
229
249
|
'20180731T123456.7891011', // missing time-offset separator
|
|
230
250
|
'2018-07-31 01:23:45.678+1', // bad offset format
|
|
231
251
|
'2018-07-31 12:34:56.789+1011Z', // bad offset format
|
|
232
|
-
'2018-07-31 01:23:45.678+2400' // offset overflow
|
|
252
|
+
'2018-07-31 01:23:45.678+2400', // offset overflow
|
|
233
253
|
];
|
|
234
|
-
invalidDateValues.forEach(value => {
|
|
254
|
+
invalidDateValues.forEach((value) => {
|
|
235
255
|
it(`should *NOT* match « ${value} »`, () => {
|
|
236
256
|
assert.isNull(ISO_DATE_PATTERN.exec(value));
|
|
237
257
|
assert.isFalse(isValidIso8601Date(value));
|
package/src/dateUtils.ts
CHANGED
|
@@ -16,7 +16,7 @@ export function isDateEqual(value: DateDefinition, expectedDate: DateDefinition)
|
|
|
16
16
|
export function isDateBetween(
|
|
17
17
|
value: DateDefinition,
|
|
18
18
|
expectedDate: DateRangeDefinition,
|
|
19
|
-
inclusivity: '()' | '[)' | '(]' | '[]' = '[]'
|
|
19
|
+
inclusivity: '()' | '[)' | '(]' | '[]' = '[]',
|
|
20
20
|
) {
|
|
21
21
|
const _moment: Moment = moment(value);
|
|
22
22
|
const from = expectedDate[0];
|
|
@@ -53,8 +53,8 @@ export function isDateRange(value: any[]): boolean {
|
|
|
53
53
|
let result: boolean = !!value && value.length === 2;
|
|
54
54
|
|
|
55
55
|
if (result) {
|
|
56
|
-
let dateItemCount
|
|
57
|
-
let otherItemCount
|
|
56
|
+
let dateItemCount = 0;
|
|
57
|
+
let otherItemCount = 0;
|
|
58
58
|
|
|
59
59
|
for (const item of value) {
|
|
60
60
|
if (utils.isValidDate(item)) {
|
|
@@ -97,8 +97,12 @@ export function getSafeDate(dateDefinition: DateDefinition): Date {
|
|
|
97
97
|
* @see `#getSafeDate`
|
|
98
98
|
*/
|
|
99
99
|
export function getSafeDateRange(dateRangeDefinition: DateRangeDefinition): [Date, Date] {
|
|
100
|
-
const lowBoundary = dateRangeDefinition[0]
|
|
101
|
-
|
|
100
|
+
const lowBoundary = dateRangeDefinition[0]
|
|
101
|
+
? getSafeDate(dateRangeDefinition[0])
|
|
102
|
+
: (dateRangeDefinition[0] as any);
|
|
103
|
+
const highBoundary = dateRangeDefinition[1]
|
|
104
|
+
? getSafeDate(dateRangeDefinition[1])
|
|
105
|
+
: (dateRangeDefinition[1] as any);
|
|
102
106
|
|
|
103
107
|
return [lowBoundary, highBoundary];
|
|
104
108
|
}
|
|
@@ -127,7 +131,7 @@ export type TimeUnitSymbol = 'ms' | 's' | 'm' | 'h' | 'd' | 'w';
|
|
|
127
131
|
export function getDateRangeAround(
|
|
128
132
|
value: DateDefinition,
|
|
129
133
|
marginValue: number,
|
|
130
|
-
marginUnit: TimeUnitSymbol
|
|
134
|
+
marginUnit: TimeUnitSymbol,
|
|
131
135
|
): DateRangeDefinition {
|
|
132
136
|
const _moment = moment(value);
|
|
133
137
|
return [_moment.subtract(marginValue, marginUnit), _moment.add(marginValue, marginUnit)];
|
|
@@ -137,7 +141,8 @@ export function getDateRangeAround(
|
|
|
137
141
|
* Pattern matching most ISO 8601 date representations (including time), and which can be used for any kind of validation.
|
|
138
142
|
* @example `2018-07-31T12:34:56.789+10:11`
|
|
139
143
|
*/
|
|
140
|
-
export const ISO_DATE_PATTERN
|
|
144
|
+
export const ISO_DATE_PATTERN =
|
|
145
|
+
/^(\d{4}(-?)(?:0\d|1[0-2])\2?(?:[0-2]\d|3[0-1]))(?:[T ]([0-2][0-3](:?)[0-5]\d\4[0-5]\d)(?:[.,](\d{3}))?([+-](?:[01]\d(?::?[0-5]\d)?)|Z)?)?$/;
|
|
141
146
|
|
|
142
147
|
/**
|
|
143
148
|
* Tells whether the provided date representation is valid as per ISO 8601.
|
|
@@ -145,7 +150,7 @@ export const ISO_DATE_PATTERN: RegExp = /^(\d{4}(-?)(?:0\d|1[0-2])\2?(?:[0-2]\d|
|
|
|
145
150
|
* @see `ISO_DATE_PATTERN`
|
|
146
151
|
*/
|
|
147
152
|
export function isValidIso8601Date(representation: string): boolean {
|
|
148
|
-
let valid
|
|
153
|
+
let valid = false;
|
|
149
154
|
|
|
150
155
|
if (representation !== undefined && representation !== null) {
|
|
151
156
|
valid = ISO_DATE_PATTERN.test(representation);
|
|
@@ -167,7 +172,10 @@ export const DEFAULT_DATE_FORMAT = 'YYYY-MM-DDTHH:mm:ss.SSSZ';
|
|
|
167
172
|
* Parses the given date representation using the provided format (or the default ISO format).
|
|
168
173
|
* @see `#formatDate`
|
|
169
174
|
*/
|
|
170
|
-
export function parseDate(
|
|
175
|
+
export function parseDate(
|
|
176
|
+
representation: string,
|
|
177
|
+
format: string | string[] = DEFAULT_DATE_FORMAT,
|
|
178
|
+
): Date {
|
|
171
179
|
const formats: string[] = format instanceof Array ? format : [format];
|
|
172
180
|
return moment.utc(representation, formats).toDate();
|
|
173
181
|
}
|
|
@@ -219,7 +227,10 @@ export function formatUtcDate(date: DateDefinition, format: string = DEFAULT_DAT
|
|
|
219
227
|
* on how the server is configured. This is why a timezone must be
|
|
220
228
|
* specified here.
|
|
221
229
|
*/
|
|
222
|
-
export function startOfDay(
|
|
230
|
+
export function startOfDay(
|
|
231
|
+
isoDate: Date | string,
|
|
232
|
+
timezone: string | Zone = 'America/Montreal',
|
|
233
|
+
): Date {
|
|
223
234
|
if (_.isNil(isoDate)) {
|
|
224
235
|
return isoDate;
|
|
225
236
|
}
|
|
@@ -247,7 +258,10 @@ export function startOfDay(isoDate: Date | string, timezone: string | Zone = 'Am
|
|
|
247
258
|
* information.
|
|
248
259
|
*
|
|
249
260
|
*/
|
|
250
|
-
export function endOfDay(
|
|
261
|
+
export function endOfDay(
|
|
262
|
+
isoDate: Date | string,
|
|
263
|
+
timezone: string | Zone = 'America/Montreal',
|
|
264
|
+
): Date {
|
|
251
265
|
if (_.isNil(isoDate)) {
|
|
252
266
|
return isoDate;
|
|
253
267
|
}
|
package/src/logLevel.ts
CHANGED
package/src/orderBy.ts
CHANGED
package/src/pagination.test.ts
CHANGED
|
@@ -16,15 +16,15 @@ describe('pagination object', () => {
|
|
|
16
16
|
{ name: 'seven', value: 7 },
|
|
17
17
|
{ name: 'eight', value: 8 },
|
|
18
18
|
{ name: 'nine', value: 9 },
|
|
19
|
-
{ name: 'ten', value: 10 }
|
|
19
|
+
{ name: 'ten', value: 10 },
|
|
20
20
|
];
|
|
21
21
|
const result: IPaginatedResult<any> = {
|
|
22
22
|
items: numberlist.slice(0, 3),
|
|
23
23
|
paging: {
|
|
24
24
|
limit: 3,
|
|
25
25
|
offset: 0,
|
|
26
|
-
totalCount: numberlist.length
|
|
27
|
-
}
|
|
26
|
+
totalCount: numberlist.length,
|
|
27
|
+
},
|
|
28
28
|
};
|
|
29
29
|
|
|
30
30
|
assert.isOk(result);
|
package/src/pagination.ts
CHANGED
|
@@ -14,7 +14,7 @@ export interface IPaginatedResult<T> {
|
|
|
14
14
|
/**
|
|
15
15
|
* IPaginatedResult Type Guard
|
|
16
16
|
*/
|
|
17
|
-
export
|
|
17
|
+
export const isPaginatedResult = (obj: any): obj is IPaginatedResult<any> => {
|
|
18
18
|
return (
|
|
19
19
|
obj &&
|
|
20
20
|
'paging' in obj &&
|
package/src/stringUtils.test.ts
CHANGED
|
@@ -39,16 +39,24 @@ describe('String Utility', () => {
|
|
|
39
39
|
assert.strictEqual(deDuplicateChars('a b', ' ', '_'), 'a_b');
|
|
40
40
|
assert.strictEqual(
|
|
41
41
|
deDuplicateChars(' \r\n \t a \r\n \t \n \t b \r\n \t ', ' \t\r\n', ' '),
|
|
42
|
-
' a b '
|
|
42
|
+
' a b ',
|
|
43
|
+
);
|
|
44
|
+
assert.strictEqual(
|
|
45
|
+
deDuplicateChars(' \r\n \t a \r\n \t \n \t b \r\n \t ', ' \t\r\n', ''),
|
|
46
|
+
'ab',
|
|
43
47
|
);
|
|
44
|
-
assert.strictEqual(deDuplicateChars(' \r\n \t a \r\n \t \n \t b \r\n \t ', ' \t\r\n', ''), 'ab');
|
|
45
48
|
});
|
|
46
49
|
|
|
47
50
|
it('With trim', () => {
|
|
48
51
|
assert.strictEqual(deDuplicateChars(' a b ', ' ', ' ', true), 'a b');
|
|
49
52
|
assert.strictEqual(
|
|
50
|
-
deDuplicateChars(
|
|
51
|
-
|
|
53
|
+
deDuplicateChars(
|
|
54
|
+
' \r\n \t a \r\n \t \n \t b \r\n \t ',
|
|
55
|
+
' \t\r\n',
|
|
56
|
+
' ',
|
|
57
|
+
true,
|
|
58
|
+
),
|
|
59
|
+
'a b',
|
|
52
60
|
);
|
|
53
61
|
});
|
|
54
62
|
});
|
|
@@ -62,8 +70,10 @@ describe('String Utility', () => {
|
|
|
62
70
|
assert.strictEqual(trimAll(' '), '');
|
|
63
71
|
assert.strictEqual(trimAll(' \r\n \r \t \n \r\t \t'), '');
|
|
64
72
|
assert.strictEqual(
|
|
65
|
-
trimAll(
|
|
66
|
-
|
|
73
|
+
trimAll(
|
|
74
|
+
' \r\n \r \t \n \r\t \t a \r\n \r \t \n \r\t \tb \r\n \r \t \n \r\t \t',
|
|
75
|
+
),
|
|
76
|
+
'a b',
|
|
67
77
|
);
|
|
68
78
|
});
|
|
69
79
|
});
|
package/src/stringUtils.ts
CHANGED
|
@@ -67,9 +67,14 @@ export function deDuplicateChars(
|
|
|
67
67
|
value: string,
|
|
68
68
|
continuousCharsToReplace: string,
|
|
69
69
|
replacement: string,
|
|
70
|
-
trimStartEnd
|
|
70
|
+
trimStartEnd = false,
|
|
71
71
|
): string {
|
|
72
|
-
if (
|
|
72
|
+
if (
|
|
73
|
+
_.isNil(value) ||
|
|
74
|
+
_.isNil(continuousCharsToReplace) ||
|
|
75
|
+
continuousCharsToReplace === '' ||
|
|
76
|
+
_.isNil(replacement)
|
|
77
|
+
) {
|
|
73
78
|
return value;
|
|
74
79
|
}
|
|
75
80
|
|
package/src/timer.test.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { utils } from './utils';
|
|
|
6
6
|
// Timer object tests
|
|
7
7
|
// ==========================================
|
|
8
8
|
describe('Timer object', () => {
|
|
9
|
-
it('Milliseconds', async function() {
|
|
9
|
+
it('Milliseconds', async function () {
|
|
10
10
|
this.timeout(4000);
|
|
11
11
|
|
|
12
12
|
const timer = new Timer();
|
|
@@ -27,7 +27,7 @@ describe('Timer object', () => {
|
|
|
27
27
|
assert.isTrue(milliSecs > 2000, `was "${milliSecs}"`);
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
-
it('Default format', async function() {
|
|
30
|
+
it('Default format', async function () {
|
|
31
31
|
this.timeout(4000);
|
|
32
32
|
|
|
33
33
|
const timer = new Timer();
|
|
@@ -43,7 +43,7 @@ describe('Timer object', () => {
|
|
|
43
43
|
assert.isTrue(elapsed.startsWith('00:00:02.'), `was "${elapsed}"`);
|
|
44
44
|
});
|
|
45
45
|
|
|
46
|
-
it('Custom format', async function() {
|
|
46
|
+
it('Custom format', async function () {
|
|
47
47
|
this.timeout(4000);
|
|
48
48
|
|
|
49
49
|
const timer = new Timer();
|
package/src/timer.ts
CHANGED
|
@@ -42,7 +42,7 @@ export class Timer {
|
|
|
42
42
|
* documentation to see how to define a custom format :
|
|
43
43
|
* https://momentjs.com/docs/#/displaying/format/
|
|
44
44
|
*/
|
|
45
|
-
public toString(format
|
|
45
|
+
public toString(format = 'HH:mm:ss.SSS'): string {
|
|
46
46
|
const millisecs = this.getMillisecondsElapsed();
|
|
47
47
|
return moment.utc(millisecs).format(format);
|
|
48
48
|
}
|