2.1.5 • Published 1 year ago

@eribrary/helpers-general v2.1.5

Weekly downloads
-
License
ISC
Repository
github
Last release
1 year ago

@eribrary/helpers-general v1.0.2

Helper functions for common Javascript operations. As a "general" helper function library, this does NOT cater to any special needs but is meant to be applicable to a wide variety of typical use cases. Examples provided below.

Installation

import * as gHelpers from '@eribrary/helpersGeneral'

Example Functions

Deep Clone Objects:

Forget the shallow clone crap! Go deep, take everything.
/**
 * Deep Clone an Object of any type and level of nesting, completely removing all dependencies.
 * 
 * @param {object} inObject - The Object to Deep Clone.
 * @returns A Coned Object.
 */
const deepCloneObject = (inObject) => {

    // First we create an empty returnObj that we fill in later and return.
    let returnObj = {};

    // Second we iterate through the top-level of inObject, filling in our returnObj.
    for (const [key, value] of Object.entries(inObject)) {

        // Third we check whether the value is of any Pass-by-Reference Type (Array or Object).
        // For each of these, we iterate through each value and determine if the values are Pass-by-Reference
        // or not.  If they are, we need a recursive call to this function.  Otherwise, this is the final call.

        if (value === null) { returnObj[key] = value; } // #TODO - should leave as null or set to "" ?
        else if (Array.isArray(value)) {

            // Start will an empty array and bMakeRecursiveCall = TRUE.
            // Since Arrays must always be of the same type, then if ANY value is NOT an Object / Array,
            // we can set bMakeRecursiveCall = FALSE.
            returnObj[key] = [];
            let bMakeRecursiveCall = true; // #TODO - #DELETE - #TEST - delete after testing - just want to make sure the code works and the type won't ever change.

            let arrLength = value.length;
            for (let i = 0; i < arrLength; i++) {
                if (bMakeRecursiveCall && checkIsEnumerableObject(value[i])) {
                    returnObj[key].push(deepCloneObject(value[i]));
                    if (bMakeRecursiveCall === false) {
                        notifyOnError(["bMakeRecursiveCall was FALSE", `${key}: ${value[i]} @ index ${i}`])
                    }
                    bMakeRecursiveCall = true;
                }
                else {
                    returnObj[key].push(value[i]);
                    bMakeRecursiveCall = false;
                }
            }
        }
        else if (checkIsEnumerableObject(value)) {
            returnObj[key] = deepCloneObject(value);
        }
        else {
            returnObj[key] = value;
        }
    }

    return returnObj;
}

Check Whether a Variable is an Enumberable Object:

Do you hate it when typeof returns object but you're not quite sure whether that means an actual Object you can iterate through or just null, undefined, a date, a function, etc.? Well wonder no more, because this function makes a final determination you can rely on!
/**
 * Check whether a variable is an enumberable Object (will have [key, value] pairs).
 * 
 * @param {object} inObject - Object to check.
 * @returns Boolean - TRUE for an Object and FALSE for NOT an Object.
 */
const checkIsEnumerableObject = (inObject) => {

    // First make sure inObject isn't null and is a typeof 'object'.
    // If it fails either of these, we return FALSE.  If it passes, then we check
    // whether it is a "true" Object (i.e. "[object Object]"), which is the only type that is enumerable.
    if (inObject !== null && typeof inObject === 'object') {
        return Object.prototype.toString.call(inObject) === '[object Object]';
    }
    else { return false };
}

Convert Any Array Into Multiple, Evenly Spaced Arrays OR 1 String[]

Have an Array you want broken down into evenly spaced mini-arrays? Or do you just want to split a String evenly into a single String[]? We've got you covered!
/**
 * Takes an Array (any type) and separates out its elements into innerArrays based on an "interval" argument.  This is especially useful for
 * the Slack interface where we may have a lengthy fieldsArray and need to split each Fields element into Sections of 2 Fields each.  
 * @param {[]} inArray - An Array of any type.
 * @param {number} interval - How many Array elements should each innerArray include in the final 2D Array (the last innerArray may contain fewer if the length of inArray is not evenly divisible by this number).  Default is 1.
 * @param {boolean} bReturnTextArray - TRUE = returns a String[] and essentially is the same as inArray.match(/.{1,X}/g) where "X" is the "interval" param and inArray is a String (but unlike .match(), this works on most types, including Number[]).  #NOTE: this will NOT work well for Object[], which returns only "[object Object]" for each element.  FALSE = behaves normally, returning a 2D array.  Default is FALSE.
 * @returns - if bReturnTextArray = FALSE, then returns a 2D Array of the same type as inArray that has the original inArray's elements spaced out in innerArrays by the interval number.  If bReturnTextArray = TRUE, then returns a String[] likewise separated.
 */
const alternateArrayElements = (inArray, interval = 1, bReturnTextArray = false) => {

    // Preliminary variables.
    let finalArray = []
    let arrayLength = inArray.length

    for (let i = 0; i < arrayLength; ++i) {

        if (((i + 1) % interval) === 0) {

            // If (i + 1) can be divided evenly by interval, then we get a number of elements equal to 
            // interval (before and including i), starting at the earliest element.

            // Here we start at interval - 1 (since we include i) and do a reverse forLoop()
            // in order to get the earliest elements first.  Each element is pushed to a dummy innerArray.
            // Then, once the forLoop() ends, we push that innerArray to the finalArray.
            let innerArray = []
            let stringArray = ""
            for (let j = interval - 1; j > -1; j--) {
                bReturnTextArray ? stringArray += inArray[i - j] : innerArray.push(inArray[i - j])
            }
            finalArray.push(bReturnTextArray ? stringArray : innerArray)
        }
        else if (i === arrayLength - 1) {
            // If we've reached the end of inArray and the arrayLength was not evenly divisible by interval
            // (in which case the above code would have been called), we will need to retrieve all unhandled elements.

            // We get unhandled elements by finding how many leftover elements there are (arrayLength % interval) and subtract -1
            // because, as before, we include i.  Then we follow the same process as above for pushing elements to the finalArray.
            let innerArray = []
            let stringArray = ""
            for (let j = (arrayLength % interval) - 1; j > -1; j--) {
                if (i - j > -1) {
                    bReturnTextArray ? stringArray += inArray[i - j] : innerArray.push(inArray[i - j])
                }
            }
            finalArray.push(bReturnTextArray ? stringArray : innerArray)
        }
    }

    return finalArray
}
2.1.1

1 year ago

2.1.4

1 year ago

2.1.3

1 year ago

2.1.5

1 year ago

2.1.0

1 year ago

1.0.2

2 years ago

1.1.0

2 years ago

2.0.1

2 years ago

1.0.4

2 years ago

2.0.0

2 years ago

1.0.3

2 years ago

1.0.1

3 years ago

1.0.0

3 years ago