ramimu's picture
Upload 586 files
1c72248 verified
import React from 'react';
/**
* Updates a deeply nested value in an object using a string path
* @param obj The object to update
* @param value The new value to set
* @param path String path to the property (e.g. 'config.process[0].model.name_or_path')
* @returns A new object with the updated value
*/
export function setNestedValue<T, V>(obj: T, value: V, path?: string): T {
// Create a copy of the original object to maintain immutability
const result = { ...obj };
// if path is not provided, be root path
if (!path) {
path = '';
}
// Split the path into segments
const pathArray = path.split('.').flatMap(segment => {
// Handle array notation like 'process[0]'
const arrayMatch = segment.match(/^([^\[]+)(\[\d+\])+/);
if (arrayMatch) {
const propName = arrayMatch[1];
const indices = segment
.substring(propName.length)
.match(/\[(\d+)\]/g)
?.map(idx => parseInt(idx.substring(1, idx.length - 1)));
// Return property name followed by array indices
return [propName, ...(indices || [])];
}
return segment;
});
// Navigate to the target location
let current: any = result;
for (let i = 0; i < pathArray.length - 1; i++) {
const key = pathArray[i];
// If current key is a number, treat it as an array index
if (typeof key === 'number') {
if (!Array.isArray(current)) {
throw new Error(`Cannot access index ${key} of non-array`);
}
// Create a copy of the array to maintain immutability
current = [...current];
} else {
// For object properties, create a new object if it doesn't exist
if (current[key] === undefined) {
// Check if the next key is a number, if so create an array, otherwise an object
const nextKey = pathArray[i + 1];
current[key] = typeof nextKey === 'number' ? [] : {};
} else {
// Create a shallow copy to maintain immutability
current[key] = Array.isArray(current[key]) ? [...current[key]] : { ...current[key] };
}
}
// Move to the next level
current = current[key];
}
// Set the value at the final path segment
const finalKey = pathArray[pathArray.length - 1];
current[finalKey] = value;
return result;
}
/**
* Custom hook for managing a complex state object with string path updates
* @param initialState The initial state object
* @returns [state, setValue] tuple
*/
export function useNestedState<T>(initialState: T): [T, (value: any, path?: string) => void] {
const [state, setState] = React.useState<T>(initialState);
const setValue = React.useCallback((value: any, path?: string) => {
if (path === undefined) {
setState(value);
return;
}
setState(prevState => setNestedValue(prevState, value, path));
}, []);
return [state, setValue];
}