1import { snakeCase } from "case-anything";
2
3// https://stackoverflow.com/questions/60269936/typescript-convert-generic-object-from-snake-to-camel-case
4
5// Typescript magic to convert any string from camelCase to snake_case at compile time
6type SnakeCase<S> = S extends string
7 ? S extends `${infer T}${infer U}`
8 ? `${T extends Capitalize<T> ? "_" : ""}${Lowercase<T>}${SnakeCase<U>}`
9 : S
10 : S;
11
12type SnakeCased<Type> = {
13 [Property in keyof Type as SnakeCase<Property>]: SnakeCased<Type[Property]>;
14};
15
16export default function snakeCaseTree<T>(object: T): SnakeCased<T> {
17 const snakeObject: any = {};
18 for (const key in object) {
19 snakeObject[snakeCase(key, { keepSpecialCharacters: true })] =
20 snakeCaseValue(object[key]);
21 }
22 return snakeObject;
23}
24
25function snakeCaseValue(value: any): any {
26 if (typeof value === "object") {
27 if (Array.isArray(value)) {
28 return value.map(snakeCaseValue);
29 } else {
30 return snakeCaseTree(value);
31 }
32 } else {
33 return value;
34 }
35}