immutable-path
Version:
Immutable `get`, `set`, `has`, `unset` deep path operations libraray for object, array and `Map`.
109 lines • 5.07 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const get_1 = __importDefault(require("./util/get"));
const set_1 = __importDefault(require("./util/set"));
const unset_1 = __importDefault(require("./util/unset"));
const has_1 = __importDefault(require("./util/has"));
const helper_1 = require("./util/helper");
/**
* Sets the property value of path on object/array/Map immutably without changing input. If a portion of path does not exist it's created.
* Provided `atomicClasses` is used to determine which type of objects are treated as atomic. Atomic classes are
* treated like primitives pretending they don't have attributes. See example below. If `preferMap` is true,
* when new objects are needed, they are created as `Map` instead of object.
*
* @param source is the object/array/map to set.
* @param path is the path of the property to set.
* @param value is the value to set.
* @param __namedParameters are options.
* @returns new object/array/Map.
* @example
* const a = set({ x: new Date() }, "x.y", 3); // 3 is not assigned to atomic class Date. Insted it is replaced: { x: { y: 3 } }
* const b = set({ x: { z: 1 } }, "x.y", 3); // 3 is not assigned to `x.y`: { x: { y: 3, z: 1 } }
* const c = set({ }, "x.y", 3); // 3 is not assigned to `x.y`: { x: { y: 3 } }
* const c = set({ }, "x.y", 3, { preferMap: true }); // Map([[x, new Map([[y, 3]])]]);
*/
function set(source, path, value, {
/** Atomic classes are treated like a scalar, because MOST PROBABLY user did not intend to update a property of it. Instead they want to replace it. */
atomicClasses = helper_1.defaultAtomicClasses,
/** If an attribute for a non-existing object should be created, whether to create a `Map` instead of `object`. */
preferMap = false, } = {}, root = source) {
const options = { atomicClasses, preferMap };
const [key, ...remainingPath] = helper_1.getPath(path);
const oldValueOfKey = helper_1.getAddressableValue(source, key, options, remainingPath[0]);
const newValueOfKey = remainingPath.length > 0 ? set(oldValueOfKey, remainingPath, value, options, root) : value;
return set_1.default(source, key, newValueOfKey, root);
}
exports.set = set;
/**
* Removes the property at path of object and returns it. Does not change input value.
*
* @param source is the object/array/map to unset a value.
* @param path is the path of the property to unset.
* @param __namedParameters are options.
* @returns new object/array/Map.
*/
function unset(source, path, {
/** Atomic classes are treated like a scalar, because MOST PROBABLY user did not intend to update a property of it. Instead they want to replace it. */
atomicClasses = helper_1.defaultAtomicClasses,
/** After unsetting a key/index if object/array/Map becomes empty, it is also unset in parent. */
unsetEmpty = true,
/** If an attribute for a non-existing object should be created, whether to create a `Map` instead of `object`. */
preferMap = false, } = {}) {
const options = { atomicClasses, unsetEmpty, preferMap };
const [key, ...remainingPath] = helper_1.getPath(path);
const addressableValue = helper_1.getAddressableValue(source, key, options);
if (remainingPath.length > 0) {
if (addressableValue) {
const unsetValue = unset(addressableValue, remainingPath, options);
const unsetFurther = unsetEmpty && helper_1.isEmpty(unsetValue, atomicClasses);
if (!unsetFurther)
return set_1.default(source, key, unsetValue);
}
else {
return source;
}
}
return unset_1.default(source, key);
}
exports.unset = unset;
/**
* Gets the property value at path of object/array/Map. If the resolved value is undefined the defaultValue is used in its place.
*
* @param source is the object/array/map to query.
* @param path is the path of the property to get.
* @param defaultValue is the value returned if the resolved value is `undefined`.
* @returns the resolved value.
*/
function get(source, path, defaultValue) {
let result = source;
// eslint-disable-next-line no-restricted-syntax
for (const key of helper_1.getPath(path)) {
result = get_1.default(result, key);
if (result === undefined)
return defaultValue;
}
return result;
}
exports.get = get;
/**
* Checks if path is a direct property of object/array/Map.
*
* @param source is the object/array/Map to query.
* @param path is the path to check.
* @returns whether path is a direct property of object/array/Map.
*/
function has(source, path) {
let current = source;
// eslint-disable-next-line no-restricted-syntax
for (const key of helper_1.getPath(path)) {
if (!has_1.default(current, key))
return false;
current = get_1.default(current, key);
}
return true;
}
exports.has = has;
//# sourceMappingURL=immutable-object-path.js.map