deep-case-crafter 2.0.0 → 2.1.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/dist/index.d.cts CHANGED
@@ -60,37 +60,50 @@ type SnakeToPascal<S extends string> = S extends `${infer P}_${infer R}` ? Snake
60
60
  */
61
61
  type SnakeToKebab<S extends string> = S extends `${infer P}_${infer R}` ? `${P}-${SnakeToKebab<R>}` : S;
62
62
  /**
63
- * Type utility that transforms a camelCase string to snake_case
64
- * Example: 'helloWorld' -> 'hello_world'
63
+ * Acronym-aware word-boundary scanner shared by all camel/pascal → snake/kebab
64
+ * conversions. Mirrors `utils/stringFormatters/toSeparatedCase.ts` exactly so the
65
+ * type-level and runtime results never diverge.
66
+ *
67
+ * Inserts `Sep` before an uppercase char when the previous char is a lowercase
68
+ * letter or digit, or when it ends an acronym run that starts a new word (the two
69
+ * preceding chars are uppercase and the next is lowercase). All output is lowercased.
70
+ */
71
+ type IsUpper<C extends string> = C extends Uppercase<C> ? (C extends Lowercase<C> ? false : true) : false;
72
+ type IsLower<C extends string> = C extends Lowercase<C> ? (C extends Uppercase<C> ? false : true) : false;
73
+ type IsLowerOrDigit<C extends string> = IsLower<C> extends true ? true : C extends `${number}` ? true : false;
74
+ type FirstChar<S extends string> = S extends `${infer F}${string}` ? F : '';
75
+ type SeparatorScan<S extends string, Sep extends string, Prev extends string, PrevPrev extends string> = S extends `${infer C}${infer R}` ? IsUpper<C> extends true ? IsLowerOrDigit<Prev> extends true ? `${Sep}${Lowercase<C>}${SeparatorScan<R, Sep, C, Prev>}` : IsUpper<Prev> extends true ? IsUpper<PrevPrev> extends true ? IsLower<FirstChar<R>> extends true ? `${Sep}${Lowercase<C>}${SeparatorScan<R, Sep, C, Prev>}` : `${Lowercase<C>}${SeparatorScan<R, Sep, C, Prev>}` : `${Lowercase<C>}${SeparatorScan<R, Sep, C, Prev>}` : `${Lowercase<C>}${SeparatorScan<R, Sep, C, Prev>}` : `${Lowercase<C>}${SeparatorScan<R, Sep, C, Prev>}` : S;
76
+ type SeparatorCase<S extends string, Sep extends string> = SeparatorScan<S, Sep, '', ''>;
77
+ /**
78
+ * Type utility that transforms a camelCase string to snake_case (acronym-aware)
79
+ * Example: 'helloWorld' -> 'hello_world', 'getHTTPResponse' -> 'get_http_response'
65
80
  */
66
- type CamelToSnake<S extends string> = S extends `${infer C}${infer R}` ? C extends Uppercase<C> ? `_${Lowercase<C>}${CamelToSnake<R>}` : `${C}${CamelToSnake<R>}` : S;
81
+ type CamelToSnake<S extends string> = SeparatorCase<S, '_'>;
67
82
  /**
68
83
  * Type utility that transforms a camelCase string to PascalCase
69
84
  * Example: 'helloWorld' -> 'HelloWorld'
70
85
  */
71
86
  type CamelToPascal<S extends string> = Capitalize<S>;
72
87
  /**
73
- * Type utility that transforms a camelCase string to kebab-case
74
- * Example: 'helloWorld' -> 'hello-world'
88
+ * Type utility that transforms a camelCase string to kebab-case (acronym-aware)
89
+ * Example: 'helloWorld' -> 'hello-world', 'getHTTPResponse' -> 'get-http-response'
75
90
  */
