some-common-functions-js 1.0.9 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -1
- package/README.md +55 -6
- package/index.js +148 -12
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -28,8 +28,12 @@ Improve README.md documentation.
|
|
|
28
28
|
- Corrected README documentation.
|
|
29
29
|
|
|
30
30
|
## Version 1.0.8 - 2025/11/21 - ITA
|
|
31
|
-
- Corrected test code and README documentation
|
|
31
|
+
- Corrected test code and README documentation.
|
|
32
32
|
|
|
33
33
|
## Version 1.0.9 - 2025/11/28 - ITA
|
|
34
34
|
- Provided more documentation in test.js to remind a developer how to symbolic-link (mimick as installed) the package and running the test code.
|
|
35
35
|
- Added new function, hasOnlyAll(), and updated the README.md documentation accordingly.
|
|
36
|
+
|
|
37
|
+
## Version 1.1.0 - 2025/12/22 - ITA
|
|
38
|
+
- Improved documentation.
|
|
39
|
+
- Moved in more functions to the package: `deepClone(anObject)`, `getSortedObject(anObject)`, `timeStampYyyyMmDd(dateInstance)` and `timeStampString(dateInstance)`.
|
package/README.md
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
# JavaScript Object Utilities
|
|
1
|
+
# JavaScript Object Utilities, Field Validation Functions, Array Binary Search, and Date timestamp Functions.
|
|
2
2
|
|
|
3
3
|
Common functions used for working with JavaScript objects and validating field values.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
## Installation
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
```
|
|
8
|
+
npm install some-common-functions-js
|
|
9
|
+
```
|
|
9
10
|
## 1. JavaScript Object Utilities
|
|
10
11
|
|
|
12
|
+
### `deepClone(anObject)`
|
|
13
|
+
Returns a deep clone of a plain Javascript object. The clone, while it has field equal to that of the original object, is separate from the original object.
|
|
14
|
+
|
|
11
15
|
### `getPaths(anObject)`
|
|
12
16
|
Returns a string array of path/field names inside a JavaScript object.
|
|
13
17
|
***Example***
|
|
@@ -30,8 +34,47 @@ let client = {
|
|
|
30
34
|
|
|
31
35
|
let paths = getPaths(client);
|
|
32
36
|
// ["name", "surname", "address.streetNum", "address.streetName", "address.suburb",
|
|
33
|
-
// "address.town", "address.country.name", "address.country.code"]
|
|
37
|
+
// "address.town", "address.country.name", "address.country.code"]
|
|
34
38
|
```
|
|
39
|
+
### `getSortedObject(anObject)`
|
|
40
|
+
Returns an object with sorted fields, by ordered by field name ascending.
|
|
41
|
+
***Examples***
|
|
42
|
+
```
|
|
43
|
+
const client = {
|
|
44
|
+
firstName: "Isaiah",
|
|
45
|
+
lastName: "Tshabalala",
|
|
46
|
+
address: {
|
|
47
|
+
houseNum: "5520",
|
|
48
|
+
streetName: "Main Road",
|
|
49
|
+
mainPlace: "Evaton",
|
|
50
|
+
subPlace: "Evaton Small Farms",
|
|
51
|
+
city: "Vereeniging",
|
|
52
|
+
country: {
|
|
53
|
+
name: "South Africa",
|
|
54
|
+
code: "ZA"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const sortedObject = getSortedObject(client);
|
|
60
|
+
/*
|
|
61
|
+
{
|
|
62
|
+
address: {
|
|
63
|
+
city: 'Vereeniging',
|
|
64
|
+
country: {
|
|
65
|
+
code: 'ZA',
|
|
66
|
+
name: 'South Africa'
|
|
67
|
+
},
|
|
68
|
+
houseNum: '5520',
|
|
69
|
+
mainPlace: 'Evaton',
|
|
70
|
+
streetName: 'Main Road',
|
|
71
|
+
subPlace: 'Evaton Small Farms'
|
|
72
|
+
},
|
|
73
|
+
firstName: 'Isaiah',
|
|
74
|
+
lastName: 'Tshabalala'
|
|
75
|
+
}
|
|
76
|
+
*/
|
|
77
|
+
```
|
|
35
78
|
### `hasOnly(anObject, ...fields)`
|
|
36
79
|
Returns `true` if the object contains **only** some or all of the specified fields and no others.
|
|
37
80
|
***Examples***
|
|
@@ -344,7 +387,7 @@ let anIndex = binarySearchObj(teamsArray, searchObj, 0, "score desc", "numGames
|
|
|
344
387
|
|
|
345
388
|
let result = objCompare(searchObj, teamsArray[anIndex], "score desc", "numGames asc"); // 0 -- an object with value { score: 85, numGames: 8} exists at teamsArray[anIndex];
|
|
346
389
|
```
|
|
347
|
-
|
|
390
|
+
### `getObjArrayWithNoDuplicates(objArray, firstOfDuplicates, ...comparisonFields)`
|
|
348
391
|
Create an array of objects with duplicates eliminated. Taking only the first or last object from each duplicate set. The input array must be sorted according to the values of comparisonFields.
|
|
349
392
|
* If firstOfDuplicates === true, then the first element in each set of duplicates is taken.
|
|
350
393
|
* if firstOfDuplicates === false, then the last element is taken from each set of duplicates.
|
|
@@ -382,7 +425,13 @@ console.log(noDuplicatesArray); // Should contain only unique objects according
|
|
|
382
425
|
]
|
|
383
426
|
*/
|
|
384
427
|
```
|
|
428
|
+
## 4. Date Timestamp Functions
|
|
429
|
+
### `timeStampYyyyMmDd(dateInstance)`
|
|
430
|
+
Converts the date object to a string of the form CCYY-MM-DD
|
|
431
|
+
|
|
432
|
+
### `timeStampString(dateInstance)`
|
|
433
|
+
Converts a date object to a string of the form CCYY-MM-DDThh:mm:ss.ccc, e.g. '2024-02-25T15:00:25.251'
|
|
434
|
+
|
|
385
435
|
---
|
|
386
436
|
## License
|
|
387
437
|
MIT
|
|
388
|
-
|
package/index.js
CHANGED
|
@@ -3,9 +3,14 @@
|
|
|
3
3
|
* Date Dev Version Description
|
|
4
4
|
* 2025/11/19 ITA 1.00 Genesis.
|
|
5
5
|
* 2025/11/28 ITA 1.01 Added function hasOnlyAll().
|
|
6
|
+
* 2025/12/22 ITA 1.02 Improved documentation of the functions and moved in more functions.
|
|
6
7
|
*/
|
|
7
8
|
const loDash = require('lodash');
|
|
8
9
|
|
|
10
|
+
/**Return true if userName is valid
|
|
11
|
+
* @param {string} userName
|
|
12
|
+
* @returns {boolean} true if a userName is valid, otherwise false.
|
|
13
|
+
*/
|
|
9
14
|
function isValidUserName(userName) {
|
|
10
15
|
if (!userName) // The username must be provided.
|
|
11
16
|
return false;
|
|
@@ -15,6 +20,10 @@ function isValidUserName(userName) {
|
|
|
15
20
|
}
|
|
16
21
|
module.exports.isValidUserName = isValidUserName;
|
|
17
22
|
|
|
23
|
+
/**Return true if a name is valid
|
|
24
|
+
* @param {string} name
|
|
25
|
+
* @returns {boolean} true if a name is valid, otherwise false.
|
|
26
|
+
*/
|
|
18
27
|
function isValidName(name) {
|
|
19
28
|
if (!name) // The name must be provided.
|
|
20
29
|
return false;
|
|
@@ -24,6 +33,10 @@ function isValidName(name) {
|
|
|
24
33
|
}
|
|
25
34
|
module.exports.isValidName = isValidName;
|
|
26
35
|
|
|
36
|
+
/**Return true if userName is valid
|
|
37
|
+
* @param {string} email
|
|
38
|
+
* @returns {boolean} true if an email is valid, otherwise false.
|
|
39
|
+
*/
|
|
27
40
|
function isValidEmail(email) {
|
|
28
41
|
if (!email)
|
|
29
42
|
return false;
|
|
@@ -33,6 +46,10 @@ function isValidEmail(email) {
|
|
|
33
46
|
}
|
|
34
47
|
module.exports.isValidEmail = isValidEmail;
|
|
35
48
|
|
|
49
|
+
/**Return true if userName is valid
|
|
50
|
+
* @param {string} num phone number
|
|
51
|
+
* @returns {boolean} true if phone number is valid, otherwise false.
|
|
52
|
+
*/
|
|
36
53
|
function isValidPhoneNum(num) {
|
|
37
54
|
if (!num) // The number must be provided.
|
|
38
55
|
return false;
|
|
@@ -42,6 +59,10 @@ function isValidPhoneNum(num) {
|
|
|
42
59
|
}
|
|
43
60
|
module.exports.isValidPhoneNum = isValidPhoneNum;
|
|
44
61
|
|
|
62
|
+
/**Return true if the name of an organisation is valid
|
|
63
|
+
* @param {string} name an organisation name
|
|
64
|
+
* @returns {boolean} true if an organisation name is valid, otherwise false.
|
|
65
|
+
*/
|
|
45
66
|
function isValidOrganisationName(name) {
|
|
46
67
|
if (!name) // The name must be provided.
|
|
47
68
|
return false;
|
|
@@ -51,6 +72,10 @@ function isValidOrganisationName(name) {
|
|
|
51
72
|
}
|
|
52
73
|
module.exports.isValidOrganisationName = isValidOrganisationName;
|
|
53
74
|
|
|
75
|
+
/**Return true if a password is valid
|
|
76
|
+
* @param {string} password
|
|
77
|
+
* @returns {boolean} true if a password is valid, otherwise false.
|
|
78
|
+
*/
|
|
54
79
|
function isValidPassword(password) {
|
|
55
80
|
if (!password)
|
|
56
81
|
return false;
|
|
@@ -83,9 +108,79 @@ function isValidPassword(password) {
|
|
|
83
108
|
}
|
|
84
109
|
module.exports.isValidPassword = isValidPassword;
|
|
85
110
|
|
|
111
|
+
/** Converts the date object to a string of the form CCYY-MM-DD
|
|
112
|
+
* @param {Date} dateObj
|
|
113
|
+
* @returns {string} string of the form CCYY-MM-DD
|
|
114
|
+
*/
|
|
115
|
+
function timeStampYyyyMmDd(dateObj) {
|
|
116
|
+
// Convert the date to string form yyyy-mm-dd
|
|
117
|
+
let year = dateObj.getFullYear();
|
|
118
|
+
let month = dateObj.getMonth() + 1;
|
|
119
|
+
month = addLeadingZeros(month, 2);
|
|
120
|
+
let day = dateObj.getDate();
|
|
121
|
+
day = addLeadingZeros(day, 2);
|
|
122
|
+
return `${year}-${month}-${day}`;
|
|
123
|
+
} // function timeStampYYYYMMDd(dateObj) {
|
|
124
|
+
module.exports.timeStampYyyyMmDd = timeStampYyyyMmDd;
|
|
125
|
+
|
|
126
|
+
/** Converts a date object to a string of the form CCYY-MM-DDThh:mm:ss.ccc, e.g. '2024-02-25T15:00:25.251'
|
|
127
|
+
* @param {Date} dateObj
|
|
128
|
+
* @returns {string} a string of the form CCYY-MM-DDThh:mm:ss.ccc.
|
|
129
|
+
*/
|
|
130
|
+
function timeStampString(dateObj) {
|
|
131
|
+
let hours = addLeadingZeros(dateObj.getHours(), 2);
|
|
132
|
+
let minutes = addLeadingZeros(dateObj.getMinutes(), 2);
|
|
133
|
+
let seconds = addLeadingZeros(dateObj.getSeconds(), 2);
|
|
134
|
+
let milliSec = addLeadingZeros(dateObj.getMilliseconds(), 3);
|
|
135
|
+
return `${timeStampYyyyMmDd(dateObj)}T${hours}:${minutes}:${seconds}.${milliSec}`;
|
|
136
|
+
} // function timeStampString(dateObj) {
|
|
137
|
+
module.exports.timeStampString = timeStampString;
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
/** Return a numeric string with trailing zeros.
|
|
141
|
+
* E.g. addLeadingZeros(9, 3) = '009'
|
|
142
|
+
* Inputs:
|
|
143
|
+
* @param {Number} aNumber an integer or integer string.
|
|
144
|
+
* @param {Number} newLength the new length of the resulting string.
|
|
145
|
+
* @returns a string of a number with the specified number of leading zeros.
|
|
146
|
+
*/
|
|
147
|
+
function addLeadingZeros(aNumber, newLength) {
|
|
148
|
+
|
|
149
|
+
let newString = aNumber + '';
|
|
150
|
+
const howManyZeros = newLength - newString.length;
|
|
151
|
+
for (let count = 1; count <= howManyZeros; count++)
|
|
152
|
+
newString = '0' + newString;
|
|
153
|
+
|
|
154
|
+
return newString;
|
|
155
|
+
} // function addLeadingZeros(aString, newLength) {
|
|
156
|
+
module.exports.addLeadingZeros = addLeadingZeros;
|
|
157
|
+
|
|
158
|
+
/**Convert numeric input to ZAR currency format string.
|
|
159
|
+
* @param {Number} a number
|
|
160
|
+
* @returns a string of the form R 256,534.00
|
|
161
|
+
*/
|
|
162
|
+
function toZarCurrencyFormat(number) {
|
|
163
|
+
const zarCurrencyFormat = new Intl.NumberFormat('en-US', {style: 'currency', currency: 'ZAR'});
|
|
164
|
+
return zarCurrencyFormat.format(number).replace(/ZAR/gi, 'R');
|
|
165
|
+
}
|
|
166
|
+
module.exports.toZarCurrencyFormat = toZarCurrencyFormat;
|
|
167
|
+
|
|
168
|
+
/**Return a deep clone of a document object.
|
|
169
|
+
* By using deep cloning, you create a new object that is entirely separate from the original original.
|
|
170
|
+
* So that whatever you do to that clone, such as deletion of fields, does not affect the original.
|
|
171
|
+
* NB. Class instance types will be converted to plain object types due to stringification.
|
|
172
|
+
* @param {object} obj a plain Javascript object.
|
|
173
|
+
* @returns a Javascript object that is separate from the original object.
|
|
174
|
+
*/
|
|
175
|
+
function deepClone(obj) {
|
|
176
|
+
return JSON.parse(JSON.stringify(obj));
|
|
177
|
+
} // function deepClone(obj) { // Return a deep clone of an object.
|
|
178
|
+
module.exports.deepClone = deepClone;
|
|
179
|
+
|
|
180
|
+
|
|
86
181
|
/**
|
|
87
182
|
* Get the paths (fields) of the plain Javascript object.
|
|
88
|
-
* @param {object} anObject
|
|
183
|
+
* @param {object} anObject a plain Javascript object.
|
|
89
184
|
* @returns a sorted string array of paths.
|
|
90
185
|
*/
|
|
91
186
|
function getPaths(anObject) {
|
|
@@ -108,11 +203,32 @@ function getPaths(anObject) {
|
|
|
108
203
|
} // function getPaths()
|
|
109
204
|
module.exports.getPaths = getPaths;
|
|
110
205
|
|
|
206
|
+
/** Return an object with sorted fields, by ordered by field name ascending.
|
|
207
|
+
* This is desirable when equality comparison is done to ensure two objects sharing equal field values
|
|
208
|
+
* the pass the equality test stringify(object1) === stringify(object2)
|
|
209
|
+
* @param {object} pObject
|
|
210
|
+
* @returns {object} an object with fields sorted in ascending order of field names.
|
|
211
|
+
*/
|
|
212
|
+
function getSortedObject(pObject) {
|
|
213
|
+
|
|
214
|
+
const paths = getPaths(pObject);
|
|
215
|
+
paths.sort();
|
|
216
|
+
const sortedObject = {};
|
|
217
|
+
|
|
218
|
+
for (let index in paths) {
|
|
219
|
+
const path = paths[index];
|
|
220
|
+
const value = loDash.get(pObject, path);
|
|
221
|
+
loDash.set(sortedObject, path, value);
|
|
222
|
+
} // for (index in paths) {
|
|
223
|
+
return sortedObject;
|
|
224
|
+
} // function getSortedObject(pObject) {
|
|
225
|
+
module.exports.getSortedObject = getSortedObject;
|
|
226
|
+
|
|
111
227
|
/**
|
|
112
|
-
* Determine whether an object contains only some or all of the specified fields, and not any other fields.
|
|
113
|
-
* @param {
|
|
228
|
+
* Determine whether an object contains only 1, some or all of the specified fields, and not any other fields.
|
|
229
|
+
* @param {object} anObject a Javascript object.
|
|
114
230
|
* @param {...string} fields one or more field names.
|
|
115
|
-
* @returns boolean.
|
|
231
|
+
* @returns boolean true or false.
|
|
116
232
|
*/
|
|
117
233
|
function hasOnly(anObject, ...fields) {
|
|
118
234
|
if (!fields || !fields.length)
|
|
@@ -134,10 +250,10 @@ function hasOnly(anObject, ...fields) {
|
|
|
134
250
|
module.exports.hasOnly = hasOnly;
|
|
135
251
|
|
|
136
252
|
/**
|
|
137
|
-
* Determine whether an object contains all of the specified fields
|
|
138
|
-
* @param {
|
|
253
|
+
* Determine whether an object contains all of the specified fields in addition to other fields.
|
|
254
|
+
* @param {object} anObject a Javascript object.
|
|
139
255
|
* @param {...string} fields one or field names.
|
|
140
|
-
* @returns boolean.
|
|
256
|
+
* @returns boolean true or false.
|
|
141
257
|
*/
|
|
142
258
|
function hasAll(anObject, ...fields) {
|
|
143
259
|
if (!fields || !fields.length)
|
|
@@ -160,9 +276,9 @@ module.exports.hasAll = hasAll;
|
|
|
160
276
|
|
|
161
277
|
/**
|
|
162
278
|
* Determine whether an object contains only all of the specified fields. Nothing more, nothing less.
|
|
163
|
-
* @param {
|
|
279
|
+
* @param {object} anObject a Javascript object.
|
|
164
280
|
* @param {...string} fields one or field names.
|
|
165
|
-
* @returns boolean.
|
|
281
|
+
* @returns boolean true or false.
|
|
166
282
|
*/
|
|
167
283
|
function hasOnlyAll(anObject, ...fields) {
|
|
168
284
|
return hasOnly(anObject, ...fields) && hasAll(anObject, ...fields);
|
|
@@ -175,6 +291,11 @@ module.exports.hasOnlyAll = hasOnlyAll;
|
|
|
175
291
|
* otherwise, the index is of closest value in the array that is before or after the search value in terms of sort order.
|
|
176
292
|
* Return -1 for an empty array.
|
|
177
293
|
* This function is to be used also in cases where values are to be inserted into the array while maintaining sort order.
|
|
294
|
+
* @param {Array} anArray an array of primitve type. All element must be the same type.
|
|
295
|
+
* @param {*} searchVal search value
|
|
296
|
+
* @param {number} [startFrom=0] index from which to start. Default: 0.
|
|
297
|
+
* @param {string} [arraySortDir='asc'] sort direction. Must be 'asc' or 'desc'. Default: 'asc'
|
|
298
|
+
* @returns {number} an index
|
|
178
299
|
*/
|
|
179
300
|
function binarySearch(anArray, searchVal, startFrom = 0, arraySortDir = 'asc') {
|
|
180
301
|
|
|
@@ -212,7 +333,10 @@ module.exports.binarySearch = binarySearch;
|
|
|
212
333
|
* A return value of -1 means that value1 is before value2 in terms of sort order.
|
|
213
334
|
* A return value of 1 means that value1 is after value2 in terms of sort order.
|
|
214
335
|
* A return value of 0 means that value1 is equal to value2.
|
|
215
|
-
*
|
|
336
|
+
* @param {*} value1
|
|
337
|
+
* @param {*} value2
|
|
338
|
+
* @param {string} [sortDir='asc']
|
|
339
|
+
* @returns {number} integer (-1, 0 or 1)
|
|
216
340
|
*/
|
|
217
341
|
function compare(value1, value2, sortDir = 'asc') {
|
|
218
342
|
if (!['asc', 'desc'].includes(sortDir))
|
|
@@ -236,8 +360,13 @@ module.exports.compare = compare;
|
|
|
236
360
|
* Return -1 for an empty array.
|
|
237
361
|
* Assumed field data types are Number, String and Date.
|
|
238
362
|
* This function is to be used also in cases where objects are to be inserted into the array while maintaining sort order.
|
|
363
|
+
* @param {Array<object} objArray an array of Javascript objects.
|
|
364
|
+
* @param {object} searchObj an object to search for.
|
|
365
|
+
* @@param {number} [startFrom=0] index from which to start searching.
|
|
366
|
+
* @param {...string} sortFields one or more search fields.
|
|
367
|
+
* @returns {number} an index.
|
|
239
368
|
*/
|
|
240
|
-
function binarySearchObj(objArray, searchObj, startFrom, ...sortFields) {
|
|
369
|
+
function binarySearchObj(objArray, searchObj, startFrom = 0, ...sortFields) {
|
|
241
370
|
if (objArray.length === 0)
|
|
242
371
|
return -1;
|
|
243
372
|
|
|
@@ -264,7 +393,7 @@ function binarySearchObj(objArray, searchObj, startFrom, ...sortFields) {
|
|
|
264
393
|
} // function binarySearchObj(objArray, searchObj, ...comparisonFields) {
|
|
265
394
|
module.exports.binarySearchObj = binarySearchObj;
|
|
266
395
|
|
|
267
|
-
/**Create an array with duplicates eliminated. Taking only the first or last object from each duplicate set.
|
|
396
|
+
/**Create an array with duplicates eliminated, according to certain fields. Taking only the first or last object from each duplicate set.
|
|
268
397
|
* If firstOfDuplicates === true, then the first element in each set of duplicates is taken.
|
|
269
398
|
* if firstOfDuplicates === false, then the last element is taken from each set of duplicates.
|
|
270
399
|
* Assumed field data types are Number, String and Date.
|
|
@@ -272,6 +401,10 @@ module.exports.binarySearchObj = binarySearchObj;
|
|
|
272
401
|
* The value of the comparison field must include both the field name and sort direction.
|
|
273
402
|
* Sort direction assumed to be "asc" if not provided.
|
|
274
403
|
* Examples of comparison fields: "firstName", "lastName desc", "address.province asc", "address.townOrCity".
|
|
404
|
+
* @param {Array<object>} objArray an input array of objects
|
|
405
|
+
* @param {boolean} firstOfDuplicates specify whether to take the first or last object in each a duplicate set.
|
|
406
|
+
* @param {...string} comparisonFields comparison fieds plus sort order.
|
|
407
|
+
* @returns {Array<object>} an array with no duplicates.
|
|
275
408
|
*/
|
|
276
409
|
function getObjArrayWithNoDuplicates(objArray, firstOfDuplicates, ...comparisonFields) {
|
|
277
410
|
function getNextSearchObj(pNext) {
|
|
@@ -367,6 +500,9 @@ module.exports.getObjArrayWithNoDuplicates = getObjArrayWithNoDuplicates;
|
|
|
367
500
|
* Sort directions: 'asc', 'desc'.
|
|
368
501
|
* Examples: 'lastName desc', 'firstName', 'firstName asc', 'address.provinceName asc'.
|
|
369
502
|
* If sort direction is not provided, then it is assumed to be ascending.
|
|
503
|
+
* @param {object} obj1 first object to compare
|
|
504
|
+
* @param {object} obj2 second object to compare
|
|
505
|
+
* @returns {number} a comparison value of 1, 0 or -1
|
|
370
506
|
*/
|
|
371
507
|
function objCompare(obj1, obj2, ...comparisonFields) {
|
|
372
508
|
if (comparisonFields.length === 0)
|