Skip to content

Commit e316a14

Browse files
committed
fix: clean, refactor
1 parent fee6a07 commit e316a14

7 files changed

Lines changed: 73 additions & 35 deletions

File tree

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"build": "node ./scripts/generate-ajv-validator.js && tsc -b tsconfig.json && pnpm --filter @nahkies/openapi-code-generator-documentation build",
2626
"build:watch": "tsc -b tsconfig.json -w",
2727
"test": "NODE_OPTIONS=--experimental-vm-modules jest",
28+
"integration:clean": "pnpm --filter @integration/* clean",
2829
"integration:generate": "node ./scripts/generate.mjs",
2930
"integration:validate": "pnpm -r validate",
3031
"e2e:generate": "pnpm --filter e2e clean && pnpm --filter e2e generate",

packages/openapi-code-generator/src/typescript/client/client-operation-builder.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ export class ClientOperationBuilder {
132132
const requestBody = this.requestBodyAsParameter()
133133

134134
const result = [
135+
// todo: generate prioritized accept header on supported content-type union
135136
hasAcceptHeader ? undefined : "'Accept': 'application/json'",
136137
!hasContentTypeHeader &&
137138
requestBody?.contentType &&
@@ -160,6 +161,7 @@ export class ClientOperationBuilder {
160161
const schemaBuilder = this.schemaBuilder
161162
const models = this.models
162163

164+
// todo: replace with responsesToArray / filter by supported content-types
163165
return Object.entries(this.operation.responses ?? {}).reduce(
164166
(acc, [status, response]) => {
165167
const content = Object.values(response.content ?? {}).pop()
@@ -229,6 +231,7 @@ export class ClientOperationBuilder {
229231
}
230232

231233
return Object.entries(responses).map(([status, response]) => {
234+
// todo: filter and union by supported content-type
232235
const responseContent = Object.values(response?.content || {}).pop()
233236

234237
if (!responseContent) {

packages/openapi-code-generator/src/typescript/common/schema-builders/abstract-schema-builder.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -325,8 +325,7 @@ export abstract class AbstractSchemaBuilder<
325325
}
326326

327327
case "never": {
328-
// todo: use z.never() ?
329-
result = `z.never()`
328+
result = this.never()
330329
break
331330
}
332331

@@ -423,6 +422,8 @@ export abstract class AbstractSchemaBuilder<
423422

424423
public abstract void(): string
425424

425+
public abstract never(): string
426+
426427
toCompilationUnit(): CompilationUnit {
427428
return new CompilationUnit(
428429
this.filename,

packages/openapi-code-generator/src/typescript/common/schema-builders/joi-schema-builder.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,11 @@ export class JoiBuilder extends AbstractSchemaBuilder<
285285
return [joi, "any()"].filter(isDefined).join(".")
286286
}
287287

288+
public never(): string {
289+
// todo: not sure if there's a better option here.
290+
return this.any()
291+
}
292+
288293
protected override unknown(): string {
289294
return this.any()
290295
}

packages/openapi-code-generator/src/typescript/common/schema-builders/zod-schema-builder.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,10 @@ export class ZodBuilder extends AbstractSchemaBuilder<
313313
return [zod, "any()"].filter(isDefined).join(".")
314314
}
315315

316+
public never(): string {
317+
return [zod, "never()"].filter(isDefined).join(".")
318+
}
319+
316320
protected override unknown(): string {
317321
return [zod, "unknown()"].filter(isDefined).join(".")
318322
}

packages/openapi-code-generator/src/typescript/common/typescript-common.ts

Lines changed: 56 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {logger} from "../../core/logger"
22
import type {
3+
IRMediaType,
34
IROperation,
45
IRParameter,
56
} from "../../core/openapi-types-normalized"
@@ -145,12 +146,45 @@ export type RequestBodyAsParameter = {
145146
contentType: string
146147
}
147148

149+
export function filterBySupportedMediaTypes(
150+
object: Record<string, IRMediaType>,
151+
supportedMediaTypes: string[],
152+
): {contentType: string; mediaType: IRMediaType}[] {
153+
const normalized = Object.fromEntries(
154+
Object.entries(object).map(([key, value]) => {
155+
const contentType = key.split(/\s*[,;]\s*/)[0]
156+
157+
if (!contentType) {
158+
throw new Error(`unspecified content type '${key}'`)
159+
}
160+
161+
return [contentType, {fullContentType: key, mediaType: value}]
162+
}),
163+
)
164+
165+
return supportedMediaTypes
166+
.map((supportedMediaType) => normalized[supportedMediaType])
167+
.filter(isDefined)
168+
.map((it) => ({
169+
contentType: it.fullContentType,
170+
mediaType: it.mediaType,
171+
}))
172+
}
173+
174+
export function firstByBySupportedMediaTypes(
175+
object: Record<string, IRMediaType>,
176+
supportedMediaTypes: string[],
177+
): {contentType: string; mediaType: IRMediaType} | undefined {
178+
return filterBySupportedMediaTypes(object, supportedMediaTypes)[0]
179+
}
180+
148181
export function requestBodyAsParameter(
149182
operation: IROperation,
150183
supportedMediaTypes = [
151184
"application/json",
152-
"text/json",
185+
"application/scim+json",
153186
"application/merge-patch+json",
187+
"text/json",
154188
],
155189
): RequestBodyAsParameter | undefined {
156190
const {requestBody} = operation
@@ -159,52 +193,41 @@ export function requestBodyAsParameter(
159193
return undefined
160194
}
161195

162-
const normalized = Object.entries(requestBody.content).map(([key, value]) => {
163-
const contentType = key.split(/\s*[,;]\s*/)[0]
196+
// todo: support multiple media types properly. https://github.com/mnahkies/openapi-code-generator/issues/42
197+
const result = firstByBySupportedMediaTypes(
198+
requestBody.content,
199+
supportedMediaTypes,
200+
)
164201

165-
if (!contentType) {
166-
throw new Error(`unspecified content type '${key}'`)
167-
}
168-
169-
return {contentType, fullContentType: key, value}
170-
})
171-
172-
// todo: https://github.com/mnahkies/openapi-code-generator/issues/42
173-
for (const supportedMediaType of supportedMediaTypes) {
174-
const result = normalized.find(
175-
(it) => it.contentType === supportedMediaType,
176-
)
177-
178-
if (result) {
179-
return {
180-
isSupported: true,
181-
contentType: result.fullContentType,
182-
parameter: {
183-
name: "requestBody",
184-
description: requestBody.description,
185-
in: "body",
186-
required: requestBody.required,
187-
schema: result.value.schema,
188-
allowEmptyValue: false,
189-
deprecated: false,
190-
},
191-
}
202+
if (result) {
203+
return {
204+
isSupported: true,
205+
contentType: result.contentType,
206+
parameter: {
207+
name: "requestBody",
208+
description: requestBody.description,
209+
in: "body",
210+
required: requestBody.required,
211+
schema: result.mediaType.schema,
212+
allowEmptyValue: false,
213+
deprecated: false,
214+
},
192215
}
193216
}
194217

195218
logger.warn("no supported content-type on defined request body ", {
196219
requestBody,
197220
})
198221

199-
const first = normalized[0]
222+
const contentType = Object.keys(requestBody.content).sort().join(", ")
200223

201-
if (!first) {
224+
if (!contentType) {
202225
return undefined
203226
}
204227

205228
return {
206229
isSupported: false,
207-
contentType: first.fullContentType,
230+
contentType,
208231
parameter: {
209232
name: "requestBody",
210233
description: requestBody.description,

scripts/ci-pipeline.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ pnpm ci-test
88
pnpm lint
99
pnpm format
1010

11+
pnpm integration:clean
1112
pnpm integration:generate
1213
pnpm integration:validate
1314

0 commit comments

Comments
 (0)