From fcab863bb1eaa5351f62522e466eefc8bccec133 Mon Sep 17 00:00:00 2001 From: Masaya Nakamura Date: Tue, 31 Oct 2023 23:50:37 +0900 Subject: [PATCH 1/3] test: add a test case for empty object response bodies, with current output --- aspida.config.js | 5 +++ samples/empty-object-response-body.yml | 34 ++++++++++++++ samples/empty-object-response-body/$api.ts | 45 +++++++++++++++++++ .../with-additional-properties-false/$api.ts | 19 ++++++++ .../with-additional-properties-false/index.ts | 6 +++ .../with-additional-properties-true/$api.ts | 25 +++++++++++ .../with-additional-properties-true/index.ts | 11 +++++ .../without-additional-properties/$api.ts | 19 ++++++++ .../without-additional-properties/index.ts | 6 +++ 9 files changed, 170 insertions(+) create mode 100644 samples/empty-object-response-body.yml create mode 100644 samples/empty-object-response-body/$api.ts create mode 100644 samples/empty-object-response-body/with-additional-properties-false/$api.ts create mode 100644 samples/empty-object-response-body/with-additional-properties-false/index.ts create mode 100644 samples/empty-object-response-body/with-additional-properties-true/$api.ts create mode 100644 samples/empty-object-response-body/with-additional-properties-true/index.ts create mode 100644 samples/empty-object-response-body/without-additional-properties/$api.ts create mode 100644 samples/empty-object-response-body/without-additional-properties/index.ts diff --git a/aspida.config.js b/aspida.config.js index 50812f29..96d848d5 100644 --- a/aspida.config.js +++ b/aspida.config.js @@ -64,6 +64,11 @@ module.exports = [ outputEachDir: true, openapi: { inputFile: 'samples/allOf-required.yml' }, }, + { + input: 'samples/empty-object-response-body', + outputEachDir: true, + openapi: { inputFile: 'samples/empty-object-response-body.yml' }, + }, // { // input: 'samples/path-at-mark', // outputEachDir: true, diff --git a/samples/empty-object-response-body.yml b/samples/empty-object-response-body.yml new file mode 100644 index 00000000..08f929c5 --- /dev/null +++ b/samples/empty-object-response-body.yml @@ -0,0 +1,34 @@ +openapi: 3.0.0 +info: + version: 1.0.0 + title: Sample +paths: + /without-additional-properties: + delete: + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + /with-additional-properties-true: + delete: + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + additionalProperties: true + /with-additional-properties-false: + delete: + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + additionalProperties: false diff --git a/samples/empty-object-response-body/$api.ts b/samples/empty-object-response-body/$api.ts new file mode 100644 index 00000000..2dc6348c --- /dev/null +++ b/samples/empty-object-response-body/$api.ts @@ -0,0 +1,45 @@ +import type { AspidaClient, BasicHeaders } from 'aspida'; +import type { Methods as Methods0 } from './with-additional-properties-false'; +import type { Methods as Methods1 } from './with-additional-properties-true'; +import type { Methods as Methods2 } from './without-additional-properties'; + +const api = ({ baseURL, fetch }: AspidaClient) => { + const prefix = (baseURL === undefined ? '' : baseURL).replace(/\/$/, ''); + const PATH0 = '/with-additional-properties-false'; + const PATH1 = '/with-additional-properties-true'; + const PATH2 = '/without-additional-properties'; + const DELETE = 'DELETE'; + + return { + with_additional_properties_false: { + delete: (option?: { config?: T | undefined } | undefined) => + fetch(prefix, PATH0, DELETE, option).send(), + $delete: (option?: { config?: T | undefined } | undefined) => + fetch(prefix, PATH0, DELETE, option).send().then(r => r.body), + $path: () => `${prefix}${PATH0}`, + }, + with_additional_properties_true: { + /** + * @returns OK + */ + delete: (option?: { config?: T | undefined } | undefined) => + fetch(prefix, PATH1, DELETE, option).json(), + /** + * @returns OK + */ + $delete: (option?: { config?: T | undefined } | undefined) => + fetch(prefix, PATH1, DELETE, option).json().then(r => r.body), + $path: () => `${prefix}${PATH1}`, + }, + without_additional_properties: { + delete: (option?: { config?: T | undefined } | undefined) => + fetch(prefix, PATH2, DELETE, option).send(), + $delete: (option?: { config?: T | undefined } | undefined) => + fetch(prefix, PATH2, DELETE, option).send().then(r => r.body), + $path: () => `${prefix}${PATH2}`, + }, + }; +}; + +export type ApiInstance = ReturnType; +export default api; diff --git a/samples/empty-object-response-body/with-additional-properties-false/$api.ts b/samples/empty-object-response-body/with-additional-properties-false/$api.ts new file mode 100644 index 00000000..231f4cc3 --- /dev/null +++ b/samples/empty-object-response-body/with-additional-properties-false/$api.ts @@ -0,0 +1,19 @@ +import type { AspidaClient, BasicHeaders } from 'aspida'; +import type { Methods as Methods0 } from '.'; + +const api = ({ baseURL, fetch }: AspidaClient) => { + const prefix = (baseURL === undefined ? '' : baseURL).replace(/\/$/, ''); + const PATH0 = '/with-additional-properties-false'; + const DELETE = 'DELETE'; + + return { + delete: (option?: { config?: T | undefined } | undefined) => + fetch(prefix, PATH0, DELETE, option).send(), + $delete: (option?: { config?: T | undefined } | undefined) => + fetch(prefix, PATH0, DELETE, option).send().then(r => r.body), + $path: () => `${prefix}${PATH0}`, + }; +}; + +export type ApiInstance = ReturnType; +export default api; diff --git a/samples/empty-object-response-body/with-additional-properties-false/index.ts b/samples/empty-object-response-body/with-additional-properties-false/index.ts new file mode 100644 index 00000000..b9ef8999 --- /dev/null +++ b/samples/empty-object-response-body/with-additional-properties-false/index.ts @@ -0,0 +1,6 @@ +/* eslint-disable */ +export type Methods = { + delete: { + status: 200 + } +} diff --git a/samples/empty-object-response-body/with-additional-properties-true/$api.ts b/samples/empty-object-response-body/with-additional-properties-true/$api.ts new file mode 100644 index 00000000..0c868038 --- /dev/null +++ b/samples/empty-object-response-body/with-additional-properties-true/$api.ts @@ -0,0 +1,25 @@ +import type { AspidaClient, BasicHeaders } from 'aspida'; +import type { Methods as Methods0 } from '.'; + +const api = ({ baseURL, fetch }: AspidaClient) => { + const prefix = (baseURL === undefined ? '' : baseURL).replace(/\/$/, ''); + const PATH0 = '/with-additional-properties-true'; + const DELETE = 'DELETE'; + + return { + /** + * @returns OK + */ + delete: (option?: { config?: T | undefined } | undefined) => + fetch(prefix, PATH0, DELETE, option).json(), + /** + * @returns OK + */ + $delete: (option?: { config?: T | undefined } | undefined) => + fetch(prefix, PATH0, DELETE, option).json().then(r => r.body), + $path: () => `${prefix}${PATH0}`, + }; +}; + +export type ApiInstance = ReturnType; +export default api; diff --git a/samples/empty-object-response-body/with-additional-properties-true/index.ts b/samples/empty-object-response-body/with-additional-properties-true/index.ts new file mode 100644 index 00000000..833ecfeb --- /dev/null +++ b/samples/empty-object-response-body/with-additional-properties-true/index.ts @@ -0,0 +1,11 @@ +/* eslint-disable */ +export type Methods = { + delete: { + status: 200 + + /** OK */ + resBody: { + [key: string]: any + } + } +} diff --git a/samples/empty-object-response-body/without-additional-properties/$api.ts b/samples/empty-object-response-body/without-additional-properties/$api.ts new file mode 100644 index 00000000..37fa16ba --- /dev/null +++ b/samples/empty-object-response-body/without-additional-properties/$api.ts @@ -0,0 +1,19 @@ +import type { AspidaClient, BasicHeaders } from 'aspida'; +import type { Methods as Methods0 } from '.'; + +const api = ({ baseURL, fetch }: AspidaClient) => { + const prefix = (baseURL === undefined ? '' : baseURL).replace(/\/$/, ''); + const PATH0 = '/without-additional-properties'; + const DELETE = 'DELETE'; + + return { + delete: (option?: { config?: T | undefined } | undefined) => + fetch(prefix, PATH0, DELETE, option).send(), + $delete: (option?: { config?: T | undefined } | undefined) => + fetch(prefix, PATH0, DELETE, option).send().then(r => r.body), + $path: () => `${prefix}${PATH0}`, + }; +}; + +export type ApiInstance = ReturnType; +export default api; diff --git a/samples/empty-object-response-body/without-additional-properties/index.ts b/samples/empty-object-response-body/without-additional-properties/index.ts new file mode 100644 index 00000000..b9ef8999 --- /dev/null +++ b/samples/empty-object-response-body/without-additional-properties/index.ts @@ -0,0 +1,6 @@ +/* eslint-disable */ +export type Methods = { + delete: { + status: 200 + } +} From 040f3ebfaa8c2a8592943540f1afff61f77676bd Mon Sep 17 00:00:00 2001 From: Masaya Nakamura Date: Wed, 1 Nov 2023 00:29:41 +0900 Subject: [PATCH 2/3] fix: type empty object with `additionalProperties: false` as `{}` --- samples/empty-object-response-body/$api.ts | 10 ++++++++-- .../with-additional-properties-false/$api.ts | 10 ++++++++-- .../with-additional-properties-false/index.ts | 4 ++++ src/builderUtils/converters.ts | 2 +- 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/samples/empty-object-response-body/$api.ts b/samples/empty-object-response-body/$api.ts index 2dc6348c..ee83b6a1 100644 --- a/samples/empty-object-response-body/$api.ts +++ b/samples/empty-object-response-body/$api.ts @@ -12,10 +12,16 @@ const api = ({ baseURL, fetch }: AspidaClient) => { return { with_additional_properties_false: { + /** + * @returns OK + */ delete: (option?: { config?: T | undefined } | undefined) => - fetch(prefix, PATH0, DELETE, option).send(), + fetch(prefix, PATH0, DELETE, option).json(), + /** + * @returns OK + */ $delete: (option?: { config?: T | undefined } | undefined) => - fetch(prefix, PATH0, DELETE, option).send().then(r => r.body), + fetch(prefix, PATH0, DELETE, option).json().then(r => r.body), $path: () => `${prefix}${PATH0}`, }, with_additional_properties_true: { diff --git a/samples/empty-object-response-body/with-additional-properties-false/$api.ts b/samples/empty-object-response-body/with-additional-properties-false/$api.ts index 231f4cc3..2c7795b9 100644 --- a/samples/empty-object-response-body/with-additional-properties-false/$api.ts +++ b/samples/empty-object-response-body/with-additional-properties-false/$api.ts @@ -7,10 +7,16 @@ const api = ({ baseURL, fetch }: AspidaClient) => { const DELETE = 'DELETE'; return { + /** + * @returns OK + */ delete: (option?: { config?: T | undefined } | undefined) => - fetch(prefix, PATH0, DELETE, option).send(), + fetch(prefix, PATH0, DELETE, option).json(), + /** + * @returns OK + */ $delete: (option?: { config?: T | undefined } | undefined) => - fetch(prefix, PATH0, DELETE, option).send().then(r => r.body), + fetch(prefix, PATH0, DELETE, option).json().then(r => r.body), $path: () => `${prefix}${PATH0}`, }; }; diff --git a/samples/empty-object-response-body/with-additional-properties-false/index.ts b/samples/empty-object-response-body/with-additional-properties-false/index.ts index b9ef8999..c68852f3 100644 --- a/samples/empty-object-response-body/with-additional-properties-false/index.ts +++ b/samples/empty-object-response-body/with-additional-properties-false/index.ts @@ -2,5 +2,9 @@ export type Methods = { delete: { status: 200 + + /** OK */ + resBody: { + } } } diff --git a/src/builderUtils/converters.ts b/src/builderUtils/converters.ts index 7ee661e9..f519be8b 100644 --- a/src/builderUtils/converters.ts +++ b/src/builderUtils/converters.ts @@ -123,7 +123,7 @@ export const schema2value = ( } else if (isArraySchema(schema)) { isArray = true; value = schema2value(schema.items); - } else if (schema.properties || schema.additionalProperties) { + } else if (schema.properties || 'additionalProperties' in schema) { value = object2value(schema); } else if (schema.format === 'binary') { value = isResponse ? 'Blob' : BINARY_TYPE; From e88a0f1e24a9dccf1d6dd2c0927378be23cd2933 Mon Sep 17 00:00:00 2001 From: Masaya Nakamura Date: Wed, 1 Nov 2023 00:38:49 +0900 Subject: [PATCH 3/3] fix: type empty object without `additionalProperties` as `{}` --- samples/empty-object-response-body/$api.ts | 10 ++++++++-- .../without-additional-properties/$api.ts | 10 ++++++++-- .../without-additional-properties/index.ts | 4 ++++ .../chats/_chatId@string/items/index.ts | 2 ++ .../openapi/api/v3/chats/_chatId@string/items/index.ts | 2 ++ src/builderUtils/converters.ts | 4 ++-- 6 files changed, 26 insertions(+), 6 deletions(-) diff --git a/samples/empty-object-response-body/$api.ts b/samples/empty-object-response-body/$api.ts index ee83b6a1..c8139fd5 100644 --- a/samples/empty-object-response-body/$api.ts +++ b/samples/empty-object-response-body/$api.ts @@ -38,10 +38,16 @@ const api = ({ baseURL, fetch }: AspidaClient) => { $path: () => `${prefix}${PATH1}`, }, without_additional_properties: { + /** + * @returns OK + */ delete: (option?: { config?: T | undefined } | undefined) => - fetch(prefix, PATH2, DELETE, option).send(), + fetch(prefix, PATH2, DELETE, option).json(), + /** + * @returns OK + */ $delete: (option?: { config?: T | undefined } | undefined) => - fetch(prefix, PATH2, DELETE, option).send().then(r => r.body), + fetch(prefix, PATH2, DELETE, option).json().then(r => r.body), $path: () => `${prefix}${PATH2}`, }, }; diff --git a/samples/empty-object-response-body/without-additional-properties/$api.ts b/samples/empty-object-response-body/without-additional-properties/$api.ts index 37fa16ba..c158d097 100644 --- a/samples/empty-object-response-body/without-additional-properties/$api.ts +++ b/samples/empty-object-response-body/without-additional-properties/$api.ts @@ -7,10 +7,16 @@ const api = ({ baseURL, fetch }: AspidaClient) => { const DELETE = 'DELETE'; return { + /** + * @returns OK + */ delete: (option?: { config?: T | undefined } | undefined) => - fetch(prefix, PATH0, DELETE, option).send(), + fetch(prefix, PATH0, DELETE, option).json(), + /** + * @returns OK + */ $delete: (option?: { config?: T | undefined } | undefined) => - fetch(prefix, PATH0, DELETE, option).send().then(r => r.body), + fetch(prefix, PATH0, DELETE, option).json().then(r => r.body), $path: () => `${prefix}${PATH0}`, }; }; diff --git a/samples/empty-object-response-body/without-additional-properties/index.ts b/samples/empty-object-response-body/without-additional-properties/index.ts index b9ef8999..c68852f3 100644 --- a/samples/empty-object-response-body/without-additional-properties/index.ts +++ b/samples/empty-object-response-body/without-additional-properties/index.ts @@ -2,5 +2,9 @@ export type Methods = { delete: { status: 200 + + /** OK */ + resBody: { + } } } diff --git a/samples/openapi/api/v3/channels/_channelId@string/chats/_chatId@string/items/index.ts b/samples/openapi/api/v3/channels/_channelId@string/chats/_chatId@string/items/index.ts index b2cd7ee0..0d44140f 100644 --- a/samples/openapi/api/v3/channels/_channelId@string/chats/_chatId@string/items/index.ts +++ b/samples/openapi/api/v3/channels/_channelId@string/chats/_chatId@string/items/index.ts @@ -16,6 +16,8 @@ export type Methods = { resBody: { limit: number offset: number + data: { + }[] } } diff --git a/samples/openapi/api/v3/chats/_chatId@string/items/index.ts b/samples/openapi/api/v3/chats/_chatId@string/items/index.ts index b81bab07..46be4b24 100644 --- a/samples/openapi/api/v3/chats/_chatId@string/items/index.ts +++ b/samples/openapi/api/v3/chats/_chatId@string/items/index.ts @@ -18,6 +18,8 @@ export type Methods = { resBody: { limit: number offset: number + data: { + }[] } } diff --git a/src/builderUtils/converters.ts b/src/builderUtils/converters.ts index f519be8b..df8b68d6 100644 --- a/src/builderUtils/converters.ts +++ b/src/builderUtils/converters.ts @@ -123,11 +123,11 @@ export const schema2value = ( } else if (isArraySchema(schema)) { isArray = true; value = schema2value(schema.items); - } else if (schema.properties || 'additionalProperties' in schema) { + } else if (schema.type === 'object' || schema.properties || 'additionalProperties' in schema) { value = object2value(schema); } else if (schema.format === 'binary') { value = isResponse ? 'Blob' : BINARY_TYPE; - } else if (schema.type !== 'object') { + } else { value = schema.type ? { integer: 'number',