76
- type CamelToKebab<S extends string> = S extends `${infer C}${infer R}` ? C extends Uppercase<C> ? `-${Lowercase<C>}${CamelToKebab<R>}` : `${C}${CamelToKebab<R>}` : S;
91
+ type CamelToKebab<S extends string> = SeparatorCase<S, '-'>;
77
92
  /**
78
93
  * Type utility that transforms a PascalCase string to camelCase
79
94
  * Example: 'HelloWorld' -> 'helloWorld'
80
95
  */
81
96
  type PascalToCamel<S extends string> = S extends `${infer F}${infer R}` ? `${Lowercase<F>}${R}` : S;
82
97
  /**
83
- * Type utility that transforms a PascalCase string to snake_case
84
- * Example: 'HelloWorld' -> 'hello_world'
98
+ * Type utility that transforms a PascalCase string to snake_case (acronym-aware)
99
+ * Example: 'HelloWorld' -> 'hello_world', 'HTTPResponse' -> 'http_response'
85
100
  */
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;
101
+ type PascalToSnake<S extends string> = SeparatorCase<S, '_'>;
88
102
  /**
89
- * Type utility that transforms a PascalCase string to kebab-case
90
- * Example: 'HelloWorld' -> 'hello-world'
103
+ * Type utility that transforms a PascalCase string to kebab-case (acronym-aware)
104
+ * Example: 'HelloWorld' -> 'hello-world', 'HTTPResponse' -> 'http-response'
91
105
  */
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;
106
+ type PascalToKebab<S extends string> = SeparatorCase<S, '-'>;
94
107
  /**
95
108
  * Type utility that transforms a kebab-case string to camelCase
96
109
  * Example: 'hello-world' -> 'helloWorld'
@@ -120,7 +133,7 @@ type KebabToSnake<S extends string> = S extends `${infer P}-${infer R}` ? `${P}_
120
133
  * Preserved keys include those with leading/trailing special characters,
121
134
  * unsupported patterns, or invalid starting/ending characters.
122
135
  */
123
- type ForbiddenStartChars = '_' | '-' | '$' | '&' | '%' | '#' | '@' | '!' | '*' | '+' | '=' | '~' | '`' | '^' | '(' | ')' | '[' | ']' | '{' | '}' | '|' | '\\' | ':' | ';' | '"' | "'" | '<' | '>' | ',' | '.' | '?' | '/';
136
+ type ForbiddenStartChars = '_' | '-' | '$' | '&' | '%' | '#' | '@' | '!' | '*' | '+' | '=' | '~' | '`' | '^' | '(' | ')' | '[' | ']' | '{' | '}' | '|' | '\\' | ':' | ';' | '"' | "'" | '<' | '>' | ',' | '.' | '?' | '/' | `${number}`;
124
137
  type ForbiddenEndChars = '_' | '-' | '$' | '&' | '%' | '#' | '@' | '!' | '*' | '+' | '=' | '~' | '`' | '^' | '(' | ')' | '[' | ']' | '{' | '}' | '|' | '\\' | ':' | ';' | '"' | "'" | '<' | '>' | ',' | '.' | '?' | '/' | `${number}`;
125
138
  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
139
  /**
package/dist/index.d.mts CHANGED
@@ -60,37 +60,50 @@ type SnakeToPascal<S extends string> = S extends `${infer P}_${infer R}` ? Snake
60
60
  */
61
61
  type SnakeToKebab<S extends string> = S extends `${infer P}_${infer R}` ? `${P}-${SnakeToKebab<R>}` : S;
