Skip to content

Commit 3d80990

Browse files
committed
improve code generation
1 parent 5042063 commit 3d80990

File tree

4 files changed

+163
-16
lines changed

4 files changed

+163
-16
lines changed

example/example-openapi.yaml

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
openapi: 3.0.3
1+
openapi: 3.1.1
22
info:
33
title: Artemis API
44
description: Sample API specification for the Artemis learning platform
5-
version: 8.6.4
5+
version: 8.7.1
66

77
servers:
88
- url: /api
@@ -16,6 +16,10 @@ tags:
1616
description: User management
1717
- name: participation
1818
description: Student participation
19+
- name: report
20+
description: Reporting endpoints
21+
- name: admin
22+
description: Administrative operations
1923

2024
paths:
2125
/courses:
@@ -425,6 +429,84 @@ paths:
425429
schema:
426430
$ref: '#/components/schemas/User'
427431

432+
/reports/summary:
433+
get:
434+
tags:
435+
- report
436+
operationId: getReportSummary
437+
summary: Get a summary report
438+
responses:
439+
'200':
440+
description: Report summary
441+
content:
442+
application/json:
443+
schema:
444+
type: array
445+
items:
446+
$ref: '#/components/schemas/Course'
447+
448+
/admin/users:
449+
post:
450+
tags:
451+
- admin
452+
operationId: createAdminUser
453+
summary: Create a user through admin APIs
454+
requestBody:
455+
required: true
456+
content:
457+
application/json:
458+
schema:
459+
$ref: '#/components/schemas/UserUpdate'
460+
responses:
461+
'201':
462+
description: User created
463+
content:
464+
application/json:
465+
schema:
466+
$ref: '#/components/schemas/User'
467+
468+
/admin/users/{userId}:
469+
put:
470+
tags:
471+
- admin
472+
operationId: updateAdminUser
473+
summary: Update a user through admin APIs
474+
parameters:
475+
- name: userId
476+
in: path
477+
required: true
478+
schema:
479+
type: integer
480+
format: int64
481+
requestBody:
482+
required: true
483+
content:
484+
application/json:
485+
schema:
486+
$ref: '#/components/schemas/UserUpdate'
487+
responses:
488+
'200':
489+
description: User updated
490+
content:
491+
application/json:
492+
schema:
493+
$ref: '#/components/schemas/User'
494+
delete:
495+
tags:
496+
- admin
497+
operationId: deleteAdminUser
498+
summary: Delete a user through admin APIs
499+
parameters:
500+
- name: userId
501+
in: path
502+
required: true
503+
schema:
504+
type: integer
505+
format: int64
506+
responses:
507+
'204':
508+
description: User deleted
509+
428510
components:
429511
schemas:
430512
Course:

src/main/java/de/tum/cit/aet/openapi/Angular21Generator.java

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
*/
55
package de.tum.cit.aet.openapi;
66

