|
| 1 | +type SplitIncludingDelimitor<S extends string, D extends string> = |
| 2 | + string extends S ? string[] : |
| 3 | + S extends '' ? [] : |
| 4 | + S extends `${infer T}${D}${infer U}` ? |
| 5 | + ( S extends `${T}${infer Z}${U}` ? [T, Z, ...SplitIncludingDelimitor<U, D>] : never ) : |
| 6 | + [S]; |
| 7 | + |
| 8 | +type Join<S extends any[], D extends string> = |
| 9 | + string[] extends S ? string : |
| 10 | + S extends [`${infer T}`, ...infer U] ? |
| 11 | + U[0] extends undefined ? T : `${T}${D}${Join<U, D>}` : |
| 12 | + ''; |
| 13 | + |
| 14 | +type UpperCaseChars = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'X' | 'Y' | 'Z'; |
| 15 | +type WordSeparators = "-"|"_"|" "; |
| 16 | + |
| 17 | +type StringPartToKebabCase<K extends string, S extends string, L extends string> = |
| 18 | + K extends S ? '-' : |
| 19 | + K extends L ? `-${Lowercase<K>}` : |
| 20 | + K; |
| 21 | +type StringArrayToKebabCase<K extends any[], S extends string, L extends string> = |
| 22 | + K extends [`${infer T}`, ...infer U] ? `${StringPartToKebabCase<T, S, L>}${StringArrayToKebabCase<U, S, L>}` : |
| 23 | + ''; |
| 24 | + |
| 25 | +/** |
| 26 | +Converts a string literal that may use another casing than kebab casing to kebab casing |
| 27 | +
|
| 28 | +This can be useful when eg. converting a camel cased object property to eg. a CSS class name or a CLI option. |
| 29 | +
|
| 30 | +@example |
| 31 | +``` |
| 32 | +import {KebabCase} from 'type-fest'; |
| 33 | +
|
| 34 | +type KebabCasedProps<T> = { |
| 35 | + [K in keyof T as KebabCase<K>]: T[K] |
| 36 | +}; |
| 37 | +
|
| 38 | +interface CliOptions { |
| 39 | + dryRun: boolean; |
| 40 | + includeFile: string; |
| 41 | + foo: number; |
| 42 | +} |
| 43 | +
|
| 44 | +const rawCliOptions: KebabCasedProps<CliOptions> = { |
| 45 | + 'dry-run': true, |
| 46 | + 'include-file': 'bar.js', |
| 47 | + foo: 123 |
| 48 | +}; |
| 49 | +``` |
| 50 | +*/ |
| 51 | +export type KebabCase<K> = K extends string ? StringArrayToKebabCase<SplitIncludingDelimitor<K, WordSeparators | UpperCaseChars>, WordSeparators, UpperCaseChars> : K; |
0 commit comments