62
62
  /**
63
- * Type utility that transforms a camelCase string to snake_case
64
- * Example: 'helloWorld' -> 'hello_world'
63
+ * Acronym-aware word-boundary scanner shared by all camel/pascal → snake/kebab
64
+ * conversions. Mirrors `utils/stringFormatters/toSeparatedCase.ts` exactly so the
65
+ * type-level and runtime results never diverge.
66
+ *
67
+ * Inserts `Sep` before an uppercase char when the previous char is a lowercase
68
+ * letter or digit, or when it ends an acronym run that starts a new word (the two
69
+ * preceding chars are uppercase and the next is lowercase). All output is lowercased.
70
+ */
71
+ type IsUpper<C extends string> = C extends Uppercase<C> ? (C extends Lowercase<C> ? false : true) : false;
72
+ type IsLower<C extends string> = C extends Lowercase<C> ? (C extends Uppercase<C> ? false : true) : false;
73
+ type IsLowerOrDigit<C extends string> = IsLower<C> extends true ? true : C extends `${number}` ? true : false;
74
+ type FirstChar<S extends string> = S extends `${infer F}${string}` ? F : '';
75
+ type SeparatorScan<S extends string, Sep extends string, Prev extends string, PrevPrev extends string> = S extends `${infer C}${infer R}` ? IsUpper<C> extends true ? IsLowerOrDigit<Prev> extends true ? `${Sep}${Lowercase<C>}${SeparatorScan<R, Sep, C, Prev>}` : IsUpper<Prev> extends true ? IsUpper<PrevPrev> extends true ? IsLower<FirstChar<R>> extends true ? `${Sep}${Lowercase<C>}${SeparatorScan<R, Sep, C, Prev>}` : `${Lowercase<C>}${SeparatorScan<R, Sep, C, Prev>}` : `${Lowercase<C>}${SeparatorScan<R, Sep, C, Prev>}` : `${Lowercase<C>}${SeparatorScan<R, Sep, C, Prev>}` : `${Lowercase<C>}${SeparatorScan<R, Sep, C, Prev>}` : S;
76
+ type SeparatorCase<S extends string, Sep extends string> = SeparatorScan<S, Sep, '', ''>;
77
+ /**
78
+ * Type utility that transforms a camelCase string to snake_case (acronym-aware)
79
+ * Example: 'helloWorld' -> 'hello_world', 'getHTTPResponse' -> 'get_http_response'
65
80
  */
66
- type CamelToSnake<S extends string> = S extends `${infer C}${infer R}` ? C extends Uppercase<C> ? `_${Lowercase<C>}${CamelToSnake<R>}` : `${C}${CamelToSnake<R>}` : S;
81
+ type CamelToSnake<S extends string> = SeparatorCase<S, '_'>;
67
82
  /**
68
83
  * Type utility that transforms a camelCase string to PascalCase
69
84
  * Example: 'helloWorld' -> 'HelloWorld'
70
85
  */
71
86
  type CamelToPascal<S extends string> = Capitalize<S>;
72
87
  /**
73
- * Type utility that transforms a camelCase string to kebab-case
74
- * Example: 'helloWorld' -> 'hello-world'
88
+ * Type utility that transforms a camelCase string to kebab-case (acronym-aware)
89
+ * Example: 'helloWorld' -> 'hello-world', 'getHTTPResponse' -> 'get-http-response'
75
90
  */
76
- type CamelToKebab<S extends string> = S extends `${infer C}${infer R}` ? C extends Uppercase<C> ? `-${Lowercase<C>}${CamelToKebab<R>}` : `${C}${CamelToKebab<R>}` : S;
91
+ type CamelToKebab<S extends string> = SeparatorCase<S, '-'>;
77
92
  /**
78
93
  * Type utility that transforms a PascalCase string to camelCase
79
94
  * Example: 'HelloWorld' -> 'helloWorld'
80
95
  */
81
96
  type PascalToCamel<S extends string> = S extends `${infer F}${infer R}` ? `${Lowercase<F>}${R}` : S;
