some-common-functions-js 1.1.3 → 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.
Files changed (3) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/index.js +109 -52
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -45,3 +45,14 @@ Improve README.md documentation.
45
45
 
46
46
  ## Version 1.1.2 - 2025/12/26 - ITA
47
47
  Corrected a minor error in the README documentation.
48
+
49
+ ## Version 1.1.3 - 2025/12/27 - ITA
50
+ - Improved getObjArrayWithNoDuplicates() and getNextDifferent functions to handle more test cases.
51
+ - Added the unset() function.
52
+
53
+ ## Version 1.1.4 - 2025/12/27 - ITA
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
- /** Return a numeric string with trailing zeros.
144
- * E.g. addLeadingZeros(9, 3) = '009'
145
- * Inputs:
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
- * NB. Class instance types will be converted to plain object types due to stringification.
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
- return JSON.parse(JSON.stringify(obj));
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
- * This is desirable when equality comparison is done to ensure two objects sharing equal field values
211
- * the pass the equality test stringify(object1) === stringify(object2)
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
- const objClone = deepClone(pObject);
217
- const paths = [];
218
- const sortedObject = {};
219
-
220
- // Obtain the outermost fields and sort them.
221
- for (let field in objClone) {
222
- paths.push(field);
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
- else {
233
- sortedObject[field] = objClone[field];
234
- } //
235
- } // for (let field in paths) {
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
- return sortedObject;
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
- * @returns {*} the value of the field specified by the path.
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
- console.log(hasAll(anObject, path), path, anObject, getPaths(anObject));
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 currentObj = deepClone(anObject);
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
- else {
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
- * Return -1 for an empty array.
370
- * This function is to be used also in cases where values are to be inserted into the array while maintaining sort order.
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} integer (-1, 0 or 1)
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
- * for example'lastName asc', 'firstName', 'address.province asc', 'address.townOrCity asc'.
435
- * If the array contains the object with values searched for, then the index returned is the location of this value in the array,
436
- * otherwise, the index is of the closest value in the array that is before or after the searchObj value.
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
- * @@param {number} [startFrom=0] index from which to start searching.
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 comparison fields plus sort order.
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
- * Assumed field data types are Number, String and Date.
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 specified in the comparison fields, and return the result.
565
- * Each each of the comparisonFields must be of the form 'fieldName sortDirection' or 'fieldName'.
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
- * Examples: 'lastName desc', 'firstName', 'firstName asc', 'address.provinceName asc'.
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
- * @returns {number} a comparison value of 1, 0 or -1
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)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "some-common-functions-js",
3
- "version": "1.1.3",
3
+ "version": "1.1.5",
4
4
  "description": "Common functions used with Javascript objects, and field validation functions.",
5
5
  "keywords": [
6
6
  "validation",