deep-case-crafter 1.0.0 → 2.0.1

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.
Files changed (42) hide show
  1. package/LICENSE +21 -0
  2. package/dist/index.d.cts +231 -0
  3. package/dist/index.d.mts +231 -0
  4. package/dist/index.d.ts +230 -4
  5. package/dist/index.js +1 -1
  6. package/dist/index.mjs +1 -0
  7. package/package.json +33 -23
  8. package/readme.md +63 -46
  9. package/dist/constants/formatterMap.d.ts +0 -21
  10. package/dist/constants/regex.d.ts +0 -9
  11. package/dist/dataTransformers/primitiveTransformer.d.ts +0 -7
  12. package/dist/dataTransformers/transformArray.d.ts +0 -19
  13. package/dist/dataTransformers/transformMap.d.ts +0 -18
  14. package/dist/dataTransformers/transformObject.d.ts +0 -21
  15. package/dist/dataTransformers/transformSingleWord.d.ts +0 -8
  16. package/dist/index.esm.js +0 -1
  17. package/dist/transform/internalTransform.d.ts +0 -15
  18. package/dist/transform/transform.d.ts +0 -21
  19. package/dist/transform/transformCase.d.ts +0 -23
  20. package/dist/types/helperTypes.d.ts +0 -3
  21. package/dist/types/stringCaseTypes.d.ts +0 -4
  22. package/dist/types/transformOptionTypes.d.ts +0 -41
  23. package/dist/types/transformTypes.d.ts +0 -279
  24. package/dist/utils/caseDetectors/isCamelCase.d.ts +0 -13
  25. package/dist/utils/caseDetectors/isKebabCase.d.ts +0 -13
  26. package/dist/utils/caseDetectors/isPascalCase.d.ts +0 -14
  27. package/dist/utils/caseDetectors/isSnakeCase.d.ts +0 -14
  28. package/dist/utils/detectSingleWord.d.ts +0 -37
  29. package/dist/utils/detectStringCase.d.ts +0 -17
  30. package/dist/utils/prepareStringTransformation.d.ts +0 -20
  31. package/dist/utils/stringFormatters/camelToKebabCase.d.ts +0 -14
  32. package/dist/utils/stringFormatters/camelToPascalCase.d.ts +0 -14
  33. package/dist/utils/stringFormatters/camelToSnakeCase.d.ts +0 -14
  34. package/dist/utils/stringFormatters/kebabToCamelCase.d.ts +0 -14
  35. package/dist/utils/stringFormatters/kebabToPascalCase.d.ts +0 -14
  36. package/dist/utils/stringFormatters/kebabToSnakeCase.d.ts +0 -14
  37. package/dist/utils/stringFormatters/pascalToCamelCase.d.ts +0 -14
  38. package/dist/utils/stringFormatters/pascalToKebabCase.d.ts +0 -15
  39. package/dist/utils/stringFormatters/pascalToSnakeCase.d.ts +0 -15
  40. package/dist/utils/stringFormatters/snakeToCamelCase.d.ts +0 -14
  41. package/dist/utils/stringFormatters/snakeToKebabCase.d.ts +0 -14
  42. package/dist/utils/stringFormatters/snakeToPascalCase.d.ts +0 -14