82
97
  /**
83
- * Type utility that transforms a PascalCase string to snake_case
84
- * Example: 'HelloWorld' -> 'hello_world'
98
+ * Type utility that transforms a PascalCase string to snake_case (acronym-aware)
99
+ * Example: 'HelloWorld' -> 'hello_world', 'HTTPResponse' -> 'http_response'
85
100
  */
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;
101
+ type PascalToSnake<S extends string> = SeparatorCase<S, '_'>;
88
102
  /**
89
- * Type utility that transforms a PascalCase string to kebab-case
90
- * Example: 'HelloWorld' -> 'hello-world'
103
+ * Type utility that transforms a PascalCase string to kebab-case (acronym-aware)
104
+ * Example: 'HelloWorld' -> 'hello-world', 'HTTPResponse' -> 'http-response'
91
105
  */
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;
106
+ type PascalToKebab<S extends string> = SeparatorCase<S, '-'>;
94
107
  /**
95
108
  * Type utility that transforms a kebab-case string to camelCase
96
109
  * Example: 'hello-world' -> 'helloWorld'
@@ -120,7 +133,7 @@ type KebabToSnake<S extends string> = S extends `${infer P}-${infer R}` ? `${P}_
120
133
  * Preserved keys include those with leading/trailing special characters,
121
134
  * unsupported patterns, or invalid starting/ending characters.
122
135
  */
123
- type ForbiddenStartChars = '_' | '-' | '$' | '&' | '%' | '#' | '@' | '!' | '*' | '+' | '=' | '~' | '`' | '^' | '(' | ')' | '[' | ']' | '{' | '}' | '|' | '\\' | ':' | ';' | '"' | "'" | '<' | '>' | ',' | '.' | '?' | '/';
136
+ type ForbiddenStartChars = '_' | '-' | '$' | '&' | '%' | '#' | '@' | '!' | '*' | '+' | '=' | '~' | '`' | '^' | '(' | ')' | '[' | ']' | '{' | '}' | '|' | '\\' | ':' | ';' | '"' | "'" | '<' | '>' | ',' | '.' | '?' | '/' | `${number}`;
124
137
  type ForbiddenEndChars = '_' | '-' | '$' | '&' | '%' | '#' | '@' | '!' | '*' | '+' | '=' | '~' | '`' | '^' | '(' | ')' | '[' | ']' | '{' | '}' | '|' | '\\' | ':' | ';' | '"' | "'" | '<' | '>' | ',' | '.' | '?' | '/' | `${number}`;
125
138
  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
139
  /**
package/dist/index.d.ts CHANGED
@@ -60,37 +60,50 @@ type SnakeToPascal<S extends string> = S extends `${infer P}_${infer R}` ? Snake
60
60
  */
61
61
  type SnakeToKebab<S extends string> = S extends `${infer P}_${infer R}` ? `${P}-${SnakeToKebab<R>}` : S;
62
62
  /**
63
- * Type utility that transforms a camelCase string to snake_case
64
- * Example: 'helloWorld' -> 'hello_world'
63
+ * Acronym-aware word-boundary scanner shared by all camel/pascal → snake/kebab
64
+ * conversions. Mirrors `utils/stringFormatters/toSeparatedCase.ts` exactly so the
65
+ * type-level and runtime results never diverge.
66
+ *
67
+ * Inserts `Sep` before an uppercase char when the previous char is a lowercase
68
+ * letter or digit, or when it ends an acronym run that starts a new word (the two
69
+ * preceding chars are uppercase and the next is lowercase). All output is lowercased.
70
+ */
71
+ type IsUpper<C extends string> = C extends Uppercase<C> ? (C extends Lowercase<C> ? false : true) : false;
72
+ type IsLower<C extends string> = C extends Lowercase<C> ? (C extends Uppercase<C> ? false : true) : false;
73
+ type IsLowerOrDigit<C extends string> = IsLower<C> extends true ? true : C extends `${number}` ? true : false;
74
+ type FirstChar<S extends string> = S extends `${infer F}${string}` ? F : '';
75
+ type SeparatorScan<S extends string, Sep extends string, Prev extends string, PrevPrev extends string> = S extends `${infer C}${infer R}` ? IsUpper<C> extends true ? IsLowerOrDigit<Prev> extends true ? `${Sep}${Lowercase<C>}${SeparatorScan<R, Sep, C, Prev>}` : IsUpper<Prev> extends true ? IsUpper<PrevPrev> extends true ? IsLower<FirstChar<R>> extends true ? `${Sep}${Lowercase<C>}${SeparatorScan<R, Sep, C, Prev>}` : `${Lowercase<C>}${SeparatorScan<R, Sep, C, Prev>}` : `${Lowercase<C>}${SeparatorScan<R, Sep, C, Prev>}` : `${Lowercase<C>}${SeparatorScan<R, Sep, C, Prev>}` : `${Lowercase<C>}${SeparatorScan<R, Sep, C, Prev>}` : S;
76
+ type SeparatorCase<S extends string, Sep extends string> = SeparatorScan<S, Sep, '', ''>;
77
+ /**
78
+ * Type utility that transforms a camelCase string to snake_case (acronym-aware)
79
+ * Example: 'helloWorld' -> 'hello_world', 'getHTTPResponse' -> 'get_http_response'
65
80
  */
