@evolis/evolis-library 1.1.0 → 1.2.1

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/EvoArray.js ADDED
@@ -0,0 +1,113 @@
1
+ /**
2
+ * @module EvoArray
3
+ * @author EmpireDemocratiqueDuPoulpe
4
+ * @version 1.2.0
5
+ * @license MIT
6
+ */
7
+ import EvoObject from "./EvoObject.js";
8
+ import EvoMisc from "./EvoMisc.js";
9
+
10
+ /*****************************************************
11
+ * Checkers
12
+ *****************************************************/
13
+
14
+ /**
15
+ * @function isArray
16
+ *
17
+ * @param {any} value - The value to test
18
+ * @returns {boolean} Return true if the value is an array
19
+ */
20
+ function isArray(value) {
21
+ return Array.isArray(value);
22
+ }
23
+
24
+ /**
25
+ * @function isDeepEqual
26
+ *
27
+ * @param {Array} array1 - First array
28
+ * @param {Array} array2 - Second array
29
+ * @param {string|null} [sortBy] - Property name used to sort objects in the array. Two identical arrays in different order will not be equal
30
+ * @returns {Boolean} Are the two array deeply equal ?
31
+ *
32
+ * @example
33
+ * EvoArray.isDeepEqual([{id: 1}, {id: 2}], [{id: 1}, {id: 2}]) // return true
34
+ * EvoArray.isDeepEqual([{id: 1}, {id: 2}], [{id: 2}, {id: 1}]) // return false
35
+ * EvoArray.isDeepEqual([{id: 1}, {id: 2}], [{id: 2}, {id: 1}], "id") // return true
36
+ */
37
+ function isDeepEqual(array1, array2, sortBy = null) {
38
+ const arr1 = [...array1], arr2 = [...array2];
39
+ const sort = (a, b) => {
40
+ if (EvoMisc.isDefined(a) && EvoMisc.isDefined(b)) {
41
+ return a[sortBy] > b[sortBy] ? 1 : -1;
42
+ } else {
43
+ return !EvoMisc.isDefined(a) ? -1 : 1;
44
+ }
45
+ };
46
+
47
+ if (sortBy) {
48
+ arr1.sort(sort);
49
+ arr2.sort(sort);
50
+ }
51
+
52
+ return arr1.every((value, index) => EvoObject.isDeepEqual(arr1[index], arr2[index]));
53
+ }
54
+
55
+ /*****************************************************
56
+ * Converters
57
+ *****************************************************/
58
+
59
+ /* ---- Array ----------------------------------- */
60
+ /**
61
+ * @function toSerialComma
62
+ *
63
+ * @param {Array<*>} array - The array to convert
64
+ * @returns {string} A string formatted as a serial comma
65
+ *
66
+ * @example
67
+ * EvoArray.toSerialComma([]) // return ""
68
+ * EvoArray.toSerialComma(["un", 2, "trois"]) // return "un, 2 et trois"
69
+ */
70
+ function toSerialComma(array) {
71
+ return isArray(array) && array.length > 0
72
+ ? array.length === 1
73
+ ? array[0]
74
+ : `${array.slice(0, -1).join(", ")} et ${array.slice(-1)}`
75
+ : "";
76
+ }
77
+
78
+ /*****************************************************
79
+ * Functions
80
+ *****************************************************/
81
+
82
+ /**
83
+ * @function shuffle
84
+ *
85
+ * @param {Array<*>} array - The array to shuffle
86
+ * @returns {Array<*>} The shuffled array
87
+ *
88
+ * @example
89
+ * EvoArray.shuffle([1, 2, 3]) // return [2, 1, 3] or [3, 2, 1] or [1, 3, 2] or ...
90
+ */
91
+ function shuffle(array) {
92
+ let arr = [...array], length = array.length, element, cache;
93
+
94
+ while (length) {
95
+ element = Math.floor(Math.random() * length--);
96
+
97
+ cache = arr[length];
98
+ arr[length] = arr[element];
99
+ arr[element] = cache;
100
+ }
101
+
102
+ return arr;
103
+ }
104
+
105
+ /*****************************************************
106
+ * Export
107
+ *****************************************************/
108
+
109
+ export default {
110
+ isArray, isDeepEqual, // Checkers
111
+ toSerialComma, // Converters
112
+ shuffle // Functions
113
+ };
package/EvoDate.js ADDED
@@ -0,0 +1,192 @@
1
+ /**
2
+ * @module EvoDate
3
+ * @author EmpireDemocratiqueDuPoulpe
4
+ * @version 1.2.0
5
+ * @license MIT
6
+ */
7
+ import EvoString from "./EvoString.js";
8
+ import EvoMisc from "./EvoMisc.js";
9
+
10
+ /*****************************************************
11
+ * Checkers
12
+ *****************************************************/
13
+
14
+ /**
15
+ * @function isDate
16
+ *
17
+ * @param {any} value - The value to test
18
+ * @returns {boolean} Return true if the value is a valid date
19
+ */
20
+ function isDate(value) {
21
+ return Object.prototype.toString.call(value) === "[object Date]" && !!value.getDate();
22
+ }
23
+
24
+ /**
25
+ * @function isMySQLDate
26
+ *
27
+ * @param {any} value - The value to test
28
+ * @returns {boolean} Return true if the value is a string with the valid MySQL date format (yyyy-mm-dd)
29
+ */
30
+ function isMySQLDate(value) {
31
+ return EvoString.isString(value) && !EvoString.isBlank(value) && /^\d{4}-\d{1,2}-\d{1,2}$/.test(value);
32
+ }
33
+
34
+ /*****************************************************
35
+ * Converters
36
+ *****************************************************/
37
+
38
+ /**
39
+ * @function toDate
40
+ *
41
+ * @param {*} d - The thing to convert
42
+ * @returns {Date|NaN} A date object or NaN if it's not convertible.
43
+ *
44
+ * @example
45
+ * EvoDate.toDate(null) // return NaN
46
+ * EvoDate.toDate(new Date().toISOString()) // return a Date object
47
+ */
48
+ function toDate(d) {
49
+ return (
50
+ !EvoMisc.isDefined(d) ? NaN :
51
+ d.constructor === Date ? d :
52
+ d.constructor === Array ? new Date(d[0],d[1],d[2]) :
53
+ d.constructor === Number ? new Date(d) :
54
+ d.constructor === String ? new Date(d) :
55
+ typeof d === "object" ? new Date(d.year, d.month, (d.date || d.day), d.hours, d.minutes, d.seconds) :
56
+ NaN
57
+ );
58
+ }
59
+
60
+ /**
61
+ * @function toString
62
+ *
63
+ * @param {Date} date - The date to convert
64
+ * @param {Boolean} [withTime=true] - Include time in the result
65
+ * @param {string} [locale="fr-FR"] - The locale used in the conversion. It may changed the returned string format
66
+ * @returns {string} A date formatted like "dd/MM/yyyy [hh:mm:ss]"
67
+ *
68
+ * @example
69
+ * EvoDate.toString(new Date()) // return "13/07/2021, 14:59:48"
70
+ */
71
+ function toString(date, withTime = true, locale = "fr-FR") {
72
+ return withTime ? date.toLocaleString(locale) : date.toLocaleDateString(locale);
73
+ }
74
+
75
+ /**
76
+ * @function toTimeString
77
+ *
78
+ * @param {Date} date - The date to convert
79
+ * @param {string} [locale="fr-FR"] - The locale used in the conversion. It may changed the returned string format
80
+ * @returns {string} A date formatted like "hh:mm:ss"
81
+ *
82
+ * @example
83
+ * EvoDate.toTimeString(new Date()) // return "14:59:48"
84
+ */
85
+ function toTimeString(date, locale = "fr-FR") {
86
+ return date.toLocaleTimeString(locale);
87
+ }
88
+
89
+ /**
90
+ * @function toFieldString
91
+ *
92
+ * @param {Date} date - The date to convert
93
+ * @returns {string} A date formatted like "yyyy-MM-dd"
94
+ *
95
+ * @example
96
+ * EvoDate.toFieldString(new Date()) // return "2021-07-13"
97
+ */
98
+ function toFieldString(date) {
99
+ return isDate(date)
100
+ ? `${date.getFullYear()}-${EvoMisc.padLeft(date.getMonth() + 1)}-${EvoMisc.padLeft(date.getDate())}`
101
+ : null;
102
+ }
103
+
104
+ /**
105
+ * @function timeStrToDate
106
+ *
107
+ * @param {string} time - The time to convert
108
+ * @param {string} [format="hh:mm"] - The format used for conversion
109
+ * @returns {Date} A date object filled with the time string provided
110
+ * @throws {Error} In case of invalid format/time string
111
+ *
112
+ * @example
113
+ * EvoDate.timeStrToDate("12:57") // works
114
+ * EvoDate.timeStrToDate("9:21") // works
115
+ * EvoDate.timeStrToDate("9::21") // error
116
+ */
117
+ function timeStrToDate(time, format = "hh:mm") {
118
+ if (!EvoString.isString(time) || !EvoString.isString(format)) return null;
119
+
120
+ const now = new Date();
121
+ const timeSplit = time.split(":");
122
+ const formatSplit = format.split(":");
123
+
124
+ formatSplit.forEach((f, index) => {
125
+ if (index >= timeSplit.length) throw Error("EvoMisc (timeStrToDate): Supplied format is invalid.");
126
+ const t = parseInt(timeSplit[index], 10);
127
+
128
+ if (f === "hh") now.setHours(t);
129
+ else if (f === "mm") now.setMinutes(t);
130
+ else if (f === "ss") now.setSeconds(t);
131
+ });
132
+
133
+ return now;
134
+ }
135
+
136
+ /**
137
+ * @function secondsToReadable
138
+ *
139
+ * @param {number} seconds - Seconds to convert
140
+ * @returns {string} The converted seconds and epoch
141
+ *
142
+ * @example
143
+ * EvoDate.secondsToReadable(120) // return "2 minutes"
144
+ * EvoDate.secondsToReadable(3600) // return "1 heure"
145
+ */
146
+ function secondsToReadable(seconds) {
147
+ const epochs = { "années": 31536000, "mois": 2592000, "jours": 86400, "heures": 3600, "minutes": 60, "secondes": 1 };
148
+ const singular = { "années": "ans", "mois": "mois", "jours": "jour", "heures": "heure", "minutes": "minute", "secondes": "seconde" };
149
+ const epoch = Object.entries(epochs).filter(([, value]) => seconds >= value).shift();
150
+ const readable = {
151
+ epoch: epoch[0],
152
+ interval: Math.trunc(seconds / epoch[1])
153
+ };
154
+
155
+ if (readable.interval === 1) {
156
+ readable.epoch = singular[readable.epoch];
157
+ }
158
+
159
+ return `${readable.interval} ${readable.epoch}`;
160
+ }
161
+
162
+ /*****************************************************
163
+ * Functions
164
+ *****************************************************/
165
+
166
+ /**
167
+ * @function dayDiff
168
+ *
169
+ * @param {Date} start - Start date
170
+ * @param {Date} end - End date
171
+ * @returns {Number} How many days between these two dates
172
+ *
173
+ * @example
174
+ * EvoDate.dayDiff(new Date("07/14/2021"), new Date("07/18/2021")) // return 4
175
+ * EvoDate.dayDiff(new Date("07/14/2021"), new Date("07/01/2021")) // return -13
176
+ */
177
+ function dayDiff(start, end) {
178
+ start.setHours(0, 0, 0, 0);
179
+ end.setHours(0, 0, 0, 0);
180
+
181
+ return Math.round((end.getTime() - start.getTime()) / (1000 * 3600 * 24));
182
+ }
183
+
184
+ /*****************************************************
185
+ * Export
186
+ *****************************************************/
187
+
188
+ export default {
189
+ isDate, isMySQLDate, // Checkers
190
+ toDate, toString, toTimeString, toFieldString, timeStrToDate, secondsToReadable, // Converters
191
+ dayDiff // Functions
192
+ };
package/EvoMisc.js ADDED
@@ -0,0 +1,148 @@
1
+ /**
2
+ * @module EvoMisc
3
+ * @author EmpireDemocratiqueDuPoulpe
4
+ * @version 1.2.0
5
+ * @license MIT
6
+ */
7
+ import EvoArray from "./EvoArray.js";
8
+
9
+ /*****************************************************
10
+ * Checkers
11
+ *****************************************************/
12
+
13
+ /**
14
+ * @function isDefined
15
+ *
16
+ * @param {*} value - The value to test
17
+ * @returns {Boolean} Return true if the value is not undefined or null
18
+ *
19
+ * @example
20
+ * EvoMisc.isDefined("") // return true
21
+ * EvoMisc.isDefined(65) // return true
22
+ * EvoMisc.isDefined(false) // return true
23
+ * EvoMisc.isDefined(null) // return false
24
+ * EvoMisc.isDefined(undefined) // return false
25
+ */
26
+ function isDefined(value) {
27
+ return value !== undefined && value !== null;
28
+ }
29
+
30
+ /**
31
+ * @function isEmail
32
+ *
33
+ * @param {any} value - The value to test
34
+ * @returns {boolean} Return true if the value is a string containing a valid email address
35
+ */
36
+ function isEmail(value) {
37
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
38
+ }
39
+
40
+ /**
41
+ * @typedef {Object} PasswordRules
42
+ *
43
+ * @property {object} mustContain - What type of character the password must contain
44
+ * @property {boolean} [mustContain.lowerCase] - Must contain at least one lower cased character
45
+ * @property {boolean} [mustContain.upperCase] - Must contain at least one upper cased character
46
+ * @property {boolean} [mustContain.digit] - Must contain at least one number
47
+ * @property {boolean} [mustContain.special] - Must contain at least one special character
48
+ * @property {number} minLength - The minimal length
49
+ */
50
+
51
+ /**
52
+ * @const
53
+ * @type {PasswordRules}
54
+ */
55
+ export const passwordRules = {
56
+ mustContain: {
57
+ lowerCase: true,
58
+ upperCase: true,
59
+ digit: true,
60
+ special: true
61
+ },
62
+ minLength: 8
63
+ };
64
+
65
+ /**
66
+ * @function isPasswordSafe
67
+ *
68
+ * @param {string|Array} password - One or multiple passwords
69
+ * @param {PasswordRules} [rules] - An object that describe security rules to follow
70
+ * @returns {boolean} Return true if the value is a safe password
71
+ */
72
+ function isPasswordSafe(password, rules) {
73
+ const usedRules = rules ? { ...passwordRules, ...rules } : passwordRules;
74
+
75
+ if (EvoArray.isArray(password)) {
76
+ return password.every(pwd => isPasswordSafe(pwd, usedRules));
77
+ }
78
+
79
+ let regex = "";
80
+
81
+ if (usedRules.mustContain.lowerCase) regex += "(?=.*[a-z])";
82
+ if (usedRules.mustContain.upperCase) regex += "(?=.*[A-Z])";
83
+ if (usedRules.mustContain.digit) regex += "(?=.*[0-9])";
84
+ // Replacing backtick (`) with quote (") will break the check for some dark magic reason
85
+ // eslint-disable-next-line quotes
86
+ if (usedRules.mustContain.special) regex += `(?=.*[\\"'!?@#$£%^&:;<>\\[\\]()\\\\\\-_+=*.])`;
87
+ regex += `.{${usedRules.minLength},}$`;
88
+
89
+ const strongPwd = new RegExp(regex);
90
+ return strongPwd.test(password);
91
+ }
92
+
93
+ /*****************************************************
94
+ * Converters
95
+ *****************************************************/
96
+
97
+ /**
98
+ * @function bytesToReadable
99
+ *
100
+ * @param {number} bytes - Bytes to convert
101
+ * @param {number} [decimals=2] - How many decimals
102
+ * @returns {string} The converted bytes size to the closest unit
103
+ *
104
+ * @example
105
+ * EvoMisc.bytesToReadable(8000000) // return "7.63 MB"
106
+ * EvoMisc.bytesToReadable(8000000, 0) // return "8 MB"
107
+ */
108
+ function bytesToReadable(bytes, decimals = 2) {
109
+ if (bytes === 0) return "0 Bytes";
110
+
111
+ const k = 1024;
112
+ const dm = decimals < 0 ? 0 : decimals;
113
+ const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
114
+
115
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
116
+ return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;
117
+ }
118
+
119
+ /*****************************************************
120
+ * Functions
121
+ *****************************************************/
122
+
123
+ /**
124
+ * @function padLeft
125
+ *
126
+ * @param {*} value - The value to pad
127
+ * @param {string} [pad="00"] - With what to pad
128
+ * @returns {string} The padded string
129
+ *
130
+ * @example
131
+ * EvoMisc.padLeft(5, "000") // return "005"
132
+ * EvoMisc.padLeft("796", "00") // return "796"
133
+ */
134
+ function padLeft(value, pad = "00") {
135
+ return isDefined(value)
136
+ ? (value.toString().length >= pad.length) ? value : (pad + value).slice(-pad.length)
137
+ : pad;
138
+ }
139
+
140
+ /*****************************************************
141
+ * Export
142
+ *****************************************************/
143
+
144
+ export default {
145
+ isDefined, isEmail, isPasswordSafe, // Checkers
146
+ bytesToReadable, // Converters
147
+ padLeft // Functions
148
+ };
package/EvoNumber.js ADDED
@@ -0,0 +1,44 @@
1
+ /**
2
+ * @module EvoNumber
3
+ * @author EmpireDemocratiqueDuPoulpe
4
+ * @version 1.2.0
5
+ * @license MIT
6
+ */
7
+ import EvoString from "./EvoString.js";
8
+
9
+ /*****************************************************
10
+ * Checkers
11
+ *****************************************************/
12
+ /**
13
+ * @function isNumber
14
+ *
15
+ * @param {any} value - The value to test
16
+ * @param {boolean} [parse=false] - If set to true, the function will parse the value to find a integer (base 10)
17
+ * @returns {boolean} Return true if the value is a number
18
+ */
19
+ function isNumber(value, parse = false) {
20
+ const val = parse ? (EvoString.isString(value) ? parseInt(value, 10) : value) : value;
21
+ return typeof val === "number" && !isNaN(val);
22
+ }
23
+
24
+ /**
25
+ * @function isFloat
26
+ *
27
+ * @param {any} value - The value to test
28
+ * @param {boolean} [parse=false] - If set to true, the function will parse the value to find a float
29
+ * @returns {boolean} Return true if the value is a float
30
+ */
31
+ function isFloat(value, parse = true) {
32
+ const val = parse ? (EvoString.isString(value) ? parseFloat(value) : value) : value;
33
+ return typeof val === "number" && !isNaN(val);
34
+ }
35
+
36
+ /*****************************************************
37
+ * Export
38
+ *****************************************************/
39
+
40
+ export default {
41
+ isNumber, isFloat // Checkers
42
+ // Converters
43
+ // Functions
44
+ };
package/EvoObject.js ADDED
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @module EvoObject
3
+ * @author EmpireDemocratiqueDuPoulpe
4
+ * @version 1.2.0
5
+ * @license MIT
6
+ */
7
+
8
+ /*****************************************************
9
+ * Checkers
10
+ *****************************************************/
11
+
12
+ /**
13
+ * @function isDeepEqual
14
+ *
15
+ * @param {Object} obj1 - First object
16
+ * @param {Object} obj2 - Second object
17
+ * @returns {Boolean} Are the two objects deeply equal ?
18
+ *
19
+ * @example
20
+ * EvoObject.isDeepEqual({id: 1, title: "skibidi wap-pa-pa"}, {title: "skibidi wap-pa-pa", id: 1}) // return true
21
+ * EvoObject.isDeepEqual({id: 7, title: "skibidi wap-pa-pa"}, {title: "skibidi woosh-oosh-oosh", id: 1}) // return false
22
+ */
23
+ function isDeepEqual(obj1, obj2) {
24
+ if (typeof obj1 === "object" && Object.keys(obj1).length > 0) {
25
+ return Object.keys(obj1).length === Object.keys(obj2).length &&
26
+ Object.keys(obj1).every(prop => isDeepEqual(obj1[prop], obj2[prop]));
27
+ } else {
28
+ return obj1 === obj2;
29
+ }
30
+ }
31
+
32
+ /*****************************************************
33
+ * Export
34
+ *****************************************************/
35
+
36
+ export default {
37
+ isDeepEqual // Checkers
38
+ // Converters
39
+ // Functions
40
+ };
package/EvoString.js ADDED
@@ -0,0 +1,88 @@
1
+ /**
2
+ * @module EvoString
3
+ * @author EmpireDemocratiqueDuPoulpe
4
+ * @version 1.2.0
5
+ * @license MIT
6
+ */
7
+ import EvoArray from "./EvoArray.js";
8
+ import EvoMisc from "./EvoMisc.js";
9
+
10
+ /*****************************************************
11
+ * Checkers
12
+ *****************************************************/
13
+
14
+ /**
15
+ * @function isString
16
+ *
17
+ * @param {any} value - The value to test
18
+ * @returns {boolean} Return true if the value is a string
19
+ */
20
+ function isString(value) {
21
+ return Object.prototype.toString.call(value) === "[object String]";
22
+ }
23
+
24
+ /**
25
+ * @function isEmpty
26
+ *
27
+ * @param {any} value - The value to test
28
+ * @returns {boolean} Return true if the value is a string and if its empty
29
+ *
30
+ * @example
31
+ * EvoString.isEmpty(""); // return true
32
+ * EvoString.isEmpty(" "); // return false
33
+ */
34
+ function isEmpty(value) {
35
+ return value === "";
36
+ }
37
+
38
+ /**
39
+ * @function isBlank
40
+ *
41
+ * @param {any} value - The value to test
42
+ * @returns {boolean} Return true if the value is a string and if its blank
43
+ *
44
+ * @example
45
+ * EvoString.isBlank(""); // return true
46
+ * EvoString.isBlank(" "); // return true
47
+ */
48
+ function isBlank(value) {
49
+ return isString(value) && value.trim().length === 0;
50
+ }
51
+
52
+ /**
53
+ * @function inRange
54
+ *
55
+ * @param {*|Array<*>} value - The value to test
56
+ * @param {Number} min - The minimum length of the string (nullable)
57
+ * @param {Number} max - The maximum length of the string (nullable)
58
+ * @param {Boolean} [includeBounds=true] - Include the min and max bounds in the range
59
+ * @param {Boolean} [canBeNull=false] - Authorize or not the string to be null or undefined
60
+ * @returns {Boolean} Return true if the value is a string between min and max or if it's an undefined/null with canBeNull set at true.
61
+ *
62
+ * @example
63
+ * EvoString.inRange("never gonna give you up", null, 100); // return true
64
+ * EvoString.inRange("oof", 5); // return false
65
+ */
66
+ function inRange(value, min, max, includeBounds = true, canBeNull = false) {
67
+ if (EvoArray.isArray(value)) {
68
+ return value.every(s => inRange(s, min, max, includeBounds, canBeNull));
69
+ }
70
+
71
+ return EvoMisc.isDefined(value)
72
+ ? isString(value)
73
+ ? includeBounds
74
+ ? (EvoMisc.isDefined(min) ? value.length >= min : true) && (EvoMisc.isDefined(max) ? value.length <= max : true)
75
+ : (EvoMisc.isDefined(min) ? value.length > min : true) && (EvoMisc.isDefined(max) ? value.length < max : true)
76
+ : false
77
+ : canBeNull;
78
+ }
79
+
80
+ /*****************************************************
81
+ * Export
82
+ *****************************************************/
83
+
84
+ export default {
85
+ isString, isEmpty, isBlank, inRange // Checkers
86
+ // Converters
87
+ // Functions
88
+ };