package/dist/index.d.ts CHANGED
@@ -1,5 +1,231 @@
1
- import transform from './transform/transform';
2
- import { StringCase } from './types/stringCaseTypes';
3
- import { TransformOptions } from './types/transformOptionTypes';
4
- export default transform;
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 = '_' | '-' | '$' | '&' | '%' | '#' | '@' | '!' | '*' | '+' | '=' | '~' | '`' | '^' | '(' | ')' | '[' | ']' | '{' | '}' | '|' | '\\' | ':' | ';' | '"' | "'" | '<' | '>' | ',' | '.' | '?' | '/' | `${number}`;
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 };
5
231
  export type { StringCase, TransformOptions };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";const e={snake:{camel:function(e){return e.toLowerCase().replace(/_([a-z0-9])/g,((e,t)=>t.toUpperCase()))},pascal:function(e){return e.toLowerCase().replace(/_+([a-z0-9])/g,((e,t)=>t.toUpperCase())).replace(/^[a-z]/,(e=>e.toUpperCase()))},kebab:function(e){return e.replace(/_/g,"-")},snake:e=>e},camel:{snake:function(e){if(!e)return e;let t=e.replace(/([a-z0-9])([A-Z])/g,"$1_$2");return t=t.replace(/([A-Z])(?=[A-Z])/g,"$1_"),t.toLowerCase()},pascal:function(e){return e?e.charAt(0).toUpperCase()+e.slice(1):e},kebab:function(e){if(!e)return e;let t=e.replace(/([a-z0-9])([A-Z])/g,"$1-$2");return t=t.replace(/([A-Z])(?=[A-Z])/g,"$1-"),t.toLowerCase()},camel:e=>e},pascal:{snake:function(e){if(!e)return e;let t=e.replace(/([A-Z]{2,})([A-Z][a-z])/g,"$1_$2");return t=t.replace(/([a-z0-9])([A-Z])/g,"$1_$2"),t.toLowerCase()},camel:function(e){return e?e.charAt(0).toLowerCase()+e.slice(1):e},kebab:function(e){if(!e)return e;let t=e.replace(/([A-Z]{2,})([A-Z][a-z])/g,"$1-$2");return t=t.replace(/([a-z0-9])([A-Z])/g,"$1-$2"),t.toLowerCase()},pascal:e=>e},kebab:{snake:function(e){return e.replace(/-/g,"_")},camel:function(e){return e.toLowerCase().replace(/-+([a-z0-9])/g,((e,t)=>t.toUpperCase()))},pascal:function(e){return e.toLowerCase().replace(/-+([a-z0-9])/g,((e,t)=>t.toUpperCase())).replace(/^[a-z]/,(e=>e.toUpperCase()))},kebab:e=>e}};const t=/^[a-z0-9_]+$/,r=/__+/,n=/^[a-z][a-zA-Z0-9]*$/,s=/^[A-Z][a-zA-Z0-9]*$/,a=/^[a-z0-9-]+$/,o=/-{2,}/,c=/[A-Z]/,u=/[a-z]/,i=/^[a-z0-9]+$/;function l(e){return"string"!=typeof e?null:function(e){if(e.includes("_")||e.includes("-")||e.includes(" "))return!1;if(e.length>0&&!/^[A-Za-z0-9]+$/.test(e))return!1;if(e.length<=1)return!0;const t=e[0],r=e.slice(1);return e===e.toLowerCase()||t===t.toUpperCase()&&r===r.toLowerCase()}(e)?"single":function(e){return"string"==typeof e&&t.test(e)&&!r.test(e)&&(e.includes("_")||i.test(e))}(e)?"snake":function(e){return"string"==typeof e&&n.test(e)&&c.test(e)}(e)?"camel":function(e){return"string"==typeof e&&s.test(e)&&u.test(e)}(e)?"pascal":function(e){return"string"==typeof e&&a.test(e)&&!o.test(e)&&(e.includes("-")||i.test(e))}(e)?"kebab":null}function f(t,r){if(!t)return t;const{targetCase:n}=r,{string:s,shouldTransform:a,sourceCase:o,singleWord:c}=function(e){if("string"!=typeof e)throw new Error("Input must be a string");if(0===e.length)return{string:e,shouldTransform:!1,sourceCase:null,singleWord:!1};if(/[^A-Za-z0-9_-]/.test(e)||/^[^A-Za-z]/.test(e)||/[^A-Za-z0-9]$/.test(e))return{string:e,shouldTransform:!1,sourceCase:null,singleWord:!1};const t=l(e);return t?"single"===t?{string:e,shouldTransform:!0,sourceCase:null,singleWord:!0}:{string:e,shouldTransform:!0,sourceCase:t,singleWord:!1}:{string:e,shouldTransform:!1,sourceCase:null,singleWord:!1}}(t);if(!a)return s;if(c)return function(e,t){switch(t){case"pascal":return e.charAt(0).toUpperCase()+e.slice(1).toLowerCase();case"camel":return e.charAt(0).toLowerCase()+e.slice(1);case"snake":case"kebab":return e.toLowerCase();default:return e}}(s,n);if(!o||o===n)return s;const u=e[o];if(!u)return s;const i=u[n];return i?i(s):s}function p(e,t){if(!(e instanceof Map))return e;const r=[];for(const[n,s]of e.entries())if("string"==typeof n){const e=f(n,t);r.push([e,s])}else r.push([n,s]);return new Map(r)}function g(e,t){if(null===e||"object"!=typeof e||Array.isArray(e))return e;const{targetCase:r,sourceCase:n}=t,s={};for(const t in e)if(Object.prototype.hasOwnProperty.call(e,t)){s[!isNaN(Number(t))&&String(Number(t))===t?Number(t):f(t,{targetCase:r,sourceCase:n})]=e[t]}if(Object.getOwnPropertySymbols){const t=Object.getOwnPropertySymbols(e);for(const r of t)s[r]=e[r]}return s}function C(e,t,r=new WeakMap,n=0){var s;if(null==e||"object"!=typeof e)return e;if(r.has(e))return r.get(e);const a=null!==(s=t.depth)&&void 0!==s?s:3;if(n>=a)return e;const o=Object.assign(Object.assign({},t),{depth:a});let c;if(Array.isArray(e))c=function(e,t){return Array.isArray(e)?e.map((e=>null==e?e:e instanceof Map?p(e,t):"object"!=typeof e||Array.isArray(e)||e instanceof Set?e:g(e,t))):e}(e,t),r.set(e,c),n<a&&(c=c.map((e=>C(e,o,r,n+1))));else if(e instanceof Map){if(c=p(e,t),r.set(e,c),n<a){const e=c;for(const[t,s]of e.entries())null!==s&&"object"==typeof s&&e.set(t,C(s,o,r,n+1))}}else if(e instanceof Set){if(c=new Set(e),r.set(e,c),n<a){const e=c,t=Array.from(e);e.clear();for(const s of t)null!==s&&"object"==typeof s?e.add(C(s,o,r,n+1)):e.add(s)}}else if(c=g(e,t),r.set(e,c),n<a){const e=c;for(const t in e){const s=e[t];null!==s&&"object"==typeof s&&(e[t]=C(s,o,r,n+1))}}return c}module.exports=function(e,t){var r;return C(e,Object.assign(Object.assign({},t),{targetCase:(null==t?void 0:t.targetCase)||"camel",depth:null!==(r=null==t?void 0:t.depth)&&void 0!==r?r:3}))};
