Skip to content

Commit

Permalink
Merge branch 'baflo-master'
Browse files Browse the repository at this point in the history
  • Loading branch information
Luis Fernando Planella Gonzalez committed Sep 9, 2024
2 parents 00b427b + da076ac commit fab9d04
Show file tree
Hide file tree
Showing 6 changed files with 205 additions and 8 deletions.
45 changes: 39 additions & 6 deletions lib/operation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,13 @@ export class Operation {
if (content && content.length > 0) {
for (const type of content) {
if (type && type.mediaType) {
map.set(this.variantMethodPart(type), type);
const part = this.variantMethodPart(type);

if (map.has(part)) {
this.logger.warn(`Overwriting variant method part '${part}' for media type '${map.get(part)?.mediaType}' by media type '${type.mediaType}'.`);
}

map.set(part, type);
}
}
}
Expand Down Expand Up @@ -234,19 +240,46 @@ export class Operation {
*/
private variantMethodPart(content: Content | null): string {
if (content) {
let type = content.mediaType.replace(/\/\*/, '');
const keep = this.keepFullResponseMediaType(content.mediaType);
let type = content.mediaType;
type = content.mediaType.replace(/\/\*/, '');
if (type === '*' || type === 'application/octet-stream') {
return '$Any';
}
type = last(type.split('/')) as string;
const plus = type.lastIndexOf('+');
if (plus >= 0) {
type = type.substring(plus + 1);

if (keep !== 'full') {
type = last(type.split('/')) as string;

if (keep !== 'tail') {
const plus = type.lastIndexOf('+');
if (plus >= 0) {
type = type.substring(plus + 1);
}
}
}

return this.options.skipJsonSuffix && type === 'json' ? '' : `$${typeName(type)}`;
} else {
return '';
}
}

/**
* Returns hint, how the expected response type in the request method names should be abbreviated.
*/
private keepFullResponseMediaType(mediaType: string) {
if (this.options.keepFullResponseMediaType === true) {
return 'full';
}

if (Array.isArray(this.options.keepFullResponseMediaType)) {
for (const check of this.options.keepFullResponseMediaType) {
if (check.mediaType === undefined || new RegExp(check.mediaType).test(mediaType)) {
return check.use ?? 'short';
}
}
}

return 'short';
}
}
12 changes: 12 additions & 0 deletions lib/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,16 @@ export interface Options {

/** List of paths to early exclude from the processing */
excludePaths?: string[];

/**
* When true, the expected response type in the request method names are not abbreviated and all response variants are kept.
* Default is false.
* When array is given, `mediaType` is expected to be a RegExp string matching the response media type. The first match in the array
* will decide whether or how to shorten the media type. If no mediaType is given, it will always match.
*
* 'short': application/x-spring-data-compact+json -> getEntities$Json
* 'tail': application/x-spring-data-compact+json -> getEntities$XSpringDataCompactJson
* 'full': application/x-spring-data-compact+json -> getEntities$ApplicationXSpringDataCompactJson
*/
keepFullResponseMediaType?: boolean | Array<{ mediaType?: string; use: 'full' | 'tail' | 'short' }>;
}
30 changes: 30 additions & 0 deletions ng-openapi-gen-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,36 @@
"description": "When true (default) models names will be camelized, besides having the first letter capitalized. Setting to false will prevent camelizing.",
"default": "true",
"type": "boolean"
},
"keepFullResponseMediaType": {
"description": "When true, the expected response type in the request method names are not abbreviated and all response variants are kept.\\nWhen array is given, `mediaType` is expected to be a RegExp string matching the response media type. The first match in the array\\nwill decide whether or how to shorten the media type. If no mediaType is given, it will always match.\\n'short': application/x-spring-data-compact+json -> getEntities$Json\\n'tail': application/x-spring-data-compact+json -> getEntities$XSpringDataCompactJson\\n'full': application/x-spring-data-compact+json -> getEntities$ApplicationXSpringDataCompactJson",
"default": "false",
"anyOf": [
{
"type": "boolean"
},
{
"type": "array",
"items": {
"type": "object",
"required": [
"use"
],
"properties": {
"mediaType": {
"type": "string"
},
"use": {
"enum": [
"full",
"tail",
"short"
]
}
}
}
}
]
}
}
}
14 changes: 13 additions & 1 deletion test/all-operations.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,17 @@
"input": "all-operations.json",
"output": "out/all-operations",
"defaultTag": "noTag",
"excludeParameters": ["X-Exclude"]
"excludeParameters": [
"X-Exclude"
],
"keepFullResponseMediaType": [
{
"mediaType": "spring",
"use": "full"
},
{
"mediaType": "hal\\+json",
"use": "tail"
}
]
}
60 changes: 60 additions & 0 deletions test/all-operations.json
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,66 @@
}
}
},
"/path8": {
"get": {
"tags": [
"tag.tag2.tag3.tag4.tag5"
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"type": "string"
}
},
"application/hal+json": {
"schema": {
"type": "string"
}
},
"application/x-spring-data-compact+json": {
"schema": {
"type": "string"
}
},
"text/uri-list": {
"schema": {
"type": "string"
}
}
},
"description": "OK"
}
}
},
"post": {
"tags": [
"tag.tag2.tag3.tag4.tag5"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "string"
}
}
},
"required": true
},
"responses": {
"201": {
"content": {
"application/hal+json": {
"schema": {
"type": "string"
}
}
}
}
}
}
},
"/duplicated1": {
"get": {
"operationId": "duplicated",
Expand Down
52 changes: 51 additions & 1 deletion test/all-operations.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ describe('Generation tests using all-operations.json', () => {
let gen: NgOpenApiGen;

beforeEach(() => {
gen = new NgOpenApiGen(allOperationsSpec as OpenAPIObject, options);
gen = new NgOpenApiGen(allOperationsSpec as OpenAPIObject, options as any);
gen.generate();
});

Expand Down Expand Up @@ -533,4 +533,54 @@ describe('Generation tests using all-operations.json', () => {
const success = operation.successResponse;
expect(success?.statusCode).toEqual('204');
});


it('GET /path8', () => {
const optionsWithCustomizedResponseType = { ...options } as Options;
gen = new NgOpenApiGen(allOperationsSpec as OpenAPIObject, optionsWithCustomizedResponseType);
gen.generate();
const operation = gen.operations.get('path8Get');
expect(operation).toBeDefined();

if (!operation) return;

// Assert each variant
const vars = operation.variants;
expect(vars.length).toBe(4);

const jsonPlain = vars[0];
expect(jsonPlain.responseType).toBe('json');
expect(jsonPlain.methodName).toBe('path8Get$Json');

const halJsonPlain = vars[1];
expect(halJsonPlain.responseType).toBe('json');
expect(halJsonPlain.methodName).toBe('path8Get$HalJson');

const compactJsonPlain = vars[2];
expect(compactJsonPlain.responseType).toBe('json');
expect(compactJsonPlain.methodName).toBe('path8Get$ApplicationXSpringDataCompactJson');

const text = vars[3];
expect(text.responseType).toBe('text');
expect(text.methodName).toBe('path8Get$UriList');
});


it('POST /path8', () => {
const optionsWithCustomizedResponseType = { ...options } as Options;
gen = new NgOpenApiGen(allOperationsSpec as OpenAPIObject, optionsWithCustomizedResponseType);
gen.generate();
const operation = gen.operations.get('path8Post');
expect(operation).toBeDefined();
expect(operation?.variants[0].responseType).toBe('json');

if (!operation) return;

// Assert each variant
const vars = operation.variants;
expect(vars.length).toBe(1);

const jsonPlain = vars[0];
expect(jsonPlain.methodName).toBe('path8Post');
});
});

0 comments on commit fab9d04

Please sign in to comment.