66
- type CamelToSnake<S extends string> = S extends `${infer C}${infer R}` ? C extends Uppercase<C> ? `_${Lowercase<C>}${CamelToSnake<R>}` : `${C}${CamelToSnake<R>}` : S;
81
+ type CamelToSnake<S extends string> = SeparatorCase<S, '_'>;
67
82
  /**
68
83
  * Type utility that transforms a camelCase string to PascalCase
69
84
  * Example: 'helloWorld' -> 'HelloWorld'
70
85
  */
71
86
  type CamelToPascal<S extends string> = Capitalize<S>;
72
87
  /**
73
- * Type utility that transforms a camelCase string to kebab-case
74
- * Example: 'helloWorld' -> 'hello-world'
88
+ * Type utility that transforms a camelCase string to kebab-case (acronym-aware)
89
+ * Example: 'helloWorld' -> 'hello-world', 'getHTTPResponse' -> 'get-http-response'
75
90
  */
76
- type CamelToKebab<S extends string> = S extends `${infer C}${infer R}` ? C extends Uppercase<C> ? `-${Lowercase<C>}${CamelToKebab<R>}` : `${C}${CamelToKebab<R>}` : S;
91
+ type CamelToKebab<S extends string> = SeparatorCase<S, '-'>;
77
92
  /**
78
93
  * Type utility that transforms a PascalCase string to camelCase
79
94
  * Example: 'HelloWorld' -> 'helloWorld'
80
95
  */
81
96
  type PascalToCamel<S extends string> = S extends `${infer F}${infer R}` ? `${Lowercase<F>}${R}` : S;
82
97
  /**
83
- * Type utility that transforms a PascalCase string to snake_case
84
- * Example: 'HelloWorld' -> 'hello_world'
98
+ * Type utility that transforms a PascalCase string to snake_case (acronym-aware)
99
+ * Example: 'HelloWorld' -> 'hello_world', 'HTTPResponse' -> 'http_response'
85
100
  */
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;
101
+ type PascalToSnake<S extends string> = SeparatorCase<S, '_'>;
88
102
  /**
89
- * Type utility that transforms a PascalCase string to kebab-case
90
- * Example: 'HelloWorld' -> 'hello-world'
103
+ * Type utility that transforms a PascalCase string to kebab-case (acronym-aware)
104
+ * Example: 'HelloWorld' -> 'hello-world', 'HTTPResponse' -> 'http-response'
91
105
  */
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;
106
+ type PascalToKebab<S extends string> = SeparatorCase<S, '-'>;
94
107
  /**
95
108
  * Type utility that transforms a kebab-case string to camelCase
96
109
  * Example: 'hello-world' -> 'helloWorld'
@@ -120,7 +133,7 @@ type KebabToSnake<S extends string> = S extends `${infer P}-${infer R}` ? `${P}_
120
133
  * Preserved keys include those with leading/trailing special characters,
121
134
  * unsupported patterns, or invalid starting/ending characters.
122
135
  */