7+
import io.swagger.v3.oas.models.OpenAPI;
8+
import io.swagger.v3.oas.models.Operation;
79
import org.openapitools.codegen.*;
810
import org.openapitools.codegen.languages.TypeScriptAngularClientCodegen;
911
import org.openapitools.codegen.model.ModelMap;
@@ -107,8 +109,6 @@ public void processOpts() {
107109

108110
// Replace base generator supporting files with our template set only.
109111
supportingFiles.clear();
110-
supportingFiles.add(new SupportingFile("index.mustache", "", "index.ts"));
111-
supportingFiles.add(new SupportingFile("models-index.mustache", "models", "index.ts"));
112112

113113
// Process custom options
114114
if (additionalProperties.containsKey(USE_HTTP_RESOURCE)) {
@@ -143,6 +143,43 @@ public void processOpts() {
143143
useHttpResource, useInjectFunction, separateResources, readonlyModels);
144144
}
145145

146+
@Override
147+
public void processOpenAPI(OpenAPI openAPI) {
148+
super.processOpenAPI(openAPI);
149+
150+
if (openapiGeneratorIgnoreList == null) {
151+
openapiGeneratorIgnoreList = new HashSet<>();
152+
}
153+
154+
Map<String, TagUsage> usageByTag = new HashMap<>();
155+
if (openAPI != null && openAPI.getPaths() != null) {
156+
openAPI.getPaths().forEach((path, pathItem) -> {
157+
if (pathItem == null) {
158+
return;
159+
}
160+
addOperationUsage(pathItem.getGet(), true, usageByTag);
161+
addOperationUsage(pathItem.getPost(), false, usageByTag);
162+
addOperationUsage(pathItem.getPut(), false, usageByTag);
163+
addOperationUsage(pathItem.getDelete(), false, usageByTag);
164+
addOperationUsage(pathItem.getPatch(), false, usageByTag);
165+
addOperationUsage(pathItem.getHead(), false, usageByTag);
166+
addOperationUsage(pathItem.getOptions(), false, usageByTag);
167+
addOperationUsage(pathItem.getTrace(), false, usageByTag);
168+
});
169+
}
170+
171+
for (Map.Entry<String, TagUsage> entry : usageByTag.entrySet()) {
172+
String apiFilename = toApiFilename(entry.getKey());
173+
TagUsage usage = entry.getValue();
174+
if (!usage.hasMutation) {
175+
openapiGeneratorIgnoreList.add("api/" + apiFilename + "-api.ts");
176+
}
177+
if (useHttpResource && separateResources && !usage.hasGet) {
178+
openapiGeneratorIgnoreList.add("api/" + apiFilename + "-resources.ts");
179+
}
180+
}
181+
}
182+
146183
@Override
147184
public String toModelFilename(String name) {
148185
// Use kebab-case for filenames without .model suffix (new Angular style guide)
@@ -160,6 +197,42 @@ public String toApiName(String name) {
160197
return StringUtils.camelize(name) + "Api";
161198
}
162199

200+
@Override
201+
public String toOperationId(String operationId) {
202+
String name = super.toOperationId(operationId);
203+
String normalized = name.replaceFirst("^_+", "");
204+
normalized = normalized.replaceFirst("\\d+$", "");
205+
if (normalized.isBlank()) {
206+
normalized = "operation";
207+
}
208+
return normalized;
209+
}
210+
211+
private void addOperationUsage(Operation operation, boolean isGet, Map<String, TagUsage> usageByTag) {
212+
if (operation == null) {
213+
return;
214+
}
215+
216+
List<String> tags = operation.getTags();
217+
if (tags == null || tags.isEmpty()) {
218+
tags = Collections.singletonList("default");
219+
}
220+
for (String tag : tags) {
221+
String sanitizedTag = sanitizeTag(tag);
222+
TagUsage usage = usageByTag.computeIfAbsent(sanitizedTag, key -> new TagUsage());
223+
if (isGet) {
224+
usage.hasGet = true;
225+
} else {
226+
usage.hasMutation = true;
227+
}
228+
}
229+
}
230+
231+
private static final class TagUsage {
232+
private boolean hasGet;
233+
private boolean hasMutation;
234+
}
235+
163236
@Override
164237
public Map<String, ModelsMap> postProcessAllModels(Map<String, ModelsMap> objs) {
165238
Map<String, ModelsMap> result = super.postProcessAllModels(objs);

src/main/resources/angular21/index.mustache

Lines changed: 0 additions & 11 deletions
This file was deleted.

src/main/resources/angular21/model.mustache

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
{{>licenseInfo}}
2-
32
{{#models}}
43
{{#model}}
4+
{{#tsImports}}
5+
import type { {{classname}} } from '{{filename}}';
6+
{{/tsImports}}
7+
58
{{#description}}
69
/**
710
* {{{.}}}

0 commit comments

Comments
 (0)