deep-case-crafter 3.2.0 → 3.3.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
@@ -67,6 +67,23 @@ interface TransformOptions extends TransformKeyOptions {
67
67
  * @default []
68
68
  */
69
69
  exclude?: readonly string[] | undefined;
70
+ /**
71
+ * Whether an object reached through several references gives one result, as in the
72
+ * input: shared objects stay shared, and circular references point back into the
73
+ * result. Pass `false` for data that cannot contain such references, such as the
74
+ * output of `JSON.parse`: the transform then skips this bookkeeping, which makes inputs
75
+ * with many objects and arrays up to about twice as fast.
76
+ *
77
+ * Use it only for tree-shaped data. An object is then copied once for every path that
78
+ * leads to it, so shared objects inside shared objects multiply. Data with more than
79
+ * 256 nested objects, arrays, Maps and Sets on one path, as circular references always
80
+ * have, is converted again from the start with the bookkeeping, so it takes longer and
81
+ * getters can run twice. With a finite `depth`, circular references stop at the depth
82
+ * limit before that, and are copied once per path down to it.
83
+ *
84
+ * @default true
85
+ */
86
+ keepReferences?: boolean | undefined;
70
87
  /**
71
88
  * @deprecated Has no effect. Every key's case is detected from the key itself, both at
72
89
  * runtime and in the result type, so there is nothing to declare.
@@ -176,7 +193,7 @@ declare const ACRONYM_PLURAL_SUFFIX = "s";
176
193
  * (tail-recursive, so long keys compile).
177
194
  */
178
195
  type HasOnlyKeyChars<S extends string> = S extends `${infer C}${infer Rest}` ? C extends KeyChar ? HasOnlyKeyChars<Rest> : false : true;
179
- /** The canonical UUID form, where `x` stands for a hexadecimal digit (`UUID_REGEX`) */
196
+ /** The canonical UUID form, where `x` stands for a hexadecimal digit (`isUuid`) */
180
197
  type UuidPattern = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx';
181
198
  /**
182
199
  * `true` when `S` is a UUID in canonical form. `S` is compared with `UuidPattern` one
@@ -185,14 +202,14 @@ type UuidPattern = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx';
185
202
  */
186
203
  type IsUuid<S extends string, Pattern extends string = UuidPattern> = Pattern extends `${infer P}${infer PatternRest}` ? S extends `${infer C}${infer Rest}` ? C extends (P extends 'x' ? HexDigit : P) ? IsUuid<Rest, PatternRest> : false : false : S extends '' ? true : false;
187
204
  /**
188
- * Keys the runtime leaves unchanged (`prepareStringTransformation`): keys containing a
205
+ * Keys the runtime leaves unchanged (`transformCase`): keys containing a
189
206
  * character outside `A-Z a-z 0-9 _ -`, keys not starting with a letter, keys ending with
190
207
  * a separator, and UUIDs. A UUID that starts with a digit is already preserved, so only
191
208
  * keys that the other rules do not preserve are compared with the UUID form.
192
209
  */
193
210
  type IsPreservedKey<K extends string> = HasOnlyKeyChars<K> extends false ? true : K extends `${LowerLetter | UpperLetter}${string}` ? K extends `${string}${Separator}` ? true : IsUuid<K> : true;
194
211
  /**
195
- * The case the runtime detects for a key that is not preserved (`detectStringCase`), or
212
+ * The case the runtime detects for a key that is not preserved (`transformCase`), or
196
213
  * `'none'` when it cannot be detected (the key is then left unchanged). A string is used
197
214
  * rather than `null`, which every type accepts without `strictNullChecks`.
198
215
  */
@@ -216,13 +233,13 @@ type ToSeparatedCase<S extends string, Sep extends Separator, Prev extends strin
216
233
  * (`XAxis` -> `xAxis`)
217
234
  */
218
235
  type PascalToCamelCase<S extends string, Prev extends string = '', Acc extends string = ''> = S extends `${infer C}${infer Rest}` ? IsWordBoundary<C, Prev, Rest> extends true ? `${Acc}${S}` : PascalToCamelCase<Rest, C, `${Acc}${Lowercase<C>}`> : Acc;
219
- /** snake_case/kebab-case to camelCase (`snakeToCamelCase`, `kebabToCamelCase`) */
236
+ /** snake_case/kebab-case to camelCase (`separatedToCamelCase`) */
220
237
  type SeparatedToCamelCase<S extends string, Sep extends Separator, Acc extends string = ''> = S extends `${infer Word}${Sep}${infer Next}${infer Rest}` ? SeparatedToCamelCase<Rest, Sep, `${Acc}${Word}${Uppercase<Next>}`> : `${Acc}${S}`;
221
- /** Replaces every `From` separator with `To` (`snakeToKebabCase`, `kebabToSnakeCase`) */
238
+ /** Replaces every `From` separator with `To` (`replaceSeparator`) */
222
239
  type ReplaceSeparator<S extends string, From extends Separator, To extends Separator, Acc extends string = ''> = S extends `${infer Head}${From}${infer Rest}` ? ReplaceSeparator<Rest, From, To, `${Acc}${Head}${To}`> : `${Acc}${S}`;
223
- /** A single word in the target case (`transformSingleWord`) */
240
+ /** A single word in the target case (`singleWordToCase`) */
224
241
  type SingleWordToCase<K extends string, To extends StringCase> = To extends 'pascal' ? Capitalize<K> : To extends 'camel' ? Uncapitalize<K> : Lowercase<K>;
225
- /** A key of the detected case `From` in the target case (`formatterMap`) */
242
+ /** A key of the detected case `From` in the target case (the formatters `transformCase` picks) */
226
243
  type FormatKey<K extends string, From extends StringCase, To extends StringCase> = From extends To ? K : From extends 'snake' | 'kebab' ? To extends 'camel' ? SeparatedToCamelCase<K, From extends 'snake' ? '_' : '-'> : To extends 'pascal' ? Capitalize<SeparatedToCamelCase<K, From extends 'snake' ? '_' : '-'>> : From extends 'snake' ? ReplaceSeparator<K, '_', '-'> : ReplaceSeparator<K, '-', '_'> : To extends 'pascal' ? Capitalize<K> : To extends 'camel' ? PascalToCamelCase<K> : ToSeparatedCase<K, To extends 'snake' ? '_' : '-'>;
227
244
  /** Applies the detected case of `K` (`transformCase`) */
228
245
  type TransformDetectedKey<K extends string, Detected, To extends StringCase> = Detected extends 'single' ? SingleWordToCase<K, To> : Detected extends StringCase ? FormatKey<K, Detected, To> : K;
@@ -501,7 +518,7 @@ declare function transform<T, To extends StringCase | undefined = StringCase | u
501
518
  *
502
519
  * @deprecated `sourceCase` has no effect: leave out the type arguments and `sourceCase`,
503
520
  * and the result type is inferred, `depth` and `exclude` included. This form does not
504
- * accept `depth` or `exclude`.
521
+ * accept `depth`, `exclude` or `keepReferences`.
505
522
  */
506
523
  declare function transform<T, From extends StringCase, To extends StringCase>(data: T, options: {
507
524
  sourceCase: From;
package/dist/index.d.mts CHANGED
@@ -67,6 +67,23 @@ interface TransformOptions extends TransformKeyOptions {
67
67
  * @default []
68
68
  */
69
69
  exclude?: readonly string[] | undefined;
70
+ /**
71
+ * Whether an object reached through several references gives one result, as in the
72
+ * input: shared objects stay shared, and circular references point back into the
73
+ * result. Pass `false` for data that cannot contain such references, such as the
74
+ * output of `JSON.parse`: the transform then skips this bookkeeping, which makes inputs
75
+ * with many objects and arrays up to about twice as fast.
76
+ *
77
+ * Use it only for tree-shaped data. An object is then copied once for every path that
78
+ * leads to it, so shared objects inside shared objects multiply. Data with more than
79
+ * 256 nested objects, arrays, Maps and Sets on one path, as circular references always
80
+ * have, is converted again from the start with the bookkeeping, so it takes longer and
81
+ * getters can run twice. With a finite `depth`, circular references stop at the depth
82
+ * limit before that, and are copied once per path down to it.
83
+ *
84
+ * @default true
85
+ */
86
+ keepReferences?: boolean | undefined;
70
87
  /**
71
88
  * @deprecated Has no effect. Every key's case is detected from the key itself, both at
72
89
  * runtime and in the result type, so there is nothing to declare.
@@ -176,7 +193,7 @@ declare const ACRONYM_PLURAL_SUFFIX = "s";
176
193
  * (tail-recursive, so long keys compile).
177
194
  */
178
195
  type HasOnlyKeyChars<S extends string> = S extends `${infer C}${infer Rest}` ? C extends KeyChar ? HasOnlyKeyChars<Rest> : false : true;
179
- /** The canonical UUID form, where `x` stands for a hexadecimal digit (`UUID_REGEX`) */
196
+ /** The canonical UUID form, where `x` stands for a hexadecimal digit (`isUuid`) */
180
197
  type UuidPattern = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx';
181
198
  /**
182
199
  * `true` when `S` is a UUID in canonical form. `S` is compared with `UuidPattern` one
@@ -185,14 +202,14 @@ type UuidPattern = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx';
185
202
  */
186
203
  type IsUuid<S extends string, Pattern extends string = UuidPattern> = Pattern extends `${infer P}${infer PatternRest}` ? S extends `${infer C}${infer Rest}` ? C extends (P extends 'x' ? HexDigit : P) ? IsUuid<Rest, PatternRest> : false : false : S extends '' ? true : false;
187
204
  /**
188
- * Keys the runtime leaves unchanged (`prepareStringTransformation`): keys containing a
205
+ * Keys the runtime leaves unchanged (`transformCase`): keys containing a
189
206
  * character outside `A-Z a-z 0-9 _ -`, keys not starting with a letter, keys ending with
190
207
  * a separator, and UUIDs. A UUID that starts with a digit is already preserved, so only
191
208
  * keys that the other rules do not preserve are compared with the UUID form.
192
209
  */
193
210
  type IsPreservedKey<K extends string> = HasOnlyKeyChars<K> extends false ? true : K extends `${LowerLetter | UpperLetter}${string}` ? K extends `${string}${Separator}` ? true : IsUuid<K> : true;
194
211
  /**
195
- * The case the runtime detects for a key that is not preserved (`detectStringCase`), or
212
+ * The case the runtime detects for a key that is not preserved (`transformCase`), or
196
213
  * `'none'` when it cannot be detected (the key is then left unchanged). A string is used
197
214
  * rather than `null`, which every type accepts without `strictNullChecks`.
198
215
  */
@@ -216,13 +233,13 @@ type ToSeparatedCase<S extends string, Sep extends Separator, Prev extends strin
216
233
  * (`XAxis` -> `xAxis`)
217
234
  */
218
235
  type PascalToCamelCase<S extends string, Prev extends string = '', Acc extends string = ''> = S extends `${infer C}${infer Rest}` ? IsWordBoundary<C, Prev, Rest> extends true ? `${Acc}${S}` : PascalToCamelCase<Rest, C, `${Acc}${Lowercase<C>}`> : Acc;
219
- /** snake_case/kebab-case to camelCase (`snakeToCamelCase`, `kebabToCamelCase`) */
236
+ /** snake_case/kebab-case to camelCase (`separatedToCamelCase`) */
220
237
  type SeparatedToCamelCase<S extends string, Sep extends Separator, Acc extends string = ''> = S extends `${infer Word}${Sep}${infer Next}${infer Rest}` ? SeparatedToCamelCase<Rest, Sep, `${Acc}${Word}${Uppercase<Next>}`> : `${Acc}${S}`;
221
- /** Replaces every `From` separator with `To` (`snakeToKebabCase`, `kebabToSnakeCase`) */
238
+ /** Replaces every `From` separator with `To` (`replaceSeparator`) */
222
239
  type ReplaceSeparator<S extends string, From extends Separator, To extends Separator, Acc extends string = ''> = S extends `${infer Head}${From}${infer Rest}` ? ReplaceSeparator<Rest, From, To, `${Acc}${Head}${To}`> : `${Acc}${S}`;
223
- /** A single word in the target case (`transformSingleWord`) */
240
+ /** A single word in the target case (`singleWordToCase`) */
224
241
  type SingleWordToCase<K extends string, To extends StringCase> = To extends 'pascal' ? Capitalize<K> : To extends 'camel' ? Uncapitalize<K> : Lowercase<K>;
225
- /** A key of the detected case `From` in the target case (`formatterMap`) */
242
+ /** A key of the detected case `From` in the target case (the formatters `transformCase` picks) */
226
243
  type FormatKey<K extends string, From extends StringCase, To extends StringCase> = From extends To ? K : From extends 'snake' | 'kebab' ? To extends 'camel' ? SeparatedToCamelCase<K, From extends 'snake' ? '_' : '-'> : To extends 'pascal' ? Capitalize<SeparatedToCamelCase<K, From extends 'snake' ? '_' : '-'>> : From extends 'snake' ? ReplaceSeparator<K, '_', '-'> : ReplaceSeparator<K, '-', '_'> : To extends 'pascal' ? Capitalize<K> : To extends 'camel' ? PascalToCamelCase<K> : ToSeparatedCase<K, To extends 'snake' ? '_' : '-'>;
227
244
  /** Applies the detected case of `K` (`transformCase`) */
228
245
  type TransformDetectedKey<K extends string, Detected, To extends StringCase> = Detected extends 'single' ? SingleWordToCase<K, To> : Detected extends StringCase ? FormatKey<K, Detected, To> : K;
@@ -501,7 +518,7 @@ declare function transform<T, To extends StringCase | undefined = StringCase | u
501
518
  *
502
519
  * @deprecated `sourceCase` has no effect: leave out the type arguments and `sourceCase`,
503
520
  * and the result type is inferred, `depth` and `exclude` included. This form does not
504
- * accept `depth` or `exclude`.
521
+ * accept `depth`, `exclude` or `keepReferences`.
505
522
  */
506
523
  declare function transform<T, From extends StringCase, To extends StringCase>(data: T, options: {
507
524
  sourceCase: From;
package/dist/index.d.ts CHANGED
@@ -67,6 +67,23 @@ interface TransformOptions extends TransformKeyOptions {
67
67
  * @default []
68
68
  */
69
69
  exclude?: readonly string[] | undefined;
70
+ /**
71
+ * Whether an object reached through several references gives one result, as in the
72
+ * input: shared objects stay shared, and circular references point back into the
73
+ * result. Pass `false` for data that cannot contain such references, such as the
74
+ * output of `JSON.parse`: the transform then skips this bookkeeping, which makes inputs
75
+ * with many objects and arrays up to about twice as fast.
76
+ *
77
+ * Use it only for tree-shaped data. An object is then copied once for every path that
78
+ * leads to it, so shared objects inside shared objects multiply. Data with more than
79
+ * 256 nested objects, arrays, Maps and Sets on one path, as circular references always
80
+ * have, is converted again from the start with the bookkeeping, so it takes longer and
81
+ * getters can run twice. With a finite `depth`, circular references stop at the depth
82
+ * limit before that, and are copied once per path down to it.
83
+ *
84
+ * @default true
85
+ */
86
+ keepReferences?: boolean | undefined;
70
87
  /**
71
88
  * @deprecated Has no effect. Every key's case is detected from the key itself, both at
72
89
  * runtime and in the result type, so there is nothing to declare.
@@ -176,7 +193,7 @@ declare const ACRONYM_PLURAL_SUFFIX = "s";
176
193
  * (tail-recursive, so long keys compile).
177
194
  */
178
195
  type HasOnlyKeyChars<S extends string> = S extends `${infer C}${infer Rest}` ? C extends KeyChar ? HasOnlyKeyChars<Rest> : false : true;
179
- /** The canonical UUID form, where `x` stands for a hexadecimal digit (`UUID_REGEX`) */
196
+ /** The canonical UUID form, where `x` stands for a hexadecimal digit (`isUuid`) */
180
197
  type UuidPattern = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx';
181
198
  /**
182
199
  * `true` when `S` is a UUID in canonical form. `S` is compared with `UuidPattern` one
@@ -185,14 +202,14 @@ type UuidPattern = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx';
185
202
  */
186
203
  type IsUuid<S extends string, Pattern extends string = UuidPattern> = Pattern extends `${infer P}${infer PatternRest}` ? S extends `${infer C}${infer Rest}` ? C extends (P extends 'x' ? HexDigit : P) ? IsUuid<Rest, PatternRest> : false : false : S extends '' ? true : false;
187
204
  /**
188
- * Keys the runtime leaves unchanged (`prepareStringTransformation`): keys containing a
205
+ * Keys the runtime leaves unchanged (`transformCase`): keys containing a
189
206
  * character outside `A-Z a-z 0-9 _ -`, keys not starting with a letter, keys ending with
190
207
  * a separator, and UUIDs. A UUID that starts with a digit is already preserved, so only
191
208
  * keys that the other rules do not preserve are compared with the UUID form.
192
209
  */
193
210
  type IsPreservedKey<K extends string> = HasOnlyKeyChars<K> extends false ? true : K extends `${LowerLetter | UpperLetter}${string}` ? K extends `${string}${Separator}` ? true : IsUuid<K> : true;
194
211
  /**
195
- * The case the runtime detects for a key that is not preserved (`detectStringCase`), or
212
+ * The case the runtime detects for a key that is not preserved (`transformCase`), or
196
213
  * `'none'` when it cannot be detected (the key is then left unchanged). A string is used
197
214
  * rather than `null`, which every type accepts without `strictNullChecks`.
198
215
  */
@@ -216,13 +233,13 @@ type ToSeparatedCase<S extends string, Sep extends Separator, Prev extends strin
216
233
  * (`XAxis` -> `xAxis`)
217
234
  */
218
235
  type PascalToCamelCase<S extends string, Prev extends string = '', Acc extends string = ''> = S extends `${infer C}${infer Rest}` ? IsWordBoundary<C, Prev, Rest> extends true ? `${Acc}${S}` : PascalToCamelCase<Rest, C, `${Acc}${Lowercase<C>}`> : Acc;
219
- /** snake_case/kebab-case to camelCase (`snakeToCamelCase`, `kebabToCamelCase`) */
236
+ /** snake_case/kebab-case to camelCase (`separatedToCamelCase`) */
220
237
  type SeparatedToCamelCase<S extends string, Sep extends Separator, Acc extends string = ''> = S extends `${infer Word}${Sep}${infer Next}${infer Rest}` ? SeparatedToCamelCase<Rest, Sep, `${Acc}${Word}${Uppercase<Next>}`> : `${Acc}${S}`;
221
- /** Replaces every `From` separator with `To` (`snakeToKebabCase`, `kebabToSnakeCase`) */
238
+ /** Replaces every `From` separator with `To` (`replaceSeparator`) */
222
239
  type ReplaceSeparator<S extends string, From extends Separator, To extends Separator, Acc extends string = ''> = S extends `${infer Head}${From}${infer Rest}` ? ReplaceSeparator<Rest, From, To, `${Acc}${Head}${To}`> : `${Acc}${S}`;
223
- /** A single word in the target case (`transformSingleWord`) */
240
+ /** A single word in the target case (`singleWordToCase`) */
224
241
  type SingleWordToCase<K extends string, To extends StringCase> = To extends 'pascal' ? Capitalize<K> : To extends 'camel' ? Uncapitalize<K> : Lowercase<K>;
225
- /** A key of the detected case `From` in the target case (`formatterMap`) */
242
+ /** A key of the detected case `From` in the target case (the formatters `transformCase` picks) */
226
243
  type FormatKey<K extends string, From extends StringCase, To extends StringCase> = From extends To ? K : From extends 'snake' | 'kebab' ? To extends 'camel' ? SeparatedToCamelCase<K, From extends 'snake' ? '_' : '-'> : To extends 'pascal' ? Capitalize<SeparatedToCamelCase<K, From extends 'snake' ? '_' : '-'>> : From extends 'snake' ? ReplaceSeparator<K, '_', '-'> : ReplaceSeparator<K, '-', '_'> : To extends 'pascal' ? Capitalize<K> : To extends 'camel' ? PascalToCamelCase<K> : ToSeparatedCase<K, To extends 'snake' ? '_' : '-'>;
227
244
  /** Applies the detected case of `K` (`transformCase`) */
228
245
  type TransformDetectedKey<K extends string, Detected, To extends StringCase> = Detected extends 'single' ? SingleWordToCase<K, To> : Detected extends StringCase ? FormatKey<K, Detected, To> : K;
@@ -501,7 +518,7 @@ declare function transform<T, To extends StringCase | undefined = StringCase | u
501
518
  *
502
519
  * @deprecated `sourceCase` has no effect: leave out the type arguments and `sourceCase`,
503
520
  * and the result type is inferred, `depth` and `exclude` included. This form does not
504
- * accept `depth` or `exclude`.
521
+ * accept `depth`, `exclude` or `keepReferences`.
505
522
  */
506
523
  declare function transform<T, From extends StringCase, To extends StringCase>(data: T, options: {
507
524
  sourceCase: From;
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";const e=/^[a-z0-9_]+$/,t=/__+/,n=/^[a-z][a-zA-Z0-9]*$/,r=/^[A-Z][a-zA-Z0-9]*$/,o=/^[a-z0-9-]+$/,s=/-{2,}/,u=/[A-Z]/,a=/[a-z]/,i=/^[a-z0-9]+$/,c=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,l=/^[^.]+(?:\.[^.]+)*$/;function f(e){if("string"==typeof e)return JSON.stringify(e);if("bigint"==typeof e)return`${e}n`;if(null===e)return"null";if("object"==typeof e||"function"==typeof e)try{return Object.prototype.toString.call(e)}catch(e){return"an object"}return String(e)}function p(e){const t=e.indexOf(".");return-1===t?[e]:[e.slice(0,t),e.slice(t+1)]}const d=[];function g(e){let t,n=!1;for(const r of e)void 0===r?n=!0:(null!=t?t:t=[]).push(r);return{keepKey:n,pathsBelow:t?h(t):d,scope:void 0}}function h(e){return 1===e.length?e:[...new Set(e)].sort()}function y(e,t){const n=[];let r;for(const t of e){const[e,o]=p(t);if("*"===e)n.push(o);else{null!=r||(r=new Map);const t=r.get(e);t?t.push(o):r.set(e,[o])}}const o=new Map;for(const[e,t]of null!=r?r:[])o.set(e,g(n.length?[...t,...n]:t));const{targetCase:s,depth:u}=t.plain.options,a={targetCase:s,depth:u,exclude:null},i={options:a,visitedRefs:[],named:o,other:g(n),root:t};return a.exclude=i,i}function w(e,t){const n="string"==typeof t?e.named.get(t):void 0;return null!=n?n:e.other}function b(e,t){var n;return null!==(n=t.scope)&&void 0!==n?n:t.scope=0===t.pathsBelow.length?e.root.plain:function(e,t){const n=JSON.stringify(e);let r=t.states.get(n);return r||(r=y(e,t),t.states.set(n,r)),r}(t.pathsBelow,e.root)}const v="[object Object]";function C(e,t,n){"__proto__"===t?Object.defineProperty(e,t,{value:n,enumerable:!0,writable:!0,configurable:!0}):e[t]=n}function m(e){return e>="a"&&e<="z"}function k(e){return e>="A"&&e<="Z"}function U(e,t){var n,r,o,s;if(!k(null!==(n=e[t])&&void 0!==n?n:""))return!1;const u=null!==(r=e[t-1])&&void 0!==r?r:"";if(m(u)||(a=u)>="0"&&a<="9")return!0;var a;if(!(k(u)&&m(null!==(o=e[t+1])&&void 0!==o?o:"")))return!1;return!("s"===e[t+1]&&!m(null!==(s=e[t+2])&&void 0!==s?s:""))}function z(e,t){if(!e)return e;let n="";for(let r=0;r<e.length;r++)U(e,r)&&(n+=t),n+=e[r].toLowerCase();return n}const $={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 z(e,"_")},pascal:function(e){return e?e.charAt(0).toUpperCase()+e.slice(1):e},kebab:function(e){return z(e,"-")},camel:e=>e},pascal:{snake:function(e){return z(e,"_")},camel:function(e){if(!e)return e;let t=1;for(;t<e.length&&!U(e,t);)t++;return e.slice(0,t).toLowerCase()+e.slice(t)},kebab:function(e){return z(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}};function j(c){return"string"!=typeof c?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()}(c)?"single":function(n){return"string"==typeof n&&e.test(n)&&!t.test(n)&&(n.includes("_")||i.test(n))}(c)?"snake":function(e){return"string"==typeof e&&n.test(e)&&u.test(e)}(c)?"camel":function(e){return"string"==typeof e&&r.test(e)&&a.test(e)}(c)?"pascal":function(e){return"string"==typeof e&&o.test(e)&&!s.test(e)&&(e.includes("-")||i.test(e))}(c)?"kebab":null}function A(e,t){if(!e)return e;const{string:n,shouldTransform:r,sourceCase:o,singleWord:s}=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)||c.test(e))return{string:e,shouldTransform:!1,sourceCase:null,singleWord:!1};const t=j(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);return r?s?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,t):o&&o!==t?$[o][t](n):n:n}const _=new Map;function x(e,t){var n;if(e.length>100)return A(e,t);let r=_.get(t);r||(r={current:new Map,previous:new Map},_.set(t,r));let o=r.current.get(e);return void 0===o&&(o=null!==(n=r.previous.get(e))&&void 0!==n?n:A(e,t),r.current.size>=1e3&&(r.previous=r.current,r.current=new Map),r.current.set(e,o)),o}function O(e,t,n=[],r=0){var o;if(null===e||"object"!=typeof e)return e;if(r>=t.depth)return e;const s=t.depth===1/0?0:r,u=null!==(o=n[s])&&void 0!==o?o:n[s]=new WeakMap;if(u.has(e))return u.get(e);if(Array.isArray(e)){const o=[];return u.set(e,o),function(e,t,n,r,o){for(const s of e)t.push(O(s,n,r,o))}(e,o,t,n,r),o}const a=r+1,i=function(e){try{return Object.prototype.toString.call(e)}catch(e){return v}}(e);if(function(e,t){if(!(e instanceof Map)&&"[object Map]"!==t)return!1;try{return Map.prototype.has.call(e,void 0),!0}catch(e){return!1}}(e,i)){const r=new Map;return u.set(e,r),null===t.exclude?function(e,t,n,r,o){for(const[s,u]of e)t.set("string"==typeof s?A(s,n.targetCase):s,O(u,n,r,o))}(e,r,t,n,a):function(e,t,n,r){for(const[o,s]of e){const e=w(n,o),u=b(n,e);t.set("string"!=typeof o||e.keepKey?o:A(o,n.options.targetCase),O(s,u.options,u.visitedRefs,r))}}(e,r,t.exclude,a),r}if(function(e,t){if(!(e instanceof Set)&&"[object Set]"!==t)return!1;try{return Set.prototype.has.call(e,void 0),!0}catch(e){return!1}}(e,i)){const r=new Set;return u.set(e,r),function(e,t,n,r,o){for(const s of e)t.add(O(s,n,r,o))}(e,r,t,n,a),r}if(i===v){const r=e,o={};if(u.set(e,o),null===t.exclude)for(const e in r)Object.prototype.hasOwnProperty.call(r,e)&&C(o,x(e,t.targetCase),O(r[e],t,n,a));else!function(e,t,n,r){for(const o in e)if(Object.prototype.hasOwnProperty.call(e,o)){const s=w(n,o),u=b(n,s);C(t,s.keepKey?o:x(o,n.options.targetCase),O(e[o],u.options,u.visitedRefs,r))}}(r,o,t.exclude,a);for(const e of Object.getOwnPropertySymbols(r))o[e]=r[e];return o}return e}const M=["camel","snake","pascal","kebab"];function T(e){const t=e||"camel";if(n=t,!M.includes(n))throw new TypeError(`Unsupported targetCase ${f(t)}. Use one of: ${M.join(", ")}.`);var n;return t}exports.transform=function(e,t){var n;const r=null==t?void 0:t.targetCase,o=null!==(n=null==t?void 0:t.depth)&&void 0!==n?n:1/0,s=T(r);if("number"!=typeof o||Number.isNaN(o))throw new TypeError(`Unsupported depth ${f(o)}. Use a number, or omit depth to transform every level.`);const u={targetCase:s,depth:o,exclude:null},a=null==t?void 0:t.exclude,i=void 0===a?null:function(e,t){if(null==e)return null;if(!Array.isArray(e))throw new TypeError(`Unsupported exclude ${f(e)}. Use an array of paths, such as ["metadata.*"].`);for(const t of e)if("string"!=typeof t||!l.test(t))throw new TypeError(`Unsupported exclude path ${f(t)}. Use non-empty keys joined with dots, such as "metadata.*".`);if(0===e.length)return null;const n={plain:{options:t,visitedRefs:[]},states:new Map};return y(h(e),n)}(a,u);return null===i?O(e,u):O(e,i.options,i.visitedRefs)},exports.transformKey=function(e,t){if("string"!=typeof e)throw new TypeError(`Unsupported key ${f(e)}. Use a string.`);if("string"==typeof t)throw new TypeError(`Unsupported options ${f(t)}. Use an options object: { targetCase: ${f(t)} }.`);return A(e,T(null==t?void 0:t.targetCase))};
1
+ "use strict";const e=/^[^.]+(?:\.[^.]+)*$/;function t(e){if("string"==typeof e)return JSON.stringify(e);if("bigint"==typeof e)return`${e}n`;if(null===e)return"null";if("object"==typeof e||"function"==typeof e)try{return Object.prototype.toString.call(e)}catch(e){return"an object"}return String(e)}function n(e){const t=e.indexOf(".");return-1===t?[e]:[e.slice(0,t),e.slice(t+1)]}const r=[];function o(e){let t,n=!1;for(const r of e)void 0===r?n=!0:(null!=t?t:t=[]).push(r);return{keepKey:n,pathsBelow:t?s(t):r,scope:void 0}}function s(e){return 1===e.length?e:[...new Set(e)].sort()}function c(e,t){const r=[];let s;for(const t of e){const[e,o]=n(t);if("*"===e)r.push(o);else{null!=s||(s=new Map);const t=s.get(e);t?t.push(o):s.set(e,[o])}}const c=new Map;for(const[e,t]of null!=s?s:[])c.set(e,o(r.length?[...t,...r]:t));const{targetCase:i,depth:u,keepReferences:f}=t.plain.options,a={targetCase:i,depth:u,keepReferences:f,exclude:null},l={options:a,visitedRefs:[],named:c,other:o(r),root:t};return a.exclude=l,l}function i(e,t){const n="string"==typeof t?e.named.get(t):void 0;return null!=n?n:e.other}function u(e,t){var n;return null!==(n=t.scope)&&void 0!==n?n:t.scope=0===t.pathsBelow.length?e.root.plain:function(e,t){const n=JSON.stringify(e);let r=t.states.get(n);return r||(r=c(e,t),t.states.set(n,r)),r}(t.pathsBelow,e.root)}const f="[object Object]";function a(e,t,n){"__proto__"===t?Object.defineProperty(e,t,{value:n,enumerable:!0,writable:!0,configurable:!0}):e[t]=n}const l={};let p=!1;function d(e,t,n,r){let o=e[t];o.size>=16e6&&(p=!0,o=e[t]=new Map([[l,o]])),o.set(n,r)}function h(e){return e>=48&&e<=57}function y(e){return e>=97&&e<=122}function g(e){return e>=65&&e<=90}const w="s".charCodeAt(0);function v(e,t){if(!g(e.charCodeAt(t)))return!1;const n=e.charCodeAt(t-1);if(y(n)||h(n))return!0;const r=e.charCodeAt(t+1);return!(!g(n)||!y(r))&&(r!==w||y(e.charCodeAt(t+2)))}function b(e,t,n){return e.split(t).join(n)}function C(e,t,n){let r=n?e[0].toUpperCase():e[0],o=1,s=e.indexOf(t,1);for(;-1!==s;)r+=e.slice(o,s)+e[s+1].toUpperCase(),o=s+2,s=e.indexOf(t,o);return r+e.slice(o)}function m(e,t){let n="",r=0;for(let o=1;o<e.length;o++)v(e,o)&&(n+=e.slice(r,o)+t,r=o);return(n+e.slice(r)).toLowerCase()}function k(e,t){const n=e.length;if(0===n)return e;let r=e.charCodeAt(0);const o=g(r);if(!o&&!y(r))return e;let s=o?1:0,c=!o,i=0,u=0,f=!1,a=r;for(let t=1;t<n;t++){if(r=e.charCodeAt(t),y(r))c=!0;else if(g(r))s++;else if(95===r)i++,95===a&&(f=!0);else if(45===r)u++,45===a&&(f=!0);else if(!h(r))return e;a=r}if(95===a||45===a)return e;if(0===i&&0===u){if(0===s||1===s&&o)return function(e,t){const n=g(e.charCodeAt(0));switch(t){case"pascal":return n?e:e[0].toUpperCase()+e.slice(1);case"camel":return n?e[0].toLowerCase()+e.slice(1):e;default:return n?e.toLowerCase():e}}(e,t);if(!o)switch(t){case"snake":return m(e,"_");case"kebab":return m(e,"-");case"pascal":return e[0].toUpperCase()+e.slice(1);default:return e}if(!c)return e;switch(t){case"snake":return m(e,"_");case"kebab":return m(e,"-");case"camel":return function(e){let t=1;for(;t<e.length&&!v(e,t);)t++;return e.slice(0,t).toLowerCase()+e.slice(t)}(e);default:return e}}if(s>0||f||i>0&&u>0)return e;if(i>0)switch(t){case"camel":return C(e,"_",!1);case"pascal":return C(e,"_",!0);case"kebab":return b(e,"_","-");default:return e}if(function(e){if(36!==e.length)return!1;for(let t=0;t<36;t++){const n=e.charCodeAt(t);if(8===t||13===t||18===t||23===t){if(45!==n)return!1}else if(!(h(n)||n>=97&&n<=102||n>=65&&n<=70))return!1}return!0}(e))return e;switch(t){case"camel":return C(e,"-",!1);case"pascal":return C(e,"-",!0);case"snake":return b(e,"-","_");default:return e}}const j=new Map;let U,x={current:new Map,previous:new Map},M=0;function O(e,t){if(e.length>100)return k(e,t);if(t!==U){let e=j.get(t);e||(e={current:new Map,previous:new Map},j.set(t,e)),U=t,x=e}const n=x;let r=n.current.get(e);if(void 0!==r)return M=0,r;if(r=n.previous.get(e),void 0===r){if(r=k(e,t),++M>256&&M%8!=0)return r}else M=0;return n.current.size>=1e3&&(n.previous=n.current,n.current=new Map),n.current.set(e,r),r}const A={reason:"nesting limit reached"};function R(e,t,n=[],r=0,o=0){var s;if(null===e||"object"!=typeof e)return e;if(r>=t.depth)return e;const c=t.depth===1/0?0:r,h=t.keepReferences;if(h){const t=function(e,t){const n=e.get(t);if(void 0!==n||!p)return n;let r=e.get(l);for(;void 0!==r;){const e=r.get(t);if(void 0!==e)return e;r=r.get(l)}}(null!==(s=n[c])&&void 0!==s?s:n[c]=new Map,e);if(void 0!==t)return t}else if(o>=256)throw A;if(Array.isArray(e)){const s=[];return h&&d(n,c,e,s),function(e,t,n,r,o,s){for(const c of e)t.push(null!==c&&"object"==typeof c?R(c,n,r,o,s+1):c)}(e,s,t,n,r,o),s}const y=r+1,g=function(e){try{return Object.prototype.toString.call(e)}catch(e){return f}}(e);if(function(e,t){if(!(e instanceof Map)&&"[object Map]"!==t)return!1;try{return Map.prototype.has.call(e,void 0),!0}catch(e){return!1}}(e,g)){const r=new Map;return h&&d(n,c,e,r),null===t.exclude?function(e,t,n,r,o,s){for(const[c,i]of e)t.set("string"==typeof c?k(c,n.targetCase):c,R(i,n,r,o,s+1))}(e,r,t,n,y,o):function(e,t,n,r,o){for(const[s,c]of e){const e=i(n,s),f=u(n,e);t.set("string"!=typeof s||e.keepKey?s:k(s,n.options.targetCase),R(c,f.options,f.visitedRefs,r,o+1))}}(e,r,t.exclude,y,o),r}if(function(e,t){if(!(e instanceof Set)&&"[object Set]"!==t)return!1;try{return Set.prototype.has.call(e,void 0),!0}catch(e){return!1}}(e,g)){const r=new Set;return h&&d(n,c,e,r),function(e,t,n,r,o,s){for(const c of e)t.add(R(c,n,r,o,s+1))}(e,r,t,n,y,o),r}if(g===f){const r=e,s={};if(h&&d(n,c,e,s),null===t.exclude)for(const e in r)Object.prototype.hasOwnProperty.call(r,e)&&a(s,O(e,t.targetCase),R(r[e],t,n,y,o+1));else!function(e,t,n,r,o){for(const s in e)if(Object.prototype.hasOwnProperty.call(e,s)){const c=i(n,s),f=u(n,c);a(t,c.keepKey?s:O(s,n.options.targetCase),R(e[s],f.options,f.visitedRefs,r,o+1))}}(r,s,t.exclude,y,o);for(const e of Object.getOwnPropertySymbols(r))s[e]=r[e];return s}return e}const S=["camel","snake","pascal","kebab"];function $(e){const n=e||"camel";if(r=n,!S.includes(r))throw new TypeError(`Unsupported targetCase ${t(n)}. Use one of: ${S.join(", ")}.`);var r;return n}function _(n,r,o){const i=void 0===o?null:function(n,r){if(null==n)return null;if(!Array.isArray(n))throw new TypeError(`Unsupported exclude ${t(n)}. Use an array of paths, such as ["metadata.*"].`);for(const r of n)if("string"!=typeof r||!e.test(r))throw new TypeError(`Unsupported exclude path ${t(r)}. Use non-empty keys joined with dots, such as "metadata.*".`);if(0===n.length)return null;const o={plain:{options:r,visitedRefs:[]},states:new Map};return c(s(n),o)}(o,r);return null===i?R(n,r):R(n,i.options,i.visitedRefs)}exports.transform=function(e,n){var r,o;const s=null==n?void 0:n.targetCase,c=null!==(r=null==n?void 0:n.depth)&&void 0!==r?r:1/0,i=$(s);if("number"!=typeof c||Number.isNaN(c))throw new TypeError(`Unsupported depth ${t(c)}. Use a number, or omit depth to transform every level.`);const u=null==n?void 0:n.exclude,f=null===(o=null==n?void 0:n.keepReferences)||void 0===o||o;if("boolean"!=typeof f)throw new TypeError(`Unsupported keepReferences ${t(f)}. Use true or false.`);if(!f)try{return _(e,{targetCase:i,depth:c,keepReferences:f,exclude:null},u)}catch(e){if(e!==A)throw e}return _(e,{targetCase:i,depth:c,keepReferences:!0,exclude:null},u)},exports.transformKey=function(e,n){if("string"!=typeof e)throw new TypeError(`Unsupported key ${t(e)}. Use a string.`);if("string"==typeof n)throw new TypeError(`Unsupported options ${t(n)}. Use an options object: { targetCase: ${t(n)} }.`);return k(e,$(null==n?void 0:n.targetCase))};
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- const e=/^[a-z0-9_]+$/,t=/__+/,n=/^[a-z][a-zA-Z0-9]*$/,r=/^[A-Z][a-zA-Z0-9]*$/,o=/^[a-z0-9-]+$/,s=/-{2,}/,u=/[A-Z]/,a=/[a-z]/,i=/^[a-z0-9]+$/,c=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,l=/^[^.]+(?:\.[^.]+)*$/;function f(e){if("string"==typeof e)return JSON.stringify(e);if("bigint"==typeof e)return`${e}n`;if(null===e)return"null";if("object"==typeof e||"function"==typeof e)try{return Object.prototype.toString.call(e)}catch(e){return"an object"}return String(e)}function p(e){const t=e.indexOf(".");return-1===t?[e]:[e.slice(0,t),e.slice(t+1)]}const d=[];function g(e){let t,n=!1;for(const r of e)void 0===r?n=!0:(null!=t?t:t=[]).push(r);return{keepKey:n,pathsBelow:t?h(t):d,scope:void 0}}function h(e){return 1===e.length?e:[...new Set(e)].sort()}function y(e,t){const n=[];let r;for(const t of e){const[e,o]=p(t);if("*"===e)n.push(o);else{null!=r||(r=new Map);const t=r.get(e);t?t.push(o):r.set(e,[o])}}const o=new Map;for(const[e,t]of null!=r?r:[])o.set(e,g(n.length?[...t,...n]:t));const{targetCase:s,depth:u}=t.plain.options,a={targetCase:s,depth:u,exclude:null},i={options:a,visitedRefs:[],named:o,other:g(n),root:t};return a.exclude=i,i}function w(e,t){const n="string"==typeof t?e.named.get(t):void 0;return null!=n?n:e.other}function b(e,t){var n;return null!==(n=t.scope)&&void 0!==n?n:t.scope=0===t.pathsBelow.length?e.root.plain:function(e,t){const n=JSON.stringify(e);let r=t.states.get(n);return r||(r=y(e,t),t.states.set(n,r)),r}(t.pathsBelow,e.root)}const v="[object Object]";function C(e,t,n){"__proto__"===t?Object.defineProperty(e,t,{value:n,enumerable:!0,writable:!0,configurable:!0}):e[t]=n}function m(e){return e>="a"&&e<="z"}function k(e){return e>="A"&&e<="Z"}function U(e,t){var n,r,o,s;if(!k(null!==(n=e[t])&&void 0!==n?n:""))return!1;const u=null!==(r=e[t-1])&&void 0!==r?r:"";if(m(u)||(a=u)>="0"&&a<="9")return!0;var a;if(!(k(u)&&m(null!==(o=e[t+1])&&void 0!==o?o:"")))return!1;return!("s"===e[t+1]&&!m(null!==(s=e[t+2])&&void 0!==s?s:""))}function z(e,t){if(!e)return e;let n="";for(let r=0;r<e.length;r++)U(e,r)&&(n+=t),n+=e[r].toLowerCase();return n}const $={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 z(e,"_")},pascal:function(e){return e?e.charAt(0).toUpperCase()+e.slice(1):e},kebab:function(e){return z(e,"-")},camel:e=>e},pascal:{snake:function(e){return z(e,"_")},camel:function(e){if(!e)return e;let t=1;for(;t<e.length&&!U(e,t);)t++;return e.slice(0,t).toLowerCase()+e.slice(t)},kebab:function(e){return z(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}};function j(c){return"string"!=typeof c?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()}(c)?"single":function(n){return"string"==typeof n&&e.test(n)&&!t.test(n)&&(n.includes("_")||i.test(n))}(c)?"snake":function(e){return"string"==typeof e&&n.test(e)&&u.test(e)}(c)?"camel":function(e){return"string"==typeof e&&r.test(e)&&a.test(e)}(c)?"pascal":function(e){return"string"==typeof e&&o.test(e)&&!s.test(e)&&(e.includes("-")||i.test(e))}(c)?"kebab":null}function A(e,t){if(!e)return e;const{string:n,shouldTransform:r,sourceCase:o,singleWord:s}=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)||c.test(e))return{string:e,shouldTransform:!1,sourceCase:null,singleWord:!1};const t=j(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);return r?s?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,t):o&&o!==t?$[o][t](n):n:n}const _=new Map;function O(e,t){var n;if(e.length>100)return A(e,t);let r=_.get(t);r||(r={current:new Map,previous:new Map},_.set(t,r));let o=r.current.get(e);return void 0===o&&(o=null!==(n=r.previous.get(e))&&void 0!==n?n:A(e,t),r.current.size>=1e3&&(r.previous=r.current,r.current=new Map),r.current.set(e,o)),o}function x(e,t,n=[],r=0){var o;if(null===e||"object"!=typeof e)return e;if(r>=t.depth)return e;const s=t.depth===1/0?0:r,u=null!==(o=n[s])&&void 0!==o?o:n[s]=new WeakMap;if(u.has(e))return u.get(e);if(Array.isArray(e)){const o=[];return u.set(e,o),function(e,t,n,r,o){for(const s of e)t.push(x(s,n,r,o))}(e,o,t,n,r),o}const a=r+1,i=function(e){try{return Object.prototype.toString.call(e)}catch(e){return v}}(e);if(function(e,t){if(!(e instanceof Map)&&"[object Map]"!==t)return!1;try{return Map.prototype.has.call(e,void 0),!0}catch(e){return!1}}(e,i)){const r=new Map;return u.set(e,r),null===t.exclude?function(e,t,n,r,o){for(const[s,u]of e)t.set("string"==typeof s?A(s,n.targetCase):s,x(u,n,r,o))}(e,r,t,n,a):function(e,t,n,r){for(const[o,s]of e){const e=w(n,o),u=b(n,e);t.set("string"!=typeof o||e.keepKey?o:A(o,n.options.targetCase),x(s,u.options,u.visitedRefs,r))}}(e,r,t.exclude,a),r}if(function(e,t){if(!(e instanceof Set)&&"[object Set]"!==t)return!1;try{return Set.prototype.has.call(e,void 0),!0}catch(e){return!1}}(e,i)){const r=new Set;return u.set(e,r),function(e,t,n,r,o){for(const s of e)t.add(x(s,n,r,o))}(e,r,t,n,a),r}if(i===v){const r=e,o={};if(u.set(e,o),null===t.exclude)for(const e in r)Object.prototype.hasOwnProperty.call(r,e)&&C(o,O(e,t.targetCase),x(r[e],t,n,a));else!function(e,t,n,r){for(const o in e)if(Object.prototype.hasOwnProperty.call(e,o)){const s=w(n,o),u=b(n,s);C(t,s.keepKey?o:O(o,n.options.targetCase),x(e[o],u.options,u.visitedRefs,r))}}(r,o,t.exclude,a);for(const e of Object.getOwnPropertySymbols(r))o[e]=r[e];return o}return e}const M=["camel","snake","pascal","kebab"];function T(e){const t=e||"camel";if(n=t,!M.includes(n))throw new TypeError(`Unsupported targetCase ${f(t)}. Use one of: ${M.join(", ")}.`);var n;return t}function L(e,t){var n;const r=null==t?void 0:t.targetCase,o=null!==(n=null==t?void 0:t.depth)&&void 0!==n?n:1/0,s=T(r);if("number"!=typeof o||Number.isNaN(o))throw new TypeError(`Unsupported depth ${f(o)}. Use a number, or omit depth to transform every level.`);const u={targetCase:s,depth:o,exclude:null},a=null==t?void 0:t.exclude,i=void 0===a?null:function(e,t){if(null==e)return null;if(!Array.isArray(e))throw new TypeError(`Unsupported exclude ${f(e)}. Use an array of paths, such as ["metadata.*"].`);for(const t of e)if("string"!=typeof t||!l.test(t))throw new TypeError(`Unsupported exclude path ${f(t)}. Use non-empty keys joined with dots, such as "metadata.*".`);if(0===e.length)return null;const n={plain:{options:t,visitedRefs:[]},states:new Map};return y(h(e),n)}(a,u);return null===i?x(e,u):x(e,i.options,i.visitedRefs)}function S(e,t){if("string"!=typeof e)throw new TypeError(`Unsupported key ${f(e)}. Use a string.`);if("string"==typeof t)throw new TypeError(`Unsupported options ${f(t)}. Use an options object: { targetCase: ${f(t)} }.`);return A(e,T(null==t?void 0:t.targetCase))}export{L as transform,S as transformKey};
1
+ const e=/^[^.]+(?:\.[^.]+)*$/;function t(e){if("string"==typeof e)return JSON.stringify(e);if("bigint"==typeof e)return`${e}n`;if(null===e)return"null";if("object"==typeof e||"function"==typeof e)try{return Object.prototype.toString.call(e)}catch(e){return"an object"}return String(e)}function n(e){const t=e.indexOf(".");return-1===t?[e]:[e.slice(0,t),e.slice(t+1)]}const r=[];function o(e){let t,n=!1;for(const r of e)void 0===r?n=!0:(null!=t?t:t=[]).push(r);return{keepKey:n,pathsBelow:t?s(t):r,scope:void 0}}function s(e){return 1===e.length?e:[...new Set(e)].sort()}function c(e,t){const r=[];let s;for(const t of e){const[e,o]=n(t);if("*"===e)r.push(o);else{null!=s||(s=new Map);const t=s.get(e);t?t.push(o):s.set(e,[o])}}const c=new Map;for(const[e,t]of null!=s?s:[])c.set(e,o(r.length?[...t,...r]:t));const{targetCase:i,depth:u,keepReferences:f}=t.plain.options,a={targetCase:i,depth:u,keepReferences:f,exclude:null},l={options:a,visitedRefs:[],named:c,other:o(r),root:t};return a.exclude=l,l}function i(e,t){const n="string"==typeof t?e.named.get(t):void 0;return null!=n?n:e.other}function u(e,t){var n;return null!==(n=t.scope)&&void 0!==n?n:t.scope=0===t.pathsBelow.length?e.root.plain:function(e,t){const n=JSON.stringify(e);let r=t.states.get(n);return r||(r=c(e,t),t.states.set(n,r)),r}(t.pathsBelow,e.root)}const f="[object Object]";function a(e,t,n){"__proto__"===t?Object.defineProperty(e,t,{value:n,enumerable:!0,writable:!0,configurable:!0}):e[t]=n}const l={};let p=!1;function d(e,t,n,r){let o=e[t];o.size>=16e6&&(p=!0,o=e[t]=new Map([[l,o]])),o.set(n,r)}function h(e){return e>=48&&e<=57}function y(e){return e>=97&&e<=122}function g(e){return e>=65&&e<=90}const w="s".charCodeAt(0);function v(e,t){if(!g(e.charCodeAt(t)))return!1;const n=e.charCodeAt(t-1);if(y(n)||h(n))return!0;const r=e.charCodeAt(t+1);return!(!g(n)||!y(r))&&(r!==w||y(e.charCodeAt(t+2)))}function b(e,t,n){return e.split(t).join(n)}function C(e,t,n){let r=n?e[0].toUpperCase():e[0],o=1,s=e.indexOf(t,1);for(;-1!==s;)r+=e.slice(o,s)+e[s+1].toUpperCase(),o=s+2,s=e.indexOf(t,o);return r+e.slice(o)}function k(e,t){let n="",r=0;for(let o=1;o<e.length;o++)v(e,o)&&(n+=e.slice(r,o)+t,r=o);return(n+e.slice(r)).toLowerCase()}function m(e,t){const n=e.length;if(0===n)return e;let r=e.charCodeAt(0);const o=g(r);if(!o&&!y(r))return e;let s=o?1:0,c=!o,i=0,u=0,f=!1,a=r;for(let t=1;t<n;t++){if(r=e.charCodeAt(t),y(r))c=!0;else if(g(r))s++;else if(95===r)i++,95===a&&(f=!0);else if(45===r)u++,45===a&&(f=!0);else if(!h(r))return e;a=r}if(95===a||45===a)return e;if(0===i&&0===u){if(0===s||1===s&&o)return function(e,t){const n=g(e.charCodeAt(0));switch(t){case"pascal":return n?e:e[0].toUpperCase()+e.slice(1);case"camel":return n?e[0].toLowerCase()+e.slice(1):e;default:return n?e.toLowerCase():e}}(e,t);if(!o)switch(t){case"snake":return k(e,"_");case"kebab":return k(e,"-");case"pascal":return e[0].toUpperCase()+e.slice(1);default:return e}if(!c)return e;switch(t){case"snake":return k(e,"_");case"kebab":return k(e,"-");case"camel":return function(e){let t=1;for(;t<e.length&&!v(e,t);)t++;return e.slice(0,t).toLowerCase()+e.slice(t)}(e);default:return e}}if(s>0||f||i>0&&u>0)return e;if(i>0)switch(t){case"camel":return C(e,"_",!1);case"pascal":return C(e,"_",!0);case"kebab":return b(e,"_","-");default:return e}if(function(e){if(36!==e.length)return!1;for(let t=0;t<36;t++){const n=e.charCodeAt(t);if(8===t||13===t||18===t||23===t){if(45!==n)return!1}else if(!(h(n)||n>=97&&n<=102||n>=65&&n<=70))return!1}return!0}(e))return e;switch(t){case"camel":return C(e,"-",!1);case"pascal":return C(e,"-",!0);case"snake":return b(e,"-","_");default:return e}}const j=new Map;let U,x={current:new Map,previous:new Map},M=0;function O(e,t){if(e.length>100)return m(e,t);if(t!==U){let e=j.get(t);e||(e={current:new Map,previous:new Map},j.set(t,e)),U=t,x=e}const n=x;let r=n.current.get(e);if(void 0!==r)return M=0,r;if(r=n.previous.get(e),void 0===r){if(r=m(e,t),++M>256&&M%8!=0)return r}else M=0;return n.current.size>=1e3&&(n.previous=n.current,n.current=new Map),n.current.set(e,r),r}const A={reason:"nesting limit reached"};function R(e,t,n=[],r=0,o=0){var s;if(null===e||"object"!=typeof e)return e;if(r>=t.depth)return e;const c=t.depth===1/0?0:r,h=t.keepReferences;if(h){const t=function(e,t){const n=e.get(t);if(void 0!==n||!p)return n;let r=e.get(l);for(;void 0!==r;){const e=r.get(t);if(void 0!==e)return e;r=r.get(l)}}(null!==(s=n[c])&&void 0!==s?s:n[c]=new Map,e);if(void 0!==t)return t}else if(o>=256)throw A;if(Array.isArray(e)){const s=[];return h&&d(n,c,e,s),function(e,t,n,r,o,s){for(const c of e)t.push(null!==c&&"object"==typeof c?R(c,n,r,o,s+1):c)}(e,s,t,n,r,o),s}const y=r+1,g=function(e){try{return Object.prototype.toString.call(e)}catch(e){return f}}(e);if(function(e,t){if(!(e instanceof Map)&&"[object Map]"!==t)return!1;try{return Map.prototype.has.call(e,void 0),!0}catch(e){return!1}}(e,g)){const r=new Map;return h&&d(n,c,e,r),null===t.exclude?function(e,t,n,r,o,s){for(const[c,i]of e)t.set("string"==typeof c?m(c,n.targetCase):c,R(i,n,r,o,s+1))}(e,r,t,n,y,o):function(e,t,n,r,o){for(const[s,c]of e){const e=i(n,s),f=u(n,e);t.set("string"!=typeof s||e.keepKey?s:m(s,n.options.targetCase),R(c,f.options,f.visitedRefs,r,o+1))}}(e,r,t.exclude,y,o),r}if(function(e,t){if(!(e instanceof Set)&&"[object Set]"!==t)return!1;try{return Set.prototype.has.call(e,void 0),!0}catch(e){return!1}}(e,g)){const r=new Set;return h&&d(n,c,e,r),function(e,t,n,r,o,s){for(const c of e)t.add(R(c,n,r,o,s+1))}(e,r,t,n,y,o),r}if(g===f){const r=e,s={};if(h&&d(n,c,e,s),null===t.exclude)for(const e in r)Object.prototype.hasOwnProperty.call(r,e)&&a(s,O(e,t.targetCase),R(r[e],t,n,y,o+1));else!function(e,t,n,r,o){for(const s in e)if(Object.prototype.hasOwnProperty.call(e,s)){const c=i(n,s),f=u(n,c);a(t,c.keepKey?s:O(s,n.options.targetCase),R(e[s],f.options,f.visitedRefs,r,o+1))}}(r,s,t.exclude,y,o);for(const e of Object.getOwnPropertySymbols(r))s[e]=r[e];return s}return e}const S=["camel","snake","pascal","kebab"];function $(e){const n=e||"camel";if(r=n,!S.includes(r))throw new TypeError(`Unsupported targetCase ${t(n)}. Use one of: ${S.join(", ")}.`);var r;return n}function _(e,n){var r,o;const s=null==n?void 0:n.targetCase,c=null!==(r=null==n?void 0:n.depth)&&void 0!==r?r:1/0,i=$(s);if("number"!=typeof c||Number.isNaN(c))throw new TypeError(`Unsupported depth ${t(c)}. Use a number, or omit depth to transform every level.`);const u=null==n?void 0:n.exclude,f=null===(o=null==n?void 0:n.keepReferences)||void 0===o||o;if("boolean"!=typeof f)throw new TypeError(`Unsupported keepReferences ${t(f)}. Use true or false.`);if(!f)try{return E(e,{targetCase:i,depth:c,keepReferences:f,exclude:null},u)}catch(e){if(e!==A)throw e}return E(e,{targetCase:i,depth:c,keepReferences:!0,exclude:null},u)}function E(n,r,o){const i=void 0===o?null:function(n,r){if(null==n)return null;if(!Array.isArray(n))throw new TypeError(`Unsupported exclude ${t(n)}. Use an array of paths, such as ["metadata.*"].`);for(const r of n)if("string"!=typeof r||!e.test(r))throw new TypeError(`Unsupported exclude path ${t(r)}. Use non-empty keys joined with dots, such as "metadata.*".`);if(0===n.length)return null;const o={plain:{options:r,visitedRefs:[]},states:new Map};return c(s(n),o)}(o,r);return null===i?R(n,r):R(n,i.options,i.visitedRefs)}function T(e,n){if("string"!=typeof e)throw new TypeError(`Unsupported key ${t(e)}. Use a string.`);if("string"==typeof n)throw new TypeError(`Unsupported options ${t(n)}. Use an options object: { targetCase: ${t(n)} }.`);return m(e,$(null==n?void 0:n.targetCase))}export{_ as transform,T as transformKey};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deep-case-crafter",
3
- "version": "3.2.0",
3
+ "version": "3.3.0",
4
4
  "description": "Convert object keys between camelCase, snake_case, kebab-case and PascalCase, deeply (objects, arrays, Map, Set), with exact TypeScript types",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
package/readme.md CHANGED
@@ -210,7 +210,7 @@ Where the others are better or different:
210
210
 
211
211
  - **Bundle size**: bundled and minified with esbuild, ts-case-convert's `objectToCamel`
212
212
  and `objectToSnake` take about 1.1 KB gzipped, deep-case-crafter's `transform` about
213
- 2.6 KB.
213
+ 2.8 KB.
214
214
  - **More output**: ts-case-convert and es-toolkit also convert to SCREAMING_SNAKE_CASE,
215
215
  which deep-case-crafter does not.
216
216
  - **Single strings**: like `transformKey`, ts-case-convert's `toSnake('userId')` and
@@ -298,12 +298,14 @@ The result **types** match all of this, so `result.get_http_response` and
298
298
  - `targetCase` (optional): `'camel' | 'snake' | 'pascal' | 'kebab'` (default: `'camel'`, also used for any falsy value such as `''`, `null` or `0`). Any other value throws a `TypeError`.
299
299
  - `depth` (optional): **How many nesting levels to transform** (default: `Infinity` — the whole structure; `null` means the same). `1` transforms only the top-level keys, `2` the keys one level down as well, and so on. The values of objects, Maps and Sets are one level deeper; array items stay on their array's level. A value that is not a number (`NaN`, `'3'`, `3n`) throws a `TypeError`.
300
300
  - `exclude` (optional): **Keys to leave unchanged**, as paths of keys joined with dots, such as `['users_by_id.*', 'metadata.*']` (default: none; `null` means the same). See [Leaving keys unchanged](#leaving-keys-unchanged). Anything but an array of such paths throws a `TypeError`.
301
- - `sourceCase` (**deprecated**): has no effect. Every key's case is detected from the key itself, at runtime and in the result type. It is still accepted, and so is the 2.x form with explicit type arguments, `transform<Data, 'snake', 'camel'>(data, { sourceCase: 'snake', targetCase: 'camel' })`, except together with `depth` or `exclude` (leave the type arguments out to use them); the key types follow the runtime, not `sourceCase` (see [3.0.0 in the changelog](https://github.com/gyrgy/deep-case-crafter/blob/main/CHANGELOG.md#300---2026-10-25)).
301
+ - `keepReferences` (optional): **Whether shared and circular references keep their shape** (default: `true`; `null` means the same). An object reached through several references then gives one result, and a circular reference points back into the result. Pass `false` for data that cannot contain such references, such as the output of `JSON.parse`, to skip that bookkeeping: inputs with many objects and arrays convert up to about twice as fast. Use it for tree-shaped data only: an object is then copied once for every path that leads to it, so shared objects inside shared objects multiply. Data with more than 256 nested objects, arrays, Maps and Sets on one path, as circular references always have, is converted again from the start with the bookkeeping, so it takes longer and getters can run twice. With a finite `depth`, circular references stop at the depth limit before that, and are copied once per path down to it. Anything but a boolean throws a `TypeError`.
302
+ - `sourceCase` (**deprecated**): has no effect. Every key's case is detected from the key itself, at runtime and in the result type. It is still accepted, and so is the 2.x form with explicit type arguments, `transform<Data, 'snake', 'camel'>(data, { sourceCase: 'snake', targetCase: 'camel' })`, except together with `depth`, `exclude` or `keepReferences` (leave the type arguments out to use them); the key types follow the runtime, not `sourceCase` (see [3.0.0 in the changelog](https://github.com/gyrgy/deep-case-crafter/blob/main/CHANGELOG.md#300---2026-10-25)).
302
303
 
303
304
  Circular references are resolved to the transformed object. With a finite `depth`, a
304
305
  cycle is transformed once per level down to the limit instead: the result grows with the
305
- depth, and a depth of more than about a thousand levels on cyclic data exceeds the call
306
- stack and throws a `RangeError`. Omit `depth` for cyclic data, or keep it small.
306
+ depth, and a depth of more than about a thousand levels on cyclic data can exceed the
307
+ call stack and throw a `RangeError` (see [Limits](#limits)). Omit `depth` for cyclic
308
+ data, or keep it small.
307
309
 
308
310
  ### Leaving keys unchanged
309
311
 
@@ -476,14 +478,36 @@ Worth knowing:
476
478
  `userId`), the last one wins.
477
479
  - Every property is read once, in order, and its value is transformed before the next one
478
480
  is read; getters run during the transformation. Maps are read through their iterator.
481
+ With `keepReferences: false`, data with more than 256 nested objects, arrays, Maps and
482
+ Sets on one path is read a second time.
479
483
  - With `depth`, values below the limit are returned as they are: the result shares them
480
484
  with the input instead of copying them. An object reached at several levels is
481
485
  transformed once per level.
482
486
  - With `exclude`, an object reached through several keys is transformed once for each
483
487
  set of paths that match below them: one result when the same paths continue below
484
488
  every key, one per set otherwise.
485
- - The transformation is recursive: data nested about a thousand levels deep or more can
486
- exceed the JavaScript call stack and throw an error (usually a `RangeError`).
489
+ - The transformation is recursive, so very deeply nested data hits a limit: see
490
+ [Limits](#limits).
491
+
492
+ ---
493
+
494
+ ## Limits
495
+
496
+ Measured with Node 24 on an Apple M4 Pro, with Node's default stack and memory sizes:
497
+
498
+ - **Nesting depth.** The conversion is recursive. Depending on the shape, the first call
499
+ in a process converts 1,300 to 2,400 levels of nesting (nested Maps the fewest, nested
500
+ objects the most), and once the code is warm about 2,600 (nested arrays) to 4,400;
501
+ deeper data throws a `RangeError`. API data nests far less, but untrusted input can nest
502
+ deeper (`JSON.parse` accepts millions of levels), so catch the error where such input is
503
+ converted.
504
+ - **Size.** There is no fixed limit on keys, objects or array items. The result is a full
505
+ copy, so the input and the result must both fit in memory: converting 1 million records
506
+ with 30 million keys (725 MB in memory) needed 1.5 GB more at its peak, and 1.1 GB with
507
+ `keepReferences: false`. When memory runs out, Node ends the process, which cannot be
508
+ caught.
509
+ - **Long keys.** Conversion time grows linearly with a key's length: about 20 ms for a key
510
+ of a million characters.
487
511
 
488
512
  ---
489
513