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