123
- type ForbiddenStartChars = '_' | '-' | '$' | '&' | '%' | '#' | '@' | '!' | '*' | '+' | '=' | '~' | '`' | '^' | '(' | ')' | '[' | ']' | '{' | '}' | '|' | '\\' | ':' | ';' | '"' | "'" | '<' | '>' | ',' | '.' | '?' | '/';
136
+ type ForbiddenStartChars = '_' | '-' | '$' | '&' | '%' | '#' | '@' | '!' | '*' | '+' | '=' | '~' | '`' | '^' | '(' | ')' | '[' | ']' | '{' | '}' | '|' | '\\' | ':' | ';' | '"' | "'" | '<' | '>' | ',' | '.' | '?' | '/' | `${number}`;
124
137
  type ForbiddenEndChars = '_' | '-' | '$' | '&' | '%' | '#' | '@' | '!' | '*' | '+' | '=' | '~' | '`' | '^' | '(' | ')' | '[' | ']' | '{' | '}' | '|' | '\\' | ':' | ';' | '"' | "'" | '<' | '>' | ',' | '.' | '?' | '/' | `${number}`;
125
138
  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
139
  /**
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})]=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}))};
1
+ "use strict";const e=e=>e>="A"&&e<="Z",t=e=>e>="a"&&e<="z",r=e=>e>="0"&&e<="9";function n(n,s){var o,a,c;if(!n)return n;let u="";for(let i=0;i<n.length;i++){const l=n[i];if(e(l)){const l=null!==(o=n[i-1])&&void 0!==o?o:"",f=t(l)||r(l),p=e(l)&&e(null!==(a=n[i-2])&&void 0!==a?a:"")&&t(null!==(c=n[i+1])&&void 0!==c?c:"");(f||p)&&(u+=s)}u+=l.toLowerCase()}return u}const s={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){return n(e,"_")},pascal:function(e){return e?e.charAt(0).toUpperCase()+e.slice(1):e},kebab:function(e){return n(e,"-")},camel:e=>e},pascal:{snake:function(e){return n(e,"_")},camel:function(e){return e?e.charAt(0).toLowerCase()+e.slice(1):e},kebab:function(e){return n(e,"-")},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 o=/^[a-z0-9_]+$/,a=/__+/,c=/^[a-z][a-zA-Z0-9]*$/,u=/^[A-Z][a-zA-Z0-9]*$/,i=/^[a-z0-9-]+$/,l=/-{2,}/,f=/[A-Z]/,p=/[a-z]/,g=/^[a-z0-9]+$/;function d(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&&o.test(e)&&!a.test(e)&&(e.includes("_")||g.test(e))}(e)?"snake":function(e){return"string"==typeof e&&c.test(e)&&f.test(e)}(e)?"camel":function(e){return"string"==typeof e&&u.test(e)&&p.test(e)}(e)?"pascal":function(e){return"string"==typeof e&&i.test(e)&&!l.test(e)&&(e.includes("-")||g.test(e))}(e)?"kebab":null}function C(e,t){if(!e)return e;const{targetCase:r}=t,{string:n,shouldTransform:o,sourceCase:a,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=d(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}}(e);if(!o)return n;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}}(n,r);if(!a||a===r)return n;const u=s[a];if(!u)return n;const i=u[r];return i?i(n):n}function b(e,t){if(!(e instanceof Map))return e;const r=[];for(const[n,s]of e.entries())if("string"==typeof n){const e=C(n,t);r.push([e,s])}else r.push([n,s]);return new Map(r)}function y(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):C(t,{targetCase:r})]=e[t]}for(const t of Object.getOwnPropertySymbols(e))s[t]=e[t];return s}function h(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 o=null!==(s=t.depth)&&void 0!==s?s:1/0;if(n>=o)return e;const a=Object.assign(Object.assign({},t),{depth:o});let c;if(Array.isArray(e))c=function(e,t){return Array.isArray(e)?e.map(e=>null==e?e:e instanceof Map?b(e,t):"object"!=typeof e||Array.isArray(e)||e instanceof Set?e:y(e,t)):e}(e,t),r.set(e,c),c=c.map(e=>h(e,a,r,n+1));else if(e instanceof Map){c=b(e,t),r.set(e,c);const s=c;for(const[e,t]of s.entries())null!==t&&"object"==typeof t&&s.set(e,h(t,a,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(h(e,a,r,n+1)):t.add(e)}else{c=y(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]=h(t,a,r,n+1))}}return c}exports.transform=function(e,t){var r;return h(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 CHANGED
@@ -1 +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};
1
+ const e=e=>e>="A"&&e<="Z",t=e=>e>="a"&&e<="z",n=e=>e>="0"&&e<="9";function r(r,s){var o,a,c;if(!r)return r;let u="";for(let i=0;i<r.length;i++){const l=r[i];if(e(l)){const l=null!==(o=r[i-1])&&void 0!==o?o:"",f=t(l)||n(l),p=e(l)&&e(null!==(a=r[i-2])&&void 0!==a?a:"")&&t(null!==(c=r[i+1])&&void 0!==c?c:"");(f||p)&&(u+=s)}u+=l.toLowerCase()}return u}const s={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){return r(e,"_")},pascal:function(e){return e?e.charAt(0).toUpperCase()+e.slice(1):e},kebab:function(e){return r(e,"-")},camel:e=>e},pascal:{snake:function(e){return r(e,"_")},camel:function(e){return e?e.charAt(0).toLowerCase()+e.slice(1):e},kebab:function(e){return r(e,"-")},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 o=/^[a-z0-9_]+$/,a=/__+/,c=/^[a-z][a-zA-Z0-9]*$/,u=/^[A-Z][a-zA-Z0-9]*$/,i=/^[a-z0-9-]+$/,l=/-{2,}/,f=/[A-Z]/,p=/[a-z]/,g=/^[a-z0-9]+$/;function d(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],n=e.slice(1);return e===e.toLowerCase()||t===t.toUpperCase()&&n===n.toLowerCase()}(e)?"single":function(e){return"string"==typeof e&&o.test(e)&&!a.test(e)&&(e.includes("_")||g.test(e))}(e)?"snake":function(e){return"string"==typeof e&&c.test(e)&&f.test(e)}(e)?"camel":function(e){return"string"==typeof e&&u.test(e)&&p.test(e)}(e)?"pascal":function(e){return"string"==typeof e&&i.test(e)&&!l.test(e)&&(e.includes("-")||g.test(e))}(e)?"kebab":null}function C(e,t){if(!e)return e;const{targetCase:n}=t,{string:r,shouldTransform:o,sourceCase:a,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=d(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}}(e);if(!o)return r;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}}(r,n);if(!a||a===n)return r;const u=s[a];if(!u)return r;const i=u[n];return i?i(r):r}function b(e,t){if(!(e instanceof Map))return e;const n=[];for(const[r,s]of e.entries())if("string"==typeof r){const e=C(r,t);n.push([e,s])}else n.push([r,s]);return new Map(n)}function y(e,t){if(null===e||"object"!=typeof e||Array.isArray(e))return e;const{targetCase:n,sourceCase:r}=t,s={};for(const t in e)if(Object.prototype.hasOwnProperty.call(e,t)){s[!isNaN(Number(t))&&String(Number(t))===t?Number(t):C(t,{targetCase:n})]=e[t]}for(const t of Object.getOwnPropertySymbols(e))s[t]=e[t];return s}function h(e,t,n=new WeakMap,r=0){var s;if(null==e||"object"!=typeof e)return e;if(n.has(e))return n.get(e);const o=null!==(s=t.depth)&&void 0!==s?s:1/0;if(r>=o)return e;const a=Object.assign(Object.assign({},t),{depth:o});let c;if(Array.isArray(e))c=function(e,t){return Array.isArray(e)?e.map(e=>null==e?e:e instanceof Map?b(e,t):"object"!=typeof e||Array.isArray(e)||e instanceof Set?e:y(e,t)):e}(e,t),n.set(e,c),c=c.map(e=>h(e,a,n,r+1));else if(e instanceof Map){c=b(e,t),n.set(e,c);const s=c;for(const[e,t]of s.entries())null!==t&&"object"==typeof t&&s.set(e,h(t,a,n,r+1))}else if(e instanceof Set){c=new Set(e),n.set(e,c);const t=c,s=Array.from(t);t.clear();for(const e of s)null!==e&&"object"==typeof e?t.add(h(e,a,n,r+1)):t.add(e)}else{c=y(e,t),n.set(e,c);const s=c;for(const e in s){const t=s[e];null!==t&&"object"==typeof t&&(s[e]=h(t,a,n,r+1))}}return c}function m(e,t){var n;return h(e,Object.assign(Object.assign({},t),{targetCase:(null==t?void 0:t.targetCase)||"camel",depth:null!==(n=null==t?void 0:t.depth)&&void 0!==n?n:1/0}))}export{m as transform};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deep-case-crafter",
3
- "version": "2.0.0",
3
+ "version": "2.1.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
6
  "module": "dist/index.mjs",
package/readme.md CHANGED
@@ -13,8 +13,9 @@
13
13
  ## Features
14
14
 
15
15
  - Converts keys to `camelCase`, `PascalCase`, `snake_case`, and `kebab-case`.
16
+ - **Acronym-aware**: `HTTPResponse` → `http_response`, `userID` → `user_id` — not `h_t_t_p_...`.
16
17
  - 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
+ - Precise TypeScript inference when `sourceCase` and `targetCase` are set (otherwise the result is `unknown`).
18
19
  - Preserves special keys (`__`, `--`, leading numbers, special characters).
19
20
  - Configurable recursion depth (default: fully recursive).
20
21
 
@@ -145,6 +146,25 @@ console.log(transform(strings, { targetCase: 'camel', sourceCase: 'snake' }));
145
146
 
146
147
  ---
147
148
 
149
+ ## Acronym-aware conversion
150
+
151
+ When converting **to** `snake_case` or `kebab-case`, runs of capitals (acronyms)
152
+ are treated as whole words instead of being split letter-by-letter:
153
+
154
+ ```typescript
155
+ const input = { getHTTPResponse: 1, userID: 2, parseHTMLString: 3 };
156
+ const result = transform(input, { sourceCase: 'camel', targetCase: 'snake' });
157
+
158
+ console.log(result);
159
+ // Output: { get_http_response: 1, user_id: 2, parse_html_string: 3 }
160
+ // (not { get_h_t_t_p_response, user_i_d, ... })
161
+ ```
162
+
163
+ The output **types** match this exactly when `sourceCase` and `targetCase` are
164
+ set, so `result.get_http_response` is known at compile time.
165
+
166
+ ---
167
+
148
168
  ## API
149
169
 
150
170
  ### `transform(data, options)`
@@ -155,7 +175,7 @@ console.log(transform(strings, { targetCase: 'camel', sourceCase: 'snake' }));
155
175
  - `sourceCase` (optional): `'snake' | 'camel' | 'pascal' | 'kebab'`. Omit it to auto-detect each key's case at runtime.
156
176
  - `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
177
 
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.
178
+ > **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`.
159
179
 
160
180
  ---
161
181