UNPKG

4.25 kBTypeScriptView Raw
1import {CamelCase, PascalCase} from 'type-fest';
2
3// eslint-disable-next-line @typescript-eslint/ban-types
4type EmptyTuple = [];
5
6/**
7Return a default type if input type is nil.
8
9@template T - Input type.
10@template U - Default type.
11*/
12type WithDefault<T, U extends T> = T extends undefined | void | null ? U : T;
13
14/**
15Check if an element is included in a tuple.
16
17TODO: Remove this once https://github.com/sindresorhus/type-fest/pull/217 is merged.
18*/
19type IsInclude<List extends readonly unknown[], Target> = List extends undefined
20 ? false
21 : List extends Readonly<EmptyTuple>
22 ? false
23 : List extends readonly [infer First, ...infer Rest]
24 ? First extends Target
25 ? true
26 : IsInclude<Rest, Target>
27 : boolean;
28
29/**
30Append a segment to dot-notation path.
31*/
32type AppendPath<S extends string, Last extends string> = S extends ''
33 ? Last
34 : `${S}.${Last}`;
35
36/**
37Convert keys of an object to camelcase strings.
38*/
39type CamelCaseKeys<
40 T extends Record<string, any> | readonly any[],
41 Deep extends boolean,
42 IsPascalCase extends boolean,
43 Exclude extends readonly unknown[],
44 StopPaths extends readonly string[],
45 Path extends string = ''
46> = T extends readonly any[]
47 // Handle arrays or tuples.
48 ? {
49 [P in keyof T]: CamelCaseKeys<
50 T[P],
51 Deep,
52 IsPascalCase,
53 Exclude,
54 StopPaths
55 >;
56 }
57 : T extends Record<string, any>
58 // Handle objects.
59 ? {
60 [P in keyof T & string as [IsInclude<Exclude, P>] extends [true]
61 ? P
62 : [IsPascalCase] extends [true]
63 ? PascalCase<P>
64 : CamelCase<P>]: [IsInclude<StopPaths, AppendPath<Path, P>>] extends [
65 true
66 ]
67 ? T[P]
68 : [Deep] extends [true]
69 ? CamelCaseKeys<
70 T[P],
71 Deep,
72 IsPascalCase,
73 Exclude,
74 StopPaths,
75 AppendPath<Path, P>
76 >
77 : T[P];
78 }
79 // Return anything else as-is.
80 : T;
81
82declare namespace camelcaseKeys {
83 interface Options {
84 /**
85 Recurse nested objects and objects in arrays.
86
87 @default false
88 */
89 readonly deep?: boolean;
90
91 /**
92 Exclude keys from being camel-cased.
93
94 If this option can be statically determined, it's recommended to add `as const` to it.
95
96 @default []
97 */
98 readonly exclude?: ReadonlyArray<string | RegExp>;
99
100 /**
101 Exclude children at the given object paths in dot-notation from being camel-cased. For example, with an object like `{a: {b: '🦄'}}`, the object path to reach the unicorn is `'a.b'`.
102
103 If this option can be statically determined, it's recommended to add `as const` to it.
104
105 @default []
106
107 @example
108 ```
109 camelcaseKeys({
110 a_b: 1,
111 a_c: {
112 c_d: 1,
113 c_e: {
114 e_f: 1
115 }
116 }
117 }, {
118 deep: true,
119 stopPaths: [
120 'a_c.c_e'
121 ]
122 }),
123 // {
124 // aB: 1,
125 // aC: {
126 // cD: 1,
127 // cE: {
128 // e_f: 1
129 // }
130 // }
131 // }
132 ```
133 */
134 readonly stopPaths?: readonly string[];
135
136 /**
137 Uppercase the first character as in `bye-bye` → `ByeBye`.
138
139 @default false
140 */
141 readonly pascalCase?: boolean;
142 }
143}
144
145/**
146Convert object keys to camel case using [`camelcase`](https://github.com/sindresorhus/camelcase).
147
148@param input - Object or array of objects to camel-case.
149
150@example
151```
152import camelcaseKeys = require('camelcase-keys');
153
154// Convert an object
155camelcaseKeys({'foo-bar': true});
156//=> {fooBar: true}
157
158// Convert an array of objects
159camelcaseKeys([{'foo-bar': true}, {'bar-foo': false}]);
160//=> [{fooBar: true}, {barFoo: false}]
161
162camelcaseKeys({'foo-bar': true, nested: {unicorn_rainbow: true}}, {deep: true});
163//=> {fooBar: true, nested: {unicornRainbow: true}}
164
165// Convert object keys to pascal case
166camelcaseKeys({'foo-bar': true, nested: {unicorn_rainbow: true}}, {deep: true, pascalCase: true});
167//=> {FooBar: true, Nested: {UnicornRainbow: true}}
168
169import minimist = require('minimist');
170
171const argv = minimist(process.argv.slice(2));
172//=> {_: [], 'foo-bar': true}
173
174camelcaseKeys(argv);
175//=> {_: [], fooBar: true}
176```
177*/
178declare function camelcaseKeys<
179 T extends Record<string, any> | readonly any[],
180 Options extends camelcaseKeys.Options = camelcaseKeys.Options
181>(
182 input: T,
183 options?: Options
184): CamelCaseKeys<
185T,
186WithDefault<Options['deep'], false>,
187WithDefault<Options['pascalCase'], false>,
188WithDefault<Options['exclude'], EmptyTuple>,
189WithDefault<Options['stopPaths'], EmptyTuple>
190>;
191
192export = camelcaseKeys;