import {isNonPlainObject} from '../is'; import type {GenericCallback, PlainObject} from '../models'; // #region Types /** * A callback transform an object's properties */ type TransformCallback = ( key: Key, value: Value[Key], ) => Value[Key]; /** * A collection of keyed callbacks to transform an object's properties */ type TransformCallbacks = Partial<{ [Key in keyof Value]: (value: Value[Key]) => Value[Key]; }>; /** * A transformer function for an object, with predefined callbacks for transforming its properties */ export type Transformer = { (value: Value): Value; }; // #endregion // #region Functions function getTransformer( input: unknown, ): TransformCallback | TransformCallbacks | undefined { if (typeof input === 'function') { return input as GenericCallback; } if (isNonPlainObject(input)) { return; } const keys = Object.keys(input) as Key[]; const {length} = keys; const transformer: Partial> = {}; for (let index = 0; index < length; index += 1) { const key = keys[index]; const value = input[key]; if (typeof value === 'function') { transformer[key] = value; } } if (Object.keys(transformer).length > 0) { return transformer; } } /** * Initialize a transformer for an object with a transformer function * * _Available as `initializeTransformer` and `transform.initialize`_ * * @param transform Transformer function * @returns Transformer */ export function initializeTransformer( transform: TransformCallback, ): Transformer; /** * Initialize a transformer for an object with transformer functions * * _Available as `initializeTransformer` and `transform.initialize`_ * * @param transformers Keyed transformer functions * @returns Transformer */ export function initializeTransformer( transformers: TransformCallbacks, ): Transformer; export function initializeTransformer( transform: unknown, ): Transformer { const transformer = getTransformer(transform); return value => transformValue(value, transformer); } /** * Transform and objects properties using a transformer function * * @param value Object to transform * @param transform Transformer function * @returns Transformed object */ export function transform( value: Value, transform: TransformCallback, ): Value; /** * Transform and objects properties using a transformer object * * @param value Object to transform * @param transformers Keyed transformer functions * @returns Transformed object */ export function transform( value: Value, transformers: TransformCallbacks, ): Value; export function transform(value: Value, transform: unknown): Value { return transformValue(value, getTransformer(transform)); } transform.initialize = initializeTransformer; function transformValue( value: Value, transformer?: TransformCallback | TransformCallbacks, ): Value { if (isNonPlainObject(value)) { return {} as Value; } if (transformer == null) { return value; } const keys = Object.keys(value) as Key[]; const {length} = keys; for (let index = 0; index < length; index += 1) { const key = keys[index]; const val = value[key]; if (typeof transformer === 'function') { value[key] = transformer(key, val) as Value[Key]; } else { value[key] = (transformer[key]?.(val) ?? val) as Value[Key]; } } return value; } // #endregion