some-common-functions-js 1.1.4 → 1.1.6
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 +7 -0
- package/index.js +115 -55
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -52,3 +52,10 @@ Corrected a minor error in the README documentation.
|
|
|
52
52
|
|
|
53
53
|
## Version 1.1.4 - 2025/12/27 - ITA
|
|
54
54
|
Added the outstanding change log for the previous version.
|
|
55
|
+
|
|
56
|
+
## Version 1.1.5 - 2025/12/28 - ITA
|
|
57
|
+
- Improved the documentation of functions to show better on the tooltip in IDEs.
|
|
58
|
+
- Improved the deepClone function to handle Date and array types that may have dates types better.
|
|
59
|
+
|
|
60
|
+
## Version 1.1.6 - 2025/12//29 - ITA
|
|
61
|
+
Removed unnecessary use of the getPaths() function in the get() function to improve effieciency.
|
package/index.js
CHANGED
|
@@ -8,6 +8,11 @@
|
|
|
8
8
|
* Added function getNextDifferent() to deal better with duplicate removal from arrays of objects.
|
|
9
9
|
* 2026/01/02 ITA 1.04 Improved the functions getNoDuplicatesArray() and getNextDifferent() to handle more test cases.
|
|
10
10
|
* Added function unset().
|
|
11
|
+
* 2025/10/28 ITA 1.05 Improved documentation of functions to show better on the tooltip in IDEs.
|
|
12
|
+
* Improved deepClone() function to handle Date objects and arrays.
|
|
13
|
+
* Updated get() function to return undefined or supplied default value for paths that do not exist.
|
|
14
|
+
* Updated test.js file accordingly.
|
|
15
|
+
* 2025/12//29 ITA 1.06 Removed unnecessary use of the getPaths() function in the get() function to improve effieciency.
|
|
11
16
|
*/
|
|
12
17
|
|
|
13
18
|
/**Return true if userName is valid
|
|
@@ -140,9 +145,11 @@ function timeStampString(dateObj) {
|
|
|
140
145
|
module.exports.timeStampString = timeStampString;
|
|
141
146
|
|
|
142
147
|
|
|
143
|
-
/**
|
|
144
|
-
*
|
|
145
|
-
*
|
|
148
|
+
/** Returns a numeric string with trailing zeros.
|
|
149
|
+
*
|
|
150
|
+
* E.g.
|
|
151
|
+
*
|
|
152
|
+
* addLeadingZeros(9, 4) = '0009', addLeadingZeros(123, 5) = '00123'
|
|
146
153
|
* @param {Number} aNumber an integer or integer string.
|
|
147
154
|
* @param {Number} newLength the new length of the resulting string.
|
|
148
155
|
* @returns a string of a number with the specified number of leading zeros.
|
|
@@ -170,13 +177,50 @@ module.exports.toZarCurrencyFormat = toZarCurrencyFormat;
|
|
|
170
177
|
|
|
171
178
|
/**Return a deep clone of a document object.
|
|
172
179
|
* By using deep cloning, you create a new object that is entirely separate from the original original.
|
|
180
|
+
*
|
|
173
181
|
* So that whatever you do to that clone, such as deletion of fields, does not affect the original.
|
|
174
|
-
*
|
|
182
|
+
*
|
|
183
|
+
* NB. Works only plain Javascript objects. Field types supported: Date, number, string, boolean, and object/array of such types.
|
|
175
184
|
* @param {object} obj a plain Javascript object.
|
|
176
185
|
* @returns a Javascript object that is separate from the original object.
|
|
177
186
|
*/
|
|
178
187
|
function deepClone(obj) {
|
|
179
|
-
|
|
188
|
+
if (Object.prototype.toString.call(obj) === '[object Object]') {
|
|
189
|
+
// continue to the next steps.
|
|
190
|
+
}
|
|
191
|
+
else if (obj instanceof Date) { // Date instance
|
|
192
|
+
return new Date(obj);
|
|
193
|
+
}
|
|
194
|
+
else if (Array.isArray(obj)) { // array
|
|
195
|
+
return obj.map(item=> deepClone(item));
|
|
196
|
+
}
|
|
197
|
+
else if (['string', 'number', 'boolean'].includes(typeof obj)) { // primitive type
|
|
198
|
+
return obj;
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
return obj; // other types such as null, undefined, etc.
|
|
202
|
+
}
|
|
203
|
+
const tempObj = {};
|
|
204
|
+
for (const path in obj) {
|
|
205
|
+
const value = obj[path];
|
|
206
|
+
if (Object.prototype.toString.call(value) === '[object Object]') {
|
|
207
|
+
tempObj[path] = deepClone(value);
|
|
208
|
+
}
|
|
209
|
+
else if (value instanceof Date) { // Date instance
|
|
210
|
+
tempObj[path] = new Date(value);
|
|
211
|
+
}
|
|
212
|
+
else if (Array.isArray(value)) { // array
|
|
213
|
+
tempObj[path] = value.map(item=> deepClone(item));
|
|
214
|
+
}
|
|
215
|
+
else if (['string', 'number', 'boolean'].includes(typeof value)) { // primitive type
|
|
216
|
+
tempObj[path] = value;
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
tempObj[path] = value; // other types such as null, undefined, etc.
|
|
220
|
+
}
|
|
221
|
+
} // for (idx in paths) {
|
|
222
|
+
|
|
223
|
+
return tempObj; // return the deep cloned object.
|
|
180
224
|
} // function deepClone(obj) { // Return a deep clone of an object.
|
|
181
225
|
module.exports.deepClone = deepClone;
|
|
182
226
|
|
|
@@ -201,64 +245,59 @@ function getPaths(anObject) {
|
|
|
201
245
|
else
|
|
202
246
|
paths.push(path);
|
|
203
247
|
}
|
|
204
|
-
paths.sort();
|
|
205
248
|
return paths;
|
|
206
249
|
} // function getPaths()
|
|
207
250
|
module.exports.getPaths = getPaths;
|
|
208
251
|
|
|
209
252
|
/** Return an object with sorted fields, ordered by field name ascending.
|
|
210
|
-
*
|
|
211
|
-
*
|
|
253
|
+
*
|
|
254
|
+
* NB. For comparison of objects, please see objCompare() function.
|
|
212
255
|
* @param {object} pObject
|
|
213
256
|
* @returns {object} an object with fields sorted in ascending order of field names.
|
|
214
257
|
*/
|
|
215
258
|
function getSortedObject(pObject) {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
}
|
|
224
|
-
paths.sort();
|
|
225
|
-
|
|
226
|
-
// Assign the sorted fields to the new object.
|
|
227
|
-
for (let index in paths) {
|
|
228
|
-
const field = paths[index];
|
|
229
|
-
if (Object.prototype.toString.call(objClone[field]) === '[object Object]') {
|
|
230
|
-
sortedObject[field] = getSortedObject(objClone[field]);
|
|
259
|
+
const objClone = deepClone(pObject);
|
|
260
|
+
const paths = [];
|
|
261
|
+
const sortedObject = {};
|
|
262
|
+
|
|
263
|
+
// Obtain the outermost fields and sort them.
|
|
264
|
+
for (let field in objClone) {
|
|
265
|
+
paths.push(field);
|
|
231
266
|
}
|
|
232
|
-
|
|
233
|
-
sortedObject[field] = objClone[field];
|
|
234
|
-
} //
|
|
235
|
-
} // for (let field in paths) {
|
|
267
|
+
paths.sort();
|
|
236
268
|
|
|
237
|
-
|
|
269
|
+
// Assign the sorted fields to the new object.
|
|
270
|
+
for (let index in paths) {
|
|
271
|
+
const field = paths[index];
|
|
272
|
+
if (Object.prototype.toString.call(objClone[field]) === '[object Object]') {
|
|
273
|
+
sortedObject[field] = getSortedObject(objClone[field]);
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
sortedObject[field] = objClone[field];
|
|
277
|
+
} //
|
|
278
|
+
} // for (let field in paths) {
|
|
279
|
+
|
|
280
|
+
return sortedObject;
|
|
238
281
|
} // function getSortedObject(pObject) {
|
|
239
282
|
module.exports.getSortedObject = getSortedObject;
|
|
240
283
|
|
|
241
284
|
/** Get the value of a field specified by the path from an object.
|
|
242
285
|
* @param {object} anObject a Javascript object.
|
|
243
286
|
* @param {string} path a path specifying the field whose value is to be obtained.
|
|
244
|
-
* @
|
|
287
|
+
* @param {*} [defaultVal=undefined] a default value to return if the path does not exist on the object.
|
|
288
|
+
* @returns {*} the value of the field specified by the path, otherwise a default value if supplied.
|
|
245
289
|
*/
|
|
246
|
-
function get(anObject, path) {
|
|
247
|
-
if (getPaths(anObject).includes(path) === false) {
|
|
248
|
-
console.log(hasAll(anObject, path), path, anObject, getPaths(anObject));
|
|
249
|
-
throw new Error(`Path ${path} does not exist on the object.`);
|
|
250
|
-
}
|
|
290
|
+
function get(anObject, path, defaultVal = undefined) {
|
|
251
291
|
let paths = path.split('.');
|
|
252
|
-
let
|
|
253
|
-
|
|
254
|
-
|
|
292
|
+
let value = anObject[paths[0]];
|
|
293
|
+
if (value === undefined) {
|
|
294
|
+
return defaultVal;
|
|
295
|
+
}
|
|
255
296
|
if (paths.length > 1) {
|
|
256
297
|
paths.splice(0, 1);
|
|
257
298
|
return get(value, paths.join('.'));
|
|
258
299
|
}
|
|
259
|
-
|
|
260
|
-
return value;
|
|
261
|
-
}
|
|
300
|
+
return deepClone(value);
|
|
262
301
|
}
|
|
263
302
|
module.exports.get = get;
|
|
264
303
|
|
|
@@ -290,8 +329,10 @@ module.exports.set = set;
|
|
|
290
329
|
*/
|
|
291
330
|
function unset(anObject, path) {
|
|
292
331
|
let paths = path.split('.');
|
|
332
|
+
const subObject = anObject[paths[0]];
|
|
333
|
+
if (subObject === undefined)
|
|
334
|
+
return; // field not found.
|
|
293
335
|
if (paths.length > 1) {
|
|
294
|
-
const subObject = anObject[paths[0]];
|
|
295
336
|
paths.splice(0, 1);
|
|
296
337
|
unset(subObject, paths.join('.'));
|
|
297
338
|
}
|
|
@@ -363,16 +404,18 @@ function hasOnlyAll(anObject, ...fields) {
|
|
|
363
404
|
module.exports.hasOnlyAll = hasOnlyAll;
|
|
364
405
|
|
|
365
406
|
/**Binary Search the sorted primitive data array for a value and return the index.
|
|
407
|
+
*
|
|
366
408
|
* ArraySortDir specifies the direction in which the array is sorted (desc or asc).
|
|
409
|
+
*
|
|
367
410
|
* If the array contains the value searched for, then the index returned is the location of this value on the array,
|
|
368
411
|
* otherwise, the index is of closest value in the array that is before or after the search value in terms of sort order.
|
|
369
|
-
*
|
|
370
|
-
* This function
|
|
412
|
+
*
|
|
413
|
+
* This function can be used also in cases where values are to be inserted into the array while maintaining sort order.
|
|
371
414
|
* @param {Array} anArray an array of primitve type. All element must be the same type.
|
|
372
415
|
* @param {*} searchVal search value
|
|
373
416
|
* @param {number} [startFrom=0] index from which to start. Default: 0.
|
|
374
417
|
* @param {string} [arraySortDir='asc'] sort direction. Must be 'asc' or 'desc'. Default: 'asc'
|
|
375
|
-
* @returns {number} an index
|
|
418
|
+
* @returns {number} an index. -1 mean value not found.
|
|
376
419
|
*/
|
|
377
420
|
function binarySearch(anArray, searchVal, startFrom = 0, arraySortDir = 'asc') {
|
|
378
421
|
|
|
@@ -407,13 +450,16 @@ function binarySearch(anArray, searchVal, startFrom = 0, arraySortDir = 'asc') {
|
|
|
407
450
|
module.exports.binarySearch = binarySearch;
|
|
408
451
|
|
|
409
452
|
/** Compare two values of the same primitive type, according to the sort direction.
|
|
453
|
+
*
|
|
410
454
|
* A return value of -1 means that value1 is before value2 in terms of sort order.
|
|
455
|
+
*
|
|
411
456
|
* A return value of 1 means that value1 is after value2 in terms of sort order.
|
|
457
|
+
*
|
|
412
458
|
* A return value of 0 means that value1 is equal to value2.
|
|
413
459
|
* @param {*} value1
|
|
414
460
|
* @param {*} value2
|
|
415
461
|
* @param {string} [sortDir='asc']
|
|
416
|
-
* @returns {number}
|
|
462
|
+
* @returns {number} -1, 0 or 1
|
|
417
463
|
*/
|
|
418
464
|
function compare(value1, value2, sortDir = 'asc') {
|
|
419
465
|
if (!['asc', 'desc'].includes(sortDir))
|
|
@@ -430,16 +476,19 @@ function compare(value1, value2, sortDir = 'asc') {
|
|
|
430
476
|
module.exports.compare = compare;
|
|
431
477
|
|
|
432
478
|
/**Binary Search the sorted (ascending or descending order) array of objects for a value and return the index.
|
|
479
|
+
*
|
|
433
480
|
* The assumption is that the array is sorted in order of 1 or more sort fields,
|
|
434
|
-
*
|
|
435
|
-
*
|
|
436
|
-
*
|
|
481
|
+
*
|
|
482
|
+
* Examples of sort fields: 'lastName asc', 'firstName', 'address.province asc', 'address.townOrCity asc'.
|
|
483
|
+
*
|
|
484
|
+
* If the array contains the object with values searched for, then the index returned is the location of this value in the array, otherwise,
|
|
485
|
+
* the index is of the closest value in the array that is before or after the searchObj value.
|
|
437
486
|
* Return -1 for an empty array.
|
|
438
487
|
* Assumed field data types are Number, String and Date.
|
|
439
488
|
* This function is to be used also in cases where objects are to be inserted into the array while maintaining sort order.
|
|
440
489
|
* @param {Array<object} objArray an array of Javascript objects.
|
|
441
490
|
* @param {object} searchObj an object to search for.
|
|
442
|
-
*
|
|
491
|
+
* @param {number} [startFrom=0] index from which to start searching.
|
|
443
492
|
* @param {...string} sortFields one or more search fields.
|
|
444
493
|
* @returns {number} an index.
|
|
445
494
|
*/
|
|
@@ -475,7 +524,7 @@ module.exports.binarySearchObj = binarySearchObj;
|
|
|
475
524
|
* @param {Array<object>} objArray an array of objects
|
|
476
525
|
* @param {object} targetObj target object
|
|
477
526
|
* @param {number} startFrom index from which to start searching
|
|
478
|
-
* @param {...string} comparisonFields
|
|
527
|
+
* @param {...string} comparisonFields the fields sort order of the array. e.g. 'score desc', 'numGames asc'.
|
|
479
528
|
* @returns index of the next different object.
|
|
480
529
|
*/
|
|
481
530
|
function getNextDifferent(objArray, targetObj, startFrom, ...comparisonFields) {
|
|
@@ -507,9 +556,13 @@ function getNextDifferent(objArray, targetObj, startFrom, ...comparisonFields) {
|
|
|
507
556
|
module.exports.getNextDifferent = getNextDifferent;
|
|
508
557
|
|
|
509
558
|
/**Create an array with duplicates eliminated, according to certain fields. Taking only the first or last object from each duplicate set.
|
|
559
|
+
*
|
|
510
560
|
* If firstOfDuplicates === true, then the first element in each set of duplicates is taken.
|
|
561
|
+
*
|
|
511
562
|
* if firstOfDuplicates === false, then the last element is taken from each set of duplicates.
|
|
512
|
-
*
|
|
563
|
+
*
|
|
564
|
+
* Assumed comparison field data types are Boolean, Number, String, Date.
|
|
565
|
+
*
|
|
513
566
|
* The array must be sorted according to the comparison fields before calling this function.
|
|
514
567
|
* The value of the comparison field must include both the field name and sort direction.
|
|
515
568
|
* Sort direction assumed to be "asc" if not provided.
|
|
@@ -561,14 +614,21 @@ function getObjArrayWithNoDuplicates(objArray, firstOfDuplicates, ...comparisonF
|
|
|
561
614
|
} // function getObjArrayWithNoDuplicates(objArray, ...comparisonFields) {
|
|
562
615
|
module.exports.getObjArrayWithNoDuplicates = getObjArrayWithNoDuplicates;
|
|
563
616
|
|
|
564
|
-
/**Compare 2 objects according to the comparison fields
|
|
565
|
-
*
|
|
617
|
+
/**Compare 2 objects according to the comparison fields, and return the result of:
|
|
618
|
+
*
|
|
619
|
+
* -1 if obj1 is before obj2, 1 if obj1 is after obj2, 0 if obj1 is equal to obj2.
|
|
620
|
+
*
|
|
621
|
+
* Each each of the comparisonFields must be of the form 'fieldName sortDirection' or 'fieldName'.
|
|
622
|
+
*
|
|
566
623
|
* Sort directions: 'asc', 'desc'.
|
|
567
|
-
*
|
|
624
|
+
*
|
|
625
|
+
* Field/sort-direction examples: 'lastName desc', 'firstName', 'firstName asc', 'address.provinceName asc'.
|
|
626
|
+
*
|
|
568
627
|
* If sort direction is not provided, then it is assumed to be ascending.
|
|
569
628
|
* @param {object} obj1 first object to compare
|
|
570
629
|
* @param {object} obj2 second object to compare
|
|
571
|
-
* @
|
|
630
|
+
* @param {...string} comparisonFields one or more comparison fields plus sort order.
|
|
631
|
+
* @returns {number} comparison result: -1, 0 or 1.
|
|
572
632
|
*/
|
|
573
633
|
function objCompare(obj1, obj2, ...comparisonFields) {
|
|
574
634
|
if (comparisonFields.length === 0)
|