Home Reference Source

src/getDefined.js

/**
 * Takes an object and returns a new object that contains only the "defined" values.
 *
 * Values are dropped if they either are included in the `drop` array, or they are an empty object and the `keepObjects` flag is not set.
 *
 * @param {Object} target - An object with properties that shall be omitted if empty
 * @param {Object} [options] - Optional settings
 * @param {Array} [options.drop=[undefined]] - Values that should be treated as "non-defined" values
 * @param {Boolean} [options.keepObjects] - Whether to keep values that are an empty object
 * @return {Object} - A new object with only the "defined" values of `target`
 */
export default function getDefined(target, { drop = [undefined], keepObjects = false } = {}) {
    if (!target) return undefined;
    const result = Object.keys(target).reduce((result, key) => {
        const value = target[key];
        if (drop.some(t => value === t)) {
            return result;
        }
        if (Array.isArray(value)) {
            result[key] = value.map(v => getDefined(v, { drop, keepObjects })).filter(v => !drop.some(t => v === t));
            if (result[key].length === 0) {
                delete result[key];
            }
        } else if (Object(value) === value) {
            // non-primitive
            result[key] = getDefined(value, { drop, keepObjects });
            if (keepObjects !== true && Object.keys(result[key]).length === 0) {
                delete result[key];
            }
        } else {
            // primitive
            result[key] = value;
        }
        return result;
    }, {});
    return result;
}