UNPKG

@snipsonian/core

Version:

Core/base reusable javascript code snippets

159 lines (138 loc) 4.49 kB
import isSet from '../../is/isSet'; import isObjectPure from '../../is/isObjectPure'; import { TAnyObject } from '../../typings/object'; import cloneObjectDataProps from '../cloneObjectDataProps'; /** * This method will * - clone the input object * - then search for (nested) properties that match the 'propPathsToObscure' * - and obscure their values with the 'obscureValue'. * * @param obj The object to obscure some sensitive data from * @param propPathsToObscure Array of property paths to obscure, where a . is used as path delimiter. * E.g. ['headers.Authorization'] to obscure the Authorization prop within the headers prop. * @param obscureValue Optional (default "***obscured***"). The string that will be used to obscure a property value. * If false, then the properties will be removed from the resulting object instead of obscured. */ const DEFAULT_OBSCURE_VALUE = '***obscured***'; export function obscureObjectProps({ obj, propPathsToObscure, obscureValue = DEFAULT_OBSCURE_VALUE, }: { // eslint-disable-next-line @typescript-eslint/ban-types obj: object; propPathsToObscure: string[]; obscureValue?: false | string; }) { if (!isObjectPure(obj)) { return obj; } return propPathsToObscure.reduce( (accumulator, propPathToObscure) => { if (isObjectPropSetByPath({ obj: accumulator as TAnyObject, propPath: propPathToObscure, })) { if (obscureValue === false) { removeObjectByPath({ obj: accumulator as TAnyObject, propPath: propPathToObscure, }); } else { setObjectPropByPath({ obj: accumulator as TAnyObject, propPath: propPathToObscure, newValue: obscureValue, }); } } return accumulator; }, cloneObjectDataProps(obj), ); } function removeObjectByPath({ obj, propPath, }: { obj: TAnyObject; propPath: string; // . separated }) { const pathParts = propPath.split('.'); if (pathParts.length === 1) { // eslint-disable-next-line no-param-reassign delete obj[pathParts[0]]; } else if (pathParts.length > 1) { const lastPathPart = pathParts.pop(); /* 'pop' removes the last element of an array */ const parentObj = getObjectPropByPathParts({ obj, propPathParts: pathParts, /* does not contain the last path part anymore because of the pop */ }); if (isObjectPure(parentObj)) { delete (parentObj as TAnyObject)[lastPathPart]; } } return obj; } function setObjectPropByPath({ obj, propPath, newValue, }: { obj: TAnyObject; propPath: string; // . separated newValue: unknown; }) { const pathParts = propPath.split('.'); if (pathParts.length === 1) { // eslint-disable-next-line no-param-reassign obj[pathParts[0]] = newValue; } else if (pathParts.length > 1) { const lastPathPart = pathParts.pop(); /* 'pop' removes the last element of an array */ const parentObj = getObjectPropByPathParts({ obj, propPathParts: pathParts, /* does not contain the last path part anymore because of the pop */ }); if (isObjectPure(parentObj)) { (parentObj as TAnyObject)[lastPathPart] = newValue; } } return obj; } function getObjectPropByPathParts({ obj, propPathParts, }: { obj: TAnyObject; propPathParts: string[]; }): unknown { if (!isObjectPure(obj)) { return null; } if (!propPathParts || propPathParts.length === 0) { return null; } const [firstPathPart, ...remainingPathParts] = propPathParts; const first = obj[firstPathPart]; return propPathParts.length === 1 ? first : getObjectPropByPathParts({ obj: first as TAnyObject, propPathParts: remainingPathParts, }); } function isObjectPropSetByPath({ obj, propPath, }: { obj: TAnyObject; propPath: string; // . separated }): boolean { return isSet( getObjectPropByPathParts({ obj, propPathParts: propPath.split('.'), }), ); }