/** * Type utilities for converting string types to camelCase at the TypeScript type level. * This module provides advanced type-level string manipulation for converting snake_case * and kebab-case property names to camelCase when using the toCamelCase option. * * Credit - https://blog.beraliv.dev/2022-07-14-camel-case */ /** * Supported separator characters for parsing string literals. * Matches underscore (snake_case) and hyphen (kebab-case) separators. */ type Separator = '_' | '-'; /** * Filters out empty word strings from the word array to prevent * trailing/leading empty strings in the parsed result. */ type FilterEmptyWord = Word extends '' ? T : { start: [Word, ...T]; end: [...T, Word]; }[S]; /** * Splits a string literal type into an array of words by separator characters. * Recursively parses string from left to right, extracting words between separators. */ type SplitBySeparator = S extends `${infer Word}${Separator}${infer Rest}` ? FilterEmptyWord, 'start'> : FilterEmptyWord; /** * Checks if the current character is a repeated separator that should be skipped. * Prevents double separators like '__' or '--' from creating empty words. */ type IsRepeatedSeparator = Ch extends Separator ? Validated extends `${string}${Separator}` ? true : false : false; /** * Removes repeated separator characters from a string literal type. * Ensures consecutive separators are treated as a single separator. */ type RemoveRepeatedSeparator = NotValidated extends `${infer Ch}${infer Rest}` ? IsRepeatedSeparator extends true ? RemoveRepeatedSeparator : RemoveRepeatedSeparator : Validated; /** * Type guard to check if a character is uppercase. * Used to identify word boundaries in PascalCase and camelCase strings. */ type IsUppercase = [Ch] extends [Uppercase] ? true : false; /** * Splits a PascalCase or camelCase string into an array of words by detecting * capital letter boundaries. Accumulates characters into words until an uppercase * letter is encountered. */ type SplitByCapital = S extends '' ? FilterEmptyWord : S extends `${infer Ch}${infer Rest}` ? IsUppercase extends true ? SplitByCapital> : SplitByCapital : []; /** * Determines which parsing strategy to use based on the string format. * Returns 'separatorBased' for snake_case/kebab-case, 'capitalBased' for PascalCase/camelCase. */ type WhichApproach = S extends `${string}${Separator}${string}` ? 'separatorBased' : 'capitalBased'; /** * Extracts an array of word strings from a string literal type using the * appropriate parsing strategy (separator-based or capital-based). */ type Words = { separatorBased: SplitBySeparator>; capitalBased: IsUppercase extends true ? [S] : SplitByCapital; }[WhichApproach]; /** * Converts a word to the specified case (PascalCase or lowercase). * Used for transforming individual words before joining. */ type WordCase = { pascal: Capitalize & string>; lower: Lowercase; }[C]; /** * Converts an array of words to PascalCase by capitalizing each word. * Recursively processes each word in the array. */ type PascalCasify = T extends [infer Head, ...infer Rest] ? PascalCasify]> : R; /** * Converts an array of words to camelCase by lowercasing the first word * and capitalizing all subsequent words. */ type CamelCasify = T extends [infer Head, ...infer Rest] ? PascalCasify]> : []; /** * Joins an array of word strings into a single concatenated string. * Recursively concatenates each word from left to right. */ type Join = T extends [infer Word, ...infer Rest] ? Join : S; /** * Converts a string literal type to camelCase at the type level. * Supports conversion from snake_case, kebab-case, PascalCase, and camelCase inputs. * * @template S - The string literal type to convert * * @example * type Result1 = CamelCase<'user_name'> // 'userName' * type Result2 = CamelCase<'first-name'> // 'firstName' * type Result3 = CamelCase<'FirstName'> // 'firstName' */ export type CamelCase = Join>>; export {};