get.js

/**
 * Returns the value at given path of given object. If path is not found then default value is returned. No exceptions
 * are thrown when undefined/null value gets in the way.
 *
 * @param {Object} source - source object to search in
 * @param {string|Array<string>} property - path to the expected value written as dot-separated property names or array
 * with property names. Use Array when your keys includes dots. Keys are treated literally, no parsing is done on keys.
 * @param {*} [defaultValue] - value to return if path is not found. If path is found, but the value is undefined -
 * default value will NOT be used, use `get(...) || default` instead
 * @example get(object, "deep.property") // equals to safe `object.deep.property`
 * @example get(object, ["deep", "property"]) // same as above
 * @example get(object, "deep[0].property")
 * // equals to:
 * object["deep[0]"].property
 * // not:
 * object.deep[0].property
 * @example get(object, "very.deep.property", 5)
 * // if object.very.deep has also `property` property then it value will be returned, even if undefined
 * // else `5` will be returned
 * @returns {*} - found value or default value
 */
const get = (source, property, defaultValue) => {
    const properties = typeof property === "string" ? property.split(".") : [...property];

    let result = source; // eslint-disable-line init-declarations
    while (properties.length) {
        const current = properties.shift();
        if (result && typeof result === "object" && current in result) {
            result = result[current];
        }
        else {
            return defaultValue;
        }
    }
    return result;
};

export default get;