UNPKG

4.29 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 ? T[P] extends Record<string, any>
70 ? CamelCaseKeys<
71 T[P],
72 Deep,
73 IsPascalCase,
74 Exclude,
75 StopPaths,
76 AppendPath<Path, P>
77 >
78 : T[P]
79 : T[P];
80 }
81 // Return anything else as-is.
82 : T;
83
84declare namespace camelcaseKeys {
85 interface Options {
86 /**
87 Recurse nested objects and objects in arrays.
88
89 @default false
90 */
91 readonly deep?: boolean;
92
93 /**
94 Exclude keys from being camel-cased.
95
96 If this option can be statically determined, it's recommended to add `as const` to it.
97
98 @default []
99 */
100 readonly exclude?: ReadonlyArray<string | RegExp>;
101
102 /**
103 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'`.
104
105 If this option can be statically determined, it's recommended to add `as const` to it.
106
107 @default []
108
109 @example
110 ```
111 camelcaseKeys({
112 a_b: 1,
113 a_c: {
114 c_d: 1,
115 c_e: {
116 e_f: 1
117 }
118 }
119 }, {
120 deep: true,
121 stopPaths: [
122 'a_c.c_e'
123 ]
124 }),
125 // {
126 // aB: 1,
127 // aC: {
128 // cD: 1,
129 // cE: {
130 // e_f: 1
131 // }
132 // }
133 // }
134 ```
135 */
136 readonly stopPaths?: readonly string[];
137
138 /**
139 Uppercase the first character as in `bye-bye` → `ByeBye`.
140
141 @default false
142 */
143 readonly pascalCase?: boolean;
144 }
145}
146
147/**
148Convert object keys to camel case using [`camelcase`](https://github.com/sindresorhus/camelcase).
149
150@param input - Object or array of objects to camel-case.
151
152@example
153```
154import camelcaseKeys = require('camelcase-keys');
155
156// Convert an object
157camelcaseKeys({'foo-bar': true});
158//=> {fooBar: true}
159
160// Convert an array of objects
161camelcaseKeys([{'foo-bar': true}, {'bar-foo': false}]);
162//=> [{fooBar: true}, {barFoo: false}]
163
164camelcaseKeys({'foo-bar': true, nested: {unicorn_rainbow: true}}, {deep: true});
165//=> {fooBar: true, nested: {unicornRainbow: true}}
166
167// Convert object keys to pascal case
168camelcaseKeys({'foo-bar': true, nested: {unicorn_rainbow: true}}, {deep: true, pascalCase: true});
169//=> {FooBar: true, Nested: {UnicornRainbow: true}}
170
171import minimist = require('minimist');
172
173const argv = minimist(process.argv.slice(2));
174//=> {_: [], 'foo-bar': true}
175
176camelcaseKeys(argv);
177//=> {_: [], fooBar: true}
178```
179*/
180declare function camelcaseKeys<
181 T extends Record<string, any> | readonly any[],
182 Options extends camelcaseKeys.Options
183>(
184 input: T,
185 options?: Options
186): CamelCaseKeys<
187T,
188WithDefault<Options['deep'], false>,
189WithDefault<Options['pascalCase'], false>,
190WithDefault<Options['exclude'], EmptyTuple>,
191WithDefault<Options['stopPaths'], EmptyTuple>
192>;
193
194export = camelcaseKeys;