1
+ "use strict";const e={snake:{camel:function(e){return e.toLowerCase().replace(/_([a-z0-9])/g,(e,t)=>t.toUpperCase())},pascal:function(e){return e.toLowerCase().replace(/_+([a-z0-9])/g,(e,t)=>t.toUpperCase()).replace(/^[a-z]/,e=>e.toUpperCase())},kebab:function(e){return e.replace(/_/g,"-")},snake:e=>e},camel:{snake:function(e){if(!e)return e;let t=e.replace(/([a-z0-9])([A-Z])/g,"$1_$2");return t=t.replace(/([A-Z])(?=[A-Z])/g,"$1_"),t.toLowerCase()},pascal:function(e){return e?e.charAt(0).toUpperCase()+e.slice(1):e},kebab:function(e){if(!e)return e;let t=e.replace(/([a-z0-9])([A-Z])/g,"$1-$2");return t=t.replace(/([A-Z])(?=[A-Z])/g,"$1-"),t.toLowerCase()},camel:e=>e},pascal:{snake:function(e){if(!e)return e;let t=e.replace(/([A-Z]{2,})([A-Z][a-z])/g,"$1_$2");return t=t.replace(/([a-z0-9])([A-Z])/g,"$1_$2"),t.toLowerCase()},camel:function(e){return e?e.charAt(0).toLowerCase()+e.slice(1):e},kebab:function(e){if(!e)return e;let t=e.replace(/([A-Z]{2,})([A-Z][a-z])/g,"$1-$2");return t=t.replace(/([a-z0-9])([A-Z])/g,"$1-$2"),t.toLowerCase()},pascal:e=>e},kebab:{snake:function(e){return e.replace(/-/g,"_")},camel:function(e){return e.toLowerCase().replace(/-+([a-z0-9])/g,(e,t)=>t.toUpperCase())},pascal:function(e){return e.toLowerCase().replace(/-+([a-z0-9])/g,(e,t)=>t.toUpperCase()).replace(/^[a-z]/,e=>e.toUpperCase())},kebab:e=>e}};const t=/^[a-z0-9_]+$/,r=/__+/,n=/^[a-z][a-zA-Z0-9]*$/,s=/^[A-Z][a-zA-Z0-9]*$/,a=/^[a-z0-9-]+$/,o=/-{2,}/,c=/[A-Z]/,u=/[a-z]/,i=/^[a-z0-9]+$/;function l(e){return"string"!=typeof e?null:function(e){if(e.includes("_")||e.includes("-")||e.includes(" "))return!1;if(e.length>0&&!/^[A-Za-z0-9]+$/.test(e))return!1;if(e.length<=1)return!0;const t=e[0],r=e.slice(1);return e===e.toLowerCase()||t===t.toUpperCase()&&r===r.toLowerCase()}(e)?"single":function(e){return"string"==typeof e&&t.test(e)&&!r.test(e)&&(e.includes("_")||i.test(e))}(e)?"snake":function(e){return"string"==typeof e&&n.test(e)&&c.test(e)}(e)?"camel":function(e){return"string"==typeof e&&s.test(e)&&u.test(e)}(e)?"pascal":function(e){return"string"==typeof e&&a.test(e)&&!o.test(e)&&(e.includes("-")||i.test(e))}(e)?"kebab":null}function f(t,r){if(!t)return t;const{targetCase:n}=r,{string:s,shouldTransform:a,sourceCase:o,singleWord:c}=function(e){if("string"!=typeof e)throw new Error("Input must be a string");if(0===e.length)return{string:e,shouldTransform:!1,sourceCase:null,singleWord:!1};if(/[^A-Za-z0-9_-]/.test(e)||/^[^A-Za-z]/.test(e)||/[^A-Za-z0-9]$/.test(e))return{string:e,shouldTransform:!1,sourceCase:null,singleWord:!1};const t=l(e);return t?"single"===t?{string:e,shouldTransform:!0,sourceCase:null,singleWord:!0}:{string:e,shouldTransform:!0,sourceCase:t,singleWord:!1}:{string:e,shouldTransform:!1,sourceCase:null,singleWord:!1}}(t);if(!a)return s;if(c)return function(e,t){switch(t){case"pascal":return e.charAt(0).toUpperCase()+e.slice(1).toLowerCase();case"camel":return e.charAt(0).toLowerCase()+e.slice(1);case"snake":case"kebab":return e.toLowerCase();default:return e}}(s,n);if(!o||o===n)return s;const u=e[o];if(!u)return s;const i=u[n];return i?i(s):s}function p(e,t){if(!(e instanceof Map))return e;const r=[];for(const[n,s]of e.entries())if("string"==typeof n){const e=f(n,t);r.push([e,s])}else r.push([n,s]);return new Map(r)}function g(e,t){if(null===e||"object"!=typeof e||Array.isArray(e))return e;const{targetCase:r,sourceCase:n}=t,s={};for(const t in e)if(Object.prototype.hasOwnProperty.call(e,t)){s[!isNaN(Number(t))&&String(Number(t))===t?Number(t):f(t,{targetCase:r})]=e[t]}for(const t of Object.getOwnPropertySymbols(e))s[t]=e[t];return s}function C(e,t,r=new WeakMap,n=0){var s;if(null==e||"object"!=typeof e)return e;if(r.has(e))return r.get(e);const a=null!==(s=t.depth)&&void 0!==s?s:1/0;if(n>=a)return e;const o=Object.assign(Object.assign({},t),{depth:a});let c;if(Array.isArray(e))c=function(e,t){return Array.isArray(e)?e.map(e=>null==e?e:e instanceof Map?p(e,t):"object"!=typeof e||Array.isArray(e)||e instanceof Set?e:g(e,t)):e}(e,t),r.set(e,c),c=c.map(e=>C(e,o,r,n+1));else if(e instanceof Map){c=p(e,t),r.set(e,c);const s=c;for(const[e,t]of s.entries())null!==t&&"object"==typeof t&&s.set(e,C(t,o,r,n+1))}else if(e instanceof Set){c=new Set(e),r.set(e,c);const t=c,s=Array.from(t);t.clear();for(const e of s)null!==e&&"object"==typeof e?t.add(C(e,o,r,n+1)):t.add(e)}else{c=g(e,t),r.set(e,c);const s=c;for(const e in s){const t=s[e];null!==t&&"object"==typeof t&&(s[e]=C(t,o,r,n+1))}}return c}exports.transform=function(e,t){var r;return C(e,Object.assign(Object.assign({},t),{targetCase:(null==t?void 0:t.targetCase)||"camel",depth:null!==(r=null==t?void 0:t.depth)&&void 0!==r?r:1/0}))};
package/dist/index.mjs ADDED
@@ -0,0 +1 @@
1
+ const e={snake:{camel:function(e){return e.toLowerCase().replace(/_([a-z0-9])/g,(e,t)=>t.toUpperCase())},pascal:function(e){return e.toLowerCase().replace(/_+([a-z0-9])/g,(e,t)=>t.toUpperCase()).replace(/^[a-z]/,e=>e.toUpperCase())},kebab:function(e){return e.replace(/_/g,"-")},snake:e=>e},camel:{snake:function(e){if(!e)return e;let t=e.replace(/([a-z0-9])([A-Z])/g,"$1_$2");return t=t.replace(/([A-Z])(?=[A-Z])/g,"$1_"),t.toLowerCase()},pascal:function(e){return e?e.charAt(0).toUpperCase()+e.slice(1):e},kebab:function(e){if(!e)return e;let t=e.replace(/([a-z0-9])([A-Z])/g,"$1-$2");return t=t.replace(/([A-Z])(?=[A-Z])/g,"$1-"),t.toLowerCase()},camel:e=>e},pascal:{snake:function(e){if(!e)return e;let t=e.replace(/([A-Z]{2,})([A-Z][a-z])/g,"$1_$2");return t=t.replace(/([a-z0-9])([A-Z])/g,"$1_$2"),t.toLowerCase()},camel:function(e){return e?e.charAt(0).toLowerCase()+e.slice(1):e},kebab:function(e){if(!e)return e;let t=e.replace(/([A-Z]{2,})([A-Z][a-z])/g,"$1-$2");return t=t.replace(/([a-z0-9])([A-Z])/g,"$1-$2"),t.toLowerCase()},pascal:e=>e},kebab:{snake:function(e){return e.replace(/-/g,"_")},camel:function(e){return e.toLowerCase().replace(/-+([a-z0-9])/g,(e,t)=>t.toUpperCase())},pascal:function(e){return e.toLowerCase().replace(/-+([a-z0-9])/g,(e,t)=>t.toUpperCase()).replace(/^[a-z]/,e=>e.toUpperCase())},kebab:e=>e}};const t=/^[a-z0-9_]+$/,r=/__+/,n=/^[a-z][a-zA-Z0-9]*$/,s=/^[A-Z][a-zA-Z0-9]*$/,a=/^[a-z0-9-]+$/,o=/-{2,}/,c=/[A-Z]/,u=/[a-z]/,i=/^[a-z0-9]+$/;function l(e){return"string"!=typeof e?null:function(e){if(e.includes("_")||e.includes("-")||e.includes(" "))return!1;if(e.length>0&&!/^[A-Za-z0-9]+$/.test(e))return!1;if(e.length<=1)return!0;const t=e[0],r=e.slice(1);return e===e.toLowerCase()||t===t.toUpperCase()&&r===r.toLowerCase()}(e)?"single":function(e){return"string"==typeof e&&t.test(e)&&!r.test(e)&&(e.includes("_")||i.test(e))}(e)?"snake":function(e){return"string"==typeof e&&n.test(e)&&c.test(e)}(e)?"camel":function(e){return"string"==typeof e&&s.test(e)&&u.test(e)}(e)?"pascal":function(e){return"string"==typeof e&&a.test(e)&&!o.test(e)&&(e.includes("-")||i.test(e))}(e)?"kebab":null}function f(t,r){if(!t)return t;const{targetCase:n}=r,{string:s,shouldTransform:a,sourceCase:o,singleWord:c}=function(e){if("string"!=typeof e)throw new Error("Input must be a string");if(0===e.length)return{string:e,shouldTransform:!1,sourceCase:null,singleWord:!1};if(/[^A-Za-z0-9_-]/.test(e)||/^[^A-Za-z]/.test(e)||/[^A-Za-z0-9]$/.test(e))return{string:e,shouldTransform:!1,sourceCase:null,singleWord:!1};const t=l(e);return t?"single"===t?{string:e,shouldTransform:!0,sourceCase:null,singleWord:!0}:{string:e,shouldTransform:!0,sourceCase:t,singleWord:!1}:{string:e,shouldTransform:!1,sourceCase:null,singleWord:!1}}(t);if(!a)return s;if(c)return function(e,t){switch(t){case"pascal":return e.charAt(0).toUpperCase()+e.slice(1).toLowerCase();case"camel":return e.charAt(0).toLowerCase()+e.slice(1);case"snake":case"kebab":return e.toLowerCase();default:return e}}(s,n);if(!o||o===n)return s;const u=e[o];if(!u)return s;const i=u[n];return i?i(s):s}function p(e,t){if(!(e instanceof Map))return e;const r=[];for(const[n,s]of e.entries())if("string"==typeof n){const e=f(n,t);r.push([e,s])}else r.push([n,s]);return new Map(r)}function g(e,t){if(null===e||"object"!=typeof e||Array.isArray(e))return e;const{targetCase:r,sourceCase:n}=t,s={};for(const t in e)if(Object.prototype.hasOwnProperty.call(e,t)){s[!isNaN(Number(t))&&String(Number(t))===t?Number(t):f(t,{targetCase:r})]=e[t]}for(const t of Object.getOwnPropertySymbols(e))s[t]=e[t];return s}function C(e,t,r=new WeakMap,n=0){var s;if(null==e||"object"!=typeof e)return e;if(r.has(e))return r.get(e);const a=null!==(s=t.depth)&&void 0!==s?s:1/0;if(n>=a)return e;const o=Object.assign(Object.assign({},t),{depth:a});let c;if(Array.isArray(e))c=function(e,t){return Array.isArray(e)?e.map(e=>null==e?e:e instanceof Map?p(e,t):"object"!=typeof e||Array.isArray(e)||e instanceof Set?e:g(e,t)):e}(e,t),r.set(e,c),c=c.map(e=>C(e,o,r,n+1));else if(e instanceof Map){c=p(e,t),r.set(e,c);const s=c;for(const[e,t]of s.entries())null!==t&&"object"==typeof t&&s.set(e,C(t,o,r,n+1))}else if(e instanceof Set){c=new Set(e),r.set(e,c);const t=c,s=Array.from(t);t.clear();for(const e of s)null!==e&&"object"==typeof e?t.add(C(e,o,r,n+1)):t.add(e)}else{c=g(e,t),r.set(e,c);const s=c;for(const e in s){const t=s[e];null!==t&&"object"==typeof t&&(s[e]=C(t,o,r,n+1))}}return c}function A(e,t){var r;return C(e,Object.assign(Object.assign({},t),{targetCase:(null==t?void 0:t.targetCase)||"camel",depth:null!==(r=null==t?void 0:t.depth)&&void 0!==r?r:1/0}))}export{A as transform};
package/package.json CHANGED
@@ -1,13 +1,21 @@
1
1
  {
2
2
  "name": "deep-case-crafter",
3
- "version": "1.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "Transforms deeply nested object, array, Map, and Set keys between common case formats while preserving TypeScript type safety",
5
5
  "main": "dist/index.js",
6
- "module": "dist/index.esm.js",
6
+ "module": "dist/index.mjs",
7
7
  "types": "dist/index.d.ts",
8
8
  "exports": {
9
- "import": "./dist/index.esm.js",
10
- "require": "./dist/index.js"
9
+ ".": {
10
+ "import": {
11
+ "types": "./dist/index.d.mts",
12
+ "default": "./dist/index.mjs"
13
+ },
14
+ "require": {
15
+ "types": "./dist/index.d.cts",
16
+ "default": "./dist/index.js"
17
+ }
18
+ }
11
19
  },
12
20
  "files": [
13
21
  "dist"
@@ -48,6 +56,7 @@
48
56
  ],
49
57
  "scripts": {
50
58
  "build": "rollup -c",
59
+ "prepack": "npm run build",
51
60
  "prepare": "husky",
52
61
  "test": "jest",
53
62
  "test-coverage": "npm test -- --coverage",
@@ -57,29 +66,30 @@
57
66
  "benchmark": "tsx benchmark/*.benchmark.ts"
58
67
  },
59
68
  "devDependencies": {
69
+ "@eslint/js": "10.0.1",
70
+ "@rollup/plugin-commonjs": "29.0.3",
71
+ "@rollup/plugin-node-resolve": "16.0.3",
72
+ "@rollup/plugin-terser": "1.0.0",
73
+ "@rollup/plugin-typescript": "12.3.0",
60
74
  "@types/benchmark": "2.1.5",
75
+ "@types/jest": "30.0.0",
76
+ "@types/node": "25.9.1",
61
77
  "benchmark": "2.1.4",
62
- "@eslint/js": "9.21.0",
63
- "@rollup/plugin-commonjs": "28.0.2",
64
- "@rollup/plugin-node-resolve": "16.0.0",
65
- "@rollup/plugin-terser": "0.4.4",
66
- "@rollup/plugin-typescript": "12.1.2",
67
- "@types/jest": "29.5.12",
68
- "@types/node": "20.14.11",
69
- "eslint": "9.21.0",
70
- "eslint-config-prettier": "10.0.1",
71
- "eslint-plugin-prettier": "5.2.3",
72
- "globals": "16.0.0",
78
+ "eslint": "10.4.1",
79
+ "eslint-config-prettier": "10.1.8",
80
+ "eslint-plugin-prettier": "5.5.6",
81
+ "globals": "17.6.0",
73
82
  "husky": "9.1.7",
74
- "lint-staged": "15.4.3",
75
- "jest": "29.7.0",
76
- "rollup": "4.28.1",
83
+ "jest": "30.4.2",
84
+ "lint-staged": "17.0.7",
85
+ "rollup": "4.61.0",
86
+ "rollup-plugin-dts": "6.4.1",
77
87
  "rollup-plugin-peer-deps-external": "2.2.4",
78
- "rollup-plugin-visualizer": "5.12.0",
79
- "ts-jest": "29.2.3",
88
+ "rollup-plugin-visualizer": "7.0.1",
89
+ "ts-jest": "29.4.11",
80
90
  "tslib": "2.8.1",
81
- "typescript": "5.7.2",
82
- "typescript-eslint": "8.24.1",
83
- "tsx": "4.19.3"
91
+ "tsx": "4.22.4",
92
+ "typescript": "6.0.3",
93
+ "typescript-eslint": "8.60.1"
84
94
  }
85
95
  }
