68 lines
1.4 KiB
TypeScript
68 lines
1.4 KiB
TypeScript
// Copyright 2022 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
|
|
import { cloneDeep, get, set } from 'lodash';
|
|
|
|
export type ObjectMappingSpecType =
|
|
| string
|
|
| ReadonlyArray<ObjectMappingSpecType>
|
|
| Readonly<{
|
|
key: string;
|
|
valueSpec: ObjectMappingSpecType;
|
|
}>
|
|
| Readonly<{
|
|
isMap: true;
|
|
valueSpec: ObjectMappingSpecType;
|
|
}>;
|
|
|
|
export function mapObjectWithSpec<Input, Output>(
|
|
spec: ObjectMappingSpecType,
|
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
data: any,
|
|
map: (value: Input) => Output,
|
|
target = cloneDeep(data)
|
|
): any {
|
|
if (!data) {
|
|
return target;
|
|
}
|
|
|
|
if (typeof spec === 'string') {
|
|
const value = get(data, spec);
|
|
|
|
if (value) {
|
|
set(target, spec, map(value));
|
|
}
|
|
return target;
|
|
}
|
|
|
|
if ('isMap' in spec) {
|
|
for (const key of Object.keys(data)) {
|
|
// eslint-disable-next-line no-param-reassign
|
|
target[key] = mapObjectWithSpec(
|
|
spec.valueSpec,
|
|
data[key],
|
|
map,
|
|
target[key]
|
|
);
|
|
}
|
|
return target;
|
|
}
|
|
|
|
if ('key' in spec) {
|
|
// eslint-disable-next-line no-param-reassign
|
|
target[spec.key] = mapObjectWithSpec(
|
|
spec.valueSpec,
|
|
data[spec.key],
|
|
map,
|
|
target[spec.key]
|
|
);
|
|
return target;
|
|
}
|
|
|
|
for (const key of spec) {
|
|
mapObjectWithSpec(key, data, map, target);
|
|
}
|
|
|
|
return target;
|
|
}
|