deep-case-crafter 1.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/index.d.cts +231 -0
- package/dist/index.d.mts +231 -0
- package/dist/index.d.ts +230 -4
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -0
- package/package.json +33 -23
- package/readme.md +63 -46
- package/dist/constants/formatterMap.d.ts +0 -21
- package/dist/constants/regex.d.ts +0 -9
- package/dist/dataTransformers/primitiveTransformer.d.ts +0 -7
- package/dist/dataTransformers/transformArray.d.ts +0 -19
- package/dist/dataTransformers/transformMap.d.ts +0 -18
- package/dist/dataTransformers/transformObject.d.ts +0 -21
- package/dist/dataTransformers/transformSingleWord.d.ts +0 -8
- package/dist/index.esm.js +0 -1
- package/dist/transform/internalTransform.d.ts +0 -15
- package/dist/transform/transform.d.ts +0 -21
- package/dist/transform/transformCase.d.ts +0 -23
- package/dist/types/helperTypes.d.ts +0 -3
- package/dist/types/stringCaseTypes.d.ts +0 -4
- package/dist/types/transformOptionTypes.d.ts +0 -41
- package/dist/types/transformTypes.d.ts +0 -279
- package/dist/utils/caseDetectors/isCamelCase.d.ts +0 -13
- package/dist/utils/caseDetectors/isKebabCase.d.ts +0 -13
- package/dist/utils/caseDetectors/isPascalCase.d.ts +0 -14
- package/dist/utils/caseDetectors/isSnakeCase.d.ts +0 -14
- package/dist/utils/detectSingleWord.d.ts +0 -37
- package/dist/utils/detectStringCase.d.ts +0 -17
- package/dist/utils/prepareStringTransformation.d.ts +0 -20
- package/dist/utils/stringFormatters/camelToKebabCase.d.ts +0 -14
- package/dist/utils/stringFormatters/camelToPascalCase.d.ts +0 -14
- package/dist/utils/stringFormatters/camelToSnakeCase.d.ts +0 -14
- package/dist/utils/stringFormatters/kebabToCamelCase.d.ts +0 -14
- package/dist/utils/stringFormatters/kebabToPascalCase.d.ts +0 -14
- package/dist/utils/stringFormatters/kebabToSnakeCase.d.ts +0 -14
- package/dist/utils/stringFormatters/pascalToCamelCase.d.ts +0 -14
- package/dist/utils/stringFormatters/pascalToKebabCase.d.ts +0 -15
- package/dist/utils/stringFormatters/pascalToSnakeCase.d.ts +0 -15
- package/dist/utils/stringFormatters/snakeToCamelCase.d.ts +0 -14
- package/dist/utils/stringFormatters/snakeToKebabCase.d.ts +0 -14
- package/dist/utils/stringFormatters/snakeToPascalCase.d.ts +0 -14
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 gyrgy
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents the supported string case formats for transformation
|
|
3
|
+
*/
|
|
4
|
+
type StringCase = 'camel' | 'pascal' | 'snake' | 'kebab';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Options for the transform function
|
|
8
|
+
*/
|
|
9
|
+
interface TransformOptions {
|
|
10
|
+
/**
|
|
11
|
+
* The target casing format to transform to
|
|
12
|
+
* @default 'camel'
|
|
13
|
+
*/
|
|
14
|
+
targetCase?: StringCase;
|
|
15
|
+
/**
|
|
16
|
+
* The source casing format to transform from
|
|
17
|
+
*
|
|
18
|
+
* When specified:
|
|
19
|
+
* - Provides precise TypeScript type transformations
|
|
20
|
+
* - Bypasses runtime case detection (more efficient)
|
|
21
|
+
* - Ensures consistent results if input has mixed casing
|
|
22
|
+
*
|
|
23
|
+
* When omitted:
|
|
24
|
+
* - Automatic case detection is used at runtime
|
|
25
|
+
* - TypeScript types will be less precise (string keys)
|
|
26
|
+
* - Works with mixed case inputs (each key detected separately)
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* // With source specified - precise types
|
|
30
|
+
* const result = transform(data, { targetCase: 'camel', sourceCase: 'snake' });
|
|
31
|
+
* // result has exact transformed types
|
|
32
|
+
*
|
|
33
|
+
* // Without source - flexible runtime behavior
|
|
34
|
+
* const result = transform(data, { targetCase: 'camel' });
|
|
35
|
+
* // TypeScript types are more general
|
|
36
|
+
*
|
|
37
|
+
* @default undefined (automatic detection)
|
|
38
|
+
*/
|
|
39
|
+
sourceCase?: StringCase;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Type utility that transforms a snake_case string to camelCase
|
|
44
|
+
* Example: 'hello_world' -> 'helloWorld'
|
|
45
|
+
*/
|
|
46
|
+
type SnakeToCamel<S extends string> = S extends `${infer P}_${infer C}${infer R}` ? `${P}${Uppercase<C>}${SnakeToCamel<R>}` : S;
|
|
47
|
+
/**
|
|
48
|
+
* Type utility that transforms a snake_case string to PascalCase
|
|
49
|
+
* Example: 'hello_world' -> 'HelloWorld'
|
|
50
|
+
*/
|
|
51
|
+
type SnakeWordsToPascal<Parts extends string[]> = Parts extends [
|
|
52
|
+
infer First extends string,
|
|
53
|
+
...infer Rest extends string[]
|
|
54
|
+
] ? `${Capitalize<First>}${SnakeWordsToPascal<Rest>}` : '';
|
|
55
|
+
type SnakeToWords<S extends string> = S extends `${infer P}_${infer R}` ? [P, ...SnakeToWords<R>] : [S];
|
|
56
|
+
type SnakeToPascal<S extends string> = S extends `${infer P}_${infer R}` ? SnakeWordsToPascal<[P, ...SnakeToWords<R>]> : Capitalize<S>;
|
|
57
|
+
/**
|
|
58
|
+
* Type utility that transforms a snake_case string to kebab-case
|
|
59
|
+
* Example: 'hello_world' -> 'hello-world'
|
|
60
|
+
*/
|
|
61
|
+
type SnakeToKebab<S extends string> = S extends `${infer P}_${infer R}` ? `${P}-${SnakeToKebab<R>}` : S;
|
|
62
|
+
/**
|
|
63
|
+
* Type utility that transforms a camelCase string to snake_case
|
|
64
|
+
* Example: 'helloWorld' -> 'hello_world'
|
|
65
|
+
*/
|
|
66
|
+
type CamelToSnake<S extends string> = S extends `${infer C}${infer R}` ? C extends Uppercase<C> ? `_${Lowercase<C>}${CamelToSnake<R>}` : `${C}${CamelToSnake<R>}` : S;
|
|
67
|
+
/**
|
|
68
|
+
* Type utility that transforms a camelCase string to PascalCase
|
|
69
|
+
* Example: 'helloWorld' -> 'HelloWorld'
|
|
70
|
+
*/
|
|
71
|
+
type CamelToPascal<S extends string> = Capitalize<S>;
|
|
72
|
+
/**
|
|
73
|
+
* Type utility that transforms a camelCase string to kebab-case
|
|
74
|
+
* Example: 'helloWorld' -> 'hello-world'
|
|
75
|
+
*/
|
|
76
|
+
type CamelToKebab<S extends string> = S extends `${infer C}${infer R}` ? C extends Uppercase<C> ? `-${Lowercase<C>}${CamelToKebab<R>}` : `${C}${CamelToKebab<R>}` : S;
|
|
77
|
+
/**
|
|
78
|
+
* Type utility that transforms a PascalCase string to camelCase
|
|
79
|
+
* Example: 'HelloWorld' -> 'helloWorld'
|
|
80
|
+
*/
|
|
81
|
+
type PascalToCamel<S extends string> = S extends `${infer F}${infer R}` ? `${Lowercase<F>}${R}` : S;
|
|
82
|
+
/**
|
|
83
|
+
* Type utility that transforms a PascalCase string to snake_case
|
|
84
|
+
* Example: 'HelloWorld' -> 'hello_world'
|
|
85
|
+
*/
|
|
86
|
+
type PascalToSnake<S extends string> = S extends `${infer F}${infer R}` ? R extends `` ? Lowercase<F> : `${Lowercase<F>}${PascalToSnakeInner<R>}` : S;
|
|
87
|
+
type PascalToSnakeInner<S extends string> = S extends `${infer C}${infer R}` ? C extends Uppercase<C> ? `_${Lowercase<C>}${PascalToSnakeInner<R>}` : `${C}${PascalToSnakeInner<R>}` : S;
|
|
88
|
+
/**
|
|
89
|
+
* Type utility that transforms a PascalCase string to kebab-case
|
|
90
|
+
* Example: 'HelloWorld' -> 'hello-world'
|
|
91
|
+
*/
|
|
92
|
+
type PascalToKebab<S extends string> = S extends `${infer F}${infer R}` ? R extends `` ? Lowercase<F> : `${Lowercase<F>}${PascalToKebabInner<R>}` : S;
|
|
93
|
+
type PascalToKebabInner<S extends string> = S extends `${infer C}${infer R}` ? C extends Uppercase<C> ? `-${Lowercase<C>}${PascalToKebabInner<R>}` : `${C}${PascalToKebabInner<R>}` : S;
|
|
94
|
+
/**
|
|
95
|
+
* Type utility that transforms a kebab-case string to camelCase
|
|
96
|
+
* Example: 'hello-world' -> 'helloWorld'
|
|
97
|
+
*/
|
|
98
|
+
type KebabToCamel<S extends string> = S extends `${infer P}-${infer C}${infer R}` ? `${P}${Uppercase<C>}${KebabToCamel<R>}` : S;
|
|
99
|
+
/**
|
|
100
|
+
* Type utility that transforms a kebab-case string to PascalCase
|
|
101
|
+
* Example: 'hello-world' -> 'HelloWorld'
|
|
102
|
+
*/
|
|
103
|
+
type KebabWordsToPascal<Parts extends string[]> = Parts extends [
|
|
104
|
+
infer First extends string,
|
|
105
|
+
...infer Rest extends string[]
|
|
106
|
+
] ? `${Capitalize<First>}${KebabWordsToPascal<Rest>}` : '';
|
|
107
|
+
type KebabToWords<S extends string> = S extends `${infer P}-${infer R}` ? [P, ...KebabToWords<R>] : [S];
|
|
108
|
+
/**
|
|
109
|
+
* Type utility that transforms a kebab-case string to PascalCase
|
|
110
|
+
* Example: 'hello-world' -> 'HelloWorld'
|
|
111
|
+
*/
|
|
112
|
+
type KebabToPascal<S extends string> = S extends `${infer P}-${infer R}` ? KebabWordsToPascal<[P, ...KebabToWords<R>]> : Capitalize<S>;
|
|
113
|
+
/**
|
|
114
|
+
* Type utility that transforms a kebab-case string to snake_case
|
|
115
|
+
* Example: 'hello-world' -> 'hello_world'
|
|
116
|
+
*/
|
|
117
|
+
type KebabToSnake<S extends string> = S extends `${infer P}-${infer R}` ? `${P}_${KebabToSnake<R>}` : S;
|
|
118
|
+
/**
|
|
119
|
+
* Utility type to detect preserved keys that shouldn't be transformed.
|
|
120
|
+
* Preserved keys include those with leading/trailing special characters,
|
|
121
|
+
* unsupported patterns, or invalid starting/ending characters.
|
|
122
|
+
*/
|
|
123
|
+
type ForbiddenStartChars = '_' | '-' | '$' | '&' | '%' | '#' | '@' | '!' | '*' | '+' | '=' | '~' | '`' | '^' | '(' | ')' | '[' | ']' | '{' | '}' | '|' | '\\' | ':' | ';' | '"' | "'" | '<' | '>' | ',' | '.' | '?' | '/';
|
|
124
|
+
type ForbiddenEndChars = '_' | '-' | '$' | '&' | '%' | '#' | '@' | '!' | '*' | '+' | '=' | '~' | '`' | '^' | '(' | ')' | '[' | ']' | '{' | '}' | '|' | '\\' | ':' | ';' | '"' | "'" | '<' | '>' | ',' | '.' | '?' | '/' | `${number}`;
|
|
125
|
+
type PreservedKey<K extends string> = K extends `${infer First}${string}` ? First extends ForbiddenStartChars ? true : K extends `${string}${infer Last}` ? Last extends ForbiddenEndChars ? true : K extends `${string}__${string}` | `${string}--${string}` ? true : false : false : false;
|
|
126
|
+
/**
|
|
127
|
+
* Type utility that selects the correct string transformation based on source and target casing
|
|
128
|
+
*/
|
|
129
|
+
type TransformKey<K extends string, O extends TransformOptions> = PreservedKey<K> extends true ? K : undefined extends O['sourceCase'] ? string : O['sourceCase'] extends 'snake' ? undefined extends O['targetCase'] ? SnakeToCamel<K> : O['targetCase'] extends 'camel' ? SnakeToCamel<K> : O['targetCase'] extends 'pascal' ? SnakeToPascal<K> : O['targetCase'] extends 'kebab' ? SnakeToKebab<K> : K : O['sourceCase'] extends 'camel' ? undefined extends O['targetCase'] ? K : O['targetCase'] extends 'snake' ? CamelToSnake<K> : O['targetCase'] extends 'pascal' ? CamelToPascal<K> : O['targetCase'] extends 'kebab' ? CamelToKebab<K> : K : O['sourceCase'] extends 'pascal' ? undefined extends O['targetCase'] ? PascalToCamel<K> : O['targetCase'] extends 'camel' ? PascalToCamel<K> : O['targetCase'] extends 'snake' ? PascalToSnake<K> : O['targetCase'] extends 'kebab' ? PascalToKebab<K> : K : O['sourceCase'] extends 'kebab' ? undefined extends O['targetCase'] ? KebabToCamel<K> : O['targetCase'] extends 'camel' ? KebabToCamel<K> : O['targetCase'] extends 'pascal' ? KebabToPascal<K> : O['targetCase'] extends 'snake' ? KebabToSnake<K> : K : K;
|
|
130
|
+
/**
|
|
131
|
+
* Recursive type transformations
|
|
132
|
+
* These types handle nested structures like arrays, objects, Maps, and Sets
|
|
133
|
+
*/
|
|
134
|
+
type SnakeToCamelRecursive<T> = T extends Array<infer U> ? Array<SnakeToCamelRecursive<U>> : T extends Map<infer K, infer V> ? Map<K extends string ? SnakeToCamel<K> : K, SnakeToCamelRecursive<V>> : T extends Set<infer V> ? Set<SnakeToCamelRecursive<V>> : T extends object ? {
|
|
135
|
+
[K in keyof T as TransformKey<K & string, {
|
|
136
|
+
sourceCase: 'snake';
|
|
137
|
+
targetCase: 'camel';
|
|
138
|
+
}>]: SnakeToCamelRecursive<T[K]>;
|
|
139
|
+
} : T;
|
|
140
|
+
type SnakeToPascalRecursive<T> = T extends Array<infer U> ? Array<SnakeToPascalRecursive<U>> : T extends Map<infer K, infer V> ? Map<K extends string ? SnakeToPascal<K> : K, SnakeToPascalRecursive<V>> : T extends Set<infer V> ? Set<SnakeToPascalRecursive<V>> : T extends object ? {
|
|
141
|
+
[K in keyof T as TransformKey<K & string, {
|
|
142
|
+
sourceCase: 'snake';
|
|
143
|
+
targetCase: 'pascal';
|
|
144
|
+
}>]: SnakeToPascalRecursive<T[K]>;
|
|
145
|
+
} : T;
|
|
146
|
+
type SnakeToKebabRecursive<T> = T extends Array<infer U> ? Array<SnakeToKebabRecursive<U>> : T extends Map<infer K, infer V> ? Map<K extends string ? SnakeToKebab<K> : K, SnakeToKebabRecursive<V>> : T extends Set<infer V> ? Set<SnakeToKebabRecursive<V>> : T extends object ? {
|
|
147
|
+
[K in keyof T as TransformKey<K & string, {
|
|
148
|
+
sourceCase: 'snake';
|
|
149
|
+
targetCase: 'kebab';
|
|
150
|
+
}>]: SnakeToKebabRecursive<T[K]>;
|
|
151
|
+
} : T;
|
|
152
|
+
type CamelToSnakeRecursive<T> = T extends Array<infer U> ? Array<CamelToSnakeRecursive<U>> : T extends Map<infer K, infer V> ? Map<K extends string ? CamelToSnake<K> : K, CamelToSnakeRecursive<V>> : T extends Set<infer V> ? Set<CamelToSnakeRecursive<V>> : T extends object ? {
|
|
153
|
+
[K in keyof T as TransformKey<K & string, {
|
|
154
|
+
sourceCase: 'camel';
|
|
155
|
+
targetCase: 'snake';
|
|
156
|
+
}>]: CamelToSnakeRecursive<T[K]>;
|
|
157
|
+
} : T;
|
|
158
|
+
type CamelToPascalRecursive<T> = T extends Array<infer U> ? Array<CamelToPascalRecursive<U>> : T extends Map<infer K, infer V> ? Map<K extends string ? CamelToPascal<K> : K, CamelToPascalRecursive<V>> : T extends Set<infer V> ? Set<CamelToPascalRecursive<V>> : T extends object ? {
|
|
159
|
+
[K in keyof T as TransformKey<K & string, {
|
|
160
|
+
sourceCase: 'camel';
|
|
161
|
+
targetCase: 'pascal';
|
|
162
|
+
}>]: CamelToPascalRecursive<T[K]>;
|
|
163
|
+
} : T;
|
|
164
|
+
type CamelToKebabRecursive<T> = T extends Array<infer U> ? Array<CamelToKebabRecursive<U>> : T extends Map<infer K, infer V> ? Map<K extends string ? CamelToKebab<K> : K, CamelToKebabRecursive<V>> : T extends Set<infer V> ? Set<CamelToKebabRecursive<V>> : T extends object ? {
|
|
165
|
+
[K in keyof T as TransformKey<K & string, {
|
|
166
|
+
sourceCase: 'camel';
|
|
167
|
+
targetCase: 'kebab';
|
|
168
|
+
}>]: CamelToKebabRecursive<T[K]>;
|
|
169
|
+
} : T;
|
|
170
|
+
type PascalToCamelRecursive<T> = T extends Array<infer U> ? Array<PascalToCamelRecursive<U>> : T extends Map<infer K, infer V> ? Map<K extends string ? PascalToCamel<K> : K, PascalToCamelRecursive<V>> : T extends Set<infer V> ? Set<PascalToCamelRecursive<V>> : T extends object ? {
|
|
171
|
+
[K in keyof T as TransformKey<K & string, {
|
|
172
|
+
sourceCase: 'pascal';
|
|
173
|
+
targetCase: 'camel';
|
|
174
|
+
}>]: PascalToCamelRecursive<T[K]>;
|
|
175
|
+
} : T;
|
|
176
|
+
type PascalToSnakeRecursive<T> = T extends Array<infer U> ? Array<PascalToSnakeRecursive<U>> : T extends Map<infer K, infer V> ? Map<K extends string ? PascalToSnake<K> : K, PascalToSnakeRecursive<V>> : T extends Set<infer V> ? Set<PascalToSnakeRecursive<V>> : T extends object ? {
|
|
177
|
+
[K in keyof T as TransformKey<K & string, {
|
|
178
|
+
sourceCase: 'pascal';
|
|
179
|
+
targetCase: 'snake';
|
|
180
|
+
}>]: PascalToSnakeRecursive<T[K]>;
|
|
181
|
+
} : T;
|
|
182
|
+
type PascalToKebabRecursive<T> = T extends Array<infer U> ? Array<PascalToKebabRecursive<U>> : T extends Map<infer K, infer V> ? Map<K extends string ? PascalToKebab<K> : K, PascalToKebabRecursive<V>> : T extends Set<infer V> ? Set<PascalToKebabRecursive<V>> : T extends object ? {
|
|
183
|
+
[K in keyof T as TransformKey<K & string, {
|
|
184
|
+
sourceCase: 'pascal';
|
|
185
|
+
targetCase: 'kebab';
|
|
186
|
+
}>]: PascalToKebabRecursive<T[K]>;
|
|
187
|
+
} : T;
|
|
188
|
+
type KebabToCamelRecursive<T> = T extends Array<infer U> ? Array<KebabToCamelRecursive<U>> : T extends Map<infer K, infer V> ? Map<K extends string ? KebabToCamel<K> : K, KebabToCamelRecursive<V>> : T extends Set<infer V> ? Set<KebabToCamelRecursive<V>> : T extends object ? {
|
|
189
|
+
[K in keyof T as TransformKey<K & string, {
|
|
190
|
+
sourceCase: 'kebab';
|
|
191
|
+
targetCase: 'camel';
|
|
192
|
+
}>]: KebabToCamelRecursive<T[K]>;
|
|
193
|
+
} : T;
|
|
194
|
+
type KebabToPascalRecursive<T> = T extends Array<infer U> ? Array<KebabToPascalRecursive<U>> : T extends Map<infer K, infer V> ? Map<K extends string ? KebabToPascal<K> : K, KebabToPascalRecursive<V>> : T extends Set<infer V> ? Set<KebabToPascalRecursive<V>> : T extends object ? {
|
|
195
|
+
[K in keyof T as TransformKey<K & string, {
|
|
196
|
+
sourceCase: 'kebab';
|
|
197
|
+
targetCase: 'pascal';
|
|
198
|
+
}>]: KebabToPascalRecursive<T[K]>;
|
|
199
|
+
} : T;
|
|
200
|
+
type KebabToSnakeRecursive<T> = T extends Array<infer U> ? Array<KebabToSnakeRecursive<U>> : T extends Map<infer K, infer V> ? Map<K extends string ? KebabToSnake<K> : K, KebabToSnakeRecursive<V>> : T extends Set<infer V> ? Set<KebabToSnakeRecursive<V>> : T extends object ? {
|
|
201
|
+
[K in keyof T as TransformKey<K & string, {
|
|
202
|
+
sourceCase: 'kebab';
|
|
203
|
+
targetCase: 'snake';
|
|
204
|
+
}>]: KebabToSnakeRecursive<T[K]>;
|
|
205
|
+
} : T;
|
|
206
|
+
/**
|
|
207
|
+
* Generic recursive transformation type
|
|
208
|
+
* Allows dynamically selecting the transformation based on source and target cases
|
|
209
|
+
*/
|
|
210
|
+
type TransformRecursive<T, FromCase extends StringCase, ToCase extends StringCase> = FromCase extends 'snake' ? ToCase extends 'camel' ? SnakeToCamelRecursive<T> : ToCase extends 'pascal' ? SnakeToPascalRecursive<T> : ToCase extends 'kebab' ? SnakeToKebabRecursive<T> : T : FromCase extends 'camel' ? ToCase extends 'snake' ? CamelToSnakeRecursive<T> : ToCase extends 'pascal' ? CamelToPascalRecursive<T> : ToCase extends 'kebab' ? CamelToKebabRecursive<T> : T : FromCase extends 'pascal' ? ToCase extends 'snake' ? PascalToSnakeRecursive<T> : ToCase extends 'camel' ? PascalToCamelRecursive<T> : ToCase extends 'kebab' ? PascalToKebabRecursive<T> : T : FromCase extends 'kebab' ? ToCase extends 'snake' ? KebabToSnakeRecursive<T> : ToCase extends 'camel' ? KebabToCamelRecursive<T> : ToCase extends 'pascal' ? KebabToPascalRecursive<T> : T : T;
|
|
211
|
+
|
|
212
|
+
declare function transform<T, From extends StringCase, To extends StringCase>(data: T, options: TransformOptions & {
|
|
213
|
+
depth?: number;
|
|
214
|
+
sourceCase: From;
|
|
215
|
+
targetCase: To;
|
|
216
|
+
}): TransformRecursive<T, From, To>;
|
|
217
|
+
/**
|
|
218
|
+
* Transform data to a specified output type.
|
|
219
|
+
*
|
|
220
|
+
* Note: When using this overload, type safety is not enforced between the input, options, and output type.
|
|
221
|
+
* The 'sourceCase' option is intentionally omitted, as it is not used for type inference here.
|
|
222
|
+
*/
|
|
223
|
+
declare function transform<T, K>(data: T, options?: Omit<TransformOptions, 'sourceCase'> & {
|
|
224
|
+
depth?: number;
|
|
225
|
+
}): K;
|
|
226
|
+
declare function transform<T>(data: T, options?: TransformOptions & {
|
|
227
|
+
depth?: number;
|
|
228
|
+
}): unknown;
|
|
229
|
+
|
|
230
|
+
export { transform };
|
|
231
|
+
export type { StringCase, TransformOptions };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents the supported string case formats for transformation
|
|
3
|
+
*/
|
|
4
|
+
type StringCase = 'camel' | 'pascal' | 'snake' | 'kebab';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Options for the transform function
|
|
8
|
+
*/
|
|
9
|
+
interface TransformOptions {
|
|
10
|
+
/**
|
|
11
|
+
* The target casing format to transform to
|
|
12
|
+
* @default 'camel'
|
|
13
|
+
*/
|
|
14
|
+
targetCase?: StringCase;
|
|
15
|
+
/**
|
|
16
|
+
* The source casing format to transform from
|
|
17
|
+
*
|
|
18
|
+
* When specified:
|
|
19
|
+
* - Provides precise TypeScript type transformations
|
|
20
|
+
* - Bypasses runtime case detection (more efficient)
|
|
21
|
+
* - Ensures consistent results if input has mixed casing
|
|
22
|
+
*
|
|
23
|
+
* When omitted:
|
|
24
|
+
* - Automatic case detection is used at runtime
|
|
25
|
+
* - TypeScript types will be less precise (string keys)
|
|
26
|
+
* - Works with mixed case inputs (each key detected separately)
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* // With source specified - precise types
|
|
30
|
+
* const result = transform(data, { targetCase: 'camel', sourceCase: 'snake' });
|
|
31
|
+
* // result has exact transformed types
|
|
32
|
+
*
|
|
33
|
+
* // Without source - flexible runtime behavior
|
|
34
|
+
* const result = transform(data, { targetCase: 'camel' });
|
|
35
|
+
* // TypeScript types are more general
|
|
36
|
+
*
|
|
37
|
+
* @default undefined (automatic detection)
|
|
38
|
+
*/
|
|
39
|
+
sourceCase?: StringCase;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Type utility that transforms a snake_case string to camelCase
|
|
44
|
+
* Example: 'hello_world' -> 'helloWorld'
|
|
45
|
+
*/
|
|
46
|
+
type SnakeToCamel<S extends string> = S extends `${infer P}_${infer C}${infer R}` ? `${P}${Uppercase<C>}${SnakeToCamel<R>}` : S;
|
|
47
|
+
/**
|
|
48
|
+
* Type utility that transforms a snake_case string to PascalCase
|
|
49
|
+
* Example: 'hello_world' -> 'HelloWorld'
|
|
50
|
+
*/
|
|
51
|
+
type SnakeWordsToPascal<Parts extends string[]> = Parts extends [
|
|
52
|
+
infer First extends string,
|
|
53
|
+
...infer Rest extends string[]
|
|
54
|
+
] ? `${Capitalize<First>}${SnakeWordsToPascal<Rest>}` : '';
|
|
55
|
+
type SnakeToWords<S extends string> = S extends `${infer P}_${infer R}` ? [P, ...SnakeToWords<R>] : [S];
|
|
56
|
+
type SnakeToPascal<S extends string> = S extends `${infer P}_${infer R}` ? SnakeWordsToPascal<[P, ...SnakeToWords<R>]> : Capitalize<S>;
|
|
57
|
+
/**
|
|
58
|
+
* Type utility that transforms a snake_case string to kebab-case
|
|
59
|
+
* Example: 'hello_world' -> 'hello-world'
|
|
60
|
+
*/
|
|
61
|
+
type SnakeToKebab<S extends string> = S extends `${infer P}_${infer R}` ? `${P}-${SnakeToKebab<R>}` : S;
|
|
62
|
+
/**
|
|
63
|
+
* Type utility that transforms a camelCase string to snake_case
|
|
64
|
+
* Example: 'helloWorld' -> 'hello_world'
|
|
65
|
+
*/
|
|
66
|
+
type CamelToSnake<S extends string> = S extends `${infer C}${infer R}` ? C extends Uppercase<C> ? `_${Lowercase<C>}${CamelToSnake<R>}` : `${C}${CamelToSnake<R>}` : S;
|
|
67
|
+
/**
|
|
68
|
+
* Type utility that transforms a camelCase string to PascalCase
|
|
69
|
+
* Example: 'helloWorld' -> 'HelloWorld'
|
|
70
|
+
*/
|
|
71
|
+
type CamelToPascal<S extends string> = Capitalize<S>;
|
|
72
|
+
/**
|
|
73
|
+
* Type utility that transforms a camelCase string to kebab-case
|
|
74
|
+
* Example: 'helloWorld' -> 'hello-world'
|
|
75
|
+
*/
|
|
76
|
+
type CamelToKebab<S extends string> = S extends `${infer C}${infer R}` ? C extends Uppercase<C> ? `-${Lowercase<C>}${CamelToKebab<R>}` : `${C}${CamelToKebab<R>}` : S;
|
|
77
|
+
/**
|
|
78
|
+
* Type utility that transforms a PascalCase string to camelCase
|
|
79
|
+
* Example: 'HelloWorld' -> 'helloWorld'
|
|
80
|
+
*/
|
|
81
|
+
type PascalToCamel<S extends string> = S extends `${infer F}${infer R}` ? `${Lowercase<F>}${R}` : S;
|
|
82
|
+
/**
|
|
83
|
+
* Type utility that transforms a PascalCase string to snake_case
|
|
84
|
+
* Example: 'HelloWorld' -> 'hello_world'
|
|
85
|
+
*/
|
|
86
|
+
type PascalToSnake<S extends string> = S extends `${infer F}${infer R}` ? R extends `` ? Lowercase<F> : `${Lowercase<F>}${PascalToSnakeInner<R>}` : S;
|
|
87
|
+
type PascalToSnakeInner<S extends string> = S extends `${infer C}${infer R}` ? C extends Uppercase<C> ? `_${Lowercase<C>}${PascalToSnakeInner<R>}` : `${C}${PascalToSnakeInner<R>}` : S;
|
|
88
|
+
/**
|
|
89
|
+
* Type utility that transforms a PascalCase string to kebab-case
|
|
90
|
+
* Example: 'HelloWorld' -> 'hello-world'
|
|
91
|
+
*/
|
|
92
|
+
type PascalToKebab<S extends string> = S extends `${infer F}${infer R}` ? R extends `` ? Lowercase<F> : `${Lowercase<F>}${PascalToKebabInner<R>}` : S;
|
|
93
|
+
type PascalToKebabInner<S extends string> = S extends `${infer C}${infer R}` ? C extends Uppercase<C> ? `-${Lowercase<C>}${PascalToKebabInner<R>}` : `${C}${PascalToKebabInner<R>}` : S;
|
|
94
|
+
/**
|
|
95
|
+
* Type utility that transforms a kebab-case string to camelCase
|
|
96
|
+
* Example: 'hello-world' -> 'helloWorld'
|
|
97
|
+
*/
|
|
98
|
+
type KebabToCamel<S extends string> = S extends `${infer P}-${infer C}${infer R}` ? `${P}${Uppercase<C>}${KebabToCamel<R>}` : S;
|
|
99
|
+
/**
|
|
100
|
+
* Type utility that transforms a kebab-case string to PascalCase
|
|
101
|
+
* Example: 'hello-world' -> 'HelloWorld'
|
|
102
|
+
*/
|
|
103
|
+
type KebabWordsToPascal<Parts extends string[]> = Parts extends [
|
|
104
|
+
infer First extends string,
|
|
105
|
+
...infer Rest extends string[]
|
|
106
|
+
] ? `${Capitalize<First>}${KebabWordsToPascal<Rest>}` : '';
|
|
107
|
+
type KebabToWords<S extends string> = S extends `${infer P}-${infer R}` ? [P, ...KebabToWords<R>] : [S];
|
|
108
|
+
/**
|
|
109
|
+
* Type utility that transforms a kebab-case string to PascalCase
|
|
110
|
+
* Example: 'hello-world' -> 'HelloWorld'
|
|
111
|
+
*/
|
|
112
|
+
type KebabToPascal<S extends string> = S extends `${infer P}-${infer R}` ? KebabWordsToPascal<[P, ...KebabToWords<R>]> : Capitalize<S>;
|
|
113
|
+
/**
|
|
114
|
+
* Type utility that transforms a kebab-case string to snake_case
|
|
115
|
+
* Example: 'hello-world' -> 'hello_world'
|
|
116
|
+
*/
|
|
117
|
+
type KebabToSnake<S extends string> = S extends `${infer P}-${infer R}` ? `${P}_${KebabToSnake<R>}` : S;
|
|
118
|
+
/**
|
|
119
|
+
* Utility type to detect preserved keys that shouldn't be transformed.
|
|
120
|
+
* Preserved keys include those with leading/trailing special characters,
|
|
121
|
+
* unsupported patterns, or invalid starting/ending characters.
|
|
122
|
+
*/
|
|
123
|
+
type ForbiddenStartChars = '_' | '-' | '$' | '&' | '%' | '#' | '@' | '!' | '*' | '+' | '=' | '~' | '`' | '^' | '(' | ')' | '[' | ']' | '{' | '}' | '|' | '\\' | ':' | ';' | '"' | "'" | '<' | '>' | ',' | '.' | '?' | '/';
|
|
124
|
+
type ForbiddenEndChars = '_' | '-' | '$' | '&' | '%' | '#' | '@' | '!' | '*' | '+' | '=' | '~' | '`' | '^' | '(' | ')' | '[' | ']' | '{' | '}' | '|' | '\\' | ':' | ';' | '"' | "'" | '<' | '>' | ',' | '.' | '?' | '/' | `${number}`;
|
|
125
|
+
type PreservedKey<K extends string> = K extends `${infer First}${string}` ? First extends ForbiddenStartChars ? true : K extends `${string}${infer Last}` ? Last extends ForbiddenEndChars ? true : K extends `${string}__${string}` | `${string}--${string}` ? true : false : false : false;
|
|
126
|
+
/**
|
|
127
|
+
* Type utility that selects the correct string transformation based on source and target casing
|
|
128
|
+
*/
|
|
129
|
+
type TransformKey<K extends string, O extends TransformOptions> = PreservedKey<K> extends true ? K : undefined extends O['sourceCase'] ? string : O['sourceCase'] extends 'snake' ? undefined extends O['targetCase'] ? SnakeToCamel<K> : O['targetCase'] extends 'camel' ? SnakeToCamel<K> : O['targetCase'] extends 'pascal' ? SnakeToPascal<K> : O['targetCase'] extends 'kebab' ? SnakeToKebab<K> : K : O['sourceCase'] extends 'camel' ? undefined extends O['targetCase'] ? K : O['targetCase'] extends 'snake' ? CamelToSnake<K> : O['targetCase'] extends 'pascal' ? CamelToPascal<K> : O['targetCase'] extends 'kebab' ? CamelToKebab<K> : K : O['sourceCase'] extends 'pascal' ? undefined extends O['targetCase'] ? PascalToCamel<K> : O['targetCase'] extends 'camel' ? PascalToCamel<K> : O['targetCase'] extends 'snake' ? PascalToSnake<K> : O['targetCase'] extends 'kebab' ? PascalToKebab<K> : K : O['sourceCase'] extends 'kebab' ? undefined extends O['targetCase'] ? KebabToCamel<K> : O['targetCase'] extends 'camel' ? KebabToCamel<K> : O['targetCase'] extends 'pascal' ? KebabToPascal<K> : O['targetCase'] extends 'snake' ? KebabToSnake<K> : K : K;
|
|
130
|
+
/**
|
|
131
|
+
* Recursive type transformations
|
|
132
|
+
* These types handle nested structures like arrays, objects, Maps, and Sets
|
|
133
|
+
*/
|
|
134
|
+
type SnakeToCamelRecursive<T> = T extends Array<infer U> ? Array<SnakeToCamelRecursive<U>> : T extends Map<infer K, infer V> ? Map<K extends string ? SnakeToCamel<K> : K, SnakeToCamelRecursive<V>> : T extends Set<infer V> ? Set<SnakeToCamelRecursive<V>> : T extends object ? {
|
|
135
|
+
[K in keyof T as TransformKey<K & string, {
|
|
136
|
+
sourceCase: 'snake';
|
|
137
|
+
targetCase: 'camel';
|
|
138
|
+
}>]: SnakeToCamelRecursive<T[K]>;
|
|
139
|
+
} : T;
|
|
140
|
+
type SnakeToPascalRecursive<T> = T extends Array<infer U> ? Array<SnakeToPascalRecursive<U>> : T extends Map<infer K, infer V> ? Map<K extends string ? SnakeToPascal<K> : K, SnakeToPascalRecursive<V>> : T extends Set<infer V> ? Set<SnakeToPascalRecursive<V>> : T extends object ? {
|
|
141
|
+
[K in keyof T as TransformKey<K & string, {
|
|
142
|
+
sourceCase: 'snake';
|
|
143
|
+
targetCase: 'pascal';
|
|
144
|
+
}>]: SnakeToPascalRecursive<T[K]>;
|
|
145
|
+
} : T;
|
|
146
|
+
type SnakeToKebabRecursive<T> = T extends Array<infer U> ? Array<SnakeToKebabRecursive<U>> : T extends Map<infer K, infer V> ? Map<K extends string ? SnakeToKebab<K> : K, SnakeToKebabRecursive<V>> : T extends Set<infer V> ? Set<SnakeToKebabRecursive<V>> : T extends object ? {
|
|
147
|
+
[K in keyof T as TransformKey<K & string, {
|
|
148
|
+
sourceCase: 'snake';
|
|
149
|
+
targetCase: 'kebab';
|
|
150
|
+
}>]: SnakeToKebabRecursive<T[K]>;
|
|
151
|
+
} : T;
|
|
152
|
+
type CamelToSnakeRecursive<T> = T extends Array<infer U> ? Array<CamelToSnakeRecursive<U>> : T extends Map<infer K, infer V> ? Map<K extends string ? CamelToSnake<K> : K, CamelToSnakeRecursive<V>> : T extends Set<infer V> ? Set<CamelToSnakeRecursive<V>> : T extends object ? {
|
|
153
|
+
[K in keyof T as TransformKey<K & string, {
|
|
154
|
+
sourceCase: 'camel';
|
|
155
|
+
targetCase: 'snake';
|
|
156
|
+
}>]: CamelToSnakeRecursive<T[K]>;
|
|
157
|
+
} : T;
|
|
158
|
+
type CamelToPascalRecursive<T> = T extends Array<infer U> ? Array<CamelToPascalRecursive<U>> : T extends Map<infer K, infer V> ? Map<K extends string ? CamelToPascal<K> : K, CamelToPascalRecursive<V>> : T extends Set<infer V> ? Set<CamelToPascalRecursive<V>> : T extends object ? {
|
|
159
|
+
[K in keyof T as TransformKey<K & string, {
|
|
160
|
+
sourceCase: 'camel';
|
|
161
|
+
targetCase: 'pascal';
|
|
162
|
+
}>]: CamelToPascalRecursive<T[K]>;
|
|
163
|
+
} : T;
|
|
164
|
+
type CamelToKebabRecursive<T> = T extends Array<infer U> ? Array<CamelToKebabRecursive<U>> : T extends Map<infer K, infer V> ? Map<K extends string ? CamelToKebab<K> : K, CamelToKebabRecursive<V>> : T extends Set<infer V> ? Set<CamelToKebabRecursive<V>> : T extends object ? {
|
|
165
|
+
[K in keyof T as TransformKey<K & string, {
|
|
166
|
+
sourceCase: 'camel';
|
|
167
|
+
targetCase: 'kebab';
|
|
168
|
+
}>]: CamelToKebabRecursive<T[K]>;
|
|
169
|
+
} : T;
|
|
170
|
+
type PascalToCamelRecursive<T> = T extends Array<infer U> ? Array<PascalToCamelRecursive<U>> : T extends Map<infer K, infer V> ? Map<K extends string ? PascalToCamel<K> : K, PascalToCamelRecursive<V>> : T extends Set<infer V> ? Set<PascalToCamelRecursive<V>> : T extends object ? {
|
|
171
|
+
[K in keyof T as TransformKey<K & string, {
|
|
172
|
+
sourceCase: 'pascal';
|
|
173
|
+
targetCase: 'camel';
|
|
174
|
+
}>]: PascalToCamelRecursive<T[K]>;
|
|
175
|
+
} : T;
|
|
176
|
+
type PascalToSnakeRecursive<T> = T extends Array<infer U> ? Array<PascalToSnakeRecursive<U>> : T extends Map<infer K, infer V> ? Map<K extends string ? PascalToSnake<K> : K, PascalToSnakeRecursive<V>> : T extends Set<infer V> ? Set<PascalToSnakeRecursive<V>> : T extends object ? {
|
|
177
|
+
[K in keyof T as TransformKey<K & string, {
|
|
178
|
+
sourceCase: 'pascal';
|
|
179
|
+
targetCase: 'snake';
|
|
180
|
+
}>]: PascalToSnakeRecursive<T[K]>;
|
|
181
|
+
} : T;
|
|
182
|
+
type PascalToKebabRecursive<T> = T extends Array<infer U> ? Array<PascalToKebabRecursive<U>> : T extends Map<infer K, infer V> ? Map<K extends string ? PascalToKebab<K> : K, PascalToKebabRecursive<V>> : T extends Set<infer V> ? Set<PascalToKebabRecursive<V>> : T extends object ? {
|
|
183
|
+
[K in keyof T as TransformKey<K & string, {
|
|
184
|
+
sourceCase: 'pascal';
|
|
185
|
+
targetCase: 'kebab';
|
|
186
|
+
}>]: PascalToKebabRecursive<T[K]>;
|
|
187
|
+
} : T;
|
|
188
|
+
type KebabToCamelRecursive<T> = T extends Array<infer U> ? Array<KebabToCamelRecursive<U>> : T extends Map<infer K, infer V> ? Map<K extends string ? KebabToCamel<K> : K, KebabToCamelRecursive<V>> : T extends Set<infer V> ? Set<KebabToCamelRecursive<V>> : T extends object ? {
|
|
189
|
+
[K in keyof T as TransformKey<K & string, {
|
|
190
|
+
sourceCase: 'kebab';
|
|
191
|
+
targetCase: 'camel';
|
|
192
|
+
}>]: KebabToCamelRecursive<T[K]>;
|
|
193
|
+
} : T;
|
|
194
|
+
type KebabToPascalRecursive<T> = T extends Array<infer U> ? Array<KebabToPascalRecursive<U>> : T extends Map<infer K, infer V> ? Map<K extends string ? KebabToPascal<K> : K, KebabToPascalRecursive<V>> : T extends Set<infer V> ? Set<KebabToPascalRecursive<V>> : T extends object ? {
|
|
195
|
+
[K in keyof T as TransformKey<K & string, {
|
|
196
|
+
sourceCase: 'kebab';
|
|
197
|
+
targetCase: 'pascal';
|
|
198
|
+
}>]: KebabToPascalRecursive<T[K]>;
|
|
199
|
+
} : T;
|
|
200
|
+
type KebabToSnakeRecursive<T> = T extends Array<infer U> ? Array<KebabToSnakeRecursive<U>> : T extends Map<infer K, infer V> ? Map<K extends string ? KebabToSnake<K> : K, KebabToSnakeRecursive<V>> : T extends Set<infer V> ? Set<KebabToSnakeRecursive<V>> : T extends object ? {
|
|
201
|
+
[K in keyof T as TransformKey<K & string, {
|
|
202
|
+
sourceCase: 'kebab';
|
|
203
|
+
targetCase: 'snake';
|
|
204
|
+
}>]: KebabToSnakeRecursive<T[K]>;
|
|
205
|
+
} : T;
|
|
206
|
+
/**
|
|
207
|
+
* Generic recursive transformation type
|
|
208
|
+
* Allows dynamically selecting the transformation based on source and target cases
|
|
209
|
+
*/
|
|
210
|
+
type TransformRecursive<T, FromCase extends StringCase, ToCase extends StringCase> = FromCase extends 'snake' ? ToCase extends 'camel' ? SnakeToCamelRecursive<T> : ToCase extends 'pascal' ? SnakeToPascalRecursive<T> : ToCase extends 'kebab' ? SnakeToKebabRecursive<T> : T : FromCase extends 'camel' ? ToCase extends 'snake' ? CamelToSnakeRecursive<T> : ToCase extends 'pascal' ? CamelToPascalRecursive<T> : ToCase extends 'kebab' ? CamelToKebabRecursive<T> : T : FromCase extends 'pascal' ? ToCase extends 'snake' ? PascalToSnakeRecursive<T> : ToCase extends 'camel' ? PascalToCamelRecursive<T> : ToCase extends 'kebab' ? PascalToKebabRecursive<T> : T : FromCase extends 'kebab' ? ToCase extends 'snake' ? KebabToSnakeRecursive<T> : ToCase extends 'camel' ? KebabToCamelRecursive<T> : ToCase extends 'pascal' ? KebabToPascalRecursive<T> : T : T;
|
|
211
|
+
|
|
212
|
+
declare function transform<T, From extends StringCase, To extends StringCase>(data: T, options: TransformOptions & {
|
|
213
|
+
depth?: number;
|
|
214
|
+
sourceCase: From;
|
|
215
|
+
targetCase: To;
|
|
216
|
+
}): TransformRecursive<T, From, To>;
|
|
217
|
+
/**
|
|
218
|
+
* Transform data to a specified output type.
|
|
219
|
+
*
|
|
220
|
+
* Note: When using this overload, type safety is not enforced between the input, options, and output type.
|
|
221
|
+
* The 'sourceCase' option is intentionally omitted, as it is not used for type inference here.
|
|
222
|
+
*/
|
|
223
|
+
declare function transform<T, K>(data: T, options?: Omit<TransformOptions, 'sourceCase'> & {
|
|
224
|
+
depth?: number;
|
|
225
|
+
}): K;
|
|
226
|
+
declare function transform<T>(data: T, options?: TransformOptions & {
|
|
227
|
+
depth?: number;
|
|
228
|
+
}): unknown;
|
|
229
|
+
|
|
230
|
+
export { transform };
|
|
231
|
+
export type { StringCase, TransformOptions };
|