package/readme.md CHANGED
@@ -1,34 +1,43 @@
1
1
  # DeepCaseCrafter
2
2
 
3
- 🚀 **DeepCaseCrafter** is a TypeScript utility that **transforms deeply nested object keys** into different case formats while maintaining **type safety**. It supports **objects, arrays, Maps, and Sets** and allows **custom recursion depth**.
3
+ **DeepCaseCrafter** transforms deeply nested object keys between case formats (`camelCase`, `PascalCase`, `snake_case`, `kebab-case`). It works on objects, arrays, Maps, and Sets, with configurable recursion depth, and produces precise output types when both `sourceCase` and `targetCase` are set.
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/deep-case-crafter)](https://www.npmjs.com/package/deep-case-crafter)
6
- [![License: MIT](https://img.shields.io/npm/l/deep-case-crafter)](https://github.com/your-repo/deep-case-crafter/blob/main/LICENSE)
7
- [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue)](https://www.typescriptlang.org/)
6
+ [![npm bundle size](https://img.shields.io/bundlephobia/minzip/deep-case-crafter)](https://bundlephobia.com/package/deep-case-crafter)
7
+ [![npm type definitions](https://img.shields.io/npm/types/deep-case-crafter)](https://www.npmjs.com/package/deep-case-crafter)
8
+ [![Dev dependency: typescript](https://img.shields.io/github/package-json/dependency-version/gyrgy/deep-case-crafter/dev/typescript/main)](https://github.com/gyrgy/deep-case-crafter/blob/main/package.json)
9
+ [![Documentation](https://img.shields.io/badge/documentation-yes-brightgreen.svg)](https://github.com/gyrgy/deep-case-crafter#readme)
10
+ [![Maintenance](https://img.shields.io/maintenance/yes/2026.svg)](https://github.com/gyrgy/deep-case-crafter/graphs/commit-activity)
11
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/gyrgy/deep-case-crafter/blob/main/LICENSE)
8
12
 
9
13
  ## Features
10
14
 
11
- - 🔄 **Automatically converts keys** to `camelCase`, `PascalCase`, `snake_case`, and `kebab-case`.
12
- - 🌍 **Works with deeply nested structures**, including objects, arrays, Maps, and Sets.
13
- - ✅ **Maintains TypeScript type inference** for better auto-completion.
14
- - 🔍 **Preserves special keys** (`__`, `--`, leading numbers, special characters).
15
- - ⚡ **Performance-optimized** with minimal overhead.
16
- - 🎛 **Configurable recursion depth** (default: `3`).
15
+ - Converts keys to `camelCase`, `PascalCase`, `snake_case`, and `kebab-case`.
16
+ - Works with deeply nested structures, including objects, arrays, Maps, and Sets.
17
+ - Precise TypeScript inference when `sourceCase` and `targetCase` are set (otherwise the result type is widened).
18
+ - Preserves special keys (`__`, `--`, leading numbers, special characters).
19
+ - Configurable recursion depth (default: fully recursive).
17
20
 
18
- ## 📦 Installation
21
+ ## Installation
19
22
 
20
23
  ```bash
21
24
  npm install deep-case-crafter
22
25
  ```
23
26
 
27
+ > **⚠️ v2 breaking change:** `transform` is now a **named export**. Update
28
+ > `import transform from 'deep-case-crafter'` to
29
+ > `import { transform } from 'deep-case-crafter'` (CommonJS:
30
+ > `const { transform } = require('deep-case-crafter')`). This fixes type
31
+ > resolution for modern (`node16`/`nodenext`/bundler) consumers.
32
+
24
33
  ---
25
34
 
26
- ## 🚀 Quick Start
35
+ ## Quick Start
27
36
 
28
- ### 1️⃣ **Basic Usage – Just Call `transform`**
37
+ ### 1. Basic usage — just call `transform`
29
38
 
30
39
  ```typescript
31
- import transform from 'deep-case-crafter';
40
+ import { transform } from 'deep-case-crafter';
32
41
 
33
42
  const input = { user_id: 1, first_name: 'John' };
34
43
  const result = transform(input);
@@ -41,7 +50,7 @@ _(Automatically converts from `snake_case` to `camelCase`)_
41
50
 
42
51
  ---
43
52
 
44
- ### 2️⃣ **Specify the `targetCase`**
53
+ ### 2. Specify the `targetCase`
45
54
 
46
55
  ```typescript
47
56
  const input = { user_id: 1, first_name: 'John' };
@@ -57,9 +66,9 @@ console.log(kebabCaseResult);
57
66
 
58
67
  ---
59
68
 
60
- ### 3️⃣ **Explicitly Define `sourceCase` for TypeScript Benefits**
69
+ ### 3. Explicitly define `sourceCase` for TypeScript benefits
61
70
 
62
- _TypeScript automatically infers key changes when `sourceCase` is set._
71
+ _TypeScript infers the exact output keys when **both** `sourceCase` and `targetCase` are set._
63
72
 
64
73
  ```typescript
65
74
  const input = { user_id: 1, first_name: 'John' };
@@ -71,7 +80,7 @@ console.log(result);
71
80
 
72
81
  ---
73
82
 
74
- ### 4️⃣ **Transform Deeply Nested Structures**
83
+ ### 4. Transform deeply nested structures
75
84
 
76
85
  ```typescript
77
86
  const nestedInput = {
@@ -94,7 +103,7 @@ console.log(transformed);
94
103
 
95
104
  ---
96
105
 
97
- ### 5️⃣ **Transforming a `Map`**
106
+ ### 5. Transforming a `Map`
98
107
 
99
108
  ```typescript
100
109
  const mapInput = new Map([
@@ -113,33 +122,44 @@ console.log(result.get('firstName')); // 'John'
113
122
 
114
123
  ---
115
124
 
116
- ### 6️⃣ **Transforming a `Set`**
125
+ ### 6. Transforming a `Set`
126
+
127
+ A `Set` is a collection of _values_, not key/value pairs, so its primitive
128
+ members (strings, numbers, etc.) are passed through unchanged — only the **keys
129
+ of objects nested inside the Set** are transformed.
117
130
 
118
131
  ```typescript
119
- const setInput = new Set(['user_id', 'first_name']);
132
+ const setInput = new Set([{ user_id: 1 }, { first_name: 'John' }]);
120
133
  const result = transform(setInput, {
121
134
  targetCase: 'camel',
122
135
  sourceCase: 'snake',
123
136
  });
124
137
 
125
- console.log(result); // Set { 'userId', 'firstName' }
138
+ console.log(result); // Set { { userId: 1 }, { firstName: 'John' } }
139
+
140
+ // Primitive members are left as-is:
141
+ const strings = new Set(['user_id', 'first_name']);
142
+ console.log(transform(strings, { targetCase: 'camel', sourceCase: 'snake' }));
143
+ // Set { 'user_id', 'first_name' }
126
144
  ```
127
145
 
128
146
  ---
129
147
 
130
- ## 📖 API
148
+ ## API
131
149
 
132
150
  ### `transform(data, options)`
133
151
 
134
152
  - **data**: The data structure to transform (`object`, `array`, `Map`, or `Set`).
135
153
  - **options**:
136
154
  - `targetCase` (optional): `'camel' | 'snake' | 'pascal' | 'kebab'` (default: `'camel'`)
137
- - `sourceCase` (optional): **Required for TypeScript inference** (`'snake' | 'camel' | 'pascal' | 'kebab'`).
138
- - `depth` (optional): **Recursion depth** (default: `3`, use `Infinity` for full recursion).
155
+ - `sourceCase` (optional): `'snake' | 'camel' | 'pascal' | 'kebab'`. Omit it to auto-detect each key's case at runtime.
156
+ - `depth` (optional): **Recursion depth** (default: `Infinity` — the whole structure is transformed). Pass a number to stop transforming below that level. Circular references are always handled safely.
157
+
158
+ > **TypeScript inference:** precise output types are produced only when both `sourceCase` and `targetCase` are passed. Without both, the call still works at runtime (auto-detecting each key) but the result type is `unknown`.
139
159
 
140
160
  ---
141
161
 
142
- ## 🧑‍💻 Advanced: Explicit Output Type Overload
162
+ ## Advanced: explicit output type overload
143
163
 
144
164
  If you want to specify the output type explicitly (for example, when you know the exact shape you want), you can use the following overload:
145
165
 
@@ -149,6 +169,7 @@ const typedResult: Output = result; // TypeScript will enforce Output type here
149
169
  ```
150
170
 
151
171
  **Note:**
172
+
152
173
  - When using this overload, you cannot pass `sourceCase` in the options. If you do, TypeScript will show an error:
153
174
  > Object literal may only specify known properties, and 'sourceCase' does not exist in type 'Omit<TransformOptions, "sourceCase"> & { depth?: number }'.
154
175
  - This overload is useful when you want to take full control of the output type, but type safety between input, options, and output is not enforced by the library.
@@ -160,42 +181,38 @@ const result = transform(obj, { targetCase: 'camel', sourceCase: 'snake' }); //
160
181
 
161
182
  ---
162
183
 
163
- ## 🚨 Key Preservation Rules
184
+ ## Key Preservation Rules
164
185
 
165
- - **Keys that start with special characters or numbers** are **not transformed**.
166
- - **Keys with `__` or `--` remain unchanged**.
167
- - **Numbers at the end of keys** are preserved.
186
+ A key is left **completely unchanged** when it:
168
187
 
169
- ---
170
-
171
- ## ⚡ Performance & Benchmarks
188
+ - **starts with anything other than a letter** (a digit or special character), e.g. `1st_place`, `_private`;
189
+ - **ends with a non-alphanumeric character**, e.g. `value_`, `count-`;
190
+ - **contains characters outside** `A-Z a-z 0-9 _ -`, e.g. `user.name`, `a@b`;
191
+ - **contains consecutive `__` or `--`**, e.g. `a__b`, `x--y` (ambiguous to detect).
172
192
 
173
- DeepCaseCrafter is optimized for speed and efficiency:
174
-
175
- ```plaintext
176
- Transform Deep Object (Depth 5, Width 10)
177
- x 361,538 ops/sec ±0.12% (91 runs sampled)
178
- ```
193
+ Trailing digits are kept but treated as part of the word, so they do **not** by
194
+ themselves preserve a key — `address_1` becomes `address1`, and the single word
195
+ `item2` stays `item2`.
179
196
 
180
197
  ---
181
198
 
182
- ## 💡 Contributing
199
+ ## Contributing
183
200
 
184
- 1. **Fork** the repository.
185
- 2. **Create a new branch** (`feature/my-feature`).
186
- 3. **Commit your changes** (`git commit -m "Add new feature"`).
187
- 4. **Submit a pull request** 🚀.
201
+ 1. Fork the repository.
202
+ 2. Create a new branch (`feature/my-feature`).
203
+ 3. Commit your changes.
204
+ 4. Submit a pull request.
188
205
 
189
206
  ---
190
207
 
191
- ## 📜 License
208
+ ## License
192
209
 
193
210
  MIT
194
211
 
195
212
  ---
196
213
 
197
- ## 🔗 Links
214
+ ## Links
198
215
 
199
216
  - [NPM Package](https://www.npmjs.com/package/deep-case-crafter)
200
- - [GitHub Repository](https://github.com/your-repo/deep-case-crafter)
217
+ - [GitHub Repository](https://github.com/gyrgy/deep-case-crafter)
201
218
  - [TypeScript Docs](https://www.typescriptlang.org/)
@@ -1,21 +0,0 @@
1
- import { StringCase } from '../types/stringCaseTypes';
2
- /**
3
- * A mapping of transformation functions for converting strings between different case formats.
4
- *
5
- * Each key of this mapping represents the detected source case (e.g., 'snake', 'camel', 'pascal', 'kebab').
6
- * The corresponding value is an object that maps target case formats to the appropriate transformation function.
7
- *
8
- * Each transformation function accepts a string (`str`) that is to be transformed.
9
- *
10
- * For instance:
11
- * - `formatterMap.snake.camel` converts a snake_case string to camelCase.
12
- * - If the source and target cases are the same (e.g., `formatterMap.snake.snake`), an identity function is provided.
13
- *
14
- * @type {Record<StringCase, Record<StringCase, (str: string) => string>>}
15
- */
16
- declare const formatterMap: {
17
- [source in StringCase]: {
18
- [target in StringCase]: (str: string) => string;
19
- };
20
- };
21
- export default formatterMap;
@@ -1,9 +0,0 @@
1
- export declare const SNAKE_ONLY_REGEX: RegExp;
2
- export declare const SNAKE_CONSECUTIVE_UNDERSCORES_REGEX: RegExp;
3
- export declare const CAMEL_ONLY_REGEX: RegExp;
4
- export declare const PASCAL_CASE_FULL_REGEX: RegExp;
5
- export declare const KEBAB_LOWER_NUMBERS_HYPHENS_REGEX: RegExp;
6
- export declare const KEBAB_CONSECUTIVE_HYPHENS_REGEX: RegExp;
7
- export declare const HAS_UPPER_CASE_REGEX: RegExp;
8
- export declare const HAS_LOWER_CASE_REGEX: RegExp;
9
- export declare const SINGLE_WORD_REGEX: RegExp;
@@ -1,7 +0,0 @@
1
- /**
2
- * Transform primitives (returns them unchanged)
3
- * @param value - The primitive value
4
- * @returns The same value
5
- * @internal This function is for internal use by the library
6
- */
7
- export default function transformPrimitive<T>(value: T): T;