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.
Files changed (3) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/index.js +115 -55
  3. 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
- /** Return a numeric string with trailing zeros.
144
- * E.g. addLeadingZeros(9, 3) = '009'
145
- * Inputs:
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
- * NB. Class instance types will be converted to plain object types due to stringification.
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
- return JSON.parse(JSON.stringify(obj));
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
- * 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)
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
- 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]);
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
- else {
233
- sortedObject[field] = objClone[field];
234
- } //
235
- } // for (let field in paths) {
267
+ paths.sort();
236
268
 
237
- return sortedObject;
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
- * @returns {*} the value of the field specified by the path.
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 currentObj = deepClone(anObject);
253
-
254
- let value = currentObj[paths[0]];
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
- else {
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
- * 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.
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} integer (-1, 0 or 1)
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
- * 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.
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
- * @@param {number} [startFrom=0] index from which to start searching.
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 comparison fields plus sort order.
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
- * Assumed field data types are Number, String and Date.
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 specified in the comparison fields, and return the result.
565
- * Each each of the comparisonFields must be of the form 'fieldName sortDirection' or 'fieldName'.
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
- * Examples: 'lastName desc', 'firstName', 'firstName asc', 'address.provinceName asc'.
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
- * @returns {number} a comparison value of 1, 0 or -1
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)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "some-common-functions-js",
3
- "version": "1.1.4",
3
+ "version": "1.1.6",
4
4
  "description": "Common functions used with Javascript objects, and field validation functions.",
5
5
  "keywords": [
6
6
  "validation",