From 01ce1194851dbdcdac07eda684386c48f4912e5d Mon Sep 17 00:00:00 2001 From: Sergey Volkov Date: Wed, 25 Jun 2025 16:32:21 +0300 Subject: [PATCH 1/2] feat: extract description from requestBody to use it in type --- src/schema-routes/schema-routes.ts | 11 +++++ templates/base/data-contract-jsdoc.ejs | 2 +- tests/__snapshots__/extended.test.ts.snap | 11 +++++ .../__snapshots__/basic.test.ts.snap | 2 + .../__snapshots__/basic.test.ts.snap | 21 ++++++++++ .../spec/requestBodyDescription/basic.test.ts | 42 +++++++++++++++++++ tests/spec/requestBodyDescription/schema.yml | 25 +++++++++++ 7 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 tests/spec/requestBodyDescription/__snapshots__/basic.test.ts.snap create mode 100644 tests/spec/requestBodyDescription/basic.test.ts create mode 100644 tests/spec/requestBodyDescription/schema.yml diff --git a/src/schema-routes/schema-routes.ts b/src/schema-routes/schema-routes.ts index abb804347..fed452745 100644 --- a/src/schema-routes/schema-routes.ts +++ b/src/schema-routes/schema-routes.ts @@ -611,7 +611,17 @@ export class SchemaRoutes { }); } + if ( + schema && + schema.typeData && + !schema.typeData.description && + requestBody?.description + ) { + schema.typeData.description = requestBody.description; + } + return { + ...(requestBody || {}), paramName: requestBodyName || requestBody?.name || DEFAULT_BODY_ARG_NAME, contentTypes, contentKind, @@ -995,6 +1005,7 @@ export class SchemaRoutes { : void 0, body: requestBodyInfo.type ? { + ...requestBodyInfo, name: nameResolver.resolve([ requestBodyInfo.paramName, ...RESERVED_BODY_ARG_NAMES, diff --git a/templates/base/data-contract-jsdoc.ejs b/templates/base/data-contract-jsdoc.ejs index cd3c3de5c..6dcfa9158 100644 --- a/templates/base/data-contract-jsdoc.ejs +++ b/templates/base/data-contract-jsdoc.ejs @@ -2,7 +2,7 @@ const { data, utils } = it; const { formatDescription, require, _ } = utils; -const stringify = (value) => _.isObject(value) ? JSON.stringify(value) : _.isString(value) ? `"${value}"` : value +const stringify = (value) => _.isObject(value) ? JSON.stringify(value) : _.isString(value) ? `"${value}"` : value; const jsDocLines = _.compact([ data.title, diff --git a/tests/__snapshots__/extended.test.ts.snap b/tests/__snapshots__/extended.test.ts.snap index c3b7c1965..caf870724 100644 --- a/tests/__snapshots__/extended.test.ts.snap +++ b/tests/__snapshots__/extended.test.ts.snap @@ -116,6 +116,7 @@ export type AllTriggersData = Trigger[]; export type BatchCreateDataData = DataResponse[]; +/** A collection of data records including \`value\` (required) and optionally including: \`lat\`, \`lon\`, \`ele\` (latitude, longitude, and elevation values), and \`created_at\` (a date/time string). */ export type BatchCreateDataPayload = { /** @format dateTime */ created_at?: string; @@ -128,6 +129,7 @@ export type BatchCreateDataPayload = { export type BatchCreateGroupFeedDataData = DataResponse[]; +/** A collection of data records including \`value\` (required) and optionally including: \`lat\`, \`lon\`, \`ele\` (latitude, longitude, and elevation values), and \`created_at\` (a date/time string). */ export type BatchCreateGroupFeedDataPayload = { /** @format dateTime */ created_at?: string; @@ -225,6 +227,7 @@ export interface CreateDashboardPayload { export type CreateDataData = Data; +/** Data record including a \`value\` field (required) and optionally including: \`lat\`, \`lon\`, \`ele\` (latitude, longitude, and elevation values), and \`created_at\` (a date/time string). */ export interface CreateDataPayload { /** @format dateTime */ created_at?: string; @@ -274,6 +277,7 @@ export type CreateGroupFeedData = Feed; export type CreateGroupFeedDataData = DataResponse; +/** Data record including a \`value\` field (required) and optionally including: \`lat\`, \`lon\`, \`ele\` (latitude, longitude, and elevation values), and \`created_at\` (a date/time string). */ export interface CreateGroupFeedDataPayload { /** @format dateTime */ created_at?: string; @@ -338,6 +342,7 @@ export interface CreateTriggerPayload { export type CreateWebhookFeedDataData = Data; +/** Webhook payload containing data \`value\` parameter. */ export interface CreateWebhookFeedDataPayload { value?: string; } @@ -621,6 +626,7 @@ export interface ReplaceDashboardPayload { export type ReplaceDataData = DataResponse; +/** Data record including a \`value\` field (required) and optionally including: \`lat\`, \`lon\`, \`ele\` (latitude, longitude, and elevation values), and \`created_at\` (a date/time string). */ export interface ReplaceDataPayload { /** @format dateTime */ created_at?: string; @@ -732,6 +738,7 @@ export interface UpdateDashboardPayload { export type UpdateDataData = DataResponse; +/** Data record including a \`value\` field (required) and optionally including: \`lat\`, \`lon\`, \`ele\` (latitude, longitude, and elevation values), and \`created_at\` (a date/time string). */ export interface UpdateDataPayload { /** @format dateTime */ created_at?: string; @@ -5285,8 +5292,10 @@ export interface Category { name?: string; } +/** List of user object */ export type CreateUsersWithArrayInputPayload = User[]; +/** List of user object */ export type CreateUsersWithListInputPayload = User[]; /** @@ -68537,8 +68546,10 @@ export interface Category { name?: string; } +/** List of user object */ export type CreateUsersWithArrayInputPayload = User[]; +/** List of user object */ export type CreateUsersWithListInputPayload = User[]; export type FindPetsByStatusData = Pet[]; diff --git a/tests/spec/extractRequestBody/__snapshots__/basic.test.ts.snap b/tests/spec/extractRequestBody/__snapshots__/basic.test.ts.snap index b14d8a463..91bc048b0 100644 --- a/tests/spec/extractRequestBody/__snapshots__/basic.test.ts.snap +++ b/tests/spec/extractRequestBody/__snapshots__/basic.test.ts.snap @@ -178,8 +178,10 @@ export interface UploadFilePayloadTTT { file?: File; } +/** List of user object */ export type CreateUsersWithArrayInputPayloadTTT = UserTTT[]; +/** List of user object */ export type CreateUsersWithListInputPayloadTTT = UserTTT[]; export type QueryParamsType = Record; diff --git a/tests/spec/requestBodyDescription/__snapshots__/basic.test.ts.snap b/tests/spec/requestBodyDescription/__snapshots__/basic.test.ts.snap new file mode 100644 index 000000000..04114383b --- /dev/null +++ b/tests/spec/requestBodyDescription/__snapshots__/basic.test.ts.snap @@ -0,0 +1,21 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`basic > requestBodyDescription 1`] = ` +"/* eslint-disable */ +/* tslint:disable */ +// @ts-nocheck +/* + * --------------------------------------------------------------- + * ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ## + * ## ## + * ## AUTHOR: acacode ## + * ## SOURCE: https://github.com/acacode/swagger-typescript-api ## + * --------------------------------------------------------------- + */ + +/** FODSFDSF DSF DSF */ +export type CreateKeksPayload = object; + +export type CreateKeksData = object; +" +`; diff --git a/tests/spec/requestBodyDescription/basic.test.ts b/tests/spec/requestBodyDescription/basic.test.ts new file mode 100644 index 000000000..c74df2304 --- /dev/null +++ b/tests/spec/requestBodyDescription/basic.test.ts @@ -0,0 +1,42 @@ +import * as fs from "node:fs/promises"; +import * as os from "node:os"; +import * as path from "node:path"; + +import { afterAll, beforeAll, describe, expect, test } from "vitest"; + +import { generateApi } from "../../../src/index.js"; + +describe("basic", async () => { + let tmpdir = ""; + + beforeAll(async () => { + tmpdir = await fs.mkdtemp(path.join(os.tmpdir(), "swagger-typescript-api")); + }); + + afterAll(async () => { + await fs.rm(tmpdir, { recursive: true }); + }); + + test("requestBodyDescription", async () => { + await generateApi({ + fileName: "schema", + input: path.resolve(import.meta.dirname, "schema.yml"), + output: tmpdir, + silent: true, + generateClient: false, + generateRouteTypes: false, + extractResponseBody: true, + extractRequestParams: true, + extractRequestBody: true, + extractResponseError: true, + extractResponses: true, + extractEnums: true, + }); + + const content = await fs.readFile(path.join(tmpdir, "schema.ts"), { + encoding: "utf8", + }); + + expect(content).toMatchSnapshot(); + }); +}); diff --git a/tests/spec/requestBodyDescription/schema.yml b/tests/spec/requestBodyDescription/schema.yml new file mode 100644 index 000000000..8fbde56ec --- /dev/null +++ b/tests/spec/requestBodyDescription/schema.yml @@ -0,0 +1,25 @@ +openapi: 3.0.3 +info: + title: teesttt + version: 0.0.0 +security: + - registryCookieAuth: [] + - cookieAuth: [ ] +paths: + /api/v333/keks: + post: + operationId: createKeks + requestBody: + description: FODSFDSF DSF DSF + required: true + content: + application/json: + schema: + type: object + responses: + '200': + description: OK. + content: + 'application/json': + schema: + type: object From 4fbf50afc6bd2e88b9df3d1518d938960bb5f15c Mon Sep 17 00:00:00 2001 From: Sergey Volkov Date: Wed, 25 Jun 2025 16:34:10 +0300 Subject: [PATCH 2/2] chore: update changeset --- .changeset/major-spies-peel.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/major-spies-peel.md diff --git a/.changeset/major-spies-peel.md b/.changeset/major-spies-peel.md new file mode 100644 index 000000000..b7643c8be --- /dev/null +++ b/.changeset/major-spies-peel.md @@ -0,0 +1,5 @@ +--- +"swagger-typescript-api": patch +--- + +better extracting description for request body extacting types