UNPKG

mobx-bonsai

Version:

A fast lightweight alternative to MobX-State-Tree + Y.js two-way binding

58 lines (52 loc) 2.32 kB
import { failure } from "../error/failure" import { getGlobalConfig } from "../globalConfig" import { isPlainObject, isPrimitive } from "../plainTypes/checks" import { getNodeTypeAndKey, NodeKeyValue } from "./nodeTypeKey/nodeType" /** * Deeply substitutes node keys in a data structure with new keys generated by a provided function. * * This function recursively traverses the input data structure and replaces all node keys with new ones * according to the provided key generator function. The function creates a deep clone of the original * data structure, ensuring no references to the original remain. * * Node keys are unique identifiers that are used internally to track and identify nodes in the data tree. * Substituting these keys is useful when cloning nodes to ensure each node has a unique identity. * * The function handles: * - Primitives: returned as-is * - Arrays: recursively processes each element * - Plain objects: identifies node keys using `getNodeTypeAndKey` and substitutes them * * @template T - The type of the input value * @param value - The value to process (primitive, array, or plain object) * @param newNodeKeyGenerator - Function to generate new node keys from old ones. * Defaults to the global key generator from configuration. * @returns A deep clone of the original value with all node keys substituted * * @throws Will throw an error if encountering a value type that isn't a primitive, array, or plain object */ export function substituteNodeKeys<T>( value: T, newNodeKeyGenerator: (oldKey: NodeKeyValue) => NodeKeyValue = getGlobalConfig().keyGenerator ): T { if (isPrimitive(value)) { return value } if (Array.isArray(value)) { return value.map((v) => substituteNodeKeys(v, newNodeKeyGenerator)) as T } if (isPlainObject(value)) { const typeAndKey = getNodeTypeAndKey(value) const keyProp = typeAndKey.type && "key" in typeAndKey.type ? typeAndKey.type.key : undefined const newValue: any = {} for (const key in value) { if (key === keyProp) { newValue[key] = newNodeKeyGenerator(value[key]) } else { newValue[key] = substituteNodeKeys(value[key], newNodeKeyGenerator) } } return newValue } throw failure("unsupported value type") }