diff --git a/CHANGELOG.md b/CHANGELOG.md index a7859f80e..a6999bc71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,18 @@ # Changelog All notable changes to this project will be documented in this file. +## [0.24.0] - 2022-06-02 +### Fixed +- Upgraded dependencies +- Escape reserved keywords in schema names (https://github.com/ferdikoomen/openapi-typescript-codegen/pull/1192) +- Fix pattern single quote escaping (https://github.com/ferdikoomen/openapi-typescript-codegen/pull/1275) +- Fix undefined request body when body is a valid JSON falsy value: false or 0, "". (https://github.com/ferdikoomen/openapi-typescript-codegen/pull/1076) +### Added +- Add model postfix (https://github.com/ferdikoomen/openapi-typescript-codegen/pull/1141) +- Support free-form objects (https://github.com/ferdikoomen/openapi-typescript-codegen/pull/1165) +- Set default providedIn to root for angular client (https://github.com/ferdikoomen/openapi-typescript-codegen/pull/1250) +- Add json support for application/problem+json content type (https://github.com/ferdikoomen/openapi-typescript-codegen/pull/1208) + ## [0.23.0] - 2022-06-02 ### Fixed - Upgraded dependencies diff --git a/README.md b/README.md index 429f905ee..1c9aab97a 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,11 @@ # OpenAPI Typescript Codegen +This is a Fork of [openapi-typescript-codegen](https://www.npmjs.com/package/openapi-typescript-codegen) with the following changes: + +- Merge of https://github.com/ferdikoomen/openapi-typescript-codegen/pull/1145 + +--- + [![NPM][npm-image]][npm-url] [![License][license-image]][license-url] [![Coverage][coverage-image]][coverage-url] diff --git a/package-lock.json b/package-lock.json index 77d207312..944641346 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "openapi-typescript-codegen", - "version": "0.23.0", + "version": "0.24.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "openapi-typescript-codegen", - "version": "0.23.0", + "version": "0.24.0", "license": "MIT", "dependencies": { "camelcase": "^6.3.0", diff --git a/package.json b/package.json index cc38c8d10..f893287d4 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { - "name": "openapi-typescript-codegen", - "version": "0.23.0", + "name": "@jshmrtn/openapi-typescript-codegen", + "version": "0.24.0", "description": "Library that generates Typescript clients based on the OpenAPI specification.", "author": "Ferdi Koomen", - "homepage": "https://github.com/ferdikoomen/openapi-typescript-codegen", + "homepage": "https://github.com/jshmrtn/openapi-typescript-codegen", "repository": { "type": "git", - "url": "git+https://github.com/ferdikoomen/openapi-typescript-codegen.git" + "url": "git+https://github.com/jshmrtn/openapi-typescript-codegen.git" }, "bugs": { "url": "https://github.com/ferdikoomen/openapi-typescript-codegen/issues" @@ -29,6 +29,10 @@ { "name": "Ferdi Koomen", "email": "info@madebyferdi.com" + }, + { + "name": "Jeremy Zahner", + "email": "zahner@joshmartin.ch" } ], "main": "dist/index.js", @@ -56,7 +60,10 @@ "eslint": "eslint .", "eslint:fix": "eslint . --fix", "prepublishOnly": "npm run clean && npm run release", - "codecov": "codecov --token=66c30c23-8954-4892-bef9-fbaed0a2e42b" + "codecov": "codecov --token=66c30c23-8954-4892-bef9-fbaed0a2e42b", + "preversion": "npm run test && npm run eslint", + "version": "npm run prepublishOnly && git add CHANGELOG.md", + "postversion": "git push && git push --tags" }, "dependencies": { "camelcase": "^6.3.0", @@ -120,7 +127,7 @@ "typescript": "4.8.4", "zone.js": "0.11.8" }, - "overrides" : { + "overrides": { "rollup": "3.2.3" } } diff --git a/src/templates/core/utils/OmitReadonly.hbs b/src/templates/core/utils/OmitReadonly.hbs new file mode 100644 index 000000000..0b6126a31 --- /dev/null +++ b/src/templates/core/utils/OmitReadonly.hbs @@ -0,0 +1,47 @@ +/** + * The contents of this file are inspired from https://github.com/ts-essentials/ts-essentials#ReadonlyKeys + * + * The MIT License + * + * Copyright (c) 2018-2019 Chris Kaczor (github.com/krzkaczor) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * */ + +type Writable = { -readonly [P in keyof T]: T[P] }; + +type IsEqualConsideringWritability = (() => T extends X ? 1 : 2) extends () => T extends Y ? 1 : 2 + ? true + : false; + +type IsFullyWritable = IsEqualConsideringWritability< + { [Q in keyof T]: T[Q] }, + Writable<{ [Q in keyof T]: T[Q] }> +>; + +/** Gets keys of an object which are readonly */ +type ReadonlyKeys = { + [P in keyof T]-?: IsFullyWritable> extends true ? never : P; +}[keyof T]; + +/** + * Exclude keys of an object which are readonly + * In case of union types containing types not extending object, type is inferred as-is + * */ +export declare type OmitReadonly = T extends object ? Omit> : T; diff --git a/src/templates/exportService.hbs b/src/templates/exportService.hbs index d6bccbbeb..bf6c25bf0 100644 --- a/src/templates/exportService.hbs +++ b/src/templates/exportService.hbs @@ -30,6 +30,7 @@ import type { BaseHttpRequest } from '../core/BaseHttpRequest'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; {{/if}} +import type { OmitReadonly } from '../core/utils/OmitReadonly'; {{#equals @root.httpClient 'angular'}} @Injectable({ diff --git a/src/templates/partials/parameters.hbs b/src/templates/partials/parameters.hbs index 57ab5a7d1..9e23a9190 100644 --- a/src/templates/partials/parameters.hbs +++ b/src/templates/partials/parameters.hbs @@ -16,13 +16,13 @@ {{/if}} */ {{/ifdef}} -{{{name}}}{{>isRequired}}: {{>type}}, +{{{name}}}{{>isRequired}}: {{>typeWithOmitReadOnly httpMethod=../method}}, {{/each}} } {{~else}} {{#each parameters}} -{{{name}}}{{>isRequired}}: {{>type}}{{#if default}} = {{{default}}}{{/if}}, +{{{name}}}{{>isRequired}}: {{>typeWithOmitReadOnly httpMethod=../method}}{{#if default}} = {{{default}}}{{/if}}, {{/each}} {{/if}} {{/if}} diff --git a/src/templates/partials/typeWithOmitReadOnly.hbs b/src/templates/partials/typeWithOmitReadOnly.hbs new file mode 100644 index 000000000..ec5359c59 --- /dev/null +++ b/src/templates/partials/typeWithOmitReadOnly.hbs @@ -0,0 +1,13 @@ +{{#equals export "reference"}} +{{#equals httpMethod "POST"~}} + OmitReadonly<{{>type}}> +{{~else equals httpMethod "PUT"~}} + OmitReadonly<{{>type}}> +{{~else equals httpMethod "PATCH"~}} + OmitReadonly<{{>type}}> +{{else}} + {{~>type}} +{{~/equals}} +{{~else}} + {{~>type}} +{{~/equals}} diff --git a/src/utils/registerHandlebarTemplates.ts b/src/utils/registerHandlebarTemplates.ts index bf77cbdc1..6ead3a7f7 100644 --- a/src/utils/registerHandlebarTemplates.ts +++ b/src/utils/registerHandlebarTemplates.ts @@ -46,6 +46,7 @@ import nodeRequest from '../templates/core/node/request.hbs'; import nodeSendRequest from '../templates/core/node/sendRequest.hbs'; import templateCoreSettings from '../templates/core/OpenAPI.hbs'; import templateCoreRequest from '../templates/core/request.hbs'; +import omitReadonly from '../templates/core/utils/OmitReadonly.hbs'; import xhrGetHeaders from '../templates/core/xhr/getHeaders.hbs'; import xhrGetRequestBody from '../templates/core/xhr/getRequestBody.hbs'; import xhrGetResponseBody from '../templates/core/xhr/getResponseBody.hbs'; @@ -83,6 +84,7 @@ import partialTypeInterface from '../templates/partials/typeInterface.hbs'; import partialTypeIntersection from '../templates/partials/typeIntersection.hbs'; import partialTypeReference from '../templates/partials/typeReference.hbs'; import partialTypeUnion from '../templates/partials/typeUnion.hbs'; +import typeWithOmitReadOnly from '../templates/partials/typeWithOmitReadOnly.hbs'; import { registerHandlebarHelpers } from './registerHandlebarHelpers'; export interface Templates { @@ -102,6 +104,9 @@ export interface Templates { request: Handlebars.TemplateDelegate; baseHttpRequest: Handlebars.TemplateDelegate; httpRequest: Handlebars.TemplateDelegate; + utils: { + omitReadonly: Handlebars.TemplateDelegate; + }; }; } @@ -134,6 +139,9 @@ export const registerHandlebarTemplates = (root: { request: Handlebars.template(templateCoreRequest), baseHttpRequest: Handlebars.template(templateCoreBaseHttpRequest), httpRequest: Handlebars.template(templateCoreHttpRequest), + utils: { + omitReadonly: Handlebars.template(omitReadonly), + }, }, }; @@ -163,6 +171,7 @@ export const registerHandlebarTemplates = (root: { Handlebars.registerPartial('typeInterface', Handlebars.template(partialTypeInterface)); Handlebars.registerPartial('typeReference', Handlebars.template(partialTypeReference)); Handlebars.registerPartial('typeUnion', Handlebars.template(partialTypeUnion)); + Handlebars.registerPartial('typeWithOmitReadOnly', Handlebars.template(typeWithOmitReadOnly)); Handlebars.registerPartial('typeIntersection', Handlebars.template(partialTypeIntersection)); Handlebars.registerPartial('base', Handlebars.template(partialBase)); diff --git a/src/utils/writeClient.spec.ts b/src/utils/writeClient.spec.ts index 3c06a95a5..bd2f744ee 100644 --- a/src/utils/writeClient.spec.ts +++ b/src/utils/writeClient.spec.ts @@ -33,6 +33,9 @@ describe('writeClient', () => { request: () => 'request', baseHttpRequest: () => 'baseHttpRequest', httpRequest: () => 'httpRequest', + utils: { + omitReadonly: () => 'omitReadonly', + }, }, }; diff --git a/src/utils/writeClient.ts b/src/utils/writeClient.ts index cea2f3d88..f93179719 100644 --- a/src/utils/writeClient.ts +++ b/src/utils/writeClient.ts @@ -52,6 +52,7 @@ export const writeClient = async ( ): Promise => { const outputPath = resolve(process.cwd(), output); const outputPathCore = resolve(outputPath, 'core'); + const outputPathCoreUtils = resolve(outputPath, 'core', 'utils'); const outputPathModels = resolve(outputPath, 'models'); const outputPathSchemas = resolve(outputPath, 'schemas'); const outputPathServices = resolve(outputPath, 'services'); @@ -62,8 +63,17 @@ export const writeClient = async ( if (exportCore) { await rmdir(outputPathCore); - await mkdir(outputPathCore); - await writeClientCore(client, templates, outputPathCore, httpClient, indent, clientName, request); + await mkdir(outputPathCoreUtils); + await writeClientCore( + client, + templates, + outputPathCore, + outputPathCoreUtils, + httpClient, + indent, + clientName, + request + ); } if (exportServices) { diff --git a/src/utils/writeClientClass.spec.ts b/src/utils/writeClientClass.spec.ts index 102f2eb57..9233dc4e5 100644 --- a/src/utils/writeClientClass.spec.ts +++ b/src/utils/writeClientClass.spec.ts @@ -33,6 +33,9 @@ describe('writeClientClass', () => { request: () => 'request', baseHttpRequest: () => 'baseHttpRequest', httpRequest: () => 'httpRequest', + utils: { + omitReadonly: () => 'omitReadonly', + }, }, }; diff --git a/src/utils/writeClientCore.spec.ts b/src/utils/writeClientCore.spec.ts index 36990054e..c3eef6856 100644 --- a/src/utils/writeClientCore.spec.ts +++ b/src/utils/writeClientCore.spec.ts @@ -35,10 +35,13 @@ describe('writeClientCore', () => { request: () => 'request', baseHttpRequest: () => 'baseHttpRequest', httpRequest: () => 'httpRequest', + utils: { + omitReadonly: () => 'omitReadonly', + }, }, }; - await writeClientCore(client, templates, '/', HttpClient.FETCH, Indent.SPACE_4); + await writeClientCore(client, templates, '/', '/utils', HttpClient.FETCH, Indent.SPACE_4); expect(writeFile).toBeCalledWith('/OpenAPI.ts', `settings${EOL}`); expect(writeFile).toBeCalledWith('/ApiError.ts', `apiError${EOL}`); @@ -46,5 +49,6 @@ describe('writeClientCore', () => { expect(writeFile).toBeCalledWith('/ApiResult.ts', `apiResult${EOL}`); expect(writeFile).toBeCalledWith('/CancelablePromise.ts', `cancelablePromise${EOL}`); expect(writeFile).toBeCalledWith('/request.ts', `request${EOL}`); + expect(writeFile).toBeCalledWith('/utils/OmitReadonly.ts', `omitReadonly${EOL}`); }); }); diff --git a/src/utils/writeClientCore.ts b/src/utils/writeClientCore.ts index 6d35849d2..74547335f 100644 --- a/src/utils/writeClientCore.ts +++ b/src/utils/writeClientCore.ts @@ -14,6 +14,7 @@ import type { Templates } from './registerHandlebarTemplates'; * @param client Client object, containing, models, schemas and services * @param templates The loaded handlebar templates * @param outputPath Directory to write the generated files to + * @param outputUtilsPath Directory to write the generated util files to * @param httpClient The selected httpClient (fetch, xhr, node or axios) * @param indent Indentation options (4, 2 or tab) * @param clientName Custom client class name @@ -23,6 +24,7 @@ export const writeClientCore = async ( client: Client, templates: Templates, outputPath: string, + outputUtilsPath: string, httpClient: HttpClient, indent: Indent, clientName?: string, @@ -43,6 +45,7 @@ export const writeClientCore = async ( await writeFile(resolve(outputPath, 'ApiResult.ts'), i(templates.core.apiResult(context), indent)); await writeFile(resolve(outputPath, 'CancelablePromise.ts'), i(templates.core.cancelablePromise(context), indent)); await writeFile(resolve(outputPath, 'request.ts'), i(templates.core.request(context), indent)); + await writeFile(resolve(outputUtilsPath, 'OmitReadonly.ts'), i(templates.core.utils.omitReadonly(context), indent)); if (isDefined(clientName)) { await writeFile(resolve(outputPath, 'BaseHttpRequest.ts'), i(templates.core.baseHttpRequest(context), indent)); diff --git a/src/utils/writeClientIndex.spec.ts b/src/utils/writeClientIndex.spec.ts index a74421115..53d34df12 100644 --- a/src/utils/writeClientIndex.spec.ts +++ b/src/utils/writeClientIndex.spec.ts @@ -31,6 +31,9 @@ describe('writeClientIndex', () => { request: () => 'request', baseHttpRequest: () => 'baseHttpRequest', httpRequest: () => 'httpRequest', + utils: { + omitReadonly: () => 'omitReadonly', + }, }, }; diff --git a/src/utils/writeClientModels.spec.ts b/src/utils/writeClientModels.spec.ts index e147c8e73..611c723ee 100644 --- a/src/utils/writeClientModels.spec.ts +++ b/src/utils/writeClientModels.spec.ts @@ -48,6 +48,9 @@ describe('writeClientModels', () => { request: () => 'request', baseHttpRequest: () => 'baseHttpRequest', httpRequest: () => 'httpRequest', + utils: { + omitReadonly: () => 'omitReadonly', + }, }, }; diff --git a/src/utils/writeClientSchemas.spec.ts b/src/utils/writeClientSchemas.spec.ts index f71286232..af6397f53 100644 --- a/src/utils/writeClientSchemas.spec.ts +++ b/src/utils/writeClientSchemas.spec.ts @@ -48,6 +48,9 @@ describe('writeClientSchemas', () => { request: () => 'request', baseHttpRequest: () => 'baseHttpRequest', httpRequest: () => 'httpRequest', + utils: { + omitReadonly: () => 'omitReadonly', + }, }, }; diff --git a/src/utils/writeClientServices.spec.ts b/src/utils/writeClientServices.spec.ts index b7ebbfe6c..835f3f08b 100644 --- a/src/utils/writeClientServices.spec.ts +++ b/src/utils/writeClientServices.spec.ts @@ -36,6 +36,9 @@ describe('writeClientServices', () => { request: () => 'request', baseHttpRequest: () => 'baseHttpRequest', httpRequest: () => 'httpRequest', + utils: { + omitReadonly: () => 'omitReadonly', + }, }, }; diff --git a/test/__snapshots__/index.spec.ts.snap b/test/__snapshots__/index.spec.ts.snap index eefa4ffe0..791dafae9 100644 --- a/test/__snapshots__/index.spec.ts.snap +++ b/test/__snapshots__/index.spec.ts.snap @@ -540,6 +540,57 @@ export const request = (config: OpenAPIConfig, options: ApiRequestOptions): C " `; +exports[`v2 should generate: ./test/generated/v2/core/utils/OmitReadonly.ts 1`] = ` +"/** + * The contents of this file are inspired from https://github.com/ts-essentials/ts-essentials#ReadonlyKeys + * + * The MIT License + * + * Copyright (c) 2018-2019 Chris Kaczor (github.com/krzkaczor) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * */ + +type Writable = { -readonly [P in keyof T]: T[P] }; + +type IsEqualConsideringWritability = (() => T extends X ? 1 : 2) extends () => T extends Y ? 1 : 2 + ? true + : false; + +type IsFullyWritable = IsEqualConsideringWritability< + { [Q in keyof T]: T[Q] }, + Writable<{ [Q in keyof T]: T[Q] }> +>; + +/** Gets keys of an object which are readonly */ +type ReadonlyKeys = { + [P in keyof T]-?: IsFullyWritable> extends true ? never : P; +}[keyof T]; + +/** + * Exclude keys of an object which are readonly + * In case of union types containing types not extending object, type is inferred as-is + * */ +export declare type OmitReadonly = T extends object ? Omit> : T; +" +`; + exports[`v2 should generate: ./test/generated/v2/index.ts 1`] = ` "/* istanbul ignore file */ /* tslint:disable */ @@ -2284,6 +2335,7 @@ exports[`v2 should generate: ./test/generated/v2/services/CollectionFormatServic import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class CollectionFormatService { @@ -2328,6 +2380,7 @@ import type { ModelWithString } from '../models/ModelWithString'; import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class ComplexService { @@ -2372,6 +2425,7 @@ exports[`v2 should generate: ./test/generated/v2/services/DefaultService.ts 1`] import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class DefaultService { @@ -2398,6 +2452,7 @@ import type { ModelWithString } from '../models/ModelWithString'; import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class DefaultsService { @@ -2444,7 +2499,7 @@ export class DefaultsService { parameterNumber: number = 123, parameterBoolean: boolean = true, parameterEnum: 'Success' | 'Warning' | 'Error' = 'Success', - parameterModel: ModelWithString = { + parameterModel: OmitReadonly = { "prop": "Hello World!" }, ): CancelablePromise { @@ -2509,6 +2564,7 @@ exports[`v2 should generate: ./test/generated/v2/services/DescriptionsService.ts import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class DescriptionsService { @@ -2557,6 +2613,7 @@ exports[`v2 should generate: ./test/generated/v2/services/DuplicateService.ts 1` import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class DuplicateService { @@ -2611,6 +2668,7 @@ exports[`v2 should generate: ./test/generated/v2/services/ErrorService.ts 1`] = import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class ErrorService { @@ -2648,6 +2706,7 @@ exports[`v2 should generate: ./test/generated/v2/services/HeaderService.ts 1`] = import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class HeaderService { @@ -2678,6 +2737,7 @@ exports[`v2 should generate: ./test/generated/v2/services/MultipleTags1Service.t import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class MultipleTags1Service { @@ -2714,6 +2774,7 @@ exports[`v2 should generate: ./test/generated/v2/services/MultipleTags2Service.t import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class MultipleTags2Service { @@ -2750,6 +2811,7 @@ exports[`v2 should generate: ./test/generated/v2/services/MultipleTags3Service.t import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class MultipleTags3Service { @@ -2775,6 +2837,7 @@ exports[`v2 should generate: ./test/generated/v2/services/NoContentService.ts 1` import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class NoContentService { @@ -2800,6 +2863,7 @@ exports[`v2 should generate: ./test/generated/v2/services/ParametersService.ts 1 import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class ParametersService { @@ -2895,6 +2959,7 @@ import type { ModelWithString } from '../models/ModelWithString'; import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class ResponseService { @@ -2959,6 +3024,7 @@ exports[`v2 should generate: ./test/generated/v2/services/SimpleService.ts 1`] = import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class SimpleService { @@ -3043,6 +3109,7 @@ exports[`v2 should generate: ./test/generated/v2/services/TypesService.ts 1`] = import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class TypesService { @@ -3633,6 +3700,57 @@ export const request = (config: OpenAPIConfig, options: ApiRequestOptions): C " `; +exports[`v3 should generate: ./test/generated/v3/core/utils/OmitReadonly.ts 1`] = ` +"/** + * The contents of this file are inspired from https://github.com/ts-essentials/ts-essentials#ReadonlyKeys + * + * The MIT License + * + * Copyright (c) 2018-2019 Chris Kaczor (github.com/krzkaczor) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * */ + +type Writable = { -readonly [P in keyof T]: T[P] }; + +type IsEqualConsideringWritability = (() => T extends X ? 1 : 2) extends () => T extends Y ? 1 : 2 + ? true + : false; + +type IsFullyWritable = IsEqualConsideringWritability< + { [Q in keyof T]: T[Q] }, + Writable<{ [Q in keyof T]: T[Q] }> +>; + +/** Gets keys of an object which are readonly */ +type ReadonlyKeys = { + [P in keyof T]-?: IsFullyWritable> extends true ? never : P; +}[keyof T]; + +/** + * Exclude keys of an object which are readonly + * In case of union types containing types not extending object, type is inferred as-is + * */ +export declare type OmitReadonly = T extends object ? Omit> : T; +" +`; + exports[`v3 should generate: ./test/generated/v3/index.ts 1`] = ` "/* istanbul ignore file */ /* tslint:disable */ @@ -6274,6 +6392,7 @@ exports[`v3 should generate: ./test/generated/v3/services/CollectionFormatServic import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class CollectionFormatService { @@ -6321,6 +6440,7 @@ import type { ModelWithString } from '../models/ModelWithString'; import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class ComplexService { @@ -6398,6 +6518,7 @@ exports[`v3 should generate: ./test/generated/v3/services/DefaultService.ts 1`] import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class DefaultService { @@ -6424,6 +6545,7 @@ import type { ModelWithString } from '../models/ModelWithString'; import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class DefaultsService { @@ -6470,7 +6592,7 @@ export class DefaultsService { parameterNumber: number = 123, parameterBoolean: boolean = true, parameterEnum: 'Success' | 'Warning' | 'Error' = 'Success', - parameterModel: ModelWithString = { + parameterModel: OmitReadonly = { "prop": "Hello World!" }, ): CancelablePromise { @@ -6537,6 +6659,7 @@ import type { DeprecatedModel } from '../models/DeprecatedModel'; import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class DeprecatedService { @@ -6546,7 +6669,7 @@ export class DeprecatedService { * @throws ApiError */ public static deprecatedCall( - parameter: DeprecatedModel | null, + parameter: OmitReadonly, ): CancelablePromise { return __request(OpenAPI, { method: 'POST', @@ -6568,6 +6691,7 @@ exports[`v3 should generate: ./test/generated/v3/services/DescriptionsService.ts import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class DescriptionsService { @@ -6616,6 +6740,7 @@ exports[`v3 should generate: ./test/generated/v3/services/DuplicateService.ts 1` import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class DuplicateService { @@ -6670,6 +6795,7 @@ exports[`v3 should generate: ./test/generated/v3/services/ErrorService.ts 1`] = import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class ErrorService { @@ -6709,6 +6835,7 @@ import type { ModelWithString } from '../models/ModelWithString'; import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class FormDataService { @@ -6719,7 +6846,7 @@ export class FormDataService { */ public static postApiFormData( parameter?: string, - formData?: ModelWithString, + formData?: OmitReadonly, ): CancelablePromise { return __request(OpenAPI, { method: 'POST', @@ -6743,6 +6870,7 @@ exports[`v3 should generate: ./test/generated/v3/services/HeaderService.ts 1`] = import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class HeaderService { @@ -6775,6 +6903,7 @@ import type { ModelWithString } from '../models/ModelWithString'; import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class MultipartService { @@ -6824,6 +6953,7 @@ exports[`v3 should generate: ./test/generated/v3/services/MultipleTags1Service.t import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class MultipleTags1Service { @@ -6860,6 +6990,7 @@ exports[`v3 should generate: ./test/generated/v3/services/MultipleTags2Service.t import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class MultipleTags2Service { @@ -6896,6 +7027,7 @@ exports[`v3 should generate: ./test/generated/v3/services/MultipleTags3Service.t import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class MultipleTags3Service { @@ -6921,6 +7053,7 @@ exports[`v3 should generate: ./test/generated/v3/services/NoContentService.ts 1` import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class NoContentService { @@ -6949,6 +7082,7 @@ import type { Pageable } from '../models/Pageable'; import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class ParametersService { @@ -6967,7 +7101,7 @@ export class ParametersService { parameterForm: string | null, parameterCookie: string | null, parameterPath: string | null, - requestBody: ModelWithString | null, + requestBody: OmitReadonly, ): CancelablePromise { return __request(OpenAPI, { method: 'POST', @@ -7009,7 +7143,7 @@ export class ParametersService { parameterQuery: string | null, parameterForm: string | null, parameterCookie: string | null, - requestBody: ModelWithString | null, + requestBody: OmitReadonly, parameterPath1?: string, parameterPath2?: string, parameterPath3?: string, @@ -7067,8 +7201,8 @@ export class ParametersService { * @throws ApiError */ public static postCallWithOptionalParam( - parameter: Pageable, - requestBody?: ModelWithString, + parameter: OmitReadonly, + requestBody?: OmitReadonly, ): CancelablePromise { return __request(OpenAPI, { method: 'POST', @@ -7094,6 +7228,7 @@ import type { ModelWithString } from '../models/ModelWithString'; import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class RequestBodyService { @@ -7104,7 +7239,7 @@ export class RequestBodyService { */ public static postApiRequestBody( parameter?: string, - requestBody?: ModelWithString, + requestBody?: OmitReadonly, ): CancelablePromise { return __request(OpenAPI, { method: 'POST', @@ -7132,6 +7267,7 @@ import type { ModelWithString } from '../models/ModelWithString'; import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class ResponseService { @@ -7196,6 +7332,7 @@ exports[`v3 should generate: ./test/generated/v3/services/SimpleService.ts 1`] = import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class SimpleService { @@ -7280,6 +7417,7 @@ exports[`v3 should generate: ./test/generated/v3/services/TypesService.ts 1`] = import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class TypesService { @@ -7337,6 +7475,7 @@ exports[`v3 should generate: ./test/generated/v3/services/UploadService.ts 1`] = import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; +import type { OmitReadonly } from '../core/utils/OmitReadonly'; export class UploadService {