Skip to content

Commit 6c68111

Browse files
committed
Fixes ferdikoomen#1252. Adds transformModelCase flag.
1 parent c8cf2ec commit 6c68111

File tree

7 files changed

+69
-5
lines changed

7 files changed

+69
-5
lines changed

bin/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const params = program
2424
.option('--postfix <value>', 'Deprecated: Use --postfixServices instead. Service name postfix', 'Service')
2525
.option('--postfixServices <value>', 'Service name postfix', 'Service')
2626
.option('--postfixModels <value>', 'Model name postfix')
27+
.option('--transformModelCase <value>', 'Transform model case [camel, snake]', 'none')
2728
.option('--request <value>', 'Path to custom request file')
2829
.parse(process.argv)
2930
.opts();
@@ -45,6 +46,7 @@ if (OpenAPI) {
4546
indent: params.indent,
4647
postfixServices: params.postfixServices ?? params.postfix,
4748
postfixModels: params.postfixModels,
49+
transformModelCase: params.transformModelCase,
4850
request: params.request,
4951
})
5052
.then(() => {

src/Case.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { Model } from './client/interfaces/Model';
2+
3+
export enum Case {
4+
NONE = 'none',
5+
CAMEL = 'camel',
6+
SNAKE = 'snake',
7+
}
8+
// Convert a string from snake case or pascal case to camel case.
9+
const toCamelCase = (str: string): string => {
10+
return str.replace(/_([a-z])/g, match => match[1].toUpperCase());
11+
};
12+
13+
// Convert a string from camel case or pascal case to snake case.
14+
const toSnakeCase = (str: string): string => {
15+
return str.replace(/([A-Z])/g, match => `_${match.toLowerCase()}`);
16+
};
17+
18+
const transforms = {
19+
[Case.CAMEL]: toCamelCase,
20+
[Case.SNAKE]: toSnakeCase,
21+
};
22+
23+
// A recursive function that looks at the models and their properties and
24+
// converts each property name using the provided transform function.
25+
export const convertModelNames = (model: Model, type: Exclude<Case, Case.NONE>): Model => {
26+
if (!model.properties.length) {
27+
return {
28+
...model,
29+
name: transforms[type](model.name),
30+
};
31+
}
32+
return {
33+
...model,
34+
properties: model.properties.map(property => {
35+
return convertModelNames(property, type);
36+
}),
37+
};
38+
};

src/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Case } from './Case';
12
import { HttpClient } from './HttpClient';
23
import { Indent } from './Indent';
34
import { parse as parseV2 } from './openApi/v2';
@@ -26,6 +27,7 @@ export type Options = {
2627
indent?: Indent;
2728
postfixServices?: string;
2829
postfixModels?: string;
30+
transformModelCase?: Case;
2931
request?: string;
3032
write?: boolean;
3133
};
@@ -47,6 +49,7 @@ export type Options = {
4749
* @param indent Indentation options (4, 2 or tab)
4850
* @param postfixServices Service name postfix
4951
* @param postfixModels Model name postfix
52+
* @param transformModelCase Transform model case (camel, snake)
5053
* @param request Path to custom request file
5154
* @param write Write the files to disk (true or false)
5255
*/
@@ -64,6 +67,7 @@ export const generate = async ({
6467
indent = Indent.SPACE_4,
6568
postfixServices = 'Service',
6669
postfixModels = '',
70+
transformModelCase = Case.NONE,
6771
request,
6872
write = true,
6973
}: Options): Promise<void> => {
@@ -94,6 +98,7 @@ export const generate = async ({
9498
indent,
9599
postfixServices,
96100
postfixModels,
101+
transformModelCase,
97102
clientName,
98103
request
99104
);
@@ -118,6 +123,7 @@ export const generate = async ({
118123
indent,
119124
postfixServices,
120125
postfixModels,
126+
transformModelCase,
121127
clientName,
122128
request
123129
);

src/utils/writeClient.spec.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Case } from '../Case';
12
import type { Client } from '../client/interfaces/Client';
23
import { HttpClient } from '../HttpClient';
34
import { Indent } from '../Indent';
@@ -49,7 +50,8 @@ describe('writeClient', () => {
4950
true,
5051
Indent.SPACE_4,
5152
'Service',
52-
'AppClient'
53+
'AppClient',
54+
Case.NONE
5355
);
5456

5557
expect(rmdir).toBeCalled();

src/utils/writeClient.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { resolve } from 'path';
22

33
import type { Client } from '../client/interfaces/Client';
4+
import { Case } from '../Case';
45
import type { HttpClient } from '../HttpClient';
56
import type { Indent } from '../Indent';
67
import { mkdir, rmdir } from './fileSystem';
@@ -30,6 +31,7 @@ import { writeClientServices } from './writeClientServices';
3031
* @param indent Indentation options (4, 2 or tab)
3132
* @param postfixServices Service name postfix
3233
* @param postfixModels Model name postfix
34+
* @param transformModelCase Transform model case (camel, snake)
3335
* @param clientName Custom client class name
3436
* @param request Path to custom request file
3537
*/
@@ -47,6 +49,7 @@ export const writeClient = async (
4749
indent: Indent,
4850
postfixServices: string,
4951
postfixModels: string,
52+
transformModelCase: Case,
5053
clientName?: string,
5154
request?: string
5255
): Promise<void> => {
@@ -91,7 +94,15 @@ export const writeClient = async (
9194
if (exportModels) {
9295
await rmdir(outputPathModels);
9396
await mkdir(outputPathModels);
94-
await writeClientModels(client.models, templates, outputPathModels, httpClient, useUnionTypes, indent);
97+
await writeClientModels(
98+
client.models,
99+
templates,
100+
outputPathModels,
101+
httpClient,
102+
useUnionTypes,
103+
indent,
104+
transformModelCase
105+
);
95106
}
96107

97108
if (isDefined(clientName)) {

src/utils/writeClientModels.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { EOL } from 'os';
2+
import { Case } from '../Case';
23

34
import type { Model } from '../client/interfaces/Model';
45
import { HttpClient } from '../HttpClient';
@@ -51,7 +52,7 @@ describe('writeClientModels', () => {
5152
},
5253
};
5354

54-
await writeClientModels(models, templates, '/', HttpClient.FETCH, false, Indent.SPACE_4);
55+
await writeClientModels(models, templates, '/', HttpClient.FETCH, false, Indent.SPACE_4, Case.NONE);
5556

5657
expect(writeFile).toBeCalledWith('/User.ts', `model${EOL}`);
5758
});

src/utils/writeClientModels.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { resolve } from 'path';
22

33
import type { Model } from '../client/interfaces/Model';
4+
import { Case, convertModelNames } from '../Case';
45
import type { HttpClient } from '../HttpClient';
56
import type { Indent } from '../Indent';
67
import { writeFile } from './fileSystem';
@@ -16,19 +17,22 @@ import type { Templates } from './registerHandlebarTemplates';
1617
* @param httpClient The selected httpClient (fetch, xhr, node or axios)
1718
* @param useUnionTypes Use union types instead of enums
1819
* @param indent Indentation options (4, 2 or tab)
20+
* @param transformModelCase Transform model case (camel, snake)
1921
*/
2022
export const writeClientModels = async (
2123
models: Model[],
2224
templates: Templates,
2325
outputPath: string,
2426
httpClient: HttpClient,
2527
useUnionTypes: boolean,
26-
indent: Indent
28+
indent: Indent,
29+
transformModelCase: Case
2730
): Promise<void> => {
2831
for (const model of models) {
32+
const newModel = transformModelCase === Case.NONE ? model : convertModelNames(model, transformModelCase);
2933
const file = resolve(outputPath, `${model.name}.ts`);
3034
const templateResult = templates.exports.model({
31-
...model,
35+
...newModel,
3236
httpClient,
3337
useUnionTypes,
3438
});

0 commit comments

Comments
 (0)