@geogirafe/lib-geoportal
Version:
GeoGirafe is a flexible application to build online geoportals.
101 lines (100 loc) • 3.61 kB
JavaScript
/**
* Get a property value out of an object by providing the path to the property.
* @returns the property or object, following the given path, and the
* parent and last key to the parent object to be able to set it (see also setPropertyByPath).
*/
export const getPropertyByPath = (obj, path) => {
let currentObj = obj;
let parentObject = null;
let lastKey = null;
if (path.trim() !== '') {
const keys = path.split('.');
for (const key of keys) {
if (key in currentObj) {
parentObject = currentObj;
lastKey = key;
currentObj = currentObj[key];
}
else {
return { found: false, object: null, parentObject, lastKey };
}
}
}
return { found: true, object: currentObj, parentObject, lastKey };
};
/**
* Sets the value of a property specified by a given path in an object.
* @returns true if the property was set successfully, false otherwise.
*/
export const setPropertyByPath = (obj, path, value) => {
const result = getPropertyByPath(obj, path);
if (result.parentObject && result.lastKey) {
result.parentObject[result.lastKey] = value;
return true;
}
return false;
};
/**
* @returns a nested object from a given path of keys. The most deeply nested value will be an empty object.
*/
export const createObjectFromPath = (path) => {
const keys = path.split('.');
const resultObject = {};
let pointer = resultObject;
keys.forEach((key) => {
const addLevel = () => (pointer[key] = {});
pointer = key ? addLevel() : pointer;
});
return resultObject;
};
/**
* Deletes a property in an object and all its predecessors, if they otherwise would be empty objects.
*/
export const deletePropertyByPath = (obj, path) => {
const result = getPropertyByPath(obj, path);
if (result.found && result.parentObject && result.lastKey) {
// Property exists, delete it
delete result.parentObject[result.lastKey];
}
else if (!result.found && result.parentObject && result.lastKey) {
// Predecessor exits, delete it if it does not contain any other properties
if (Object.keys(result.parentObject[result.lastKey]).length === 0) {
delete result.parentObject[result.lastKey];
}
else {
// This predecessor contains additional properties, no more predecessor cna be removed
return;
}
}
else {
// Function arrived at root level of object
return;
}
deletePropertyByPath(obj, path);
};
/**
* Merges the properties of two objects recursively. If properties in both objects
* are of type 'object', they will be merged deeply. Otherwise, properties in the
* second object will overwrite properties with the same keys in the first object.
*
* @param obj1 - The target object to be merged into.
* @param obj2 - The source object providing properties to merge.
* @returns The merged object containing properties from both input objects.
*/
export const mergeObjects = (obj1, obj2) => {
for (const key in obj2) {
if (Object.prototype.hasOwnProperty.call(obj1, key)) {
// NOSONAR: Can be solved when migrating to ES2022
if (typeof obj1[key] === 'object' && typeof obj2[key] === 'object') {
mergeObjects(obj1[key], obj2[key]);
}
else {
obj1[key] = obj2[key];
}
}
else {
obj1[key] = obj2[key];
}
}
return obj1;
};