UNPKG

@feugene/mu

Version:

Helpful TS utilities without dependencies

48 lines 1.95 kB
import isEmpty from '../is/isEmpty.mjs'; import isObject from '../is/isObject.mjs'; const FORBIDDEN = new Set(['__proto__', 'prototype', 'constructor']); function isForbiddenKey(key) { return typeof key === 'string' ? FORBIDDEN.has(key) : false; } /** * Build or update a nested object structure by a string path. * * Security: forbidden keys ("__proto__", "prototype", "constructor") are ignored to prevent prototype pollution. * * @param paths Path string, e.g. `"a.b.c"`. If empty, the original object is returned. * @param value Value to set at the terminal key (default: `null`). * @param object Target object to modify (mutates this object as per existing API). * @param divider Path segment divider (default: `'.'`). * @param replaceOnExist Replace existing keys along the path (default: `true`). * @returns The same `object` reference with the path set (if valid). */ export default function pathToObject(paths = '', value = null, object = {}, divider = '.', replaceOnExist = true) { if (isEmpty(paths)) { return object; } const pathsArray = paths.split(divider), pathsCount = pathsArray.length; let current = object; for (let i = 0; i < pathsCount; i++) { const k = pathsArray[i]; // Security: skip forbidden keys to avoid prototype pollution if (isForbiddenKey(k)) { return object; } if (isObject(current)) { if (isObject(current[k])) { if (pathsCount - 1 === i) { current[k] = value; } } else { const hasOwn = Object.hasOwn(current, k); if ((hasOwn && replaceOnExist) || !hasOwn) { current[k] = pathsCount - 1 === i ? value : {}; } } } current = current[k]; } return object; } //# sourceMappingURL=pathToObject.mjs.map