import { get, set, merge } from 'lodash'; export function decoder(paths: [string, object, object][], obj: TIn): TOut { const output: Partial = {}; const array_notation_test = /(.+)\[](\..+)?/; const paths_to_process = paths.slice(); while (paths_to_process.length > 0) { const [path, from, to] = paths_to_process.pop() as [string, object, object]; let value = get(obj, path) as unknown; const matches = array_notation_test.exec(Array.isArray(value) ? `${path}[]` : path); // Array Expansion logic if (matches) { const [, pre_path, post_path] = matches; const base = get(obj, pre_path, []) as unknown[]; paths_to_process.push( ...base.map<[string, object, object]>((_, index) => [`${pre_path}[${index}]${post_path || ''}`, from, to]) ); } else { // Correct for the enum value being reversed if (typeof value !== 'number' && (value as never) in from) { value = from[value as never]; } if ((value as never) in from && (value as never) in to) { set(output, path, to[value as never]); } else if ( ((value as never) in from && !((value as never) in to)) || ((value as never) in to && !((value as never) in from)) ) { throw new Error(`Failed to decode value at '${path}': MISMATCH`); } } } return merge({}, obj, output) as unknown as TOut; }