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/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,231 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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 };
|
|
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,(
|
|
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": "
|
|
3
|
+
"version": "2.0.0",
|
|
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.
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
8
|
"exports": {
|
|
9
|
-
"
|
|
10
|
-
|
|
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
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
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
|
-
"
|
|
75
|
-
"
|
|
76
|
-
"rollup": "4.
|
|
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": "
|
|
79
|
-
"ts-jest": "29.
|
|
88
|
+
"rollup-plugin-visualizer": "7.0.1",
|
|
89
|
+
"ts-jest": "29.4.11",
|
|
80
90
|
"tslib": "2.8.1",
|
|
81
|
-
"
|
|
82
|
-
"typescript
|
|
83
|
-
"
|
|
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
|
-
|
|
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
|
[](https://www.npmjs.com/package/deep-case-crafter)
|
|
6
|
-
[](https://bundlephobia.com/package/deep-case-crafter)
|
|
7
|
+
[](https://www.npmjs.com/package/deep-case-crafter)
|
|
8
|
+
[](https://github.com/gyrgy/deep-case-crafter/blob/main/package.json)
|
|
9
|
+
[](https://github.com/gyrgy/deep-case-crafter#readme)
|
|
10
|
+
[](https://github.com/gyrgy/deep-case-crafter/graphs/commit-activity)
|
|
11
|
+
[](https://github.com/gyrgy/deep-case-crafter/blob/main/LICENSE)
|
|
8
12
|
|
|
9
13
|
## Features
|
|
10
14
|
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
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
|
-
##
|
|
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
|
-
##
|
|
35
|
+
## Quick Start
|
|
27
36
|
|
|
28
|
-
### 1
|
|
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
|
|
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
|
|
69
|
+
### 3. Explicitly define `sourceCase` for TypeScript benefits
|
|
61
70
|
|
|
62
|
-
_TypeScript
|
|
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
|
|
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
|
|
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
|
|
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([
|
|
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 {
|
|
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
|
-
##
|
|
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):
|
|
138
|
-
- `depth` (optional): **Recursion depth** (default: `
|
|
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 widened.
|
|
139
159
|
|
|
140
160
|
---
|
|
141
161
|
|
|
142
|
-
##
|
|
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
|
-
##
|
|
184
|
+
## Key Preservation Rules
|
|
164
185
|
|
|
165
|
-
|
|
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
|
-
|
|
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
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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
|
-
##
|
|
199
|
+
## Contributing
|
|
183
200
|
|
|
184
|
-
1.
|
|
185
|
-
2.
|
|
186
|
-
3.
|
|
187
|
-
4.
|
|
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
|
-
##
|
|
208
|
+
## License
|
|
192
209
|
|
|
193
210
|
MIT
|
|
194
211
|
|
|
195
212
|
---
|
|
196
213
|
|
|
197
|
-
##
|
|
214
|
+
## Links
|
|
198
215
|
|
|
199
216
|
- [NPM Package](https://www.npmjs.com/package/deep-case-crafter)
|
|
200
|
-
- [GitHub Repository](https://github.com/
|
|
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;
|