deep-case-crafter 2.1.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.cts +249 -180
- package/dist/index.d.mts +249 -180
- package/dist/index.d.ts +249 -180
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +9 -4
- package/readme.md +187 -40
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "deep-case-crafter",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Transforms deeply nested object, array, Map, and Set keys between common case formats while preserving TypeScript type safety",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -60,10 +60,15 @@
|
|
|
60
60
|
"prepare": "husky",
|
|
61
61
|
"test": "jest",
|
|
62
62
|
"test-coverage": "npm test -- --coverage",
|
|
63
|
+
"test:types": "tsc --noEmit",
|
|
63
64
|
"tsc": "tsc --noEmit",
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"
|
|
65
|
+
"test:dist-types": "tsc -p dist-type-tests && tsc -p dist-type-tests/tsconfig.declarations.json && tsc -p dist-type-tests/tsconfig.loose.json",
|
|
66
|
+
"lint": "eslint --ext .js,.jsx,.ts,.tsx src/ --max-warnings=0 --no-cache",
|
|
67
|
+
"lint:fix": "eslint --ext .js,.jsx,.ts,.tsx src/ --fix --max-warnings=0 --no-cache",
|
|
68
|
+
"format": "prettier --write src dist-type-tests benchmark .github readme.md",
|
|
69
|
+
"format:check": "prettier --check src dist-type-tests benchmark .github readme.md",
|
|
70
|
+
"benchmark": "tsx benchmark/*.benchmark.ts",
|
|
71
|
+
"check": "npm run lint && npm run format:check && npm run test:types && npm run test-coverage && npm run build && npm run test:dist-types"
|
|
67
72
|
},
|
|
68
73
|
"devDependencies": {
|
|
69
74
|
"@eslint/js": "10.0.1",
|
package/readme.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# DeepCaseCrafter
|
|
2
2
|
|
|
3
|
-
**DeepCaseCrafter** transforms deeply nested object keys between case formats (`camelCase`, `PascalCase`, `snake_case`, `kebab-case`). It works on objects, arrays, Maps, and Sets, with configurable recursion depth, and
|
|
3
|
+
**DeepCaseCrafter** transforms deeply nested object keys between case formats (`camelCase`, `PascalCase`, `snake_case`, `kebab-case`). It works on objects, arrays, Maps, and Sets, with configurable recursion depth, and types the result precisely: every key is typed the way it is transformed at runtime (with a few [exceptions](#result-types)).
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/deep-case-crafter)
|
|
6
6
|
[](https://bundlephobia.com/package/deep-case-crafter)
|
|
@@ -13,10 +13,11 @@
|
|
|
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
|
+
- **Acronym-aware**: `HTTPResponse` → `http_response` or `httpResponse`, `userID` → `user_id` — not `h_t_t_p_...` or `hTTPResponse`.
|
|
17
17
|
- Works with deeply nested structures, including objects, arrays, Maps, and Sets.
|
|
18
|
-
-
|
|
19
|
-
-
|
|
18
|
+
- Leaves `Date`, `RegExp`, `Error`, typed arrays, `Buffer` and other built-in values untouched.
|
|
19
|
+
- **Precise result types**: every key is typed the way it is transformed at runtime, so `result.firstName` is known at compile time without casts.
|
|
20
|
+
- Preserves special keys (`__`, `--`, leading numbers, special characters, words in capitals).
|
|
20
21
|
- Configurable recursion depth (default: fully recursive).
|
|
21
22
|
|
|
22
23
|
## Installation
|
|
@@ -25,12 +26,18 @@
|
|
|
25
26
|
npm install deep-case-crafter
|
|
26
27
|
```
|
|
27
28
|
|
|
29
|
+
The type definitions require TypeScript 4.7 or later.
|
|
30
|
+
|
|
28
31
|
> **⚠️ v2 breaking change:** `transform` is now a **named export**. Update
|
|
29
32
|
> `import transform from 'deep-case-crafter'` to
|
|
30
33
|
> `import { transform } from 'deep-case-crafter'` (CommonJS:
|
|
31
34
|
> `const { transform } = require('deep-case-crafter')`). This fixes type
|
|
32
35
|
> resolution for modern (`node16`/`nodenext`/bundler) consumers.
|
|
33
36
|
|
|
37
|
+
> **⚠️ v3 breaking changes:** result types are precise without `sourceCase`, a few keys
|
|
38
|
+
> convert differently, built-in values are returned untouched, and invalid options
|
|
39
|
+
> throw. See [Upgrading to v3](#upgrading-to-v3).
|
|
40
|
+
|
|
34
41
|
---
|
|
35
42
|
|
|
36
43
|
## Quick Start
|
|
@@ -42,12 +49,13 @@ import { transform } from 'deep-case-crafter';
|
|
|
42
49
|
|
|
43
50
|
const input = { user_id: 1, first_name: 'John' };
|
|
44
51
|
const result = transform(input);
|
|
52
|
+
// ^? { userId: number; firstName: string }
|
|
45
53
|
|
|
46
54
|
console.log(result);
|
|
47
55
|
// Output: { userId: 1, firstName: 'John' }
|
|
48
56
|
```
|
|
49
57
|
|
|
50
|
-
_(Automatically converts from `snake_case` to `camelCase
|
|
58
|
+
_(Automatically converts from `snake_case` to `camelCase`; the case of every key is detected from the key itself)_
|
|
51
59
|
|
|
52
60
|
---
|
|
53
61
|
|
|
@@ -67,16 +75,18 @@ console.log(kebabCaseResult);
|
|
|
67
75
|
|
|
68
76
|
---
|
|
69
77
|
|
|
70
|
-
### 3.
|
|
71
|
-
|
|
72
|
-
_TypeScript infers the exact output keys when **both** `sourceCase` and `targetCase` are set._
|
|
78
|
+
### 3. Name the result type with `TransformResult`
|
|
73
79
|
|
|
74
80
|
```typescript
|
|
75
|
-
|
|
76
|
-
const result = transform(input, { targetCase: 'camel', sourceCase: 'snake' });
|
|
81
|
+
import { transform, type TransformResult } from 'deep-case-crafter';
|
|
77
82
|
|
|
78
|
-
|
|
79
|
-
|
|
83
|
+
type ApiUser = { user_id: number; first_name: string; created_at: Date };
|
|
84
|
+
type User = TransformResult<ApiUser>;
|
|
85
|
+
// { userId: number; firstName: string; createdAt: Date }
|
|
86
|
+
|
|
87
|
+
function toUser(apiUser: ApiUser): User {
|
|
88
|
+
return transform(apiUser);
|
|
89
|
+
}
|
|
80
90
|
```
|
|
81
91
|
|
|
82
92
|
---
|
|
@@ -89,10 +99,7 @@ const nestedInput = {
|
|
|
89
99
|
posts: [{ post_id: 1, post_title: 'Hello' }],
|
|
90
100
|
};
|
|
91
101
|
|
|
92
|
-
const transformed = transform(nestedInput, {
|
|
93
|
-
targetCase: 'camel',
|
|
94
|
-
sourceCase: 'snake',
|
|
95
|
-
});
|
|
102
|
+
const transformed = transform(nestedInput, { targetCase: 'camel' });
|
|
96
103
|
|
|
97
104
|
console.log(transformed);
|
|
98
105
|
// Output:
|
|
@@ -107,15 +114,12 @@ console.log(transformed);
|
|
|
107
114
|
### 5. Transforming a `Map`
|
|
108
115
|
|
|
109
116
|
```typescript
|
|
110
|
-
const mapInput = new Map([
|
|
117
|
+
const mapInput = new Map<string, number | string>([
|
|
111
118
|
['user_id', 1],
|
|
112
119
|
['first_name', 'John'],
|
|
113
120
|
]);
|
|
114
121
|
|
|
115
|
-
const result = transform(mapInput, {
|
|
116
|
-
targetCase: 'camel',
|
|
117
|
-
sourceCase: 'snake',
|
|
118
|
-
});
|
|
122
|
+
const result = transform(mapInput, { targetCase: 'camel' });
|
|
119
123
|
|
|
120
124
|
console.log(result.get('userId')); // 1
|
|
121
125
|
console.log(result.get('firstName')); // 'John'
|
|
@@ -131,16 +135,13 @@ of objects nested inside the Set** are transformed.
|
|
|
131
135
|
|
|
132
136
|
```typescript
|
|
133
137
|
const setInput = new Set([{ user_id: 1 }, { first_name: 'John' }]);
|
|
134
|
-
const result = transform(setInput, {
|
|
135
|
-
targetCase: 'camel',
|
|
136
|
-
sourceCase: 'snake',
|
|
137
|
-
});
|
|
138
|
+
const result = transform(setInput, { targetCase: 'camel' });
|
|
138
139
|
|
|
139
140
|
console.log(result); // Set { { userId: 1 }, { firstName: 'John' } }
|
|
140
141
|
|
|
141
142
|
// Primitive members are left as-is:
|
|
142
143
|
const strings = new Set(['user_id', 'first_name']);
|
|
143
|
-
console.log(transform(strings, { targetCase: 'camel'
|
|
144
|
+
console.log(transform(strings, { targetCase: 'camel' }));
|
|
144
145
|
// Set { 'user_id', 'first_name' }
|
|
145
146
|
```
|
|
146
147
|
|
|
@@ -153,15 +154,40 @@ are treated as whole words instead of being split letter-by-letter:
|
|
|
153
154
|
|
|
154
155
|
```typescript
|
|
155
156
|
const input = { getHTTPResponse: 1, userID: 2, parseHTMLString: 3 };
|
|
156
|
-
const result = transform(input, {
|
|
157
|
+
const result = transform(input, { targetCase: 'snake' });
|
|
157
158
|
|
|
158
159
|
console.log(result);
|
|
159
160
|
// Output: { get_http_response: 1, user_id: 2, parse_html_string: 3 }
|
|
160
161
|
// (not { get_h_t_t_p_response, user_i_d, ... })
|
|
161
162
|
```
|
|
162
163
|
|
|
163
|
-
|
|
164
|
-
|
|
164
|
+
A plural `s` stays with its acronym: `allowedURLs` → `allowed_urls`,
|
|
165
|
+
`getURLsForIDs` → `get_urls_for_ids`. An `s` word that follows an acronym directly is
|
|
166
|
+
read the same way, so `SSLIsEnabled` becomes `sslis_enabled`.
|
|
167
|
+
|
|
168
|
+
When converting `PascalCase` **to** `camelCase`, a leading acronym is lowercased as
|
|
169
|
+
a whole. Two capitals followed by a lowercase letter are a one-letter word and the next
|
|
170
|
+
word, unless that letter is a plural `s` ending the acronym:
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
const input = { HTTPResponse: 1, UserID: 2, XAxis: 3, IDs: 4 };
|
|
174
|
+
const result = transform(input, { targetCase: 'camel' });
|
|
175
|
+
|
|
176
|
+
console.log(result);
|
|
177
|
+
// Output: { httpResponse: 1, userID: 2, xAxis: 3, ids: 4 }
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Words of two or more capitals, such as `ID`, `USD` or `GET`, are left unchanged, like
|
|
181
|
+
`SCREAMING_SNAKE` keys (see [Key Preservation Rules](#key-preservation-rules)). A single
|
|
182
|
+
capital, with or without digits (`S`, `S3`), is converted as a one-letter word.
|
|
183
|
+
|
|
184
|
+
Converting back to `PascalCase` cannot restore a lowercased acronym: `httpResponse`
|
|
185
|
+
becomes `HttpResponse`, and `ids` becomes `Ids`. In the other direction, a camelCase key
|
|
186
|
+
that starts with a one-letter word before an acronym does not come back either:
|
|
187
|
+
`iOSVersion` → `IOSVersion` → `iosVersion`.
|
|
188
|
+
|
|
189
|
+
The result **types** match all of this, so `result.get_http_response` and
|
|
190
|
+
`result.httpResponse` are known at compile time.
|
|
165
191
|
|
|
166
192
|
---
|
|
167
193
|
|
|
@@ -171,11 +197,45 @@ set, so `result.get_http_response` is known at compile time.
|
|
|
171
197
|
|
|
172
198
|
- **data**: The data structure to transform (`object`, `array`, `Map`, or `Set`).
|
|
173
199
|
- **options**:
|
|
174
|
-
- `targetCase` (optional): `'camel' | 'snake' | 'pascal' | 'kebab'` (default: `'camel'`)
|
|
175
|
-
- `
|
|
176
|
-
- `
|
|
177
|
-
|
|
178
|
-
|
|
200
|
+
- `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`.
|
|
201
|
+
- `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`.
|
|
202
|
+
- `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` (leave the type arguments out to use `depth`); the key types follow the runtime, not `sourceCase` (see [Upgrading to v3](#upgrading-to-v3)).
|
|
203
|
+
|
|
204
|
+
Circular references are resolved to the transformed object. With a finite `depth`, a
|
|
205
|
+
cycle is transformed once per level down to the limit instead: the result grows with the
|
|
206
|
+
depth, and a depth of more than about a thousand levels on cyclic data exceeds the call
|
|
207
|
+
stack and throws a `RangeError`. Omit `depth` for cyclic data, or keep it small.
|
|
208
|
+
|
|
209
|
+
### Result types
|
|
210
|
+
|
|
211
|
+
The result type follows the runtime: every key is typed the way it is transformed
|
|
212
|
+
(including the [preservation rules](#key-preservation-rules)), untouched values such as
|
|
213
|
+
`Date` keep their type, and `readonly` arrays, tuples, Maps and Sets keep their shape. Use
|
|
214
|
+
`TransformResult<Data, TargetCase, Depth>` to name it.
|
|
215
|
+
|
|
216
|
+
- A literal `depth` is applied to the type precisely. A depth only known as a `number` (a
|
|
217
|
+
variable, or `Infinity`) gives `unknown`, so omit `depth` to transform everything.
|
|
218
|
+
- `targetCase` and `depth` may be string enum members, branded literals, unions, or come
|
|
219
|
+
from a stored options object: every options value they may hold gives its own result.
|
|
220
|
+
Options that are not known at all give `unknown`: an options object that may be
|
|
221
|
+
`undefined`, one typed as `TransformOptions` or `any`, one carrying other properties
|
|
222
|
+
(without `sourceCase`), and options passed with only the input type given
|
|
223
|
+
(`transform<Data>(data, options)`). Leave the type arguments out to get the precise
|
|
224
|
+
type.
|
|
225
|
+
- When a library exports a value or function built on `transform`, annotate it with
|
|
226
|
+
`TransformResult<...>`. Otherwise the result type is written out into its declaration
|
|
227
|
+
files: recursive types (trees, JSON values) are cut off as `any`, and very large types
|
|
228
|
+
or symbol-keyed members fail to compile (TS7056, TS4118). Generic functions around
|
|
229
|
+
`transform` are not affected.
|
|
230
|
+
- Some values cannot be told apart by their types. `Error`, `URL`, boxed primitives,
|
|
231
|
+
iterators, module namespace objects and other built-ins whose types do not declare a
|
|
232
|
+
`Symbol.toStringTag` are returned untouched, but typed as plain objects with
|
|
233
|
+
transformed keys. Class instances lose their prototype methods, getters and setters at
|
|
234
|
+
runtime, while their type still lists them. A class that implements `Map`, `Set`,
|
|
235
|
+
`ReadonlyMap` or `ReadonlySet` without extending `Map` or `Set` (and a Proxy around a
|
|
236
|
+
Map or Set) is typed as a transformed `Map` or `Set`, but at runtime it is returned
|
|
237
|
+
untouched when it has a `Symbol.toStringTag` (as every class implementing `Map` or
|
|
238
|
+
`Set` does), and rebuilt as a plain object otherwise.
|
|
179
239
|
|
|
180
240
|
---
|
|
181
241
|
|
|
@@ -190,13 +250,12 @@ const typedResult: Output = result; // TypeScript will enforce Output type here
|
|
|
190
250
|
|
|
191
251
|
**Note:**
|
|
192
252
|
|
|
193
|
-
- When using this overload, you cannot pass `sourceCase` in the options
|
|
194
|
-
> Object literal may only specify known properties, and 'sourceCase' does not exist in type 'Omit<TransformOptions, "sourceCase"> & { depth?: number }'.
|
|
253
|
+
- When using this overload, you cannot pass `sourceCase` in the options; TypeScript reports an error if you do.
|
|
195
254
|
- This overload is useful when you want to take full control of the output type, but type safety between input, options, and output is not enforced by the library.
|
|
196
|
-
- If you want
|
|
255
|
+
- If you want the result type inferred, use the standard overload:
|
|
197
256
|
|
|
198
257
|
```typescript
|
|
199
|
-
const result = transform(obj, { targetCase: 'camel'
|
|
258
|
+
const result = transform(obj, { targetCase: 'camel' }); // Output type is inferred
|
|
200
259
|
```
|
|
201
260
|
|
|
202
261
|
---
|
|
@@ -208,12 +267,98 @@ A key is left **completely unchanged** when it:
|
|
|
208
267
|
- **starts with anything other than a letter** (a digit or special character), e.g. `1st_place`, `_private`;
|
|
209
268
|
- **ends with a non-alphanumeric character**, e.g. `value_`, `count-`;
|
|
210
269
|
- **contains characters outside** `A-Z a-z 0-9 _ -`, e.g. `user.name`, `a@b`;
|
|
211
|
-
- **contains consecutive `__` or `--`**, e.g. `a__b`, `x--y` (ambiguous to detect)
|
|
270
|
+
- **contains consecutive `__` or `--`**, e.g. `a__b`, `x--y` (ambiguous to detect);
|
|
271
|
+
- **is not written in one recognisable case**, e.g. `mixed_Case`, `USER_ID`, `a_b-c`, or
|
|
272
|
+
is a word of two or more capitals, e.g. `ID`, `USD`, `B2B`.
|
|
212
273
|
|
|
213
274
|
Trailing digits are kept but treated as part of the word, so they do **not** by
|
|
214
275
|
themselves preserve a key — `address_1` becomes `address1`, and the single word
|
|
215
276
|
`item2` stays `item2`.
|
|
216
277
|
|
|
278
|
+
These rules apply to the result types as well.
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## What Gets Transformed
|
|
283
|
+
|
|
284
|
+
| Value | Result |
|
|
285
|
+
| --------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
|
|
286
|
+
| Plain objects, `Object.create(null)` objects | A new plain object with transformed keys |
|
|
287
|
+
| Class instances | A new plain object with their own enumerable properties (prototype methods are not copied) |
|
|
288
|
+
| Arrays | A new array with every item transformed |
|
|
289
|
+
| `Map`, including one from another realm | A new `Map` with string keys transformed and every value transformed |
|
|
290
|
+
| `Set`, including one from another realm | A new `Set` with every member transformed (primitive members are kept as-is) |
|
|
291
|
+
| Primitives, functions and built-ins such as `Date`, `RegExp`, `Error`, `URL`, `Promise`, typed arrays, `Buffer` | Returned untouched (the same reference) |
|
|
292
|
+
| Objects with a `Symbol.toStringTag` of their own or from their class, `arguments` objects, module namespaces, and Proxies around a Map or Set | Returned untouched (the same reference) |
|
|
293
|
+
|
|
294
|
+
Symbol-keyed properties are copied unchanged.
|
|
295
|
+
|
|
296
|
+
Worth knowing:
|
|
297
|
+
|
|
298
|
+
- If two keys of one object become the same key (`user_id` and `userId` both become
|
|
299
|
+
`userId`), the last one wins.
|
|
300
|
+
- Every property is read once, in order, and its value is transformed before the next one
|
|
301
|
+
is read; getters run during the transformation. Maps are read through their iterator.
|
|
302
|
+
- With `depth`, values below the limit are returned as they are: the result shares them
|
|
303
|
+
with the input instead of copying them. An object reached at several levels is
|
|
304
|
+
transformed once per level.
|
|
305
|
+
- The transformation is recursive: data nested about a thousand levels deep or more can
|
|
306
|
+
exceed the JavaScript call stack and throw an error (usually a `RangeError`).
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## Upgrading to v3
|
|
311
|
+
|
|
312
|
+
Runtime behaviour:
|
|
313
|
+
|
|
314
|
+
- A few keys convert differently:
|
|
315
|
+
- a leading acronym is lowercased as a whole in camelCase: `HTTPResponse` →
|
|
316
|
+
`httpResponse` (was `hTTPResponse`), `IOStream` → `ioStream`, `URLs` → `urls`;
|
|
317
|
+
- a plural `s` stays with its acronym: `allowedURLs` → snake_case `allowed_urls` (was
|
|
318
|
+
`allowed_ur_ls`), `IDs` → camelCase `ids` (was `iDs`). An `s` word right after an
|
|
319
|
+
acronym is read as a plural too: `SSLIsEnabled` → `sslis_enabled` (was
|
|
320
|
+
`ssl_is_enabled`);
|
|
321
|
+
- a key named `Infinity` is converted like any other word (`infinity`).
|
|
322
|
+
- `Date`, `RegExp`, `Error`, `URL`, typed arrays, `Buffer` and other built-ins, objects
|
|
323
|
+
with a `Symbol.toStringTag` (their own or their class's), `arguments` objects and module
|
|
324
|
+
namespaces are returned untouched. 2.x rebuilt them as plain objects, which turned a
|
|
325
|
+
`Date` into `{}`.
|
|
326
|
+
- Maps and Sets from another realm (an iframe, `node:vm`) are transformed, and a Proxy
|
|
327
|
+
around a Map or Set is returned untouched (2.x threw).
|
|
328
|
+
- Enumerable properties added to `Object.prototype` are no longer copied into results.
|
|
329
|
+
- Properties are read and transformed one at a time, so getters run in a different order,
|
|
330
|
+
and Maps are read through their iterator rather than `entries()`.
|
|
331
|
+
- With a finite `depth`, an object reached at several levels is transformed once per
|
|
332
|
+
level, and a circular reference is transformed down to the limit (see the API section
|
|
333
|
+
for large depths). 2.x shared one result, which depended on key order and ignored the
|
|
334
|
+
limit.
|
|
335
|
+
- An unsupported `targetCase`, or a `depth` that is not a number, throws a `TypeError`.
|
|
336
|
+
- Very deeply nested data reaches the call stack limit at different depths: nested
|
|
337
|
+
objects can go deeper than in 2.x, chains of Maps or Sets nested more than about 1,400
|
|
338
|
+
levels deep no longer fit.
|
|
339
|
+
|
|
340
|
+
Types:
|
|
341
|
+
|
|
342
|
+
- The result type is precise without `sourceCase`, which is deprecated and has no effect.
|
|
343
|
+
`TransformResult` is exported to name it.
|
|
344
|
+
- Assigning or casting (`as Foo`) the result of `transform(x)` to a declared type now
|
|
345
|
+
checks it against the real result type; a cast to an unrelated type fails with TS2352.
|
|
346
|
+
If `x` is typed `unknown` or loosely, state the output type:
|
|
347
|
+
`transform<Input, Output>(x)`.
|
|
348
|
+
- `depth: Infinity` (or any `depth` not known as a literal) gives `unknown`: omit `depth`
|
|
349
|
+
instead.
|
|
350
|
+
- An input typed `any` gives `any` (2.x gave `unknown`).
|
|
351
|
+
- Key types follow the runtime, also when `sourceCase` is passed, so code that relied on
|
|
352
|
+
2.x's key types for keys the runtime converts differently (`result.hTTPResponse`) no
|
|
353
|
+
longer compiles.
|
|
354
|
+
- `TransformOptions` includes `depth`, so `Required<TransformOptions>` requires it.
|
|
355
|
+
- The 2.x form with three type arguments, `transform<Data, 'snake', 'camel'>(...)`, no
|
|
356
|
+
longer accepts `depth`: leave the type arguments out instead. As an instantiation
|
|
357
|
+
expression (`ReturnType<typeof transform<Data, 'snake', 'camel'>>`) it no longer
|
|
358
|
+
compiles: use `TransformResult<Data, 'camel'>`.
|
|
359
|
+
- `Parameters<typeof transform>[1]` (the options of the last overload) no longer includes
|
|
360
|
+
the deprecated `sourceCase`.
|
|
361
|
+
|
|
217
362
|
---
|
|
218
363
|
|
|
219
364
|
## Contributing
|
|
@@ -221,7 +366,9 @@ themselves preserve a key — `address_1` becomes `address1`, and the single wor
|
|
|
221
366
|
1. Fork the repository.
|
|
222
367
|
2. Create a new branch (`feature/my-feature`).
|
|
223
368
|
3. Commit your changes.
|
|
224
|
-
4.
|
|
369
|
+
4. Run `npm run check` (lint, formatting, types, tests with coverage, build and the
|
|
370
|
+
published types).
|
|
371
|
+
5. Submit a pull request.
|
|
225
372
|
|
|
226
373
|
---
|
|
227
374
|
|