From 0d3a98691d8d82ac68093d53269931b4ee051903 Mon Sep 17 00:00:00 2001 From: Masaya Nakamura Date: Fri, 21 Jul 2023 00:34:51 +0900 Subject: [PATCH 1/3] test: add a test case with headers --- aspida.config.js | 5 +++++ samples/headers.yml | 33 +++++++++++++++++++++++++++++++++ samples/headers/$api.ts | 27 +++++++++++++++++++++++++++ samples/headers/ping/$api.ts | 25 +++++++++++++++++++++++++ samples/headers/ping/index.ts | 16 ++++++++++++++++ 5 files changed, 106 insertions(+) create mode 100644 samples/headers.yml create mode 100644 samples/headers/$api.ts create mode 100644 samples/headers/ping/$api.ts create mode 100644 samples/headers/ping/index.ts diff --git a/aspida.config.js b/aspida.config.js index 84ecb492..af6f55e8 100644 --- a/aspida.config.js +++ b/aspida.config.js @@ -48,6 +48,11 @@ module.exports = [ input: 'samples/responses', outputEachDir: true, openapi: { inputFile: 'samples/responses.yml' } + }, + { + input: 'samples/headers', + outputEachDir: true, + openapi: { inputFile: 'samples/headers.yml' } } // { // input: 'samples/path-at-mark', diff --git a/samples/headers.yml b/samples/headers.yml new file mode 100644 index 00000000..a9644a59 --- /dev/null +++ b/samples/headers.yml @@ -0,0 +1,33 @@ +openapi: 3.0.0 +info: + version: 1.0.0 + title: Sample +paths: + /ping: + get: + responses: + '200': + description: OK + headers: + X-Simple: + $ref: '#/components/headers/X-Simple' + X-Description: + $ref: '#/components/headers/X-Description' + X-Ref: + $ref: '#/components/headers/X-Ref' + content: + application/json: + schema: + type: string + example: pong +components: + headers: + X-Simple: + schema: + type: string + X-Description: + schema: + type: integer + description: This header has a description. + X-Ref: + $ref: '#/components/headers/X-Simple' diff --git a/samples/headers/$api.ts b/samples/headers/$api.ts new file mode 100644 index 00000000..6618c657 --- /dev/null +++ b/samples/headers/$api.ts @@ -0,0 +1,27 @@ +import type { AspidaClient } from 'aspida' +import type { Methods as Methods0 } from './ping' + +const api = ({ baseURL, fetch }: AspidaClient) => { + const prefix = (baseURL === undefined ? '' : baseURL).replace(/\/$/, '') + const PATH0 = '/ping' + const GET = 'GET' + + return { + ping: { + /** + * @returns OK + */ + get: (option?: { config?: T | undefined } | undefined) => + fetch(prefix, PATH0, GET, option).text(), + /** + * @returns OK + */ + $get: (option?: { config?: T | undefined } | undefined) => + fetch(prefix, PATH0, GET, option).text().then(r => r.body), + $path: () => `${prefix}${PATH0}` + } + } +} + +export type ApiInstance = ReturnType +export default api diff --git a/samples/headers/ping/$api.ts b/samples/headers/ping/$api.ts new file mode 100644 index 00000000..b3f18fa2 --- /dev/null +++ b/samples/headers/ping/$api.ts @@ -0,0 +1,25 @@ +import type { AspidaClient } from 'aspida' +import type { Methods as Methods0 } from '.' + +const api = ({ baseURL, fetch }: AspidaClient) => { + const prefix = (baseURL === undefined ? '' : baseURL).replace(/\/$/, '') + const PATH0 = '/ping' + const GET = 'GET' + + return { + /** + * @returns OK + */ + get: (option?: { config?: T | undefined } | undefined) => + fetch(prefix, PATH0, GET, option).text(), + /** + * @returns OK + */ + $get: (option?: { config?: T | undefined } | undefined) => + fetch(prefix, PATH0, GET, option).text().then(r => r.body), + $path: () => `${prefix}${PATH0}` + } +} + +export type ApiInstance = ReturnType +export default api diff --git a/samples/headers/ping/index.ts b/samples/headers/ping/index.ts new file mode 100644 index 00000000..05689ab8 --- /dev/null +++ b/samples/headers/ping/index.ts @@ -0,0 +1,16 @@ +/* eslint-disable */ +import type * as Types from '../@types' + +export type Methods = { + get: { + status: 200 + /** OK */ + resBody: string + + resHeaders: { + 'X-Simple': Types.X_Simple + 'X-Description': Types.X_Description + 'X-Ref': Types.X_Ref + } + } +} From a9602625171769a3327ea02710ed8512c2a03dfb Mon Sep 17 00:00:00 2001 From: Masaya Nakamura Date: Fri, 21 Jul 2023 00:36:30 +0900 Subject: [PATCH 2/3] feat: generate header component types --- samples/headers/@types/index.ts | 6 ++++++ src/buildV3.ts | 12 +++++++++++- src/builderUtils/headers2Props.ts | 24 ++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 samples/headers/@types/index.ts create mode 100644 src/builderUtils/headers2Props.ts diff --git a/samples/headers/@types/index.ts b/samples/headers/@types/index.ts new file mode 100644 index 00000000..6b88be3a --- /dev/null +++ b/samples/headers/@types/index.ts @@ -0,0 +1,6 @@ +/* eslint-disable */ +export type X_Simple = string + +export type X_Description = number + +export type X_Ref = X_Simple diff --git a/src/buildV3.ts b/src/buildV3.ts index dd8cd824..85bdba03 100644 --- a/src/buildV3.ts +++ b/src/buildV3.ts @@ -19,6 +19,7 @@ import schemas2Props from './builderUtils/schemas2Props' import parameters2Props from './builderUtils/parameters2Props' import requestBodies2Props from './builderUtils/requestBodies2Props' import responses2Props from './builderUtils/responses2Props' +import headers2Props from './builderUtils/headers2Props' const methodNames = ['get', 'post', 'put', 'delete', 'head', 'options', 'patch'] as const @@ -33,6 +34,7 @@ export default (openapi: OpenAPIV3.Document) => { const parameters = parameters2Props(openapi.components?.parameters, openapi, false) || [] const requestBodies = requestBodies2Props(openapi.components?.requestBodies) || [] const responses = responses2Props(openapi.components?.responses) || [] + const headers = headers2Props(openapi.components?.headers) || [] files.push( ...Object.keys(openapi.paths) @@ -370,7 +372,7 @@ export default (openapi: OpenAPIV3.Document) => { ) const typesText = - parameters.length + schemas.length + requestBodies.length + responses.length + parameters.length + schemas.length + requestBodies.length + responses.length + headers.length ? [ ...parameters.map(p => ({ name: p.name, @@ -397,6 +399,14 @@ export default (openapi: OpenAPIV3.Document) => { typeof r.value === 'string' ? r.value : value2String(r.value, '').replace(/\n {2}/g, '\n') + })), + ...headers.map(h => ({ + name: h.name, + description: null, + text: + typeof h.value === 'string' + ? h.value + : value2String(h.value, '').replace(/\n {2}/g, '\n') })) ] .map(p => `\n${description2Doc(p.description, '')}export type ${p.name} = ${p.text}\n`) diff --git a/src/builderUtils/headers2Props.ts b/src/builderUtils/headers2Props.ts new file mode 100644 index 00000000..11cf3f34 --- /dev/null +++ b/src/builderUtils/headers2Props.ts @@ -0,0 +1,24 @@ +import { OpenAPIV3 } from 'openapi-types' +import { isRefObject, defKey2defName, $ref2Type, schema2value } from './converters' +import { PropValue } from './props2String' + +export type Header = { name: string; value: string | PropValue } + +export default (headers: OpenAPIV3.ComponentsObject['headers']) => + headers && + Object.keys(headers) + .map(defKey => { + const target = headers[defKey] + let value: Header['value'] + + if (isRefObject(target)) { + value = $ref2Type(target.$ref) + } else { + const result = schema2value(target.schema, false) + if (!result) return null + value = result + } + + return { name: defKey2defName(defKey), value } + }) + .filter((v): v is Header => !!v) From 67995e96856c28fd58a1d76969fdfa94b33c6bf6 Mon Sep 17 00:00:00 2001 From: Masaya Nakamura Date: Fri, 21 Jul 2023 00:38:54 +0900 Subject: [PATCH 3/3] feat: output header descriptions as comments --- samples/headers/@types/index.ts | 1 + src/buildV3.ts | 2 +- src/builderUtils/headers2Props.ts | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/samples/headers/@types/index.ts b/samples/headers/@types/index.ts index 6b88be3a..b5f363d3 100644 --- a/samples/headers/@types/index.ts +++ b/samples/headers/@types/index.ts @@ -1,6 +1,7 @@ /* eslint-disable */ export type X_Simple = string +/** This header has a description. */ export type X_Description = number export type X_Ref = X_Simple diff --git a/src/buildV3.ts b/src/buildV3.ts index 85bdba03..894ea9ca 100644 --- a/src/buildV3.ts +++ b/src/buildV3.ts @@ -402,7 +402,7 @@ export default (openapi: OpenAPIV3.Document) => { })), ...headers.map(h => ({ name: h.name, - description: null, + description: typeof h.value === 'string' ? null : h.value.description, text: typeof h.value === 'string' ? h.value diff --git a/src/builderUtils/headers2Props.ts b/src/builderUtils/headers2Props.ts index 11cf3f34..7989aa37 100644 --- a/src/builderUtils/headers2Props.ts +++ b/src/builderUtils/headers2Props.ts @@ -16,7 +16,7 @@ export default (headers: OpenAPIV3.ComponentsObject['headers']) => } else { const result = schema2value(target.schema, false) if (!result) return null - value = result + value = { ...result, description: target.description ?? null } } return { name: defKey2defName(defKey), value }