nhb-toolbox
Version:
A versatile collection of smart, efficient, and reusable utility functions and classes for everyday development needs.
145 lines (144 loc) • 5.43 kB
JavaScript
/**
* * Converts the values of specified keys in an object or array of objects to either string or number.
* * Supports nested objects using dot-notation keys.
*
* @param data The object or array of objects to convert.
* @param options Options object specifying the conversion mapping.
* - `keys`: The keys in the object to be converted (dot-notation supported).
* - `convertTo`: The target type, either "string" or "number".
* @returns The modified object or array of objects with the converted values, with updated types.
*/
export function convertObjectValues(data, options) {
const { keys, convertTo } = options;
/** * Helper function to determine if value should be preserved. */
const _shouldPreserveValue = (value) => convertTo === 'number' &&
(typeof value !== 'string' || isNaN(Number(value)));
/** * Helper function to resolve a dot-notation key path and modify the corresponding value in the object. */
const _setValueAtPath = (obj, path, convertTo) => {
const segments = path.split('.');
let current = obj;
segments?.forEach((key, index) => {
if (index === segments?.length - 1) {
const value = current?.[key];
if (_shouldPreserveValue(value)) {
return;
}
if (convertTo === 'string' && typeof value !== 'string') {
current[key] = String(value);
}
else if (convertTo === 'number' &&
typeof value !== 'number' &&
!isNaN(Number(value))) {
current[key] = Number(value);
}
}
else {
if (typeof current?.[key] === 'object' &&
current?.[key] !== null) {
current = current?.[key];
}
else {
current[key] = {};
current = current?.[key];
}
}
});
return obj;
};
/** * Recursively process a single object. */
const _convertValue = (obj) => {
let newObj = structuredClone(obj);
keys?.forEach((key) => {
newObj = _setValueAtPath(newObj, key, convertTo);
});
return newObj;
};
if (Array.isArray(data)) {
return data?.map((d) => _convertValue(d));
}
return _convertValue(data);
}
/**
* * Pick specific fields from an object and create a new object with specified fields.
*
* @description This function creates a new object containing only the specified fields from the source object.
* It is useful for creating a new object with a subset of properties from an existing object.
*
* @param T The type of the source object.
* @param U The type of the keys to pick from the source object.
*
* @param source The source object from which to pick fields.
* @param keys The keys of the fields to pick from the source object.
*
* @returns An object containing only the picked fields.
*/
export function pickFields(source, keys) {
const result = {};
keys?.forEach((key) => {
result[key] = source?.[key];
});
return result;
}
/**
* * Create a new object by removing specific keys from the source object.
*
* @param source - The original (source) object from which to delete fields.
* @param keys - An array of keys (fields) to remove from the object.
*
* @returns A new object without the specified keys.
*
* @example
* deleteFields({ a: 1, b: 2, c: 3 }, ['b'])
* // => { a: 1, c: 3 }
*
* @notes
* - Does not mutate the original object.
* - Useful for excluding sensitive or unwanted fields.
*/
export function deleteFields(source, keys) {
const result = {};
for (const key in source) {
if (!keys.includes(key)) {
result[key] = source?.[key];
}
}
return result;
}
/**
* * Pick specific fields from an object based on a given condition.
*
* @description This function creates a new object containing only the fields that satisfy the given condition.
* The condition can be based on the field's value or type, depending on the implementation.
*
* @param T The type of the source object.
*
* @param source The source object from which to pick fields.
* @param condition A function that takes the key and value of a property and returns a boolean indicating whether the property should be picked.
*
* @returns An object containing only the fields that satisfy the condition.
*/
export function pickObjectFieldsByCondition(source, condition) {
const result = {};
Object.entries(source)?.forEach(([key, value]) => {
if (condition(key, value)) {
result[key] = value;
}
});
return result;
}
/**
* * Remap fields from one object to another.
* @description This function creates a new object with fields remapped from the source object to the target object based on the provided field map.
*
* @param source The source object from which to remap fields.
* @param fieldMap An object that maps target keys to source keys.
* @returns An object with fields remapped according to the field map.
*/
export function remapFields(source, fieldMap) {
const result = {};
for (const targetKey in fieldMap) {
const sourceKey = fieldMap?.[targetKey];
result[targetKey] = source?.[sourceKey];
}
return result;
}