Created
July 25, 2022 14:00
-
-
Save IPRIT/7d520ff10d53cb0db888efbdb3121d90 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type CapitalLetters = | |
| 'A' | |
| 'B' | |
| 'C' | |
| 'D' | |
| 'E' | |
| 'F' | |
| 'G' | |
| 'H' | |
| 'I' | |
| 'J' | |
| 'K' | |
| 'L' | |
| 'M' | |
| 'N' | |
| 'O' | |
| 'P' | |
| 'Q' | |
| 'R' | |
| 'S' | |
| 'T' | |
| 'U' | |
| 'V' | |
| 'W' | |
| 'X' | |
| 'Y' | |
| 'Z' | |
export type ToCamel<S extends string | number | symbol> = S extends string | |
? S extends `${infer Head}_${infer Tail}` | |
? Head extends '' | |
? Tail extends '' | |
? '_' | |
: Tail extends `_${infer CAPS}` | |
? `_${Capitalize<ToCamel<CAPS>>}` | |
: `${Capitalize<ToCamel<Tail>>}` | |
: Tail extends `_${infer CAPS}` | |
? CAPS extends '' | |
? `${Uncapitalize<Head>}__` | |
: `${Uncapitalize<Head>}_${Capitalize<ToCamel<CAPS>>}` | |
: `${Uncapitalize<Head>}${Capitalize<ToCamel<Tail>>}` | |
: S | |
: never | |
export type ToCamelSafe<S extends string | number | symbol> = S extends string | |
? ToSnake<ToCamel<S>> extends S | |
? ToCamel<S> | |
: `$${S}` | |
: never | |
export type UnwrapSafe<S extends string> = S extends `$${infer Body}` ? Body : S | |
export type ToSnakeSafe<S extends string | number | symbol> = S extends `$${infer Body}` ? `${Body}` : ToSnake<S> | |
export type ToSnake<S extends string | number | symbol> = S extends string | |
? S extends `${infer Head}${CapitalLetters}${infer Tail}` // string has a capital char somewhere | |
? Head extends '' // there is a capital char in the first position | |
? Tail extends '' | |
? `_${Lowercase<S>}` /* 'A' */ | |
: S extends `${infer Caps}${Tail}` // tail exists, has capital characters | |
? Caps extends CapitalLetters | |
? Tail extends CapitalLetters | |
? `_${Lowercase<Caps>}_${Lowercase<Tail>}` /* 'AB' */ | |
: Tail extends `${CapitalLetters}${string}` | |
? `${ToSnake<Caps>}_${ToSnake<Tail>}` /* first tail char is upper? 'ABcd' */ | |
: `${ToSnake<Caps>}${ToSnake<Tail>}` /* 'AbCD','AbcD', */ /* TODO: if tail is only numbers, append without underscore */ | |
: never /* never reached, used for inference of caps */ | |
: never | |
: Tail extends '' /* 'aB' 'abCD' 'ABCD' 'AB' */ | |
? S extends `${Head}${infer Caps}` | |
? Caps extends CapitalLetters | |
? Head extends Lowercase<Head> /* 'abcD' */ | |
? `${ToSnake<Head>}${ToSnake<Caps>}` | |
: never /* stop union type forming */ | |
: never | |
: never /* never reached, used for inference of caps */ | |
: S extends `${Head}${infer Caps}${Tail}` /* 'abCd' 'ABCD' 'AbCd' 'ABcD' */ | |
? Caps extends CapitalLetters | |
? Head extends Lowercase<Head> /* is 'abCd' 'abCD' ? */ | |
? Tail extends CapitalLetters /* is 'abCD' where Caps = 'C' */ | |
? `${ToSnake<Head>}_${ToSnake<Caps>}_${Lowercase<Tail>}` /* aBCD Tail = 'D', Head = 'aB' */ | |
: Tail extends `${CapitalLetters}${string}` /* is 'aBCd' where Caps = 'B' */ | |
? `${Head}_${ToSnake<Caps>}_${ToSnake<Tail>}` /* 'aBCd' => `${'a'}_${Lowercase<'B'>}_${ToSnake<'Cd'>}` */ | |
: `${ToSnake<Head>}_${Lowercase<Caps>}${ToSnake<Tail>}` /* 'aBcD' where Caps = 'B' tail starts as lowercase */ | |
: never | |
: never | |
: never | |
: S /* 'abc' */ | |
: never | |
export type ObjectToSnake<T extends unknown, SAFE extends boolean> = T extends undefined | |
? undefined | |
: T extends null | |
? null | |
: T extends Array<infer ArrayType> | |
? ArrayType extends Record<string, unknown> | |
? Array<ObjectToSnake<ArrayType, SAFE>> | |
: Array<ArrayType> | |
: T extends Buffer | |
? Buffer | |
: { | |
[K in keyof T as SAFE extends true ? ToSnakeSafe<K> : ToSnake<K>]: T[K] extends | |
| Array<infer ArrayType> | |
| undefined | |
| null | |
? ArrayType extends Record<string, unknown> | |
? Array<ObjectToSnake<ArrayType, SAFE>> | |
: Array<ArrayType> | |
: T[K] extends Record<string, unknown> | undefined | null | |
? ObjectToSnake<T[K], SAFE> | |
: T[K] | |
} | |
export type ObjectToCamel<T extends unknown, SAFE extends boolean> = T extends undefined | |
? undefined | |
: T extends null | |
? null | |
: T extends Array<infer ArrayType> | |
? ArrayType extends Record<string, unknown> | |
? Array<ObjectToCamel<ArrayType, SAFE>> | |
: Array<ArrayType> | |
: T extends Buffer | |
? Buffer | |
: { | |
[K in keyof T as SAFE extends true ? ToCamelSafe<K> : ToCamel<K>]: T[K] extends Array<infer ArrayType> | |
? ArrayType extends Record<string, unknown> | |
? Array<ObjectToCamel<ArrayType, SAFE>> | |
: Array<ArrayType> | |
: T[K] extends Record<string, unknown> | |
? ObjectToCamel<T[K], SAFE> | |
: T[K] | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment