From db9691fe04166f69d51ae2b4b017ad73878593dd Mon Sep 17 00:00:00 2001 From: Adam Basfop Cavendish Date: Mon, 9 Nov 2026 07:31:44 +0000 Subject: [PATCH] fix: emit TypeScript clients with stable Vite+ formatting - Lay out declarations, imports, unions, and converter expressions in the generator while retaining structural type references and import tracking. - Emit formatted runtime templates, Markdown examples, and JSON configuration, and regenerate the TypeScript golden files from their source emitters. - Enable full Vite+ checks directly on generated output before and after packing, with a fmt script for manual edits and dist excluded from formatting. --- CHANGELOG.md | 6 + docs/src/golden_testing.md | 16 +- docs/src/ts_config.md | 17 +- just/golden-typescript-clients.just | 4 +- scripts/golden-build-typescript.sh | 2 +- src/generators/typescript/fetch/codegen.rs | 143 +++- .../fetch/config/typescript_fetch_config.rs | 4 +- src/generators/typescript/fetch/layout.rs | 715 ++++++++++++++++ src/generators/typescript/fetch/mod.rs | 1 + .../typescript/fetch/project_files.rs | 51 +- .../fetch/project_files/README.md.txt | 16 +- .../fetch/project_files/runtime.ts.txt | 257 ++++-- src/generators/typescript/fetch/sigil_emit.rs | 364 +++++--- .../typescript/fetch/sigil_emit_api.rs | 240 +++--- tests/generated-clients/typescript/README.md | 9 +- .../additional-properties/README.md.golden | 14 +- .../apis/AdditionalPropertiesApi.ts.golden | 283 ++++-- .../additional-properties/package.json.golden | 34 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../api-interface/README.md.golden | 14 +- .../api-interface/apis/EntriesApi.ts.golden | 357 +++++--- .../api-interface/package.json.golden | 32 +- .../api-interface/runtime/runtime.ts.golden | 257 ++++-- .../api-interface/tsconfig.esm.json.golden | 2 +- .../api-interface/tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/TransferApi.ts.golden | 204 +++-- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../comprehensive-schemas/README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 52 +- ...ectWithTypedAdditionalProperties.ts.golden | 5 +- .../comprehensive-schemas/package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/TestResourceApi.ts.golden | 212 +++-- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../duplicate-param-names/README.md.golden | 14 +- .../apis/ItemsApi.ts.golden | 115 ++- .../apis/UsersApi.ts.golden | 132 ++- .../duplicate-param-names/package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../enum-repr/README.md.golden | 14 +- .../enum-repr/apis/EnumReprApi.ts.golden | 476 ++++++++--- .../models/AdjacentlyTaggedEnum.ts.golden | 4 +- .../models/ExternallyTaggedEnum.ts.golden | 4 +- .../models/InternallyTaggedEnum.ts.golden | 4 +- .../enum-repr/package.json.golden | 34 +- .../enum-repr/runtime/runtime.ts.golden | 257 ++++-- .../enum-repr/tsconfig.esm.json.golden | 2 +- .../enum-repr/tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../media-type-selection/README.md.golden | 14 +- .../apis/MediaApi.ts.golden | 407 ++++++--- .../media-type-selection/package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../media-type-selection/tsconfig.json.golden | 20 +- .../typescript-fetch/minimal/README.md.golden | 14 +- .../minimal/apis/DefaultApi.ts.golden | 57 +- .../minimal/package.json.golden | 32 +- .../minimal/runtime/runtime.ts.golden | 257 ++++-- .../minimal/tsconfig.esm.json.golden | 2 +- .../minimal/tsconfig.json.golden | 20 +- .../multipart-edge-cases/README.md.golden | 14 +- .../apis/MultipartApi.ts.golden | 158 ++-- .../multipart-edge-cases/package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../multipart-edge-cases/tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/TransferApi.ts.golden | 89 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/MultipartApi.ts.golden | 89 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/TransferApi.ts.golden | 86 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/TestApiApi.ts.golden | 159 ++-- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../naming-conventions/README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 163 ++-- .../naming-conventions/package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../naming-conventions/tsconfig.json.golden | 20 +- .../nested-nullable/README.md.golden | 14 +- .../nested-nullable/apis/ValuesApi.ts.golden | 190 +++-- .../nested-nullable/package.json.golden | 32 +- .../nested-nullable/runtime/runtime.ts.golden | 257 ++++-- .../nested-nullable/tsconfig.esm.json.golden | 2 +- .../nested-nullable/tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../models/Event.ts.golden | 4 +- .../models/ExternalEvent.ts.golden | 5 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../optional-request-bodies/README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 281 ++++-- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../petstore/README.md.golden | 14 +- .../petstore/apis/PetApi.ts.golden | 805 +++++++++++++----- .../petstore/apis/StoreApi.ts.golden | 399 ++++++--- .../petstore/apis/UserApi.ts.golden | 630 ++++++++++---- .../petstore/package.json.golden | 34 +- .../petstore/runtime/runtime.ts.golden | 257 ++++-- .../petstore/tsconfig.esm.json.golden | 2 +- .../petstore/tsconfig.json.golden | 20 +- .../query-param-enum/README.md.golden | 14 +- .../query-param-enum/apis/ItemsApi.ts.golden | 109 ++- .../query-param-enum/package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../query-param-enum/tsconfig.esm.json.golden | 2 +- .../query-param-enum/tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 52 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 52 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 52 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 52 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 52 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 52 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 52 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 52 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 52 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 52 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 52 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 52 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 52 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 52 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 52 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 52 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 56 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 552 ++++++++---- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/WidgetApi.ts.golden | 72 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../response-body-fallback/README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 177 ++-- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/WidgetApi.ts.golden | 98 ++- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/FooApi.ts.golden | 123 ++- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../response-dispatch/README.md.golden | 14 +- .../apis/ResponsesApi.ts.golden | 500 ++++++++--- .../response-dispatch/package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../response-dispatch/tsconfig.json.golden | 20 +- .../server-object/README.md.golden | 14 +- .../server-object/apis/DefaultApi.ts.golden | 184 ++-- .../server-object/package.json.golden | 34 +- .../server-object/runtime/runtime.ts.golden | 257 ++++-- .../server-object/tsconfig.esm.json.golden | 2 +- .../server-object/tsconfig.json.golden | 20 +- .../server-path-prefix/README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 196 +++-- .../server-path-prefix/package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../server-path-prefix/tsconfig.json.golden | 20 +- .../ts-enum-const/README.md.golden | 14 +- .../ts-enum-const/apis/DefaultApi.ts.golden | 61 +- .../ts-enum-const/package.json.golden | 32 +- .../ts-enum-const/runtime/runtime.ts.golden | 257 ++++-- .../ts-enum-const/tsconfig.esm.json.golden | 2 +- .../ts-enum-const/tsconfig.json.golden | 20 +- .../README.md.golden | 36 +- .../models/AliasArrayMap.ts.golden | 55 +- .../models/AliasMap.ts.golden | 50 +- .../models/AliasNullableMap.ts.golden | 55 +- .../models/AllOfJsonDictionary.ts.golden | 65 +- .../AllOfJsonDictionaryAllOf1.ts.golden | 8 +- .../models/AllOfMixedStringMap.ts.golden | 38 +- .../AllOfMixedStringMapAllOf1.ts.golden | 8 +- .../models/AllOfRenamedMap.ts.golden | 58 +- .../models/AllOfRenamedMapAllOf2.ts.golden | 66 +- .../models/ArrayModelMap.ts.golden | 55 +- .../models/ClosedExternalEvent.ts.golden | 12 +- .../models/HeterogeneousAllOf.ts.golden | 65 +- .../models/HeterogeneousAllOfAllOf1.ts.golden | 58 +- .../models/HeterogeneousAllOfAllOf2.ts.golden | 58 +- .../models/JsonModelAllOf.ts.golden | 50 +- .../models/JsonModelAllOfAllOf1.ts.golden | 54 +- .../models/JsonModelAllOfAllOf2.ts.golden | 54 +- .../models/MixedBooleanMap.ts.golden | 28 +- .../models/MixedExternalEvent.ts.golden | 38 +- .../models/MixedInlineAnyMap.ts.golden | 28 +- .../models/MixedJsonMap.ts.golden | 28 +- .../models/MixedModelMap.ts.golden | 50 +- .../models/MixedNumberMap.ts.golden | 28 +- .../models/MixedStringMap.ts.golden | 28 +- .../models/NestedModelMap.ts.golden | 63 +- .../models/NullableModelMap.ts.golden | 57 +- .../models/OpenExternalEvent.ts.golden | 56 +- .../models/PlainJsonMap.ts.golden | 6 +- .../models/PlainModelMap.ts.golden | 24 +- .../models/PlainStringMap.ts.golden | 6 +- .../models/QuotedMap.ts.golden | 64 +- .../models/RecursiveMap.ts.golden | 50 +- .../models/RenamedMap.ts.golden | 58 +- .../models/SearchItem.ts.golden | 36 +- .../models/SearchStreamEvent.ts.golden | 40 +- ...archStreamEventResponseCompleted.ts.golden | 12 +- ...ntResponseWebSearchCallSearching.ts.golden | 72 +- .../models/TypedExternalEvent.ts.golden | 59 +- .../models/index.ts.golden | 65 +- .../package.json.golden | 41 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../vite.config.ts.golden | 4 + .../README.md.golden | 14 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../models/ExternallyTaggedEnum.ts.golden | 16 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 91 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/MultipartApi.ts.golden | 89 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/ResponsesApi.ts.golden | 516 +++++++---- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/TestResourceApi.ts.golden | 226 +++-- .../CreateTestResourceResponse.ts.golden | 8 +- .../DeleteTestResourceResponse.ts.golden | 8 +- .../models/index.ts.golden | 20 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 21 +- .../apis/DefaultApi.ts.golden | 91 +- .../models/ScheduleRule.ts.golden | 28 +- .../models/ScheduleRuleCron.ts.golden | 4 +- .../models/ScheduleRuleInterval.ts.golden | 8 +- .../models/ScheduleRuleOnce.ts.golden | 4 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 36 +- .../apis/DefaultApi.ts.golden | 91 +- .../models/Setup.ts.golden | 28 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 15 +- .../apis/DefaultApi.ts.golden | 91 +- .../models/ContainerImage.ts.golden | 31 +- .../models/ContainerImageCustom.ts.golden | 4 +- .../models/ContainerImageManaged.ts.golden | 8 +- .../models/index.ts.golden | 5 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 91 +- .../models/Bar.ts.golden | 4 +- .../models/Baz.ts.golden | 4 +- .../models/Qux.ts.golden | 8 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 173 ++-- .../models/NamingConventionTest.ts.golden | 52 +- ...mingConventionTestItemsArrayItem.ts.golden | 8 +- ...NamingConventionTestNestedObject.ts.golden | 8 +- ...ngConventionTestPascalCaseObject.ts.golden | 8 +- .../models/index.ts.golden | 30 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 41 +- .../apis/DefaultApi.ts.golden | 91 +- .../models/FooAdjacentPayload.ts.golden | 73 +- .../FooAdjacentPayloadFooInlineNone.ts.golden | 12 +- ...yloadFooInlineObjectPayloadValue.ts.golden | 8 +- .../models/FooClosedVariant.ts.golden | 4 +- .../models/FooMappedTagUnion.ts.golden | 24 +- .../models/FooNullableItems.ts.golden | 6 +- .../models/FooNullableRefHolder.ts.golden | 4 +- .../models/FooOpenVariant.ts.golden | 28 +- .../models/FooTagOnlyUnion.ts.golden | 39 +- .../FooTagOnlyUnionFooUnitAlpha.ts.golden | 12 +- .../FooTagOnlyUnionFooUnitBeta.ts.golden | 12 +- .../models/FooTaggedRef.ts.golden | 11 +- .../models/index.ts.golden | 60 +- .../package.json.golden | 41 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../vite.config.ts.golden | 4 + .../README.md.golden | 30 +- .../apis/DefaultApi.ts.golden | 52 +- ...ectWithTypedAdditionalProperties.ts.golden | 5 +- .../package.json.golden | 41 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../vite.config.ts.golden | 4 + .../README.md.golden | 30 +- .../apis/TestResourceApi.ts.golden | 226 +++-- .../CreateTestResourceResponse.ts.golden | 8 +- .../DeleteTestResourceResponse.ts.golden | 8 +- .../models/index.ts.golden | 20 +- .../package.json.golden | 41 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../vite.config.ts.golden | 4 + .../README.md.golden | 30 +- .../apis/EnumReprApi.ts.golden | 476 ++++++++--- .../models/AdjacentlyTaggedEnum.ts.golden | 4 +- .../models/ExternallyTaggedEnum.ts.golden | 4 +- .../models/InternallyTaggedEnum.ts.golden | 4 +- .../package.json.golden | 43 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../vite.config.ts.golden | 4 + .../ts-toolchain-vp-petstore/README.md.golden | 30 +- .../apis/PetApi.ts.golden | 805 +++++++++++++----- .../apis/StoreApi.ts.golden | 399 ++++++--- .../apis/UserApi.ts.golden | 630 ++++++++++---- .../package.json.golden | 43 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../vite.config.ts.golden | 4 + .../README.md.golden | 30 +- .../apis/DefaultApi.ts.golden | 60 +- .../models/Foo.ts.golden | 6 +- .../package.json.golden | 41 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../vite.config.ts.golden | 4 + .../ts-toolchain-vp/README.md.golden | 31 +- .../ts-toolchain-vp/apis/DefaultApi.ts.golden | 91 +- .../models/ContainerImage.ts.golden | 31 +- .../models/ContainerImageCustom.ts.golden | 4 +- .../models/ContainerImageManaged.ts.golden | 8 +- .../ts-toolchain-vp/models/index.ts.golden | 5 +- .../ts-toolchain-vp/package.json.golden | 41 +- .../ts-toolchain-vp/runtime/runtime.ts.golden | 257 ++++-- .../ts-toolchain-vp/tsconfig.esm.json.golden | 2 +- .../ts-toolchain-vp/tsconfig.json.golden | 20 +- .../ts-toolchain-vp/vite.config.ts.golden | 4 + .../ts-type-guards/README.md.golden | 14 +- .../ts-type-guards/apis/DefaultApi.ts.golden | 83 +- .../ts-type-guards/models/AppEvent.ts.golden | 17 +- .../ts-type-guards/models/Shape.ts.golden | 8 +- .../ts-type-guards/package.json.golden | 32 +- .../ts-type-guards/runtime/runtime.ts.golden | 257 ++++-- .../ts-type-guards/tsconfig.esm.json.golden | 2 +- .../ts-type-guards/tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 87 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 26 +- .../apis/DefaultApi.ts.golden | 87 +- .../models/Event.ts.golden | 5 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 21 +- .../apis/DefaultApi.ts.golden | 87 +- .../models/Resource.ts.golden | 5 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 21 +- .../apis/DefaultApi.ts.golden | 92 +- ...dUnionTypeNameForTesting20260630.ts.golden | 5 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 21 +- .../apis/DefaultApi.ts.golden | 87 +- .../models/Setup.ts.golden | 5 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 15 +- .../apis/DefaultApi.ts.golden | 159 ++-- .../models/ContainerKind.ts.golden | 4 +- .../models/VolumeKind.ts.golden | 4 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 15 +- .../apis/DefaultApi.ts.golden | 87 +- .../models/ContainerImage.ts.golden | 4 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 87 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 20 +- .../apis/DefaultApi.ts.golden | 162 ++-- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 87 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 87 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../type-aliases-union-mixed/README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 87 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 87 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 89 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 87 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 14 +- .../apis/DefaultApi.ts.golden | 87 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../typed-error-responses/README.md.golden | 14 +- .../apis/ResourcesApi.ts.golden | 420 ++++++--- .../typed-error-responses/package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- .../README.md.golden | 20 +- .../models/AllOfJsonDictionary.ts.golden | 5 +- .../models/ClosedExternalEvent.ts.golden | 2 +- .../models/MixedExternalEvent.ts.golden | 6 +- .../models/OpenExternalEvent.ts.golden | 6 +- .../models/PlainJsonMap.ts.golden | 3 +- .../models/PlainModelMap.ts.golden | 3 +- .../models/PlainStringMap.ts.golden | 3 +- .../models/SearchStreamEvent.ts.golden | 6 +- ...ntResponseWebSearchCallSearching.ts.golden | 5 +- .../models/TypedExternalEvent.ts.golden | 6 +- .../package.json.golden | 32 +- .../runtime/runtime.ts.golden | 257 ++++-- .../tsconfig.esm.json.golden | 2 +- .../tsconfig.json.golden | 20 +- 647 files changed, 33592 insertions(+), 13711 deletions(-) create mode 100644 src/generators/typescript/fetch/layout.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index aa623f217..07d7e70a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Generate TypeScript source, runtime templates, Markdown examples, and JSON + configuration with formatting compatible with Vite+ checks. Lay out long + signatures, imports, unions, and converter expressions directly in Rust. + Enable full `vp check` and validate freshly generated clients before and after + packing, without a formatter preparation step. Exclude `dist/` from formatting + and provide a `fmt` script for manual edits. - Upgrade generated TypeScript clients to Vite+ `^1.5.0`, including Vite `8.3.5`, Vitest `5.1.0`, Rolldown `1.2.16`, Oxfmt `0.76.0`, Oxlint `1.91.0`, oxlint-tsgolint `7.0.2005`, and tsdown `0.23.4`. Pin CI validation and diff --git a/docs/src/golden_testing.md b/docs/src/golden_testing.md index 9d4ff1398..ad86ecf7c 100644 --- a/docs/src/golden_testing.md +++ b/docs/src/golden_testing.md @@ -47,7 +47,7 @@ CI materializes each golden directory into a temp folder (stripping the `.golden | Language | Command | Marker file | |----------|---------|-------------| -| TypeScript | `vp check --no-fmt && vp pack` or `tsc --noEmit` (see below) | `tsconfig.json.golden` | +| TypeScript | `vp check && vp pack && vp check` or `tsc --noEmit` (see below) | `tsconfig.json.golden` | | Go | `go build ./...` | `go.mod.golden` | | Rust | `cargo check` | `Cargo.toml.golden` | | Python | `pyright` | `pyproject.toml.golden` | @@ -61,7 +61,7 @@ This catches type errors that snapshot comparison alone cannot. The TypeScript golden build script selects the toolchain per-test based on whether `vite.config.ts.golden` exists in the test directory: -- **With `vite.config.ts`** — runs `vp install && vp check --no-fmt && vp pack`. This is the `toolchain = "vp"` path: installs deps, runs type-aware linting, then builds the library bundle. +- **With `vite.config.ts`** — runs `vp install && vp check && vp pack && vp check`. This is the `toolchain = "vp"` path: installs deps, checks the original generated files for formatting and type-aware linting/types, then builds the library bundle. The second check verifies that formatting still passes after packing; generated `dist/` output is excluded from formatting. - **Without `vite.config.ts`** — runs `tsc --noEmit`. This is the `toolchain = "tsc"` path: type-checks only. Both paths are always exercised in CI. Both `vp` and `tsc` must be available. @@ -121,9 +121,9 @@ just golden-build-all # all languages just golden-typescript-clients::test ``` -This generates fresh preserve/camelCase clients, validates and packs them with -Vite+, checks their packed declarations with strict TypeScript, and runs ordinary -Node tests against the real bundle. Full additional-property payload equality, +This generates fresh preserve/camelCase clients, validates, and packs +them with Vite+, checks their packed declarations with strict TypeScript, and +runs ordinary Node tests against the real bundle. Full additional-property payload equality, typed dictionary conversion, allOf and search-event composition, renamed-key collisions, optional-field absence, and prototype-sensitive keys are covered. The preserve client supplies type-contract coverage, not a second runtime @@ -131,8 +131,10 @@ conversion path (it does not emit converters). Generation, compilation, and execution are separate just recipes. Builds run in temporary directories so Vite+ does not skip gitignored generated sources; no -generated manifests or source files are patched. The consumer type check uses -the generated package's installed compiler rather than the global `tsc` selection. +generated manifests or source files receive compatibility patches or formatter +rewrites. Full `vp check` runs on the original generated output, then runs again +after packing. The consumer type check uses the generated package's installed +compiler rather than the global `tsc` selection. The current global Vite+ CLI also needs TypeScript installed alongside the CLI for declaration packing (`npm install -g typescript@7.0.2 vite-plus@1.5.0`). CI reuses that bootstrap and its generator cache in the existing TypeScript/Vite+ diff --git a/docs/src/ts_config.md b/docs/src/ts_config.md index 0ea57809a..125ef61aa 100644 --- a/docs/src/ts_config.md +++ b/docs/src/ts_config.md @@ -113,7 +113,7 @@ Variants with "UNSPECIFIED" in the discriminator value, discriminator values equ Selects the type checking and build toolchain. One of `"tsc"` (default) or `"vp"`. - `"tsc"` — bare TypeScript compiler. Generates `tsconfig.json` only. Build script: `tsc`. -- `"vp"` — vite-plus. Generates `vite.config.ts` with `pack` config for library output (ESM + .d.ts). Build script: `vp pack`. Check script: `vp check --no-fmt`. +- `"vp"` — vite-plus. Generates `vite.config.ts` with `pack` config for library output (ESM + .d.ts). Build script: `vp pack`. Format script: `vp fmt`. Check script: `vp check`. When `toolchain = "vp"`, the generated `package.json` includes `vite-plus` (`^1.5.0`) and `typescript` (`^7.0.2`) as dev dependencies, and scripts use `vp pack` (library mode) rather than `vp build` (app mode). @@ -124,6 +124,21 @@ component versions. Vite+ 1.5.0 requires Node.js `^22.18.0 || ^24.11.0 || >=26.0.0`. +After generating or regenerating a Vite+ client, run: + +```sh +vp install +vp check +vp pack +``` + +The generator emits sources, JSON, and Markdown using the configured single-quote +style and standard Oxfmt layout. `vp check` validates formatting, lint rules, and +types directly on these files without modifying them. No formatter is required +between generation and validation. Use `vp fmt` (or `npm run fmt`) for subsequent +manual edits. The generated configuration excludes `dist/`, so checks also pass +after packing. Generation itself requires only Rust, without Node.js or Vite+. + ```toml [generators.typescript-fetch] toolchain = "vp" diff --git a/just/golden-typescript-clients.just b/just/golden-typescript-clients.just index eac879ff5..de4dd655b 100644 --- a/just/golden-typescript-clients.just +++ b/just/golden-typescript-clients.just @@ -1,4 +1,4 @@ -# Native TypeScript consumer tests against fresh, unmodified generated clients. +# Native TypeScript consumer tests against freshly generated clients checked directly by Vite+. set working-directory := '..' @@ -20,7 +20,7 @@ set working-directory := '..' # Like golden builds, validate outside the ignored generated directory: # Vite+ otherwise skips every source file because of the repository ignore. tar --exclude=node_modules --exclude=dist -C "$output" -cf - . | tar -C "$build" -xf - - (cd "$build" && vp install && vp --version && vp check --no-fmt && vp pack) + (cd "$build" && vp install && vp --version && vp check && vp pack && vp check) mkdir -p "$output/dist" cp "$build"/dist/* "$output/dist/" done diff --git a/scripts/golden-build-typescript.sh b/scripts/golden-build-typescript.sh index 786f3115b..fadd775a3 100755 --- a/scripts/golden-build-typescript.sh +++ b/scripts/golden-build-typescript.sh @@ -46,7 +46,7 @@ for test_dir in "$golden"/*/; do log=$(mktemp) if [ "$toolchain" = "vp" ]; then - if (cd "$tmp" && vp install && vp check --no-fmt && vp pack) >>"$log" 2>&1; then + if (cd "$tmp" && vp install && vp check && vp pack && vp check) >>"$log" 2>&1; then echo "ok" passed=$((passed + 1)) else diff --git a/src/generators/typescript/fetch/codegen.rs b/src/generators/typescript/fetch/codegen.rs index 4a7cecfc3..e02a81186 100644 --- a/src/generators/typescript/fetch/codegen.rs +++ b/src/generators/typescript/fetch/codegen.rs @@ -2,6 +2,7 @@ use heck::{ToKebabCase as _, ToLowerCamelCase as _, ToPascalCase as _, ToSnakeCase as _}; +use super::layout::named_list; use sigil_stitch::lang::typescript::TypeScript; use super::config::TypeScriptFetchConfig; @@ -98,12 +99,15 @@ impl TypeScriptFetchCodeGenerator { if value_names.is_empty() { if extra_types.is_empty() { - exports.push(format!("export type {{ {type_name} }} from './{stem}';")); + exports.push(named_list( + "export type", + std::slice::from_ref(&type_name), + &format!("./{stem}"), + )); } else { let mut all_types = vec![type_name.clone()]; all_types.extend(extra_types); - let joined = all_types.join(", "); - exports.push(format!("export type {{ {joined} }} from './{stem}';")); + exports.push(named_list("export type", &all_types, &format!("./{stem}"))); } } else { let type_name_is_value = value_names.contains(&type_name); @@ -121,19 +125,20 @@ impl TypeScriptFetchCodeGenerator { // `export { X }` covers both the type and value sides. let mut all_names = vec![type_name.clone()]; all_names.extend(unique_values); - let joined = all_names.join(", "); - exports.push(format!("export {{ {joined} }} from './{stem}';")); + exports.push(named_list("export", &all_names, &format!("./{stem}"))); } else { // Type is separate from value exports. // Emit `export type { X, X$Wire }` for types and a separate // `export { xFromJSON, xToJSON }` for value exports. let mut all_types = vec![type_name.clone()]; all_types.extend(extra_types); - let type_joined = all_types.join(", "); - exports.push(format!("export type {{ {type_joined} }} from './{stem}';")); + exports.push(named_list("export type", &all_types, &format!("./{stem}"))); if !unique_values.is_empty() { - let joined = unique_values.join(", "); - exports.push(format!("export {{ {joined} }} from './{stem}';")); + exports.push(named_list( + "export", + &unique_values, + &format!("./{stem}"), + )); } } } @@ -142,7 +147,11 @@ impl TypeScriptFetchCodeGenerator { let type_name = model.name.to_pascal_case(); let filename = self.generate_filename(&model.name); let stem = filename.trim_end_matches(".ts"); - exports.push(format!("export type {{ {type_name} }} from './{stem}';")); + exports.push(named_list( + "export type", + std::slice::from_ref(&type_name), + &format!("./{stem}"), + )); } files.push(render_index_file(&ir.info, "models/index.ts", &exports)); } @@ -175,8 +184,9 @@ impl TypeScriptFetchCodeGenerator { for (schema_name, type_names) in imports { let filename = self.generate_filename(&schema_name); let stem = filename.trim_end_matches(".ts"); - let names = type_names.into_iter().collect::>().join(", "); - content.push_str(&format!("import type {{ {names} }} from './{stem}';\n")); + let names = type_names.into_iter().collect::>(); + content.push_str(&named_list("import type", &names, &format!("./{stem}"))); + content.push('\n'); } if needs_upload || !model.fields.is_empty() { content.push('\n'); @@ -226,7 +236,12 @@ impl TypeScriptFetchCodeGenerator { request_inputs.has_uploads(), )); - files.push(render_readme_file(ir)); + files.push(render_readme_file( + ir, + self.config.toolchain == Toolchain::Vp + && self.config.generate_package + && self.config.include_build_scripts, + )); let has_apis = !ir.operations.is_empty(); let has_models = @@ -317,10 +332,10 @@ impl TypeScriptFetchCodeGenerator { let license: Option = ir.info.license.as_ref().map(|l| l.name.clone()); let keywords = vec![ - "openapi".to_string(), "api-client".to_string(), - "typescript".to_string(), "generated".to_string(), + "openapi".to_string(), + "typescript".to_string(), ]; let package_name = self @@ -370,7 +385,8 @@ impl TypeScriptFetchCodeGenerator { Toolchain::Vp => { package_json["scripts"] = serde_json::json!({ "build": "vp pack", - "check": "vp check --no-fmt", + "check": "vp check", + "fmt": "vp fmt", }); package_json["devDependencies"] = serde_json::json!({ "typescript": "^7.0.2", @@ -380,8 +396,7 @@ impl TypeScriptFetchCodeGenerator { } } - let content = - serde_json::to_string_pretty(&package_json).unwrap_or_else(|_| "{}".to_string()); + let content = render_project_json(&package_json, true); FileInfo::project("package.json".to_string(), content) } @@ -411,7 +426,7 @@ impl TypeScriptFetchCodeGenerator { }); tsconfig["compilerOptions"]["lib"] = serde_json::json!(self.config.ts_lib); - let content = serde_json::to_string_pretty(&tsconfig).unwrap_or_else(|_| "{}".to_string()); + let content = render_project_json(&tsconfig, false); FileInfo::project("tsconfig.json".to_string(), content) } @@ -426,8 +441,7 @@ impl TypeScriptFetchCodeGenerator { } }); - let content = - serde_json::to_string_pretty(&tsconfig_esm).unwrap_or_else(|_| "{}".to_string()); + let content = render_project_json(&tsconfig_esm, false); FileInfo::project("tsconfig.esm.json".to_string(), content) } @@ -436,6 +450,10 @@ impl TypeScriptFetchCodeGenerator { let content = r#"import { defineConfig } from 'vite-plus'; export default defineConfig({ + fmt: { + singleQuote: true, + ignorePatterns: ['dist/**'], + }, lint: { options: { typeAware: true, @@ -592,19 +610,74 @@ impl FileWriter for TypeScriptFetchCodeGenerator {} /// single-line form fits within ~100 cols, else break each name onto its own /// line. Keeps short barrels dense and long ones scannable. fn format_named_reexport(kind: &str, names: &[String], filename_base: &str) -> String { - let one_line = format!( - "{} {{ {} }} from './{}';", - kind, - names.join(", "), - filename_base - ); - if names.len() <= 1 || one_line.len() <= 100 { - return one_line; - } - let mut out = format!("{} {{\n", kind); - for name in names { - out.push_str(&format!(" {},\n", name)); + named_list(kind, names, &format!("./{filename_base}")) +} + +/// Emit JSON with compact configuration arrays and npm's manifest field order. +fn render_project_json(value: &serde_json::Value, package: bool) -> String { + fn render(value: &serde_json::Value, depth: usize, package: bool) -> String { + let pad = " ".repeat(depth); + let inner_pad = " ".repeat(depth + 1); + match value { + serde_json::Value::Object(map) if !map.is_empty() => { + let mut keys = map.keys().collect::>(); + if package && depth == 0 { + let order = [ + "name", + "version", + "description", + "keywords", + "license", + "files", + "type", + "main", + "types", + "exports", + "scripts", + "devDependencies", + ]; + keys.sort_by_key(|key| { + order + .iter() + .position(|known| known == &key.as_str()) + .unwrap_or(order.len()) + }); + } + let entries = keys + .into_iter() + .map(|key| { + format!( + "{inner_pad}{}: {}", + serde_json::to_string(key).expect("JSON key"), + render(&map[key], depth + 1, package) + ) + }) + .collect::>(); + format!("{{\n{}\n{pad}}}", entries.join(",\n")) + } + serde_json::Value::Array(items) if !items.is_empty() => { + if !package { + format!( + "[{}]", + items + .iter() + .map(|item| serde_json::to_string(item).expect("JSON value")) + .collect::>() + .join(", ") + ) + } else { + format!( + "[\n{}\n{pad}]", + items + .iter() + .map(|item| format!("{inner_pad}{}", render(item, depth + 1, package))) + .collect::>() + .join(",\n") + ) + } + } + _ => serde_json::to_string(value).expect("JSON value"), + } } - out.push_str(&format!("}} from './{}';", filename_base)); - out + format!("{}\n", render(value, 0, package)) } diff --git a/src/generators/typescript/fetch/config/typescript_fetch_config.rs b/src/generators/typescript/fetch/config/typescript_fetch_config.rs index 3af9d2313..7aa3ad577 100644 --- a/src/generators/typescript/fetch/config/typescript_fetch_config.rs +++ b/src/generators/typescript/fetch/config/typescript_fetch_config.rs @@ -22,7 +22,7 @@ pub enum PropertyNaming { /// Toolchain for type checking and building. /// /// `Tsc` uses bare `tsc` (default). -/// `Vp` uses vite-plus (`vp check --no-fmt`) with type-aware linting. +/// `Vp` uses vite-plus (`vp check`) with formatting and type-aware linting. #[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum Toolchain { @@ -92,7 +92,7 @@ pub struct TypeScriptFetchConfig { /// Toolchain for type checking and building. /// /// - `tsc` (default): bare TypeScript compiler. - /// - `vp`: vite-plus with type-aware linting and type checking. + /// - `vp`: vite-plus with formatting, type-aware linting, and type checking. #[serde(default)] pub toolchain: Toolchain, diff --git a/src/generators/typescript/fetch/layout.rs b/src/generators/typescript/fetch/layout.rs new file mode 100644 index 000000000..b89745362 --- /dev/null +++ b/src/generators/typescript/fetch/layout.rs @@ -0,0 +1,715 @@ +//! Layout of the TypeScript declarations emitted by this generator. +//! +//! Keep structural type references until sigil-stitch resolves imports. Layout +//! decisions use declaration parts, never reparsed generated source. + +use sigil_stitch::code_block::{Arg, CodeBlock}; +use sigil_stitch::error::SigilStitchError; +use sigil_stitch::import::ImportGroup; +use sigil_stitch::lang::capability::{FunctionContext, FunctionForm, LanguageCapabilities}; +use sigil_stitch::lang::{CodeLang, RendererLang}; +use sigil_stitch::spec::modifiers::{DeclarationContext, TypeKind, Visibility}; +use sigil_stitch::type_name::TypeName; + +const WIDTH: usize = 100; + +#[derive(Debug, Clone)] +pub struct TypeScript(sigil_stitch::lang::typescript::TypeScript); + +impl TypeScript { + fn width(&self, block: &CodeBlock) -> usize { + block + .render_standalone(&self.0, usize::MAX) + .expect("valid TypeScript fragment") + .lines() + .next() + .unwrap_or("") + .chars() + .count() + } +} + +impl RendererLang for TypeScript { + fn lower_type_name( + &self, + type_name: &sigil_stitch::type_name::TypeName, + ) -> Result { + let mut block = self.0.lower_type_name(type_name)?; + fn flatten(nodes: &mut [sigil_stitch::code_node::CodeNode]) { + use sigil_stitch::code_node::CodeNode; + for node in nodes { + match node { + CodeNode::SoftBreak => *node = CodeNode::Literal(" ".into()), + CodeNode::Nested(block) => flatten(block.nodes_mut()), + CodeNode::Sequence(children) => flatten(children), + _ => {} + } + } + } + flatten(block.nodes_mut()); + Ok(block) + } + fn file_extension(&self) -> &str { + self.0.file_extension() + } + fn reserved_words(&self) -> &[&str] { + self.0.reserved_words() + } + fn render_string_literal(&self, s: &str) -> String { + self.0.render_string_literal(s) + } + fn render_verbatim_string(&self, s: &str) -> String { + self.0.render_verbatim_string(s) + } + fn line_comment_prefix(&self) -> &str { + self.0.line_comment_prefix() + } + fn indent_unit(&self) -> &str { + self.0.indent_unit() + } + fn render_statement_end(&self) -> Result<&str, sigil_stitch::error::SigilStitchError> { + self.0.render_statement_end() + } + fn render_block_open( + &self, + _intent: sigil_stitch::code_node::BlockIntent, + _condition: &str, + ) -> Result<&str, sigil_stitch::error::SigilStitchError> { + self.0.render_block_open(_intent, _condition) + } + fn render_block_close( + &self, + _intent: sigil_stitch::code_node::BlockIntent, + _condition: &str, + ) -> Result<&str, sigil_stitch::error::SigilStitchError> { + self.0.render_block_close(_intent, _condition) + } + fn render_branch_transition( + &self, + _intent: sigil_stitch::code_node::BlockIntent, + _condition: &str, + ) -> Result { + self.0.render_branch_transition(_intent, _condition) + } +} + +impl CodeLang for TypeScript { + fn validate_function( + &self, + function: sigil_stitch::lang::FunctionIntent<'_>, + ) -> Result<(), SigilStitchError> { + self.0.validate_function(function) + } + fn validate_resolved_imports( + &self, + imports: &sigil_stitch::import::ImportGroup, + ) -> Result<(), sigil_stitch::error::SigilStitchError> { + self.0.validate_resolved_imports(imports) + } + fn capabilities(&self) -> LanguageCapabilities<'_> { + self.0.capabilities() + } + fn validate_type( + &self, + type_: sigil_stitch::lang::TypeIntent<'_>, + ) -> Result<(), SigilStitchError> { + self.0.validate_type(type_) + } + fn validate_fields( + &self, + fields: sigil_stitch::lang::FieldSequenceIntent<'_>, + ) -> Result<(), SigilStitchError> { + self.0.validate_fields(fields) + } + fn collect_field_validation_errors( + &self, + fields: sigil_stitch::lang::FieldSequenceIntent<'_>, + errors: &mut Vec, + ) { + self.0.collect_field_validation_errors(fields, errors) + } + fn validate_property( + &self, + property: sigil_stitch::lang::PropertyIntent<'_>, + ) -> Result<(), SigilStitchError> { + self.0.validate_property(property) + } + fn collect_property_validation_errors( + &self, + property: sigil_stitch::lang::PropertyIntent<'_>, + errors: &mut Vec, + ) { + self.0.collect_property_validation_errors(property, errors) + } + fn lower_property( + &self, + property: sigil_stitch::lang::ValidatedProperty<'_>, + ) -> Result, SigilStitchError> { + self.0.lower_property(property) + } + fn validate_type_members( + &self, + members: sigil_stitch::lang::TypeMembersIntent<'_>, + ) -> Result<(), SigilStitchError> { + self.0.validate_type_members(members) + } + fn collect_type_members_validation_errors( + &self, + members: sigil_stitch::lang::TypeMembersIntent<'_>, + errors: &mut Vec, + ) { + self.0 + .collect_type_members_validation_errors(members, errors) + } + fn lower_variants( + &self, + variants: sigil_stitch::lang::ValidatedVariants<'_>, + ) -> Result { + self.0.lower_variants(variants) + } + fn validate_function_type_constraints( + &self, + function_name: &str, + type_params: &[sigil_stitch::spec::where_spec::GenericParamView<'_>], + constraints: &[sigil_stitch::spec::where_spec::WhereConstraint], + ) -> Result<(), SigilStitchError> { + self.0 + .validate_function_type_constraints(function_name, type_params, constraints) + } + fn constructor_name_matches(&self, name: &str, _declaring_type: Option<&str>) -> bool { + self.0.constructor_name_matches(name, _declaring_type) + } + fn static_constructor_name_matches(&self, _name: &str, _declaring_type: Option<&str>) -> bool { + self.0 + .static_constructor_name_matches(_name, _declaring_type) + } + fn function_visibility_is_valid( + &self, + context: FunctionContext, + _form: FunctionForm, + _is_static: bool, + visibility: Visibility, + ) -> bool { + self.0 + .function_visibility_is_valid(context, _form, _is_static, visibility) + } + fn function_parameters_require_trailing_defaults( + &self, + _context: FunctionContext, + _form: FunctionForm, + ) -> bool { + self.0 + .function_parameters_require_trailing_defaults(_context, _form) + } + fn constructor_name_is_valid(&self, name: &str, _declaring_type: Option<&str>) -> bool { + self.0.constructor_name_is_valid(name, _declaring_type) + } + fn escape_field_name(&self, name: &str) -> String { + self.0.escape_field_name(name) + } + fn render_doc_comment(&self, lines: &[&str]) -> String { + self.0.render_doc_comment(lines) + } + fn render_visibility(&self, vis: Visibility, ctx: DeclarationContext) -> &str { + self.0.render_visibility(vis, ctx) + } + + fn render_imports(&self, imports: &ImportGroup) -> String { + if imports + .entries() + .iter() + .any(|entry| entry.is_side_effect || entry.is_wildcard) + { + return self.0.render_imports(imports); + } + let mut modules = std::collections::BTreeMap::<&str, (Vec, Vec)>::new(); + for entry in imports.entries() { + let names = modules.entry(&entry.module).or_default(); + let name = entry.alias.as_ref().map_or_else( + || entry.name.clone(), + |alias| format!("{} as {alias}", entry.name), + ); + if entry.is_type_only { + names.0.push(name); + } else { + names.1.push(name); + } + } + let mut lines = Vec::new(); + for (module, (mut types, mut values)) in modules { + types.sort(); + values.sort(); + for (prefix, names) in [("import type", types), ("import", values)] { + if !names.is_empty() { + lines.push(named_list(prefix, &names, module)); + } + } + } + lines.join("\n") + } + + fn lower_type( + &self, + ty: sigil_stitch::lang::ValidatedType<'_>, + ) -> Result, SigilStitchError> { + // These constructs are not emitted by this generator. Preserve the base + // language's complete lowering if a caller supplies one in the future. + if ty.generic_params().next().is_some() + || !ty.properties().is_empty() + || ty.variants().is_some() + || !ty.primary_constructor_parameters().is_empty() + || ty.modifiers().is_abstract + { + return self.0.lower_type(ty); + } + let mut cb = CodeBlock::builder(); + if !ty.doc().is_empty() { + cb.add( + "%L\n", + self.render_doc_comment(&ty.doc().iter().map(String::as_str).collect::>()), + ); + } + for annotation in ty.annotation_specs() { + cb.add_code(annotation.emit_with_syntax("@", "")?); + cb.add_line(); + } + for annotation in ty.annotations() { + cb.add_code(annotation.clone()); + cb.add_line(); + } + let export = if ty.modifiers().visibility == Visibility::Public { + "export " + } else { + "" + }; + if ty.kind() == TypeKind::TypeAlias { + let prefix = format!("{export}type {} =", ty.name()); + let target = ty.target_type().expect("validated alias target"); + cb.add("%L", prefix.as_str()); + cb.add_code(self.type_expression(target, prefix.chars().count() + 1, 0)?); + cb.add(";\n", ()); + return Ok(vec![cb.build()?]); + } + let keyword = match ty.kind() { + TypeKind::Interface | TypeKind::Trait => "interface", + TypeKind::Enum => "enum", + _ => "class", + }; + cb.add( + "%L", + format!( + "{export}{keyword}{} {}", + if ty.modifiers().is_abstract { + " abstract" + } else { + "" + }, + ty.name() + ), + ); + for (connector, bases) in [ + (" extends ", ty.nominal_super_types()), + (" implements ", ty.implemented_types()), + ] { + if !bases.is_empty() { + cb.add(connector, ()); + for (i, base) in bases.iter().enumerate() { + if i > 0 { + cb.add(", ", ()); + } + cb.add_code(self.type_part( + base, + export.len() + keyword.len() + ty.name().len() + connector.len() + 1, + 0, + )?); + } + } + } + if ty.fields().is_none_or(|fields| fields.fields().is_empty()) + && ty.methods().is_empty() + && ty.extra_members().is_empty() + { + cb.add(" {}\n", ()); + return Ok(vec![cb.build()?]); + } + cb.add(" {\n%>", ()); + if let Some(fields) = ty.fields() { + cb.add_code(self.lower_fields(fields.clone())?); + } + if !ty.methods().is_empty() && ty.fields().is_some_and(|f| !f.fields().is_empty()) { + cb.add_line(); + } + for (i, method) in ty.methods().iter().enumerate() { + if i > 0 { + cb.add_line(); + } + cb.add_code(self.lower_function(*method)?); + } + for member in ty.extra_members() { + cb.add_code(member.clone()); + } + cb.add("%<}\n", ()); + Ok(vec![cb.build()?]) + } + + fn lower_fields( + &self, + fields: sigil_stitch::lang::ValidatedFields<'_>, + ) -> Result { + if fields.fields().iter().any(|field| { + !field.annotations().is_empty() + || !field.annotation_specs().is_empty() + || !matches!( + field.modifiers().visibility, + Visibility::Public | Visibility::Inherited + ) + }) { + return self.0.lower_fields(fields); + } + let mut cb = CodeBlock::builder(); + for field in fields.fields() { + if !field.doc().is_empty() { + cb.add( + "%L\n", + self.render_doc_comment( + &field.doc().iter().map(String::as_str).collect::>(), + ), + ); + } + let prefix = format!( + "{}{}{}{}:", + if field.modifiers().is_static { + "static " + } else { + "" + }, + if field.modifiers().is_readonly { + "readonly " + } else { + "" + }, + field.name(), + if field.is_optional() { "?" } else { "" } + ); + cb.add("%L", prefix.as_str()); + cb.add_code(self.type_expression( + field.field_type(), + prefix.chars().count() + self.indent_unit().len() + 1, + 1, + )?); + if let Some(initializer) = field.initializer() { + cb.add(" = %L", initializer.clone()); + } + cb.add(";\n", ()); + } + cb.build() + } + + fn lower_function( + &self, + function: sigil_stitch::lang::ValidatedFunction<'_>, + ) -> Result { + if function.generic_params().next().is_some() + || !function.annotations().is_empty() + || !function.annotation_specs().is_empty() + || function.delegation().is_some() + || function.modifiers().is_abstract + || function.modifiers().is_override + || function.parameters().iter().any(|parameter| { + parameter.is_property() + || parameter.is_mutable_property() + || parameter.is_variadic() + }) + { + return self.0.lower_function(function); + } + let mut cb = CodeBlock::builder(); + if !function.doc().is_empty() { + cb.add( + "%L\n", + self.render_doc_comment( + &function + .doc() + .iter() + .map(String::as_str) + .collect::>(), + ), + ); + } + let top = function.declaration_context() == DeclarationContext::TopLevel; + let prefix = format!( + "{}{}{}{}{}", + self.render_visibility( + function.modifiers().visibility, + function.declaration_context() + ), + if function.modifiers().is_static { + "static " + } else { + "" + }, + if function.modifiers().is_async { + "async " + } else { + "" + }, + if top && function.form() != FunctionForm::Constructor { + "function " + } else { + "" + }, + function.name() + ); + let mut parameters = Vec::new(); + for parameter in function.parameters() { + let mut p = CodeBlock::builder(); + if parameter.is_variadic() { + p.add("...", ()); + } + p.add("%L", parameter.name()); + if !parameter.param_type().is_empty() { + p.add(": %T", parameter.param_type().clone()); + } + if let Some(default) = parameter.default_value() { + p.add(" = %L", inline(default.clone())); + } + parameters.push(p.build()?); + } + let mut suffix = CodeBlock::builder(); + suffix.add(")", ()); + for text in function.suffixes() { + suffix.add(" %L", text.as_str()); + } + if let Some(returns) = function.returns() { + if let Some(ty) = returns.first() { + suffix.add(": %T", ty.clone()); + } else { + suffix.add(": void", ()); + } + } + suffix.add(if function.body().is_some() { " {" } else { ";" }, ()); + let suffix = suffix.build()?; + let width = (if top { 0 } else { self.indent_unit().len() }) + + prefix.chars().count() + + 1 + + parameters.iter().map(|p| self.width(p)).sum::() + + parameters.len().saturating_sub(1) * 2 + + self.width(&suffix); + let multiline = !parameters.is_empty() && width > WIDTH; + cb.add("%L(", prefix); + if multiline { + cb.add("\n%>", ()); + } + for (i, parameter) in parameters.into_iter().enumerate() { + if i > 0 && !multiline { + cb.add(", ", ()); + } + cb.add_code(parameter); + if multiline { + cb.add(",\n", ()); + } + } + if multiline { + cb.add("%<", ()); + } + cb.add_code(suffix); + cb.add_line(); + if let Some(body) = function.body() { + cb.add("%>", ()); + cb.add_code(body.clone()); + if !body.ends_with_newline_or_block_close() { + cb.add_line(); + } + cb.add("%<}\n", ()); + } + cb.build() + } +} + +/// Import and barrel export lists share the same line-width policy. +pub(super) fn named_list(prefix: &str, names: &[String], module: &str) -> String { + let quoted = sigil_stitch::lang::typescript::TypeScript::new().render_string_literal(module); + let inline = format!("{prefix} {{ {} }} from {quoted};", names.join(", ")); + if names.len() <= 1 || inline.chars().count() <= WIDTH { + inline + } else { + format!( + "{prefix} {{\n{}}} from {quoted};", + names + .iter() + .map(|name| format!(" {name},\n")) + .collect::() + ) + } +} + +impl TypeScript { + fn type_part( + &self, + ty: &TypeName, + column: usize, + depth: usize, + ) -> Result { + let fragment = CodeBlock::of("%T", ty.clone())?; + if column + self.width(&fragment) + 2 <= WIDTH { + return Ok(fragment); + } + if let TypeName::Application { base, arguments } = ty { + use sigil_stitch::spec::where_spec::TypeArgument; + let mut cb = CodeBlock::builder(); + cb.add("%T<\n%>", *base.clone()); + for (i, arg) in arguments.iter().enumerate() { + if i > 0 { + cb.add(",\n", ()); + } + let TypeArgument::Single(ty) = arg else { + return Ok(fragment); + }; + cb.add_code(self.type_part( + ty, + (depth + 1) * self.indent_unit().len(), + depth + 1, + )?); + } + cb.add("\n%<>", ()); + return cb.build(); + } + Ok(fragment) + } + + fn type_expression( + &self, + ty: &TypeName, + column: usize, + depth: usize, + ) -> Result { + let inline = CodeBlock::of("%T", ty.clone())?; + if let TypeName::Callable { + parameters, + returns, + } = ty + && column + self.width(&inline) > WIDTH + { + use sigil_stitch::spec::where_spec::{CallableParam, CallableParamPresence}; + let mut cb = CodeBlock::builder(); + cb.add(" (\n%>", ()); + for parameter in parameters { + let CallableParam::Single { + name, + type_name, + presence, + } = parameter + else { + return CodeBlock::of(" %T", ty.clone()); + }; + cb.add( + "%L%L: %T,\n", + vec![ + Arg::Literal(name.clone().unwrap_or_else(|| "arg".into())), + Arg::Literal(if *presence == CallableParamPresence::Optional { + "?".into() + } else { + String::new() + }), + Arg::TypeName(type_name.clone()), + ], + ); + } + cb.add( + "%<) => %T", + returns + .first() + .cloned() + .unwrap_or_else(|| TypeName::primitive("void")), + ); + return cb.build(); + } + if column + self.width(&inline) <= WIDTH || !matches!(ty, TypeName::Union(_)) { + let mut cb = CodeBlock::builder(); + cb.add(" ", ()); + cb.add_code(self.type_part(ty, column, depth)?); + return cb.build(); + } + let TypeName::Union(members) = ty else { + unreachable!() + }; + let mut cb = CodeBlock::builder(); + cb.add("\n%>", ()); + for (i, member) in members.iter().enumerate() { + if i > 0 { + cb.add_line(); + } + if let TypeName::Intersection(parts) = member { + cb.add("| (", ()); + let multiline = 5 + self.width(&CodeBlock::of("%T", member.clone())?) > WIDTH; + for (i, part) in parts.iter().enumerate() { + if i > 0 { + cb.add(if multiline { " &\n%>%>" } else { " & " }, ()); + } + cb.add("%T", part.clone()); + if multiline && i > 0 { + cb.add("%<%<", ()); + } + } + cb.add(")", ()); + } else { + cb.add("| %T", member.clone()); + } + } + cb.add("%<", ()); + cb.build() + } +} + +/// Compose an expression without the statement newline added by a quoted block. +pub(super) fn inline(mut block: CodeBlock) -> CodeBlock { + fn trim(nodes: &mut Vec) { + use sigil_stitch::code_node::CodeNode; + match nodes.last_mut() { + Some(CodeNode::Newline) => { + nodes.pop(); + } + Some(CodeNode::Sequence(children)) => trim(children), + Some(CodeNode::Nested(block)) => trim(block.nodes_mut()), + _ => {} + } + } + trim(block.nodes_mut()); + block +} + +pub(super) fn fragment_width(block: &CodeBlock) -> usize { + block + .render_standalone( + &sigil_stitch::lang::typescript::TypeScript::new(), + usize::MAX, + ) + .expect("valid TypeScript fragment") + .lines() + .next() + .unwrap_or("") + .chars() + .count() +} + +pub(super) fn return_object(fields: &[String], cast: Option<&str>, column: usize) -> String { + let suffix = cast.map_or_else(String::new, |ty| format!(" as {ty}")); + let inline = format!("return {{ {} }}{suffix};", fields.join(", ")); + if column + inline.chars().count() <= WIDTH { + inline + } else { + format!( + "return {{\n{}}}{suffix};", + fields + .iter() + .map(|field| format!(" {field},\n")) + .collect::() + ) + } +} + +impl From for TypeScript { + fn from(lang: sigil_stitch::lang::typescript::TypeScript) -> Self { + Self(lang) + } +} diff --git a/src/generators/typescript/fetch/mod.rs b/src/generators/typescript/fetch/mod.rs index 62d800561..68c82f674 100644 --- a/src/generators/typescript/fetch/mod.rs +++ b/src/generators/typescript/fetch/mod.rs @@ -1,5 +1,6 @@ pub mod codegen; pub mod config; +mod layout; pub mod project_files; pub mod sigil_emit; pub mod sigil_emit_api; diff --git a/src/generators/typescript/fetch/project_files.rs b/src/generators/typescript/fetch/project_files.rs index 221f53588..06d79cf20 100644 --- a/src/generators/typescript/fetch/project_files.rs +++ b/src/generators/typescript/fetch/project_files.rs @@ -2,6 +2,7 @@ use heck::ToKebabCase as _; use heck::ToPascalCase as _; +use sigil_stitch::lang::RendererLang as _; use crate::codegen::traits::file_writer::FileInfo; use crate::ir::types::{IrInfo, IrSpec}; @@ -84,14 +85,17 @@ pub fn render_runtime_file(info: &IrInfo, base_path: &str, include_upload_file: }; content.push_str( &RUNTIME_TS_BODY - .replace("{{BASE_PATH}}", base_path) + .replace( + "{{BASE_PATH_LITERAL}}", + &sigil_stitch::lang::typescript::TypeScript::new().render_string_literal(base_path), + ) .replace("{{UPLOAD_FILE_HELPERS}}", &upload_helpers), ); FileInfo::runtime("runtime.ts".to_string(), content) } /// Render the top-level `README.md`. -pub fn render_readme_file(ir: &IrSpec) -> FileInfo { +pub fn render_readme_file(ir: &IrSpec, include_vp_scripts: bool) -> FileInfo { let title = ir.info.title.as_str(); let version = ir.info.version.as_str(); let description = ir @@ -100,12 +104,51 @@ pub fn render_readme_file(ir: &IrSpec) -> FileInfo { .as_deref() .unwrap_or("Generated API client"); let package_name = title.to_kebab_case(); + let toolchain_checks = if include_vp_scripts { + "### Formatting and validation\n\n\ + After generating or regenerating this client, install its development dependencies,\n\ + run all checks on the generated files and build the library:\n\n\ + ```bash\n\ + vp install\n\ + vp check\n\ + vp pack\n\ + ```\n\n\ + The `check` and `build` npm scripts run the same Vite+ commands.\n\ + Use `vp fmt` (or the `fmt` script) to format any subsequent manual edits.\n\ + `vp check` validates formatting, lint rules, and types without modifying files.\n\ + Build output in `dist/` is excluded from formatting.\n\n" + } else { + "" + }; - let content = README_MD_BODY + let mut content = README_MD_BODY.to_string(); + for names in [ + vec!["Configuration", "{{EXAMPLE_API_CLASS}}"], + vec!["Configuration", "Middleware"], + vec!["ResponseError", "FetchError", "RequiredError"], + vec!["User", "CreateUserRequest"], + ] { + let type_only = names[0] == "User"; + let prefix = if type_only { "import type" } else { "import" }; + let template = format!( + "{prefix} {{ {} }} from '{{{{PACKAGE_NAME}}}}';", + names.join(", ") + ); + let names = names + .iter() + .map(|name| name.replace("{{EXAMPLE_API_CLASS}}", &pick_example_api_class(ir))) + .collect::>(); + content = content.replace( + &template, + &super::layout::named_list(prefix, &names, &package_name), + ); + } + let content = content .replace("{{PACKAGE_NAME}}", &package_name) - .replace("{{DESCRIPTION}}", description) + .replace("{{DESCRIPTION}}", description.trim_end()) .replace("{{VERSION}}", version) .replace("{{TITLE}}", title) + .replace("{{TOOLCHAIN_CHECKS}}", toolchain_checks) .replace("{{EXAMPLE_API_CLASS}}", &pick_example_api_class(ir)); FileInfo::readme("README.md".to_string(), content) diff --git a/src/generators/typescript/fetch/project_files/README.md.txt b/src/generators/typescript/fetch/project_files/README.md.txt index 956c26f05..b8e25806c 100644 --- a/src/generators/typescript/fetch/project_files/README.md.txt +++ b/src/generators/typescript/fetch/project_files/README.md.txt @@ -52,8 +52,8 @@ import { Configuration, {{EXAMPLE_API_CLASS}} } from '{{PACKAGE_NAME}}'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -190,7 +190,7 @@ To build ES modules: npm run build ``` -## TypeScript Support +{{TOOLCHAIN_CHECKS}}## TypeScript Support This package includes TypeScript type definitions. No additional `@types` package is needed. @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from '{{PACKAGE_NAME}}'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/src/generators/typescript/fetch/project_files/runtime.ts.txt b/src/generators/typescript/fetch/project_files/runtime.ts.txt index a44946025..fe6e2a185 100644 --- a/src/generators/typescript/fetch/project_files/runtime.ts.txt +++ b/src/generators/typescript/fetch/project_files/runtime.ts.txt @@ -1,4 +1,4 @@ -export const BASE_PATH = "{{BASE_PATH}}".replace(/\/+$/, ""); +export const BASE_PATH = {{BASE_PATH_LITERAL}}.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -8,7 +8,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -87,8 +90,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -130,12 +135,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -145,7 +156,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -161,9 +172,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -178,13 +187,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -194,7 +205,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -204,10 +215,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -216,18 +228,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -235,16 +251,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -263,11 +280,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -277,7 +294,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -287,7 +304,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -301,12 +318,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -324,15 +359,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -408,16 +456,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -444,7 +582,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -471,7 +612,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -481,5 +622,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/src/generators/typescript/fetch/sigil_emit.rs b/src/generators/typescript/fetch/sigil_emit.rs index 10e157e5d..ac1a2d03e 100644 --- a/src/generators/typescript/fetch/sigil_emit.rs +++ b/src/generators/typescript/fetch/sigil_emit.rs @@ -673,23 +673,58 @@ fn build_json_converter( $C(access) !== undefined ? $C(value) : undefined })?; } - let field = if target_key == "__proto__" { - // A literal __proto__ property changes an object literal's prototype. - sigil_quote!(TypeScript { [$S(target_key)]: $C(value), })? - } else if is_unescaped_ts_property(&target_key) { - sigil_quote!(TypeScript { $N(target_key): $C(value), })? + let key = if target_key == "__proto__" { + format!("[{}]", TypeScript::new().render_string_literal(&target_key)) + } else if is_valid_ts_identifier(&target_key) { + target_key.clone() } else { - sigil_quote!(TypeScript { $S(target_key): $C(value), })? + TypeScript::new().render_string_literal(&target_key) }; - fields.push(if !prop.required && obj.additional_properties.is_some() { - sigil_quote!(TypeScript { - ...(Object.prototype.hasOwnProperty.call($N(source), $S(source_key)) ? { - $C(field) - } : {}), - })? + let value = super::layout::inline(value); + let format = + if 4 + key.chars().count() + 2 + super::layout::fragment_width(&value) + 1 > 100 { + "%L:\n%>%L,%<\n" + } else { + "%L: %L,\n" + }; + let field = if !prop.required && obj.additional_properties.is_some() { + let condition = sigil_quote!(TypeScript { Object.prototype.hasOwnProperty.call($N(source), $S(source_key)) })?; + let object = CodeBlock::of( + "{ %L: %L }", + vec![ + sigil_stitch::code_block::Arg::Literal(key), + sigil_stitch::code_block::Arg::Code(value), + ], + )?; + let condition = super::layout::inline(condition); + let multiline = 4 + + 4 + + super::layout::fragment_width(&condition) + + 3 + + super::layout::fragment_width(&object) + + 7 + > 100; + CodeBlock::of( + if multiline { + "...(%L\n%>? %L\n: {}),%<\n" + } else { + "...(%L ? %L : {}),\n" + }, + vec![ + sigil_stitch::code_block::Arg::Code(condition), + sigil_stitch::code_block::Arg::Code(object), + ], + )? } else { - field - }); + CodeBlock::of( + format, + vec![ + sigil_stitch::code_block::Arg::Literal(key), + sigil_stitch::code_block::Arg::Code(value), + ], + )? + }; + fields.push(field); } let body = if obj.properties.is_empty() && !obj @@ -763,19 +798,6 @@ fn build_open_object_conversion( ), TypeName::primitive("undefined"), ]); - let entries = sigil_quote!(TypeScript { - Object.entries($N(source)) - $if(!source_keys.is_empty()) { - .filter(([key]) => ![$for(key in &source_keys; separator = ", ") { $S(key) }].includes(key)) - } - })?; - let entries = if restore { - sigil_quote!(TypeScript { - Object.entries({ ...Object.fromEntries($C(entries)), ...retainedProperties }) - })? - } else { - entries - }; let cast_additional = !obj.properties.is_empty() && !type_expr_collapses_to_unknown(additional, unknown_aliases); let converted = json_conversion_expr( @@ -785,41 +807,66 @@ fn build_open_object_conversion( convertible, direction, )?; - let visible = if retain { - sigil_quote!(TypeScript { - Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => ![$for(key in &target_keys; separator = ", ") { $S(key) }].includes(key))) - })? - } else { - sigil_quote!(TypeScript { - additionalProperties - })? + let keys = |keys: &[String]| { + keys.iter() + .map(|key| TypeScript::new().render_string_literal(key)) + .collect::>() + .join(", ") }; - // An extension may have the same spelling as a renamed declared field. - // Keep the declared property usable and retain the shadowed extension in - // enumerable symbol metadata: object spread preserves it, JSON does not. - sigil_quote!(TypeScript { - $if(restore) { - const retainedProperties = Object.getOwnPropertyDescriptor($N(source), Symbol.for($S(metadata_key)))?.value as $T(retained_type); - } - const additionalProperties = Object.fromEntries($C(entries).map(([key, value]) => { - const additionalValue = $if(cast_additional) { value as $T(additional_type) } $else { value }; - return [key, $C(converted)] as const; - })); - const result = { - ...$C(visible), - $C_each(fields) - }; - $if(retain) { - const shadowedProperties = Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => [$for(key in &target_keys; separator = ", ") { $S(key) }].includes(key))); - if (Object.keys(shadowedProperties).length > 0) { - Object.defineProperty(result, Symbol.for($S(metadata_key)), { - value: shadowedProperties, - enumerable: true, - }); - } - } - return result; - }) + let mut cb = CodeBlock::builder(); + if restore { + cb.add("const retainedProperties = Object.getOwnPropertyDescriptor(\n %N,\n Symbol.for(%S),\n)?.value as %T;\n", vec![sigil_stitch::code_block::Arg::Name(source.into()), sigil_stitch::code_block::Arg::StringLit(metadata_key.into()), sigil_stitch::code_block::Arg::TypeName(retained_type)]); + } + if source_keys.is_empty() { + cb.add( + "const sourceEntries = Object.entries(%N);\n", + vec![sigil_stitch::code_block::Arg::Name(source.into())], + ); + } else { + cb.add("const sourceEntries = Object.entries(%N).filter(([key]) => {\n return ![%L].includes(key);\n});\n", vec![sigil_stitch::code_block::Arg::Name(source.into()), sigil_stitch::code_block::Arg::Literal(keys(&source_keys))]); + } + if restore { + cb.add("const sourceProperties = Object.fromEntries(sourceEntries);\nconst additionalEntries = Object.entries({ ...sourceProperties, ...retainedProperties });\n", ()); + } else { + cb.add("const additionalEntries = sourceEntries;\n", ()); + } + cb.add("const additionalProperties = Object.fromEntries(\n%>additionalEntries.map(([key, value]) => {\n%>const additionalValue = value", ()); + if cast_additional { + cb.add(" as %T", additional_type); + } + if matches!(additional, IrTypeExpr::Map(_)) && needs_conversion(additional, convertible) { + cb.add( + ";\nconst convertedValue = %L;\nreturn [key, convertedValue] as const;\n%<}),\n%<);\n", + super::layout::inline(converted), + ); + } else { + cb.add( + ";\nreturn [key, %L] as const;\n%<}),\n%<);\n", + super::layout::inline(converted), + ); + } + if retain { + cb.add("const visibleProperties = Object.fromEntries(\n Object.entries(additionalProperties).filter(([key]) => {\n return ![%L].includes(key);\n }),\n);\n", keys(&target_keys)); + } + cb.add("const result = {\n%>", ()); + cb.add( + if retain { + "...visibleProperties,\n" + } else { + "...additionalProperties,\n" + }, + (), + ); + for field in fields { + cb.add_code(field); + } + cb.add("%<};\n", ()); + if retain { + cb.add("const shadowedProperties = Object.fromEntries(\n Object.entries(additionalProperties).filter(([key]) => {\n return [%L].includes(key);\n }),\n);\n", keys(&target_keys)); + cb.add("if (Object.keys(shadowedProperties).length > 0) {\n Object.defineProperty(result, Symbol.for(%S), {\n value: shadowedProperties,\n enumerable: true,\n });\n}\n", vec![sigil_stitch::code_block::Arg::StringLit(metadata_key.into())]); + } + cb.add("return result;\n", ()); + cb.build() } fn json_property_access(object: &str, key: &str) -> Result { @@ -882,9 +929,14 @@ fn json_conversion_expr( convertible, direction, )?; - sigil_quote!(TypeScript { - Object.fromEntries(Object.entries($C(access) ?? {}).map(([k, v]) => [k, $C(value)])) - }) + let args = vec![ + sigil_stitch::code_block::Arg::Code(super::layout::inline(access)), + sigil_stitch::code_block::Arg::Code(super::layout::inline(value)), + ]; + CodeBlock::of( + "Object.fromEntries(\n%>Object.entries(%L ?? {}).map(([k, v]) => [k, %L]),\n%<)", + args, + ) } _ => Ok(access), } @@ -1188,17 +1240,14 @@ fn emit_alias_file( } let rhs = type_expr_to_typename(expr); - let type_alias = sigil_quote!(TypeScript { - export type $N(name.as_str()) = $T(rhs); - }) - .ok()?; + let type_alias = build_type_alias(&name, rhs, None).ok()?; let filename = format!("{}.ts", name); let mut fb = FileSpec::builder_with(&filename, ts.clone()); if let Some(doc) = &schema.description { fb = fb.add_raw(&format!("/** {doc} */\n")); } - fb.add_code(type_alias).build().ok() + fb.add_type(type_alias).build().ok() } fn build_type_alias( @@ -1249,17 +1298,14 @@ fn emit_union_file( } let union_ty = union_typename(members); - let type_alias = sigil_quote!(TypeScript { - export type $N(name.as_str()) = $T(union_ty); - }) - .ok()?; + let type_alias = build_type_alias(&name, union_ty, None).ok()?; let filename = format!("{}.ts", name); let mut fb = FileSpec::builder_with(&filename, ts.clone()); if let Some(doc) = &schema.description { fb = fb.add_raw(&format!("/** {doc} */\n")); } - fb.add_code(type_alias).build().ok() + fb.add_type(type_alias).build().ok() } /// Intersection file: `export type Name = A & B & C;` @@ -1304,10 +1350,7 @@ fn emit_intersection_file( inter_ty }; - let type_alias = sigil_quote!(TypeScript { - export type $N(name.as_str()) = $T(inter_ty); - }) - .expect("intersection type alias builds"); + let type_alias = build_type_alias(&name, inter_ty, None).ok()?; let filename = format!("{}.ts", name); let mut fb = FileSpec::builder_with(&filename, ts.clone()); @@ -1315,7 +1358,7 @@ fn emit_intersection_file( // FileSpec has no structural doc slot for a code member. fb = fb.add_raw(&format!("/** {doc} */\n")); } - fb.add_code(type_alias).build().ok() + fb.add_type(type_alias).build().ok() } /// Tagged union file: discriminated `export type` across three tagging styles. @@ -1496,25 +1539,21 @@ fn emit_open_external_union_file( sigil_quote!(TypeScript { additionalValue }).expect("external extension input builds"), &schema.name, convertible, direction, ).expect("external extension conversion builds"); - sigil_quote!(TypeScript { - const additionalProperties = Object.fromEntries(Object.entries($N(source)) - .filter(([key]) => key !== $S(key)) - .map(([key, value]) => { - const additionalValue = $if(cast) { value as $T(ty) } $else { value }; - return [key, $C(converted)] as const; - })); - }).expect("external extension collection builds") + let mut cb = CodeBlock::builder(); + cb.add("const additionalProperties = Object.fromEntries(\n%>Object.entries(%N)\n%>.filter(([key]) => key !== %S)\n.map(([key, value]) => {\n%>const additionalValue = value", vec![sigil_stitch::code_block::Arg::Name(source.into()), sigil_stitch::code_block::Arg::StringLit(key.clone())]); + if cast { cb.add(" as %T", ty); } + cb.add(";\nreturn [key, %L] as const;\n%<}),\n%<%<);\n", super::layout::inline(converted)); + cb.build().expect("external extension collection builds") }); - sigil_quote!(TypeScript { - if (Object.prototype.hasOwnProperty.call($N(source), $S(key))) { - const contentValue = ($N(source) as $T(content_record))[$S(key)]; - $if(let Some(additional) = additional) { $C(additional) } - return { - $if(variant.additional_properties.is_some()) { ...additionalProperties, } - [$S(key)]: $C(content), - }; - } - }).expect("external wrapper conversion branch builds") + let mut cb = CodeBlock::builder(); + cb.begin_control_flow("if (Object.prototype.hasOwnProperty.call(%N, %S))", vec![sigil_stitch::code_block::Arg::Name(source.into()), sigil_stitch::code_block::Arg::StringLit(key.clone())]); + cb.add("const contentValue = (%N as %T)[%S];\n", vec![sigil_stitch::code_block::Arg::Name(source.into()), sigil_stitch::code_block::Arg::TypeName(content_record), sigil_stitch::code_block::Arg::StringLit(key.clone())]); + if let Some(additional) = additional { cb.add_code(additional); } + cb.add("return { ", ()); + if variant.additional_properties.is_some() { cb.add("...additionalProperties, ", ()); } + cb.add("[%S]: %L };\n", vec![sigil_stitch::code_block::Arg::StringLit(key.clone()), sigil_stitch::code_block::Arg::Code(super::layout::inline(content))]); + cb.end_control_flow(); + cb.build().expect("external wrapper conversion branch builds") }).collect(); let body = sigil_quote!(TypeScript { $C_each(branches) @@ -1658,7 +1697,10 @@ fn build_tagged_union_from_json( &tu.discriminator_field, convertible, ); - case_lines.push(format!("case '{val}': {case_body}")); + case_lines.push(format!( + "case '{val}':\n {}", + case_body.replace('\n', "\n ") + )); } sigil_quote!(TypeScript { export function $N(fn_name)(json: $N(wire_name)): $N(name) { @@ -1690,7 +1732,14 @@ fn internal_or_adjacent_from_json_case( if convertible.contains(ref_name) { let pascal = ref_name.to_pascal_case(); let converter = format!("{}FromJSON", fn_base_name(&pascal)); - format!("return {{ ...{converter}(json), {disc_field_camel}: '{val}' }};") + super::layout::return_object( + &[ + format!("...{converter}(json)"), + format!("{disc_field_camel}: '{val}'"), + ], + None, + 6, + ) } else { format!("return {{ ...json, {disc_field_camel}: '{val}' }};") } @@ -1709,7 +1758,14 @@ fn internal_or_adjacent_from_json_case( format!("json['{content_field}']") }; let content_expr = from_json_expr_inner(content_type, &content_access, convertible); - format!("return {{ {disc_field_camel}: '{val}', {content_camel}: {content_expr} }};") + super::layout::return_object( + &[ + format!("{disc_field_camel}: '{val}'"), + format!("{content_camel}: {content_expr}"), + ], + None, + 6, + ) } TaggingStyle::External => unreachable!(), } @@ -1746,7 +1802,14 @@ fn external_variant_from_json_expr( ) -> String { let val_access = format!("json['{val}']"); let content_expr = from_json_expr_inner(content_type, &val_access, convertible); - format!("{{ '{val}': {content_expr} }}") + format!( + "{{ {}: {content_expr} }}", + if is_valid_ts_identifier(val) { + val.to_string() + } else { + format!("'{val}'") + } + ) } /// Build toJSON for a tagged union: switch on the camelCase discriminator field. @@ -1789,7 +1852,10 @@ fn build_tagged_union_to_json( tag_only, convertible, ); - case_lines.push(format!("case '{val}': {case_body}")); + case_lines.push(format!( + "case '{val}':\n {}", + case_body.replace('\n', "\n ") + )); } sigil_quote!(TypeScript { export function $N(fn_name)(value: $N(name)): $N(wire_name) { @@ -1821,8 +1887,13 @@ fn internal_or_adjacent_to_json_case( if convertible.contains(ref_name) { let pascal = ref_name.to_pascal_case(); let converter = format!("{}ToJSON", fn_base_name(&pascal)); - format!( - "return {{ ...{converter}(value), {disc_wire_key}: '{val}' }} as {wire_name};" + super::layout::return_object( + &[ + format!("...{converter}(value)"), + format!("{disc_wire_key}: '{val}'"), + ], + Some(wire_name), + 6, ) } else { format!("return {{ ...value, {disc_wire_key}: '{val}' }} as {wire_name};") @@ -1847,7 +1918,14 @@ fn internal_or_adjacent_to_json_case( format!("value['{content_camel}']") }; let content_expr = to_json_expr_inner(content_type, &content_access, convertible); - format!("return {{ {disc_wire_key}: '{val}', {content_wire_key}: {content_expr} }};") + super::layout::return_object( + &[ + format!("{disc_wire_key}: '{val}'"), + format!("{content_wire_key}: {content_expr}"), + ], + None, + 6, + ) } TaggingStyle::External => unreachable!(), } @@ -1884,7 +1962,14 @@ fn external_variant_to_json_expr( ) -> String { let val_access = format!("value['{val}']"); let content_expr = to_json_expr_inner(content_type, &val_access, convertible); - format!("{{ '{val}': {content_expr} }}") + format!( + "{{ {}: {content_expr} }}", + if is_valid_ts_identifier(val) { + val.to_string() + } else { + format!("'{val}'") + } + ) } // --------------------------------------------------------------------------- @@ -2482,20 +2567,37 @@ fn variant_type_format( disc_value: &str, content_field_mode: Option, content: &str, + multiline: bool, ) -> String { + let (padding, closing_padding) = if multiline { + ("\n ", ";\n") + } else { + (" ", " ") + }; match tagging { TaggingStyle::Internal => { - format!("({{ {disc_field}: '{disc_value}' }} & {content})") + if multiline { + format!("{{{padding}{disc_field}: '{disc_value}'{closing_padding}}} & {content}") + } else { + format!("({{{padding}{disc_field}: '{disc_value}'{closing_padding}}} & {content})") + } } TaggingStyle::Adjacent { content_field } => { let emitted_content_field = match content_field_mode { Some(PropertyNamingMode::CamelCase) => content_field.to_lower_camel_case(), None => content_field.clone(), }; - format!("{{ {disc_field}: '{disc_value}'; {emitted_content_field}: {content} }}") + format!( + "{{{padding}{disc_field}: '{disc_value}';{padding}{emitted_content_field}: {content}{closing_padding}}}" + ) } TaggingStyle::External => { - format!("{{ '{disc_value}': {content} }}") + let key = if is_valid_ts_identifier(disc_value) { + disc_value.to_string() + } else { + format!("'{disc_value}'") + }; + format!("{{{padding}{key}: {content}{closing_padding}}}") } } } @@ -2516,7 +2618,14 @@ fn tagged_variant_type_string( { return format!("{{ {disc_field}: '{disc_value}' }}"); } - variant_type_format(tagging, disc_field, disc_value, content_field_mode, content) + variant_type_format( + tagging, + disc_field, + disc_value, + content_field_mode, + content, + false, + ) } /// Build the runtime narrowing expression for one variant. @@ -2592,12 +2701,14 @@ fn guard_check_and_type( None }; let check = variant_check_body(tagging, &emitted_disc_field, disc_value); + // Multiline object predicates let Oxfmt lay out long signatures in one pass. let ty = variant_type_format( tagging, &emitted_disc_field, disc_value, content_field_mode, &TsTypeDisplay(content_type).to_string(), + true, ); (check, ty) } @@ -2623,21 +2734,37 @@ where &variant.discriminator_value, &variant.content_type, ); - tagged_variant_type_string( + let member = tagged_variant_type_string( &tu.tagging, discriminator_field, &variant.discriminator_value, content_field_mode, &type_name_for(&variant.content_type), tag_only, - ) + ); + if member.chars().count() + 4 > 100 && matches!(tu.tagging, TaggingStyle::Internal) { + let object = variant_type_format( + &tu.tagging, + discriminator_field, + &variant.discriminator_value, + content_field_mode, + &type_name_for(&variant.content_type), + true, + ); + format!("({})", object.replace('\n', "\n ")) + } else { + member + } }) .collect(); - sigil_quote!(TypeScript { - export type $N(name) = $for(member in &members; separator = " | ") { $L(member.as_str()) }; - }) - .ok() + let inline = format!("export type {name} = {};\n", members.join(" | ")); + let text = if inline.trim_end().chars().count() <= 100 { + inline + } else { + format!("export type {name} =\n | {};\n", members.join("\n | ")) + }; + CodeBlock::of("%L", text).ok() } /// Build the pipe-joined literal body for an enum: `'a' | 1 | true | null`. @@ -2844,6 +2971,7 @@ pub fn generate_model_files( kind: format!("{:?}", schema.kind), })?; let body = file_spec + .with_lang(super::layout::TypeScript::from(ts.clone())) .render(100) .map_err(|source| GeneratorError::emission(ArtifactKind::Model, name, source))?; let content = format!("{header}{body}"); @@ -3287,11 +3415,11 @@ components: for (direction, expected) in [ ( JsonDirection::FromWire, - "import { detailFromJSON } from './Detail';\n\nObject.fromEntries(Object.entries(values ?? {}).map(([k, v]) => [k, v != null ? detailFromJSON(v) : null]))\n", + "import { detailFromJSON } from './Detail';\n\nObject.fromEntries(\n Object.entries(values ?? {}).map(([k, v]) => [k, v != null ? detailFromJSON(v) : null]),\n)\n", ), ( JsonDirection::ToWire, - "import { detailToJSON } from './Detail';\n\nObject.fromEntries(Object.entries(values ?? {}).map(([k, v]) => [k, v != null ? detailToJSON(v) : null]))\n", + "import { detailToJSON } from './Detail';\n\nObject.fromEntries(\n Object.entries(values ?? {}).map(([k, v]) => [k, v != null ? detailToJSON(v) : null]),\n)\n", ), ] { let access = sigil_quote!(TypeScript { values }).unwrap(); diff --git a/src/generators/typescript/fetch/sigil_emit_api.rs b/src/generators/typescript/fetch/sigil_emit_api.rs index 163a68619..740e91186 100644 --- a/src/generators/typescript/fetch/sigil_emit_api.rs +++ b/src/generators/typescript/fetch/sigil_emit_api.rs @@ -78,9 +78,12 @@ pub fn generate_api_files( .map_err(|source| { GeneratorError::emission(ArtifactKind::Api, format!("{tag} API"), source) })?; - let body = file_spec.render(100).map_err(|source| { - GeneratorError::emission(ArtifactKind::Api, format!("{tag} API"), source) - })?; + let body = file_spec + .with_lang(super::layout::TypeScript::from(ts.clone())) + .render(100) + .map_err(|source| { + GeneratorError::emission(ArtifactKind::Api, format!("{tag} API"), source) + })?; let filename = format!("{}Api.ts", tag.to_pascal_case()); let content = format!("{header}{body}"); files.push(FileInfo::api(filename, content)); @@ -270,11 +273,10 @@ fn build_response_aliases_block(ops: &[&IrOperation]) -> Result Result { let mut cb = CodeBlock::builder(); - cb.add(&format!("export type {detail_alias} =\n"), vec![]); let mut used = HashSet::new(); - for (idx, resp) in error_responses.iter().enumerate() { - let prefix = if idx == 0 { " " } else { " | " }; + let mut members = Vec::new(); + for resp in error_responses { let kind = unique_ts_kind(&response_detail_kind(&resp.status), &mut used); let status_ty = resp .status @@ -353,27 +354,48 @@ fn build_error_detail_alias_block( .ok() .map(|n| n.to_string()) .unwrap_or_else(|| "number".to_string()); - let value_ty = response_value_type(resp); - cb.add(prefix, vec![]); + members.push((kind, status_ty, response_value_type(resp))); + } + members.push(( + "unexpected".to_string(), + "number".to_string(), + TypeName::primitive("Blob"), + )); + cb.add("export type %L =", detail_alias); + let union = members.len() > 1; + if union { + cb.add("\n%>", ()); + } else { + cb.add(" ", ()); + } + for (index, (kind, status, value)) in members.into_iter().enumerate() { + if index > 0 { + cb.add_line(); + } + if union { + cb.add("| ", ()); + } + cb.add("{\n%>", ()); + // Union object members align two columns after the pipe. + let pad = if union { " " } else { "" }; cb.add( - &format!( - "{{ kind: '{}'; status: {}; raw: Response; value(): Promise<%T> }}\n", - kind, status_ty - ), - vec![Arg::TypeName(value_ty)], + "%Lkind: %S;\n%Lstatus: %L;\n%Lraw: Response;\n%Lvalue(): Promise<%T>;\n%<%L}", + vec![ + Arg::Literal(pad.into()), + Arg::StringLit(kind), + Arg::Literal(pad.into()), + Arg::Literal(status), + Arg::Literal(pad.into()), + Arg::Literal(pad.into()), + Arg::TypeName(value), + Arg::Literal(if union { " " } else { "" }.into()), + ], ); } - let prefix = if error_responses.is_empty() { - " " - } else { - " | " - }; - cb.add( - &format!( - "{prefix}{{ kind: 'unexpected'; status: number; raw: Response; value(): Promise<%T> }};\n" - ), - vec![Arg::TypeName(TypeName::primitive("Blob"))], - ); + if union { + cb.add("%<", ()); + } + cb.add(";\n", ()); cb.build() } @@ -831,7 +853,7 @@ fn emit_required_param_checks( let access = request_parameters_access(&pname); cb.add( &format!( - "if ({0} === undefined || {0} === null) {{\n throw new %T(\n '{1}',\n 'Required parameter \"{1}\" was null or undefined when calling {2}().'\n );\n}}\n", + "if ({0} === undefined || {0} === null) {{\n throw new %T(\n '{1}',\n 'Required parameter \"{1}\" was null or undefined when calling {2}().',\n );\n}}\n", access, pname, method_name ), vec![Arg::TypeName(rt_value("RequiredError"))], @@ -867,12 +889,17 @@ fn emit_url_path( let original = &p.name; let access = request_parameters_access(&resolved); let placeholder = format!("{{{original}}}"); - cb.add_code( - sigil_quote!(TypeScript { - urlPath = urlPath.replace($V(placeholder.as_str()), encodeURIComponent(String($L(access.as_str())))); - }) - ?, + let inline = format!( + "urlPath = urlPath.replace(`{placeholder}`, encodeURIComponent(String({access})));" ); + if inline.chars().count() + 4 <= 100 { + cb.add_code(sigil_quote!(TypeScript { urlPath = urlPath.replace($V(placeholder.as_str()), encodeURIComponent(String($L(access.as_str())))); })?); + } else { + cb.add( + "urlPath = urlPath.replace(\n %V,\n encodeURIComponent(String(%L)),\n);\n", + vec![Arg::VerbatimStr(placeholder), Arg::Literal(access)], + ); + } } Ok(()) } @@ -908,17 +935,20 @@ fn emit_headers( op: &IrOperation, ) -> Result<(), SigilStitchError> { cb.add("// Build headers\n", vec![]); - cb.add( - "const headerParameters: Record = {\n", - vec![], - ); if let Some(rb) = &op.request_body && let Some(media_type) = preferred_request_media_type(rb) && media_type_base(&media_type) != "multipart/form-data" { - cb.add(&format!(" 'Content-Type': '{}',\n", media_type), vec![]); + cb.add( + "const headerParameters: Record = {\n 'Content-Type': %S,\n};\n\n", + vec![Arg::StringLit(media_type)], + ); + } else { + cb.add( + "const headerParameters: Record = {};\n\n", + (), + ); } - cb.add("};\n\n", vec![]); let names = resolve_param_names(op); for p in op .parameters @@ -1170,26 +1200,9 @@ fn emit_make_request( has_body: bool, ) { let method = op.method.to_uppercase(); - let request_with_body = format!( - "const response = await this.request({{\n path: urlPath,\n method: '{}',\n headers: headerParameters,\n query: queryParameters,\n body: requestBody,\n}}, initOverrides);", - method - ); - let request_without_body = format!( - "const response = await this.request({{\n path: urlPath,\n method: '{}',\n headers: headerParameters,\n query: queryParameters,\n body: undefined,\n}}, initOverrides);", - method - ); - cb.add("// Make request\n", vec![]); - cb.add_code( - sigil_quote!(TypeScript { - $if(has_body) { - $L(request_with_body) - } $else { - $L(request_without_body) - } - }) - .expect("make request block builds"), - ); - cb.add_line(); + let body = if has_body { "requestBody" } else { "undefined" }; + cb.add("// Make request\n", ()); + cb.add("const response = await this.request(\n {\n path: urlPath,\n method: %S,\n headers: headerParameters,\n query: queryParameters,\n body: %L,\n },\n initOverrides,\n);\n\n", vec![Arg::StringLit(method), Arg::Literal(body.into())]); } fn emit_response_handler( @@ -1272,33 +1285,23 @@ fn build_status_dispatch( let mut cb = CodeBlock::builder(); let has_branches = !branches.is_empty(); for (index, (condition, body)) in branches.into_iter().enumerate() { - let branch = if index == 0 { - sigil_quote!(TypeScript { - if ($C(condition)) { - $C(body) - } - }) + if index == 0 { + cb.begin_control_flow("if (%L)", super::layout::inline(condition)); } else { - sigil_quote!(TypeScript { - else if ($C(condition)) { - $C(body) - } - }) - }?; - cb.add_code(branch); + cb.next_control_flow("else if (%L)", super::layout::inline(condition)); + } + cb.add_code(body); } if has_branches { - cb.add_code(sigil_quote!(TypeScript { - else { - $C(fallback) - } - })?); + cb.next_control_flow("else", ()); } else { - // A bare scope is ambiguous with an object literal in sigil_quote!; - // the structural block API expresses that intent without raw braces. - cb.begin_control_flow_with_intent(sigil_stitch::code_node::BlockIntent::Generic, "", ()); - cb.add_code(fallback); + cb.add("{\n%>", ()); + } + cb.add_code(fallback); + if has_branches { cb.end_control_flow(); + } else { + cb.add("%<}\n", ()); } cb.build() } @@ -1418,12 +1421,16 @@ fn build_error_throw( type_application(TypeName::primitive("Promise"), vec![value_type]), TypeName::primitive("undefined"), ]); - // sigil_quote! normalizes inline object literals without brace padding. - // Keep the existing brace padding with static spaces; values stay structured. - sigil_quote!(TypeScript { - let errorValue: $T(cached_type); - throw new $N(class_name)(response, {$L(" ")$N("kind"): $S(kind), status: $C(status), raw: response, value: () => errorValue ??= $C(value)$L(" ")}); - }) + CodeBlock::of( + "let errorValue: %T;\nthrow new %N(response, {\n%>kind: %S,\nstatus: %L,\nraw: response,\nvalue: () => {\n%>errorValue ??= %L;\nreturn errorValue;\n%<},\n%<});\n", + vec![ + Arg::TypeName(cached_type), + Arg::Name(class_name), + Arg::StringLit(kind.into()), + Arg::Code(super::layout::inline(status)), + Arg::Code(super::layout::inline(value)), + ], + ) } fn error_value_expr( @@ -1436,8 +1443,7 @@ fn error_value_expr( && let ResponseKind::Json(Some(_)) = &kind && let Some(from_json) = response_from_json_transformer(resp, convertible)? { - let wrapper_type = - type_application(rt_value("JSONApiResponse"), vec![response_value_type(resp)]); + let wrapper_type = rt_value("JSONApiResponse"); return sigil_quote!(TypeScript { new $T(wrapper_type)(errorRaw.clone(), $C(from_json)).value() }); @@ -1501,9 +1507,15 @@ fn build_response_return( }; let status_type = response_status_type(&status_ty); - sigil_quote!(TypeScript { - return new $T(wrapper_value)(response) as $T(wrapper_type)$L(" & ")$T(status_type); - }) + let flat = sigil_quote!(TypeScript { + return new $T(wrapper_value.clone())(response) as $T(wrapper_type.clone())$L(" & ")$T(status_type.clone()); + })?; + if super::layout::fragment_width(&flat) + 6 > 100 { + let status_type = TypeName::raw(&format!("{{\n status: {status_ty};\n}}")); + sigil_quote!(TypeScript { return new $T(wrapper_value)(response) as $T(wrapper_type)$L(" & ")$T(status_type); }) + } else { + Ok(flat) + } } fn response_status_type(status_ty: &str) -> TypeName { @@ -1521,7 +1533,7 @@ fn build_fallback_return(any_body: bool) -> Result let success_response = rt_type("HttpSuccessResponse"); sigil_quote!(TypeScript { $if(any_body) { - return new $T(json_response.clone())(response) as $T(json_response)<$T(unknown)> & $T(success_response.clone()); + return new $T(json_response.clone())(response) as $T(json_response)<$T(unknown)>$L(" & ")$T(success_response.clone()); } $else { return new $T(void_response.clone())(response) as $T(void_response) & $T(success_response); } @@ -1555,7 +1567,7 @@ fn build_convenience_method(op: &IrOperation) -> Result (json as $T(TypeName::array(wire))).map($T(from_fn)) + (json) => { + return (json as $T(TypeName::array(wire))).map($T(from_fn)); + } }) } else { sigil_quote!(TypeScript { - (json) => $T(from_fn)(json as $T(wire)) + (json) => { + return $T(from_fn)(json as $T(wire)); + } }) }?; Ok(Some(transformer)) @@ -2547,7 +2563,17 @@ import { detailFromJSON } from '../models/Detail'; import { JSONApiResponse } from '../runtime/runtime'; let errorValue: Promise | undefined; -throw new ReadMixedError(response, { kind: 'unauthorized', status: response.status as 401, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone(), (json) => (json as Detail$Wire[]).map(detailFromJSON)).value() }); +throw new ReadMixedError(response, { + kind: 'unauthorized', + status: response.status as 401, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone(), (json) => { + return (json as Detail$Wire[]).map(detailFromJSON); + }).value(); + return errorValue; + }, +}); "# ); Ok(()) @@ -2585,12 +2611,10 @@ import { JSONApiResponse } from '../runtime/runtime'; if (response.status === 201) { return new JSONApiResponse(response) as JSONApiResponse & { status: 201 }; -} -else if (response.status >= 200 && response.status < 300) { +} else if (response.status >= 200 && response.status < 300) { return new JSONApiResponse(response) as JSONApiResponse & { status: number }; -} -else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; +} else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } "# ); @@ -2617,9 +2641,19 @@ import { JSONApiResponse } from '../runtime/runtime'; if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new ReadDefaultError(response, { kind: 'default', status: response.status, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone(), (json) => detailFromJSON(json as Detail$Wire)).value() }); + throw new ReadDefaultError(response, { + kind: 'default', + status: response.status, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone(), (json) => { + return detailFromJSON(json as Detail$Wire); + }).value(); + return errorValue; + }, + }); } } "# diff --git a/tests/generated-clients/typescript/README.md b/tests/generated-clients/typescript/README.md index ec8f853e7..85c13c747 100644 --- a/tests/generated-clients/typescript/README.md +++ b/tests/generated-clients/typescript/README.md @@ -16,12 +16,15 @@ packing declarations, so the generated package's compiler alone is insufficient. The strict consumer check itself uses that package's installed compiler. - `prepare` runs the public generator CLI with an explicit empty configuration, - producing fresh, unmodified preserve and camelCase clients. + producing fresh preserve and camelCase clients. - `build` copies each client to a temporary build directory, runs `vp install`, reports the resolved Vite+ component versions with `vp --version`, runs - `vp check --no-fmt` and `vp pack`, then copies its bundle/declarations back. + full `vp check` and `vp pack`, then checks again after packing and + copies its bundle/declarations back. Building outside the repository avoids Vite+ skipping gitignored generated - sources. Generated source, manifests, and configuration are never patched. + sources. Checks run directly on the original generated source, manifests, + and configuration, without formatter rewrites or compatibility patches. The generated formatter + configuration excludes `dist/`, so checks do not reformat build output. - `typecheck.ts` checks the actual packed declarations with strict typing and `exactOptionalPropertyTypes`, including negative dictionary-type and readonly `allOf` assertions for preserve, ergonomic, and wire declarations. diff --git a/tests/golden/typescript/typescript-fetch/additional-properties/README.md.golden b/tests/golden/typescript/typescript-fetch/additional-properties/README.md.golden index ac78f8eda..10fc27c4c 100644 --- a/tests/golden/typescript/typescript-fetch/additional-properties/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/additional-properties/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, AdditionalPropertiesApi } from 'additional-properties-ap const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'additional-properties-api'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/additional-properties/apis/AdditionalPropertiesApi.ts.golden b/tests/golden/typescript/typescript-fetch/additional-properties/apis/AdditionalPropertiesApi.ts.golden index f6676403d..8a3645aa1 100644 --- a/tests/golden/typescript/typescript-fetch/additional-properties/apis/AdditionalPropertiesApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/additional-properties/apis/AdditionalPropertiesApi.ts.golden @@ -7,8 +7,20 @@ import type { LeafValue } from '../models/LeafValue'; import type { MiddleLevel } from '../models/MiddleLevel'; import type { RootLevel } from '../models/RootLevel'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError, VoidApiResponse } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, + VoidApiResponse, +} from '../runtime/runtime'; export interface ApiPostLeafRequest { body: LeafValue; @@ -23,73 +35,121 @@ export interface ApiPostRootRequest { } export type PostLeafRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type PostMiddleRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type PostRootRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type PostLeafErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class PostLeafError extends ResponseError { readonly detail: PostLeafErrorDetail; - constructor(response: Response, detail: PostLeafErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: PostLeafErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type PostMiddleErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class PostMiddleError extends ResponseError { readonly detail: PostMiddleErrorDetail; - constructor(response: Response, detail: PostMiddleErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: PostMiddleErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type PostRootErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class PostRootError extends ResponseError { readonly detail: PostRootErrorDetail; - constructor(response: Response, detail: PostRootErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: PostRootErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface AdditionalPropertiesApiInterface { - postLeafRaw: (requestParameters: ApiPostLeafRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - postLeaf: (requestParameters: ApiPostLeafRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - postMiddleRaw: (requestParameters: ApiPostMiddleRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - postMiddle: (requestParameters: ApiPostMiddleRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - postRootRaw: (requestParameters: ApiPostRootRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - postRoot: (requestParameters: ApiPostRootRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + postLeafRaw: ( + requestParameters: ApiPostLeafRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + postLeaf: ( + requestParameters: ApiPostLeafRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + postMiddleRaw: ( + requestParameters: ApiPostMiddleRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + postMiddle: ( + requestParameters: ApiPostMiddleRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + postRootRaw: ( + requestParameters: ApiPostRootRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + postRoot: ( + requestParameters: ApiPostRootRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class AdditionalPropertiesApi extends BaseAPI implements AdditionalPropertiesApiInterface { @@ -100,12 +160,14 @@ export class AdditionalPropertiesApi extends BaseAPI implements AdditionalProper super(configuration ?? DefaultConfig); } - async postLeafRaw(requestParameters: ApiPostLeafRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async postLeafRaw( + requestParameters: ApiPostLeafRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling postLeafRaw().' + 'Required parameter "body" was null or undefined when calling postLeafRaw().', ); } // Build path with path parameters @@ -120,46 +182,67 @@ export class AdditionalPropertiesApi extends BaseAPI implements AdditionalProper // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new PostLeafError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new PostLeafError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new PostLeafError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new PostLeafError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async postLeaf(requestParameters: ApiPostLeafRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async postLeaf( + requestParameters: ApiPostLeafRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.postLeafRaw(requestParameters, initOverrides); - return await response.value() as LeafValue; + return (await response.value()) as LeafValue; } - async postMiddleRaw(requestParameters: ApiPostMiddleRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async postMiddleRaw( + requestParameters: ApiPostMiddleRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling postMiddleRaw().' + 'Required parameter "body" was null or undefined when calling postMiddleRaw().', ); } // Build path with path parameters @@ -174,46 +257,67 @@ export class AdditionalPropertiesApi extends BaseAPI implements AdditionalProper // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new PostMiddleError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new PostMiddleError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new PostMiddleError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new PostMiddleError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async postMiddle(requestParameters: ApiPostMiddleRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async postMiddle( + requestParameters: ApiPostMiddleRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.postMiddleRaw(requestParameters, initOverrides); - return await response.value() as MiddleLevel; + return (await response.value()) as MiddleLevel; } - async postRootRaw(requestParameters: ApiPostRootRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async postRootRaw( + requestParameters: ApiPostRootRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling postRootRaw().' + 'Required parameter "body" was null or undefined when calling postRootRaw().', ); } // Build path with path parameters @@ -228,37 +332,56 @@ export class AdditionalPropertiesApi extends BaseAPI implements AdditionalProper // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new PostRootError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new PostRootError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new PostRootError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new PostRootError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async postRoot(requestParameters: ApiPostRootRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async postRoot( + requestParameters: ApiPostRootRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.postRootRaw(requestParameters, initOverrides); - return await response.value() as RootLevel; + return (await response.value()) as RootLevel; } } diff --git a/tests/golden/typescript/typescript-fetch/additional-properties/package.json.golden b/tests/golden/typescript/typescript-fetch/additional-properties/package.json.golden index 082a2d7da..0eb17c5db 100644 --- a/tests/golden/typescript/typescript-fetch/additional-properties/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/additional-properties/package.json.golden @@ -1,27 +1,27 @@ { + "name": "additional-properties-api", + "version": "1.0.0", "description": "API demonstrating OpenAPI additionalProperties with multiple levels of structs (RootLevel -> MiddleLevel -> LeafValue), each with HashMap fields.", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "license": "MIT OR Apache-2.0", + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "license": "MIT OR Apache-2.0", - "main": "./dist/index.js", - "name": "additional-properties-api", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/additional-properties/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/additional-properties/runtime/runtime.ts.golden index 826b043cd..9671c309e 100644 --- a/tests/golden/typescript/typescript-fetch/additional-properties/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/additional-properties/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Additional Properties API — 1.0.0 * API demonstrating OpenAPI additionalProperties with multiple levels of structs (RootLevel -> MiddleLevel -> LeafValue), each with HashMap fields. */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/additional-properties/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/additional-properties/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/additional-properties/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/additional-properties/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/additional-properties/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/additional-properties/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/additional-properties/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/additional-properties/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/api-interface/README.md.golden b/tests/golden/typescript/typescript-fetch/api-interface/README.md.golden index 522719047..e743c6611 100644 --- a/tests/golden/typescript/typescript-fetch/api-interface/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/api-interface/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, EntriesApi } from 'type-script-api-interface'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'type-script-api-interface'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/api-interface/apis/EntriesApi.ts.golden b/tests/golden/typescript/typescript-fetch/api-interface/apis/EntriesApi.ts.golden index 0eef59815..67f577704 100644 --- a/tests/golden/typescript/typescript-fetch/api-interface/apis/EntriesApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/api-interface/apis/EntriesApi.ts.golden @@ -4,11 +4,23 @@ * TypeScript API Interface — 1.0.0 */ import type { Entry } from '../models/Entry'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError, TextApiResponse, VoidApiResponse } from '../runtime/runtime'; - -export interface ApiCookieInputRequest { -} +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, + TextApiResponse, + VoidApiResponse, +} from '../runtime/runtime'; + +export interface ApiCookieInputRequest {} export interface ApiGetEntriesRequest { id: string; @@ -23,113 +35,154 @@ export interface ApiSubmitRequest { } export type CookieInputRawResponse = - | VoidApiResponse & { status: 204 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 204 }) + | (VoidApiResponse & HttpSuccessResponse); export type GetEntriesRawResponse = - | JSONApiResponse & { status: 200 } - | TextApiResponse & { status: 206 } - | JSONApiResponse<(string | null)[]> & { status: 207 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (TextApiResponse & { status: 206 }) + | (JSONApiResponse<(string | null)[]> & { status: 207 }) + | (JSONApiResponse & HttpSuccessResponse); export type NoInputRawResponse = - | VoidApiResponse & { status: 204 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 204 }) + | (VoidApiResponse & HttpSuccessResponse); export type OptionalInputRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type SubmitRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); - -export type CookieInputErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type CookieInputErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class CookieInputError extends ResponseError { readonly detail: CookieInputErrorDetail; - constructor(response: Response, detail: CookieInputErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: CookieInputErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type GetEntriesErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type GetEntriesErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class GetEntriesError extends ResponseError { readonly detail: GetEntriesErrorDetail; - constructor(response: Response, detail: GetEntriesErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: GetEntriesErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type NoInputErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type NoInputErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class NoInputError extends ResponseError { readonly detail: NoInputErrorDetail; - constructor(response: Response, detail: NoInputErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: NoInputErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type OptionalInputErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type OptionalInputErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class OptionalInputError extends ResponseError { readonly detail: OptionalInputErrorDetail; - constructor(response: Response, detail: OptionalInputErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: OptionalInputErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type SubmitErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type SubmitErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class SubmitError extends ResponseError { readonly detail: SubmitErrorDetail; - constructor(response: Response, detail: SubmitErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: SubmitErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface EntriesApiInterface { - cookieInputRaw: (initOverrides?: RequestInit - | InitOverrideFunction) => Promise; + cookieInputRaw: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; cookieInput: (initOverrides?: RequestInit | InitOverrideFunction) => Promise; - getEntriesRaw: (requestParameters: ApiGetEntriesRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - getEntries: (requestParameters: ApiGetEntriesRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + getEntriesRaw: ( + requestParameters: ApiGetEntriesRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + getEntries: ( + requestParameters: ApiGetEntriesRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; noInputRaw: (initOverrides?: RequestInit | InitOverrideFunction) => Promise; noInput: (initOverrides?: RequestInit | InitOverrideFunction) => Promise; - optionalInputRaw: (requestParameters: ApiOptionalInputRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - optionalInput: (requestParameters: ApiOptionalInputRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - submitRaw: (requestParameters: ApiSubmitRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - submit: (requestParameters: ApiSubmitRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + optionalInputRaw: ( + requestParameters: ApiOptionalInputRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + optionalInput: ( + requestParameters: ApiOptionalInputRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + submitRaw: ( + requestParameters: ApiSubmitRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + submit: ( + requestParameters: ApiSubmitRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class EntriesApi extends BaseAPI implements EntriesApiInterface { @@ -140,37 +193,47 @@ export class EntriesApi extends BaseAPI implements EntriesApiInterface { super(configuration ?? DefaultConfig); } - async cookieInputRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async cookieInputRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/cookie-input`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new CookieInputError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new CookieInputError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 204) { return new VoidApiResponse(response) as VoidApiResponse & { status: 204 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } @@ -180,12 +243,14 @@ export class EntriesApi extends BaseAPI implements EntriesApiInterface { return await response.value(); } - async getEntriesRaw(requestParameters: ApiGetEntriesRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getEntriesRaw( + requestParameters: ApiGetEntriesRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.id === undefined || requestParameters.id === null) { throw new RequiredError( 'id', - 'Required parameter "id" was null or undefined when calling getEntriesRaw().' + 'Required parameter "id" was null or undefined when calling getEntriesRaw().', ); } // Build path with path parameters @@ -194,77 +259,96 @@ export class EntriesApi extends BaseAPI implements EntriesApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new GetEntriesError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new GetEntriesError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else if (response.status === 206) { + } else if (response.status === 206) { return new TextApiResponse(response) as TextApiResponse & { status: 206 }; - } - else if (response.status === 207) { + } else if (response.status === 207) { return new JSONApiResponse(response) as JSONApiResponse<(string | null)[]> & { status: 207 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async getEntries(requestParameters: ApiGetEntriesRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getEntries( + requestParameters: ApiGetEntriesRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.getEntriesRaw(requestParameters, initOverrides); - return await response.value() as Entry[] | string | (string | null)[]; + return (await response.value()) as Entry[] | string | (string | null)[]; } - async noInputRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async noInputRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/no-input`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new NoInputError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new NoInputError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 204) { return new VoidApiResponse(response) as VoidApiResponse & { status: 204 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } @@ -274,8 +358,10 @@ export class EntriesApi extends BaseAPI implements EntriesApiInterface { return await response.value(); } - async optionalInputRaw(requestParameters: ApiOptionalInputRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async optionalInputRaw( + requestParameters: ApiOptionalInputRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/optional-input`; // Build query parameters @@ -284,42 +370,55 @@ export class EntriesApi extends BaseAPI implements EntriesApiInterface { queryParameters['filter'] = requestParameters.filter; } // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new OptionalInputError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new OptionalInputError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async optionalInput(requestParameters: ApiOptionalInputRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async optionalInput( + requestParameters: ApiOptionalInputRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.optionalInputRaw(requestParameters, initOverrides); - return await response.value() as Entry; + return (await response.value()) as Entry; } - async submitRaw(requestParameters: ApiSubmitRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async submitRaw( + requestParameters: ApiSubmitRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/submit`; // Build query parameters @@ -332,33 +431,45 @@ export class EntriesApi extends BaseAPI implements EntriesApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new SubmitError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new SubmitError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async submit(requestParameters: ApiSubmitRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async submit( + requestParameters: ApiSubmitRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.submitRaw(requestParameters, initOverrides); - return await response.value() as Entry; + return (await response.value()) as Entry; } } diff --git a/tests/golden/typescript/typescript-fetch/api-interface/package.json.golden b/tests/golden/typescript/typescript-fetch/api-interface/package.json.golden index 5761c8dcb..bd1e61016 100644 --- a/tests/golden/typescript/typescript-fetch/api-interface/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/api-interface/package.json.golden @@ -1,26 +1,26 @@ { + "name": "type-script-api-interface", + "version": "1.0.0", "description": "TypeScript client for TypeScript API Interface", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "type-script-api-interface", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/api-interface/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/api-interface/runtime/runtime.ts.golden index 55bc288f9..23025b2c7 100644 --- a/tests/golden/typescript/typescript-fetch/api-interface/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/api-interface/runtime/runtime.ts.golden @@ -3,7 +3,7 @@ * * TypeScript API Interface — 1.0.0 */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -13,7 +13,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -92,8 +95,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -135,12 +140,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -150,7 +161,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -166,9 +177,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -183,13 +192,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -199,7 +210,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -209,10 +220,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -221,18 +233,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -240,16 +256,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -268,11 +285,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -282,7 +299,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -292,7 +309,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -306,12 +323,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -329,15 +364,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -413,16 +461,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -449,7 +587,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -476,7 +617,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -486,5 +627,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/api-interface/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/api-interface/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/api-interface/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/api-interface/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/api-interface/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/api-interface/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/api-interface/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/api-interface/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/binary-transfer-media-types/README.md.golden b/tests/golden/typescript/typescript-fetch/binary-transfer-media-types/README.md.golden index 171922bb0..68c74cc17 100644 --- a/tests/golden/typescript/typescript-fetch/binary-transfer-media-types/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/binary-transfer-media-types/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, TransferApi } from 'binary-transfer-media-types'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'binary-transfer-media-types'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/binary-transfer-media-types/apis/TransferApi.ts.golden b/tests/golden/typescript/typescript-fetch/binary-transfer-media-types/apis/TransferApi.ts.golden index 1adcf7895..1c6d8a283 100644 --- a/tests/golden/typescript/typescript-fetch/binary-transfer-media-types/apis/TransferApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/binary-transfer-media-types/apis/TransferApi.ts.golden @@ -6,8 +6,24 @@ */ import type { UploadAssetMultipartRequestBody } from '../models/UploadAssetMultipartRequestBody'; import type { UploadMetadata } from '../models/UploadMetadata'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, BlobApiResponse, DefaultConfig, JSONApiResponse, RequiredError, ResponseError, VoidApiResponse, multipartHeaderValue, uploadFileData, uploadFileFilename } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + BlobApiResponse, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, + VoidApiResponse, + multipartHeaderValue, + uploadFileData, + uploadFileFilename, +} from '../runtime/runtime'; export interface ApiDownloadAssetRequest { assetId: string; @@ -18,51 +34,83 @@ export interface ApiUploadAssetRequest { } export type DownloadAssetRawResponse = - | BlobApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (BlobApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type UploadAssetRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type DownloadAssetErrorDetail = - { kind: 'notFound'; status: 404; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'notFound'; + status: 404; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class DownloadAssetError extends ResponseError { readonly detail: DownloadAssetErrorDetail; - constructor(response: Response, detail: DownloadAssetErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: DownloadAssetErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type UploadAssetErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class UploadAssetError extends ResponseError { readonly detail: UploadAssetErrorDetail; - constructor(response: Response, detail: UploadAssetErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: UploadAssetErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface TransferApiInterface { - downloadAssetRaw: (requestParameters: ApiDownloadAssetRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - downloadAsset: (requestParameters: ApiDownloadAssetRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - uploadAssetRaw: (requestParameters: ApiUploadAssetRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - uploadAsset: (requestParameters: ApiUploadAssetRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + downloadAssetRaw: ( + requestParameters: ApiDownloadAssetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + downloadAsset: ( + requestParameters: ApiDownloadAssetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + uploadAssetRaw: ( + requestParameters: ApiUploadAssetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + uploadAsset: ( + requestParameters: ApiUploadAssetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class TransferApi extends BaseAPI implements TransferApiInterface { @@ -73,12 +121,14 @@ export class TransferApi extends BaseAPI implements TransferApiInterface { super(configuration ?? DefaultConfig); } - async downloadAssetRaw(requestParameters: ApiDownloadAssetRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async downloadAssetRaw( + requestParameters: ApiDownloadAssetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.assetId === undefined || requestParameters.assetId === null) { throw new RequiredError( 'assetId', - 'Required parameter "assetId" was null or undefined when calling downloadAssetRaw().' + 'Required parameter "assetId" was null or undefined when calling downloadAssetRaw().', ); } // Build path with path parameters @@ -87,50 +137,70 @@ export class TransferApi extends BaseAPI implements TransferApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 404) { let errorValue: Promise | undefined; - throw new DownloadAssetError(response, { kind: 'notFound', status: response.status as 404, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new DownloadAssetError(response, { + kind: 'notFound', + status: response.status as 404, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new DownloadAssetError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new DownloadAssetError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new BlobApiResponse(response) as BlobApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async downloadAsset(requestParameters: ApiDownloadAssetRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async downloadAsset( + requestParameters: ApiDownloadAssetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.downloadAssetRaw(requestParameters, initOverrides); - return await response.value() as Blob; + return (await response.value()) as Blob; } - async uploadAssetRaw(requestParameters: ApiUploadAssetRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async uploadAssetRaw( + requestParameters: ApiUploadAssetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling uploadAssetRaw().' + 'Required parameter "body" was null or undefined when calling uploadAssetRaw().', ); } // Build path with path parameters @@ -138,8 +208,7 @@ export class TransferApi extends BaseAPI implements TransferApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Prepare request body const multipartBoundary = '----openapi-nexus-' + Math.random().toString(16).slice(2); @@ -160,37 +229,56 @@ export class TransferApi extends BaseAPI implements TransferApiInterface { multipartChunks.push('--' + multipartBoundary + '--\r\n'); const requestBody = new Blob(multipartChunks); // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new UploadAssetError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new UploadAssetError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new UploadAssetError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new UploadAssetError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async uploadAsset(requestParameters: ApiUploadAssetRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async uploadAsset( + requestParameters: ApiUploadAssetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.uploadAssetRaw(requestParameters, initOverrides); - return await response.value() as UploadMetadata; + return (await response.value()) as UploadMetadata; } } diff --git a/tests/golden/typescript/typescript-fetch/binary-transfer-media-types/package.json.golden b/tests/golden/typescript/typescript-fetch/binary-transfer-media-types/package.json.golden index 49330bb35..2e75cea35 100644 --- a/tests/golden/typescript/typescript-fetch/binary-transfer-media-types/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/binary-transfer-media-types/package.json.golden @@ -1,26 +1,26 @@ { + "name": "binary-transfer-media-types", + "version": "1.0.0", "description": "Covers multipart upload and octet-stream download.", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "binary-transfer-media-types", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/binary-transfer-media-types/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/binary-transfer-media-types/runtime/runtime.ts.golden index a74139e76..6f798fdb7 100644 --- a/tests/golden/typescript/typescript-fetch/binary-transfer-media-types/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/binary-transfer-media-types/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Binary Transfer Media Types — 1.0.0 * Covers multipart upload and octet-stream download. */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -126,8 +129,10 @@ function isFile(value: UploadFileInput): value is File { * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -169,12 +174,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -184,7 +195,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -200,9 +211,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -217,13 +226,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -233,7 +244,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -243,10 +254,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -255,18 +267,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -274,16 +290,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -302,11 +319,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -316,7 +333,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -326,7 +343,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -340,12 +357,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -363,15 +398,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -447,16 +495,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -483,7 +621,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -510,7 +651,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -520,5 +661,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/binary-transfer-media-types/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/binary-transfer-media-types/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/binary-transfer-media-types/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/binary-transfer-media-types/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/binary-transfer-media-types/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/binary-transfer-media-types/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/binary-transfer-media-types/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/binary-transfer-media-types/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/comprehensive-schemas/README.md.golden b/tests/golden/typescript/typescript-fetch/comprehensive-schemas/README.md.golden index 4764722a0..e348a51ec 100644 --- a/tests/golden/typescript/typescript-fetch/comprehensive-schemas/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/comprehensive-schemas/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'comprehensive-schema-types-example'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'comprehensive-schema-types-example const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/comprehensive-schemas/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/comprehensive-schemas/apis/DefaultApi.ts.golden index 7ab3facda..6b3aaae1d 100644 --- a/tests/golden/typescript/typescript-fetch/comprehensive-schemas/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/comprehensive-schemas/apis/DefaultApi.ts.golden @@ -4,22 +4,33 @@ * Comprehensive Schema Types Example — 1.0.0 * Comprehensive test for all OpenAPI v3.1.2 schema types */ -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; import { BaseAPI, DefaultConfig, ResponseError, VoidApiResponse } from '../runtime/runtime'; export type TestRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); - -export type TestErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestError extends ResponseError { readonly detail: TestErrorDetail; - constructor(response: Response, detail: TestErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } @@ -44,30 +55,39 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } diff --git a/tests/golden/typescript/typescript-fetch/comprehensive-schemas/models/ObjectWithTypedAdditionalProperties.ts.golden b/tests/golden/typescript/typescript-fetch/comprehensive-schemas/models/ObjectWithTypedAdditionalProperties.ts.golden index 294ca5fb8..925919d94 100644 --- a/tests/golden/typescript/typescript-fetch/comprehensive-schemas/models/ObjectWithTypedAdditionalProperties.ts.golden +++ b/tests/golden/typescript/typescript-fetch/comprehensive-schemas/models/ObjectWithTypedAdditionalProperties.ts.golden @@ -7,7 +7,8 @@ /** * Object with typed additional properties */ -export interface ObjectWithTypedAdditionalProperties extends Readonly> { +export interface ObjectWithTypedAdditionalProperties extends Readonly< + Record +> { readonly name: string; } diff --git a/tests/golden/typescript/typescript-fetch/comprehensive-schemas/package.json.golden b/tests/golden/typescript/typescript-fetch/comprehensive-schemas/package.json.golden index b8a308393..476b64103 100644 --- a/tests/golden/typescript/typescript-fetch/comprehensive-schemas/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/comprehensive-schemas/package.json.golden @@ -1,26 +1,26 @@ { + "name": "comprehensive-schema-types-example", + "version": "1.0.0", "description": "Comprehensive test for all OpenAPI v3.1.2 schema types", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "comprehensive-schema-types-example", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/comprehensive-schemas/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/comprehensive-schemas/runtime/runtime.ts.golden index f0efc3478..cec4a3bfd 100644 --- a/tests/golden/typescript/typescript-fetch/comprehensive-schemas/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/comprehensive-schemas/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Comprehensive Schema Types Example — 1.0.0 * Comprehensive test for all OpenAPI v3.1.2 schema types */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/comprehensive-schemas/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/comprehensive-schemas/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/comprehensive-schemas/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/comprehensive-schemas/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/comprehensive-schemas/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/comprehensive-schemas/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/comprehensive-schemas/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/comprehensive-schemas/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/delete-with-response-schema/README.md.golden b/tests/golden/typescript/typescript-fetch/delete-with-response-schema/README.md.golden index ff149e7a1..43696a245 100644 --- a/tests/golden/typescript/typescript-fetch/delete-with-response-schema/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/delete-with-response-schema/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, TestResourceApi } from 'test-api-with-delete-response-sc const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'test-api-with-delete-response-sche const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/delete-with-response-schema/apis/TestResourceApi.ts.golden b/tests/golden/typescript/typescript-fetch/delete-with-response-schema/apis/TestResourceApi.ts.golden index 6ad4ba0e5..d2431956b 100644 --- a/tests/golden/typescript/typescript-fetch/delete-with-response-schema/apis/TestResourceApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/delete-with-response-schema/apis/TestResourceApi.ts.golden @@ -8,8 +8,19 @@ import type { CreateTestResourceRequest } from '../models/CreateTestResourceRequ import type { CreateTestResourceResponse } from '../models/CreateTestResourceResponse'; import type { DeleteTestResourceResponse } from '../models/DeleteTestResourceResponse'; import type { HttpErrorResponse } from '../models/HttpErrorResponse'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, +} from '../runtime/runtime'; export interface ApiCreateTestResourceRequest { body: CreateTestResourceRequest; @@ -23,51 +34,82 @@ export interface ApiDeleteTestResourceRequest { } export type CreateTestResourceRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type DeleteTestResourceRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); -export type CreateTestResourceErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type CreateTestResourceErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class CreateTestResourceError extends ResponseError { readonly detail: CreateTestResourceErrorDetail; - constructor(response: Response, detail: CreateTestResourceErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: CreateTestResourceErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type DeleteTestResourceErrorDetail = - { kind: 'clientError'; status: number; raw: Response; value(): Promise } - | { kind: 'serverError'; status: number; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'clientError'; + status: number; + raw: Response; + value(): Promise; + } + | { + kind: 'serverError'; + status: number; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class DeleteTestResourceError extends ResponseError { readonly detail: DeleteTestResourceErrorDetail; - constructor(response: Response, detail: DeleteTestResourceErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: DeleteTestResourceErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface TestResourceApiInterface { - createTestResourceRaw: (requestParameters: ApiCreateTestResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - createTestResource: (requestParameters: ApiCreateTestResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - deleteTestResourceRaw: (requestParameters: ApiDeleteTestResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - deleteTestResource: (requestParameters: ApiDeleteTestResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + createTestResourceRaw: ( + requestParameters: ApiCreateTestResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + createTestResource: ( + requestParameters: ApiCreateTestResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + deleteTestResourceRaw: ( + requestParameters: ApiDeleteTestResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + deleteTestResource: ( + requestParameters: ApiDeleteTestResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class TestResourceApi extends BaseAPI implements TestResourceApiInterface { @@ -78,12 +120,14 @@ export class TestResourceApi extends BaseAPI implements TestResourceApiInterface super(configuration ?? DefaultConfig); } - async createTestResourceRaw(requestParameters: ApiCreateTestResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async createTestResourceRaw( + requestParameters: ApiCreateTestResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling createTestResourceRaw().' + 'Required parameter "body" was null or undefined when calling createTestResourceRaw().', ); } // Build path with path parameters @@ -98,89 +142,135 @@ export class TestResourceApi extends BaseAPI implements TestResourceApiInterface // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new CreateTestResourceError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new CreateTestResourceError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response) as JSONApiResponse & { + status: 200; + }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async createTestResource(requestParameters: ApiCreateTestResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async createTestResource( + requestParameters: ApiCreateTestResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.createTestResourceRaw(requestParameters, initOverrides); - return await response.value() as CreateTestResourceResponse; + return (await response.value()) as CreateTestResourceResponse; } - async deleteTestResourceRaw(requestParameters: ApiDeleteTestResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async deleteTestResourceRaw( + requestParameters: ApiDeleteTestResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.resourceId === undefined || requestParameters.resourceId === null) { throw new RequiredError( 'resourceId', - 'Required parameter "resourceId" was null or undefined when calling deleteTestResourceRaw().' + 'Required parameter "resourceId" was null or undefined when calling deleteTestResourceRaw().', ); } // Build path with path parameters let urlPath = `/v1/api/test-resource/{resource_id}`; - urlPath = urlPath.replace(`{resource_id}`, encodeURIComponent(String(requestParameters.resourceId))); + urlPath = urlPath.replace( + `{resource_id}`, + encodeURIComponent(String(requestParameters.resourceId)), + ); // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'DELETE', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status >= 400 && response.status < 500) { let errorValue: Promise | undefined; - throw new DeleteTestResourceError(response, { kind: 'clientError', status: response.status, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone()).value() }); - } - else if (response.status >= 500 && response.status < 600) { + throw new DeleteTestResourceError(response, { + kind: 'clientError', + status: response.status, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status >= 500 && response.status < 600) { let errorValue: Promise | undefined; - throw new DeleteTestResourceError(response, { kind: 'serverError', status: response.status, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone()).value() }); - } - else { + throw new DeleteTestResourceError(response, { + kind: 'serverError', + status: response.status, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new DeleteTestResourceError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new DeleteTestResourceError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response) as JSONApiResponse & { + status: 200; + }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async deleteTestResource(requestParameters: ApiDeleteTestResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async deleteTestResource( + requestParameters: ApiDeleteTestResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.deleteTestResourceRaw(requestParameters, initOverrides); - return await response.value() as DeleteTestResourceResponse; + return (await response.value()) as DeleteTestResourceResponse; } } diff --git a/tests/golden/typescript/typescript-fetch/delete-with-response-schema/package.json.golden b/tests/golden/typescript/typescript-fetch/delete-with-response-schema/package.json.golden index 7309084d9..1a5e1912a 100644 --- a/tests/golden/typescript/typescript-fetch/delete-with-response-schema/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/delete-with-response-schema/package.json.golden @@ -1,26 +1,26 @@ { + "name": "test-api-with-delete-response-schema", + "version": "1.0.0", "description": "Test fixture for DELETE operations with JSON response schemas and type alias request bodies", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "test-api-with-delete-response-schema", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/delete-with-response-schema/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/delete-with-response-schema/runtime/runtime.ts.golden index 37c19d852..827aebb74 100644 --- a/tests/golden/typescript/typescript-fetch/delete-with-response-schema/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/delete-with-response-schema/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Test API with DELETE Response Schema — 1.0.0 * Test fixture for DELETE operations with JSON response schemas and type alias request bodies */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/delete-with-response-schema/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/delete-with-response-schema/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/delete-with-response-schema/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/delete-with-response-schema/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/delete-with-response-schema/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/delete-with-response-schema/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/delete-with-response-schema/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/delete-with-response-schema/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/duplicate-param-names/README.md.golden b/tests/golden/typescript/typescript-fetch/duplicate-param-names/README.md.golden index a86601673..2a0776f89 100644 --- a/tests/golden/typescript/typescript-fetch/duplicate-param-names/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/duplicate-param-names/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, ItemsApi } from 'duplicate-parameter-names-test-api'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'duplicate-parameter-names-test-api const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/duplicate-param-names/apis/ItemsApi.ts.golden b/tests/golden/typescript/typescript-fetch/duplicate-param-names/apis/ItemsApi.ts.golden index 491df765a..12b9b3350 100644 --- a/tests/golden/typescript/typescript-fetch/duplicate-param-names/apis/ItemsApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/duplicate-param-names/apis/ItemsApi.ts.golden @@ -6,8 +6,20 @@ */ import type { CreateItemWithBodyConflictRequest } from '../models/CreateItemWithBodyConflictRequest'; import type { CreateItemWithBodyConflictResponse200 } from '../models/CreateItemWithBodyConflictResponse200'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError, VoidApiResponse } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, + VoidApiResponse, +} from '../runtime/runtime'; export interface ApiCreateItemWithBodyConflictRequest { /** @@ -22,31 +34,45 @@ export interface ApiCreateItemWithBodyConflictRequest { } export type CreateItemWithBodyConflictRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type CreateItemWithBodyConflictErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class CreateItemWithBodyConflictError extends ResponseError { readonly detail: CreateItemWithBodyConflictErrorDetail; - constructor(response: Response, detail: CreateItemWithBodyConflictErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: CreateItemWithBodyConflictErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface ItemsApiInterface { - createItemWithBodyConflictRaw: (requestParameters: ApiCreateItemWithBodyConflictRequest, - initOverrides?: RequestInit - | InitOverrideFunction) => Promise; - createItemWithBodyConflict: (requestParameters: ApiCreateItemWithBodyConflictRequest, - initOverrides?: RequestInit - | InitOverrideFunction) => Promise; + createItemWithBodyConflictRaw: ( + requestParameters: ApiCreateItemWithBodyConflictRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + createItemWithBodyConflict: ( + requestParameters: ApiCreateItemWithBodyConflictRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class ItemsApi extends BaseAPI implements ItemsApiInterface { @@ -57,19 +83,20 @@ export class ItemsApi extends BaseAPI implements ItemsApiInterface { super(configuration ?? DefaultConfig); } - async createItemWithBodyConflictRaw(requestParameters: ApiCreateItemWithBodyConflictRequest, - initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createItemWithBodyConflictRaw( + requestParameters: ApiCreateItemWithBodyConflictRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.itemId === undefined || requestParameters.itemId === null) { throw new RequiredError( 'itemId', - 'Required parameter "itemId" was null or undefined when calling createItemWithBodyConflictRaw().' + 'Required parameter "itemId" was null or undefined when calling createItemWithBodyConflictRaw().', ); } if (requestParameters.bodyBody === undefined || requestParameters.bodyBody === null) { throw new RequiredError( 'bodyBody', - 'Required parameter "bodyBody" was null or undefined when calling createItemWithBodyConflictRaw().' + 'Required parameter "bodyBody" was null or undefined when calling createItemWithBodyConflictRaw().', ); } // Build path with path parameters @@ -88,38 +115,58 @@ export class ItemsApi extends BaseAPI implements ItemsApiInterface { // Prepare request body const requestBody = requestParameters.bodyBody; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new CreateItemWithBodyConflictError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new CreateItemWithBodyConflictError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new CreateItemWithBodyConflictError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new CreateItemWithBodyConflictError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response) as JSONApiResponse & { + status: 200; + }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async createItemWithBodyConflict(requestParameters: ApiCreateItemWithBodyConflictRequest, - initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createItemWithBodyConflict( + requestParameters: ApiCreateItemWithBodyConflictRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.createItemWithBodyConflictRaw(requestParameters, initOverrides); - return await response.value() as CreateItemWithBodyConflictResponse200; + return (await response.value()) as CreateItemWithBodyConflictResponse200; } } diff --git a/tests/golden/typescript/typescript-fetch/duplicate-param-names/apis/UsersApi.ts.golden b/tests/golden/typescript/typescript-fetch/duplicate-param-names/apis/UsersApi.ts.golden index 096590ef0..c32822273 100644 --- a/tests/golden/typescript/typescript-fetch/duplicate-param-names/apis/UsersApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/duplicate-param-names/apis/UsersApi.ts.golden @@ -5,8 +5,20 @@ * Test API with duplicate parameter names across different locations */ import type { GetUserByIdDuplicateResponse200 } from '../models/GetUserByIdDuplicateResponse200'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError, VoidApiResponse } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, + VoidApiResponse, +} from '../runtime/runtime'; export interface ApiGetUserByIdDuplicateRequest { /** @@ -24,30 +36,51 @@ export interface ApiGetUserByIdDuplicateRequest { } export type GetUserByIdDuplicateRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type GetUserByIdDuplicateErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'notFound'; status: 404; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'notFound'; + status: 404; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class GetUserByIdDuplicateError extends ResponseError { readonly detail: GetUserByIdDuplicateErrorDetail; - constructor(response: Response, detail: GetUserByIdDuplicateErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: GetUserByIdDuplicateErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface UsersApiInterface { - getUserByIdDuplicateRaw: (requestParameters: ApiGetUserByIdDuplicateRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - getUserByIdDuplicate: (requestParameters: ApiGetUserByIdDuplicateRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + getUserByIdDuplicateRaw: ( + requestParameters: ApiGetUserByIdDuplicateRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + getUserByIdDuplicate: ( + requestParameters: ApiGetUserByIdDuplicateRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class UsersApi extends BaseAPI implements UsersApiInterface { @@ -58,12 +91,14 @@ export class UsersApi extends BaseAPI implements UsersApiInterface { super(configuration ?? DefaultConfig); } - async getUserByIdDuplicateRaw(requestParameters: ApiGetUserByIdDuplicateRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async getUserByIdDuplicateRaw( + requestParameters: ApiGetUserByIdDuplicateRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.pathId === undefined || requestParameters.pathId === null) { throw new RequiredError( 'pathId', - 'Required parameter "pathId" was null or undefined when calling getUserByIdDuplicateRaw().' + 'Required parameter "pathId" was null or undefined when calling getUserByIdDuplicateRaw().', ); } // Build path with path parameters @@ -75,48 +110,75 @@ export class UsersApi extends BaseAPI implements UsersApiInterface { queryParameters['id'] = requestParameters.queryId; } // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; if (requestParameters.headerId !== undefined) { headerParameters['id'] = String(requestParameters.headerId); } // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new GetUserByIdDuplicateError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 404) { + throw new GetUserByIdDuplicateError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 404) { let errorValue: Promise | undefined; - throw new GetUserByIdDuplicateError(response, { kind: 'notFound', status: response.status as 404, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new GetUserByIdDuplicateError(response, { + kind: 'notFound', + status: response.status as 404, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new GetUserByIdDuplicateError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new GetUserByIdDuplicateError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response) as JSONApiResponse & { + status: 200; + }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async getUserByIdDuplicate(requestParameters: ApiGetUserByIdDuplicateRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async getUserByIdDuplicate( + requestParameters: ApiGetUserByIdDuplicateRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.getUserByIdDuplicateRaw(requestParameters, initOverrides); - return await response.value() as GetUserByIdDuplicateResponse200; + return (await response.value()) as GetUserByIdDuplicateResponse200; } } diff --git a/tests/golden/typescript/typescript-fetch/duplicate-param-names/package.json.golden b/tests/golden/typescript/typescript-fetch/duplicate-param-names/package.json.golden index b6ccf254a..a278e8276 100644 --- a/tests/golden/typescript/typescript-fetch/duplicate-param-names/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/duplicate-param-names/package.json.golden @@ -1,26 +1,26 @@ { + "name": "duplicate-parameter-names-test-api", + "version": "1.0.0", "description": "Test API with duplicate parameter names across different locations", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "duplicate-parameter-names-test-api", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/duplicate-param-names/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/duplicate-param-names/runtime/runtime.ts.golden index 0a723ac90..707940f99 100644 --- a/tests/golden/typescript/typescript-fetch/duplicate-param-names/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/duplicate-param-names/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Duplicate Parameter Names Test API — 1.0.0 * Test API with duplicate parameter names across different locations */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/duplicate-param-names/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/duplicate-param-names/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/duplicate-param-names/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/duplicate-param-names/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/duplicate-param-names/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/duplicate-param-names/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/duplicate-param-names/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/duplicate-param-names/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/enum-repr/README.md.golden b/tests/golden/typescript/typescript-fetch/enum-repr/README.md.golden index 40aa603eb..4cb4c8453 100644 --- a/tests/golden/typescript/typescript-fetch/enum-repr/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/enum-repr/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, EnumReprApi } from 'enum-representation-api'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'enum-representation-api'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/enum-repr/apis/EnumReprApi.ts.golden b/tests/golden/typescript/typescript-fetch/enum-repr/apis/EnumReprApi.ts.golden index abf9597ce..5cdd1da80 100644 --- a/tests/golden/typescript/typescript-fetch/enum-repr/apis/EnumReprApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/enum-repr/apis/EnumReprApi.ts.golden @@ -9,8 +9,20 @@ import type { ExternallyTaggedEnum } from '../models/ExternallyTaggedEnum'; import type { InternallyTaggedEnum } from '../models/InternallyTaggedEnum'; import type { MixedEnum } from '../models/MixedEnum'; import type { UntaggedEnum } from '../models/UntaggedEnum'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError, VoidApiResponse } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, + VoidApiResponse, +} from '../runtime/runtime'; export interface ApiHandleAdjacentlyTaggedRequest { body: AdjacentlyTaggedEnum; @@ -33,117 +45,197 @@ export interface ApiHandleUntaggedRequest { } export type HandleAdjacentlyTaggedRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type HandleExternallyTaggedRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type HandleInternallyTaggedRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type HandleMixedRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type HandleUntaggedRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type HandleAdjacentlyTaggedErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class HandleAdjacentlyTaggedError extends ResponseError { readonly detail: HandleAdjacentlyTaggedErrorDetail; - constructor(response: Response, detail: HandleAdjacentlyTaggedErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: HandleAdjacentlyTaggedErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type HandleExternallyTaggedErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class HandleExternallyTaggedError extends ResponseError { readonly detail: HandleExternallyTaggedErrorDetail; - constructor(response: Response, detail: HandleExternallyTaggedErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: HandleExternallyTaggedErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type HandleInternallyTaggedErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class HandleInternallyTaggedError extends ResponseError { readonly detail: HandleInternallyTaggedErrorDetail; - constructor(response: Response, detail: HandleInternallyTaggedErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: HandleInternallyTaggedErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type HandleMixedErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class HandleMixedError extends ResponseError { readonly detail: HandleMixedErrorDetail; - constructor(response: Response, detail: HandleMixedErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: HandleMixedErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type HandleUntaggedErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class HandleUntaggedError extends ResponseError { readonly detail: HandleUntaggedErrorDetail; - constructor(response: Response, detail: HandleUntaggedErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: HandleUntaggedErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface EnumReprApiInterface { - handleAdjacentlyTaggedRaw: (requestParameters: ApiHandleAdjacentlyTaggedRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - handleAdjacentlyTagged: (requestParameters: ApiHandleAdjacentlyTaggedRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - handleExternallyTaggedRaw: (requestParameters: ApiHandleExternallyTaggedRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - handleExternallyTagged: (requestParameters: ApiHandleExternallyTaggedRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - handleInternallyTaggedRaw: (requestParameters: ApiHandleInternallyTaggedRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - handleInternallyTagged: (requestParameters: ApiHandleInternallyTaggedRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - handleMixedRaw: (requestParameters: ApiHandleMixedRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - handleMixed: (requestParameters: ApiHandleMixedRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - handleUntaggedRaw: (requestParameters: ApiHandleUntaggedRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - handleUntagged: (requestParameters: ApiHandleUntaggedRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + handleAdjacentlyTaggedRaw: ( + requestParameters: ApiHandleAdjacentlyTaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + handleAdjacentlyTagged: ( + requestParameters: ApiHandleAdjacentlyTaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + handleExternallyTaggedRaw: ( + requestParameters: ApiHandleExternallyTaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + handleExternallyTagged: ( + requestParameters: ApiHandleExternallyTaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + handleInternallyTaggedRaw: ( + requestParameters: ApiHandleInternallyTaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + handleInternallyTagged: ( + requestParameters: ApiHandleInternallyTaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + handleMixedRaw: ( + requestParameters: ApiHandleMixedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + handleMixed: ( + requestParameters: ApiHandleMixedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + handleUntaggedRaw: ( + requestParameters: ApiHandleUntaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + handleUntagged: ( + requestParameters: ApiHandleUntaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class EnumReprApi extends BaseAPI implements EnumReprApiInterface { @@ -154,13 +246,14 @@ export class EnumReprApi extends BaseAPI implements EnumReprApiInterface { super(configuration ?? DefaultConfig); } - async handleAdjacentlyTaggedRaw(requestParameters: ApiHandleAdjacentlyTaggedRequest, - initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async handleAdjacentlyTaggedRaw( + requestParameters: ApiHandleAdjacentlyTaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling handleAdjacentlyTaggedRaw().' + 'Required parameter "body" was null or undefined when calling handleAdjacentlyTaggedRaw().', ); } // Build path with path parameters @@ -175,47 +268,69 @@ export class EnumReprApi extends BaseAPI implements EnumReprApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new HandleAdjacentlyTaggedError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new HandleAdjacentlyTaggedError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new HandleAdjacentlyTaggedError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new HandleAdjacentlyTaggedError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response) as JSONApiResponse & { + status: 200; + }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async handleAdjacentlyTagged(requestParameters: ApiHandleAdjacentlyTaggedRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async handleAdjacentlyTagged( + requestParameters: ApiHandleAdjacentlyTaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.handleAdjacentlyTaggedRaw(requestParameters, initOverrides); - return await response.value() as AdjacentlyTaggedEnum; + return (await response.value()) as AdjacentlyTaggedEnum; } - async handleExternallyTaggedRaw(requestParameters: ApiHandleExternallyTaggedRequest, - initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async handleExternallyTaggedRaw( + requestParameters: ApiHandleExternallyTaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling handleExternallyTaggedRaw().' + 'Required parameter "body" was null or undefined when calling handleExternallyTaggedRaw().', ); } // Build path with path parameters @@ -230,47 +345,69 @@ export class EnumReprApi extends BaseAPI implements EnumReprApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new HandleExternallyTaggedError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new HandleExternallyTaggedError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new HandleExternallyTaggedError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new HandleExternallyTaggedError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response) as JSONApiResponse & { + status: 200; + }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async handleExternallyTagged(requestParameters: ApiHandleExternallyTaggedRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async handleExternallyTagged( + requestParameters: ApiHandleExternallyTaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.handleExternallyTaggedRaw(requestParameters, initOverrides); - return await response.value() as ExternallyTaggedEnum; + return (await response.value()) as ExternallyTaggedEnum; } - async handleInternallyTaggedRaw(requestParameters: ApiHandleInternallyTaggedRequest, - initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async handleInternallyTaggedRaw( + requestParameters: ApiHandleInternallyTaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling handleInternallyTaggedRaw().' + 'Required parameter "body" was null or undefined when calling handleInternallyTaggedRaw().', ); } // Build path with path parameters @@ -285,46 +422,69 @@ export class EnumReprApi extends BaseAPI implements EnumReprApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new HandleInternallyTaggedError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new HandleInternallyTaggedError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new HandleInternallyTaggedError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new HandleInternallyTaggedError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response) as JSONApiResponse & { + status: 200; + }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async handleInternallyTagged(requestParameters: ApiHandleInternallyTaggedRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async handleInternallyTagged( + requestParameters: ApiHandleInternallyTaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.handleInternallyTaggedRaw(requestParameters, initOverrides); - return await response.value() as InternallyTaggedEnum; + return (await response.value()) as InternallyTaggedEnum; } - async handleMixedRaw(requestParameters: ApiHandleMixedRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async handleMixedRaw( + requestParameters: ApiHandleMixedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling handleMixedRaw().' + 'Required parameter "body" was null or undefined when calling handleMixedRaw().', ); } // Build path with path parameters @@ -339,46 +499,67 @@ export class EnumReprApi extends BaseAPI implements EnumReprApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new HandleMixedError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new HandleMixedError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new HandleMixedError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new HandleMixedError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async handleMixed(requestParameters: ApiHandleMixedRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async handleMixed( + requestParameters: ApiHandleMixedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.handleMixedRaw(requestParameters, initOverrides); - return await response.value() as MixedEnum; + return (await response.value()) as MixedEnum; } - async handleUntaggedRaw(requestParameters: ApiHandleUntaggedRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async handleUntaggedRaw( + requestParameters: ApiHandleUntaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling handleUntaggedRaw().' + 'Required parameter "body" was null or undefined when calling handleUntaggedRaw().', ); } // Build path with path parameters @@ -393,37 +574,56 @@ export class EnumReprApi extends BaseAPI implements EnumReprApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new HandleUntaggedError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new HandleUntaggedError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new HandleUntaggedError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new HandleUntaggedError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async handleUntagged(requestParameters: ApiHandleUntaggedRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async handleUntagged( + requestParameters: ApiHandleUntaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.handleUntaggedRaw(requestParameters, initOverrides); - return await response.value() as UntaggedEnum; + return (await response.value()) as UntaggedEnum; } } diff --git a/tests/golden/typescript/typescript-fetch/enum-repr/models/AdjacentlyTaggedEnum.ts.golden b/tests/golden/typescript/typescript-fetch/enum-repr/models/AdjacentlyTaggedEnum.ts.golden index b2b831564..af385123d 100644 --- a/tests/golden/typescript/typescript-fetch/enum-repr/models/AdjacentlyTaggedEnum.ts.golden +++ b/tests/golden/typescript/typescript-fetch/enum-repr/models/AdjacentlyTaggedEnum.ts.golden @@ -12,4 +12,6 @@ import type { VariantB } from './VariantB'; The tag and content are separate fields: `{"ty": "VariantA", "data": {"field1": "...", "field2": 123}}` */ -export type AdjacentlyTaggedEnum = { ty: 'ADJACENTLY_TAGGED_ENUM_VARIANT_A'; data: VariantA } | { ty: 'ADJACENTLY_TAGGED_ENUM_VARIANT_B'; data: VariantB }; +export type AdjacentlyTaggedEnum = + | { ty: 'ADJACENTLY_TAGGED_ENUM_VARIANT_A'; data: VariantA } + | { ty: 'ADJACENTLY_TAGGED_ENUM_VARIANT_B'; data: VariantB }; diff --git a/tests/golden/typescript/typescript-fetch/enum-repr/models/ExternallyTaggedEnum.ts.golden b/tests/golden/typescript/typescript-fetch/enum-repr/models/ExternallyTaggedEnum.ts.golden index 51446f1fa..09dc7debe 100644 --- a/tests/golden/typescript/typescript-fetch/enum-repr/models/ExternallyTaggedEnum.ts.golden +++ b/tests/golden/typescript/typescript-fetch/enum-repr/models/ExternallyTaggedEnum.ts.golden @@ -12,4 +12,6 @@ import type { VariantB } from './VariantB'; This is the default representation where the variant name is the key and the content is the value: `{"VariantA": {"field1": "...", "field2": 123}}` */ -export type ExternallyTaggedEnum = { 'EXTERNALLY_TAGGED_ENUM_VARIANT_A': VariantA } | { 'EXTERNALLY_TAGGED_ENUM_VARIANT_B': VariantB }; +export type ExternallyTaggedEnum = + | { EXTERNALLY_TAGGED_ENUM_VARIANT_A: VariantA } + | { EXTERNALLY_TAGGED_ENUM_VARIANT_B: VariantB }; diff --git a/tests/golden/typescript/typescript-fetch/enum-repr/models/InternallyTaggedEnum.ts.golden b/tests/golden/typescript/typescript-fetch/enum-repr/models/InternallyTaggedEnum.ts.golden index b7c003a81..75b637a62 100644 --- a/tests/golden/typescript/typescript-fetch/enum-repr/models/InternallyTaggedEnum.ts.golden +++ b/tests/golden/typescript/typescript-fetch/enum-repr/models/InternallyTaggedEnum.ts.golden @@ -12,4 +12,6 @@ import type { VariantB } from './VariantB'; The tag is a field inside the object alongside other fields: `{"ty": "VariantA", "field1": "...", "field2": 123}` */ -export type InternallyTaggedEnum = ({ ty: 'INTERNALLY_TAGGED_ENUM_VARIANT_A' } & VariantA) | ({ ty: 'INTERNALLY_TAGGED_ENUM_VARIANT_B' } & VariantB); +export type InternallyTaggedEnum = + | ({ ty: 'INTERNALLY_TAGGED_ENUM_VARIANT_A' } & VariantA) + | ({ ty: 'INTERNALLY_TAGGED_ENUM_VARIANT_B' } & VariantB); diff --git a/tests/golden/typescript/typescript-fetch/enum-repr/package.json.golden b/tests/golden/typescript/typescript-fetch/enum-repr/package.json.golden index 7101a4201..3c8b24351 100644 --- a/tests/golden/typescript/typescript-fetch/enum-repr/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/enum-repr/package.json.golden @@ -1,27 +1,27 @@ { + "name": "enum-representation-api", + "version": "1.0.0", "description": "This API demonstrates all 4 kinds of enum representation types: Externally Tagged, Internally Tagged, Adjacently Tagged, and Untagged", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "license": "MIT OR Apache-2.0", + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "license": "MIT OR Apache-2.0", - "main": "./dist/index.js", - "name": "enum-representation-api", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/enum-repr/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/enum-repr/runtime/runtime.ts.golden index b8ea08e2f..03d20b4a2 100644 --- a/tests/golden/typescript/typescript-fetch/enum-repr/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/enum-repr/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Enum Representation API — 1.0.0 * This API demonstrates all 4 kinds of enum representation types: Externally Tagged, Internally Tagged, Adjacently Tagged, and Untagged */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/enum-repr/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/enum-repr/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/enum-repr/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/enum-repr/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/enum-repr/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/enum-repr/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/enum-repr/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/enum-repr/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/interface-with-enum-reference/README.md.golden b/tests/golden/typescript/typescript-fetch/interface-with-enum-reference/README.md.golden index 6fbe7e6ce..610b5b809 100644 --- a/tests/golden/typescript/typescript-fetch/interface-with-enum-reference/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/interface-with-enum-reference/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'interface-with-enum-reference-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'interface-with-enum-reference-test const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/interface-with-enum-reference/package.json.golden b/tests/golden/typescript/typescript-fetch/interface-with-enum-reference/package.json.golden index 3365d12ea..9ae346ee9 100644 --- a/tests/golden/typescript/typescript-fetch/interface-with-enum-reference/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/interface-with-enum-reference/package.json.golden @@ -1,26 +1,26 @@ { + "name": "interface-with-enum-reference-test", + "version": "1.0.0", "description": "Test case for interfaces that reference enum types", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "interface-with-enum-reference-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/interface-with-enum-reference/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/interface-with-enum-reference/runtime/runtime.ts.golden index c23d8f45b..e3b7205d3 100644 --- a/tests/golden/typescript/typescript-fetch/interface-with-enum-reference/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/interface-with-enum-reference/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Interface with Enum Reference Test — 1.0.0 * Test case for interfaces that reference enum types */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/interface-with-enum-reference/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/interface-with-enum-reference/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/interface-with-enum-reference/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/interface-with-enum-reference/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/interface-with-enum-reference/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/interface-with-enum-reference/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/interface-with-enum-reference/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/interface-with-enum-reference/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/media-type-selection/README.md.golden b/tests/golden/typescript/typescript-fetch/media-type-selection/README.md.golden index d1515a18f..1d11ca296 100644 --- a/tests/golden/typescript/typescript-fetch/media-type-selection/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/media-type-selection/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, MediaApi } from 'media-type-selection'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'media-type-selection'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/media-type-selection/apis/MediaApi.ts.golden b/tests/golden/typescript/typescript-fetch/media-type-selection/apis/MediaApi.ts.golden index 5b125cd51..c31516cb5 100644 --- a/tests/golden/typescript/typescript-fetch/media-type-selection/apis/MediaApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/media-type-selection/apis/MediaApi.ts.golden @@ -6,8 +6,25 @@ */ import type { Payload } from '../models/Payload'; import type { SendParameterizedMultipartMultipartRequestBody } from '../models/SendParameterizedMultipartMultipartRequestBody'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, BlobApiResponse, DefaultConfig, JSONApiResponse, RequiredError, ResponseError, TextApiResponse, VoidApiResponse, multipartHeaderValue, uploadFileData, uploadFileFilename } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + BlobApiResponse, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, + TextApiResponse, + VoidApiResponse, + multipartHeaderValue, + uploadFileData, + uploadFileFilename, +} from '../runtime/runtime'; export interface ApiSendJsonPreferredRequest { body: Payload; @@ -22,130 +39,180 @@ export interface ApiSendVendorJsonRequest { } export type SendJsonPreferredRawResponse = - | VoidApiResponse & { status: 204 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 204 }) + | (VoidApiResponse & HttpSuccessResponse); export type SendParameterizedMultipartRawResponse = - | VoidApiResponse & { status: 204 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 204 }) + | (VoidApiResponse & HttpSuccessResponse); export type SendVendorJsonRawResponse = - | VoidApiResponse & { status: 204 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 204 }) + | (VoidApiResponse & HttpSuccessResponse); export type GetOctetPreferredRawResponse = - | BlobApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (BlobApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type GetTextPreferredRawResponse = - | TextApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (TextApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type GetVendorJsonRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); - -export type SendJsonPreferredErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type SendJsonPreferredErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class SendJsonPreferredError extends ResponseError { readonly detail: SendJsonPreferredErrorDetail; - constructor(response: Response, detail: SendJsonPreferredErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: SendJsonPreferredErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type SendParameterizedMultipartErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type SendParameterizedMultipartErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class SendParameterizedMultipartError extends ResponseError { readonly detail: SendParameterizedMultipartErrorDetail; - constructor(response: Response, detail: SendParameterizedMultipartErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: SendParameterizedMultipartErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type SendVendorJsonErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type SendVendorJsonErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class SendVendorJsonError extends ResponseError { readonly detail: SendVendorJsonErrorDetail; - constructor(response: Response, detail: SendVendorJsonErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: SendVendorJsonErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type GetOctetPreferredErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type GetOctetPreferredErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class GetOctetPreferredError extends ResponseError { readonly detail: GetOctetPreferredErrorDetail; - constructor(response: Response, detail: GetOctetPreferredErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: GetOctetPreferredErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type GetTextPreferredErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type GetTextPreferredErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class GetTextPreferredError extends ResponseError { readonly detail: GetTextPreferredErrorDetail; - constructor(response: Response, detail: GetTextPreferredErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: GetTextPreferredErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type GetVendorJsonErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type GetVendorJsonErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class GetVendorJsonError extends ResponseError { readonly detail: GetVendorJsonErrorDetail; - constructor(response: Response, detail: GetVendorJsonErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: GetVendorJsonErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface MediaApiInterface { - sendJsonPreferredRaw: (requestParameters: ApiSendJsonPreferredRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - sendJsonPreferred: (requestParameters: ApiSendJsonPreferredRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - sendParameterizedMultipartRaw: (requestParameters: ApiSendParameterizedMultipartRequest, - initOverrides?: RequestInit - | InitOverrideFunction) => Promise; - sendParameterizedMultipart: (requestParameters: ApiSendParameterizedMultipartRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - sendVendorJsonRaw: (requestParameters: ApiSendVendorJsonRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - sendVendorJson: (requestParameters: ApiSendVendorJsonRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - getOctetPreferredRaw: (initOverrides?: RequestInit - | InitOverrideFunction) => Promise; + sendJsonPreferredRaw: ( + requestParameters: ApiSendJsonPreferredRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + sendJsonPreferred: ( + requestParameters: ApiSendJsonPreferredRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + sendParameterizedMultipartRaw: ( + requestParameters: ApiSendParameterizedMultipartRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + sendParameterizedMultipart: ( + requestParameters: ApiSendParameterizedMultipartRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + sendVendorJsonRaw: ( + requestParameters: ApiSendVendorJsonRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + sendVendorJson: ( + requestParameters: ApiSendVendorJsonRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + getOctetPreferredRaw: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; getOctetPreferred: (initOverrides?: RequestInit | InitOverrideFunction) => Promise; - getTextPreferredRaw: (initOverrides?: RequestInit - | InitOverrideFunction) => Promise; + getTextPreferredRaw: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; getTextPreferred: (initOverrides?: RequestInit | InitOverrideFunction) => Promise; - getVendorJsonRaw: (initOverrides?: RequestInit - | InitOverrideFunction) => Promise; + getVendorJsonRaw: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; getVendorJson: (initOverrides?: RequestInit | InitOverrideFunction) => Promise; } @@ -157,12 +224,14 @@ export class MediaApi extends BaseAPI implements MediaApiInterface { super(configuration ?? DefaultConfig); } - async sendJsonPreferredRaw(requestParameters: ApiSendJsonPreferredRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async sendJsonPreferredRaw( + requestParameters: ApiSendJsonPreferredRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling sendJsonPreferredRaw().' + 'Required parameter "body" was null or undefined when calling sendJsonPreferredRaw().', ); } // Build path with path parameters @@ -177,43 +246,56 @@ export class MediaApi extends BaseAPI implements MediaApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new SendJsonPreferredError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new SendJsonPreferredError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 204) { return new VoidApiResponse(response) as VoidApiResponse & { status: 204 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async sendJsonPreferred(requestParameters: ApiSendJsonPreferredRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async sendJsonPreferred( + requestParameters: ApiSendJsonPreferredRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.sendJsonPreferredRaw(requestParameters, initOverrides); return await response.value(); } - async sendParameterizedMultipartRaw(requestParameters: ApiSendParameterizedMultipartRequest, - initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async sendParameterizedMultipartRaw( + requestParameters: ApiSendParameterizedMultipartRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling sendParameterizedMultipartRaw().' + 'Required parameter "body" was null or undefined when calling sendParameterizedMultipartRaw().', ); } // Build path with path parameters @@ -221,8 +303,7 @@ export class MediaApi extends BaseAPI implements MediaApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Prepare request body const multipartBoundary = '----openapi-nexus-' + Math.random().toString(16).slice(2); @@ -242,42 +323,56 @@ export class MediaApi extends BaseAPI implements MediaApiInterface { multipartChunks.push('--' + multipartBoundary + '--\r\n'); const requestBody = new Blob(multipartChunks); // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new SendParameterizedMultipartError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new SendParameterizedMultipartError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 204) { return new VoidApiResponse(response) as VoidApiResponse & { status: 204 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async sendParameterizedMultipart(requestParameters: ApiSendParameterizedMultipartRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async sendParameterizedMultipart( + requestParameters: ApiSendParameterizedMultipartRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.sendParameterizedMultipartRaw(requestParameters, initOverrides); return await response.value(); } - async sendVendorJsonRaw(requestParameters: ApiSendVendorJsonRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async sendVendorJsonRaw( + requestParameters: ApiSendVendorJsonRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling sendVendorJsonRaw().' + 'Required parameter "body" was null or undefined when calling sendVendorJsonRaw().', ); } // Build path with path parameters @@ -292,153 +387,195 @@ export class MediaApi extends BaseAPI implements MediaApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'PATCH', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new SendVendorJsonError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new SendVendorJsonError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 204) { return new VoidApiResponse(response) as VoidApiResponse & { status: 204 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async sendVendorJson(requestParameters: ApiSendVendorJsonRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async sendVendorJson( + requestParameters: ApiSendVendorJsonRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.sendVendorJsonRaw(requestParameters, initOverrides); return await response.value(); } - async getOctetPreferredRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getOctetPreferredRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/response/octet-before-xml`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new GetOctetPreferredError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new GetOctetPreferredError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new BlobApiResponse(response) as BlobApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } async getOctetPreferred(initOverrides?: RequestInit | InitOverrideFunction): Promise { const response = await this.getOctetPreferredRaw(initOverrides); - return await response.value() as Blob; + return (await response.value()) as Blob; } - async getTextPreferredRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getTextPreferredRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/response/text-before-xml`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new GetTextPreferredError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new GetTextPreferredError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new TextApiResponse(response) as TextApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } async getTextPreferred(initOverrides?: RequestInit | InitOverrideFunction): Promise { const response = await this.getTextPreferredRaw(initOverrides); - return await response.value() as string; + return (await response.value()) as string; } - async getVendorJsonRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getVendorJsonRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/response/vendor-json`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new GetVendorJsonError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new GetVendorJsonError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } async getVendorJson(initOverrides?: RequestInit | InitOverrideFunction): Promise { const response = await this.getVendorJsonRaw(initOverrides); - return await response.value() as Payload; + return (await response.value()) as Payload; } } diff --git a/tests/golden/typescript/typescript-fetch/media-type-selection/package.json.golden b/tests/golden/typescript/typescript-fetch/media-type-selection/package.json.golden index 8f68aac7c..c33db181e 100644 --- a/tests/golden/typescript/typescript-fetch/media-type-selection/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/media-type-selection/package.json.golden @@ -1,26 +1,26 @@ { + "name": "media-type-selection", + "version": "1.0.0", "description": "Covers normalized media-type selection for requests and responses.", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "media-type-selection", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/media-type-selection/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/media-type-selection/runtime/runtime.ts.golden index 015503755..b546f79f3 100644 --- a/tests/golden/typescript/typescript-fetch/media-type-selection/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/media-type-selection/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Media Type Selection — 1.0.0 * Covers normalized media-type selection for requests and responses. */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -126,8 +129,10 @@ function isFile(value: UploadFileInput): value is File { * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -169,12 +174,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -184,7 +195,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -200,9 +211,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -217,13 +226,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -233,7 +244,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -243,10 +254,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -255,18 +267,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -274,16 +290,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -302,11 +319,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -316,7 +333,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -326,7 +343,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -340,12 +357,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -363,15 +398,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -447,16 +495,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -483,7 +621,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -510,7 +651,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -520,5 +661,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/media-type-selection/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/media-type-selection/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/media-type-selection/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/media-type-selection/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/media-type-selection/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/media-type-selection/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/media-type-selection/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/media-type-selection/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/minimal/README.md.golden b/tests/golden/typescript/typescript-fetch/minimal/README.md.golden index d815c698a..ecb719c11 100644 --- a/tests/golden/typescript/typescript-fetch/minimal/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/minimal/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'minimal-api'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'minimal-api'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/minimal/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/minimal/apis/DefaultApi.ts.golden index 58867e324..0a914dcfa 100644 --- a/tests/golden/typescript/typescript-fetch/minimal/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/minimal/apis/DefaultApi.ts.golden @@ -3,22 +3,33 @@ * * Minimal API — 1.0.0 */ -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; import { BaseAPI, DefaultConfig, ResponseError, VoidApiResponse } from '../runtime/runtime'; export type GetTestRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); - -export type GetTestErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type GetTestErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class GetTestError extends ResponseError { readonly detail: GetTestErrorDetail; - constructor(response: Response, detail: GetTestErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: GetTestErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } @@ -37,37 +48,47 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async getTestRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getTestRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/test`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new GetTestError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new GetTestError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } diff --git a/tests/golden/typescript/typescript-fetch/minimal/package.json.golden b/tests/golden/typescript/typescript-fetch/minimal/package.json.golden index 660fc0d00..e2e9fe06f 100644 --- a/tests/golden/typescript/typescript-fetch/minimal/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/minimal/package.json.golden @@ -1,26 +1,26 @@ { + "name": "minimal-api", + "version": "1.0.0", "description": "TypeScript client for Minimal API", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "minimal-api", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/minimal/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/minimal/runtime/runtime.ts.golden index 245651890..1061fadac 100644 --- a/tests/golden/typescript/typescript-fetch/minimal/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/minimal/runtime/runtime.ts.golden @@ -3,7 +3,7 @@ * * Minimal API — 1.0.0 */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -13,7 +13,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -92,8 +95,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -135,12 +140,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -150,7 +161,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -166,9 +177,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -183,13 +192,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -199,7 +210,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -209,10 +220,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -221,18 +233,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -240,16 +256,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -268,11 +285,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -282,7 +299,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -292,7 +309,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -306,12 +323,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -329,15 +364,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -413,16 +461,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -449,7 +587,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -476,7 +617,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -486,5 +627,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/minimal/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/minimal/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/minimal/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/minimal/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/minimal/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/minimal/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/minimal/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/minimal/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/multipart-edge-cases/README.md.golden b/tests/golden/typescript/typescript-fetch/multipart-edge-cases/README.md.golden index 3f8afb9b6..4e060a2e3 100644 --- a/tests/golden/typescript/typescript-fetch/multipart-edge-cases/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/multipart-edge-cases/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, MultipartApi } from 'multipart-edge-cases'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'multipart-edge-cases'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/multipart-edge-cases/apis/MultipartApi.ts.golden b/tests/golden/typescript/typescript-fetch/multipart-edge-cases/apis/MultipartApi.ts.golden index 7f5c38dc2..da46eb60e 100644 --- a/tests/golden/typescript/typescript-fetch/multipart-edge-cases/apis/MultipartApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/multipart-edge-cases/apis/MultipartApi.ts.golden @@ -6,8 +6,22 @@ */ import type { SendOptionalPartsMultipartRequestBody } from '../models/SendOptionalPartsMultipartRequestBody'; import type { SendTextFieldsMultipartRequestBody } from '../models/SendTextFieldsMultipartRequestBody'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, RequiredError, ResponseError, VoidApiResponse, multipartHeaderValue, uploadFileData, uploadFileFilename } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + RequiredError, + ResponseError, + VoidApiResponse, + multipartHeaderValue, + uploadFileData, + uploadFileFilename, +} from '../runtime/runtime'; export interface ApiSendOptionalPartsRequest { body?: SendOptionalPartsMultipartRequestBody; @@ -18,49 +32,69 @@ export interface ApiSendTextFieldsRequest { } export type SendOptionalPartsRawResponse = - | VoidApiResponse & { status: 204 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 204 }) + | (VoidApiResponse & HttpSuccessResponse); export type SendTextFieldsRawResponse = - | VoidApiResponse & { status: 204 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 204 }) + | (VoidApiResponse & HttpSuccessResponse); -export type SendOptionalPartsErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type SendOptionalPartsErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class SendOptionalPartsError extends ResponseError { readonly detail: SendOptionalPartsErrorDetail; - constructor(response: Response, detail: SendOptionalPartsErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: SendOptionalPartsErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type SendTextFieldsErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type SendTextFieldsErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class SendTextFieldsError extends ResponseError { readonly detail: SendTextFieldsErrorDetail; - constructor(response: Response, detail: SendTextFieldsErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: SendTextFieldsErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface MultipartApiInterface { - sendOptionalPartsRaw: (requestParameters: ApiSendOptionalPartsRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - sendOptionalParts: (requestParameters: ApiSendOptionalPartsRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - sendTextFieldsRaw: (requestParameters: ApiSendTextFieldsRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - sendTextFields: (requestParameters: ApiSendTextFieldsRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + sendOptionalPartsRaw: ( + requestParameters: ApiSendOptionalPartsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + sendOptionalParts: ( + requestParameters: ApiSendOptionalPartsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + sendTextFieldsRaw: ( + requestParameters: ApiSendTextFieldsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + sendTextFields: ( + requestParameters: ApiSendTextFieldsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class MultipartApi extends BaseAPI implements MultipartApiInterface { @@ -71,15 +105,16 @@ export class MultipartApi extends BaseAPI implements MultipartApiInterface { super(configuration ?? DefaultConfig); } - async sendOptionalPartsRaw(requestParameters: ApiSendOptionalPartsRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async sendOptionalPartsRaw( + requestParameters: ApiSendOptionalPartsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/multipart/optional`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Prepare request body let requestBody: Blob | undefined = undefined; @@ -119,42 +154,56 @@ export class MultipartApi extends BaseAPI implements MultipartApiInterface { requestBody = new Blob(multipartChunks); } // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new SendOptionalPartsError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new SendOptionalPartsError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 204) { return new VoidApiResponse(response) as VoidApiResponse & { status: 204 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async sendOptionalParts(requestParameters: ApiSendOptionalPartsRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async sendOptionalParts( + requestParameters: ApiSendOptionalPartsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.sendOptionalPartsRaw(requestParameters, initOverrides); return await response.value(); } - async sendTextFieldsRaw(requestParameters: ApiSendTextFieldsRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async sendTextFieldsRaw( + requestParameters: ApiSendTextFieldsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling sendTextFieldsRaw().' + 'Required parameter "body" was null or undefined when calling sendTextFieldsRaw().', ); } // Build path with path parameters @@ -162,8 +211,7 @@ export class MultipartApi extends BaseAPI implements MultipartApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Prepare request body const multipartBoundary = '----openapi-nexus-' + Math.random().toString(16).slice(2); @@ -181,32 +229,44 @@ export class MultipartApi extends BaseAPI implements MultipartApiInterface { multipartChunks.push('--' + multipartBoundary + '--\r\n'); const requestBody = new Blob(multipartChunks); // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new SendTextFieldsError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new SendTextFieldsError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 204) { return new VoidApiResponse(response) as VoidApiResponse & { status: 204 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async sendTextFields(requestParameters: ApiSendTextFieldsRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async sendTextFields( + requestParameters: ApiSendTextFieldsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.sendTextFieldsRaw(requestParameters, initOverrides); return await response.value(); } diff --git a/tests/golden/typescript/typescript-fetch/multipart-edge-cases/package.json.golden b/tests/golden/typescript/typescript-fetch/multipart-edge-cases/package.json.golden index 44bd1c150..63eb8039b 100644 --- a/tests/golden/typescript/typescript-fetch/multipart-edge-cases/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/multipart-edge-cases/package.json.golden @@ -1,26 +1,26 @@ { + "name": "multipart-edge-cases", + "version": "1.0.0", "description": "Covers optional multipart bodies, optional parts, and text-only multipart fields.", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "multipart-edge-cases", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/multipart-edge-cases/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/multipart-edge-cases/runtime/runtime.ts.golden index e6aa24313..9cfc74b13 100644 --- a/tests/golden/typescript/typescript-fetch/multipart-edge-cases/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/multipart-edge-cases/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Multipart Edge Cases — 1.0.0 * Covers optional multipart bodies, optional parts, and text-only multipart fields. */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -126,8 +129,10 @@ function isFile(value: UploadFileInput): value is File { * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -169,12 +174,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -184,7 +195,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -200,9 +211,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -217,13 +226,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -233,7 +244,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -243,10 +254,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -255,18 +267,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -274,16 +290,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -302,11 +319,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -316,7 +333,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -326,7 +343,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -340,12 +357,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -363,15 +398,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -447,16 +495,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -483,7 +621,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -510,7 +651,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -520,5 +661,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/multipart-edge-cases/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/multipart-edge-cases/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/multipart-edge-cases/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/multipart-edge-cases/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/multipart-edge-cases/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/multipart-edge-cases/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/multipart-edge-cases/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/multipart-edge-cases/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/multipart-explicit-encoding/README.md.golden b/tests/golden/typescript/typescript-fetch/multipart-explicit-encoding/README.md.golden index 88ef8ba41..fbc60bd14 100644 --- a/tests/golden/typescript/typescript-fetch/multipart-explicit-encoding/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/multipart-explicit-encoding/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, TransferApi } from 'multipart-explicit-encoding'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'multipart-explicit-encoding'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/multipart-explicit-encoding/apis/TransferApi.ts.golden b/tests/golden/typescript/typescript-fetch/multipart-explicit-encoding/apis/TransferApi.ts.golden index 37c0cb7ed..7b9ef2a8c 100644 --- a/tests/golden/typescript/typescript-fetch/multipart-explicit-encoding/apis/TransferApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/multipart-explicit-encoding/apis/TransferApi.ts.golden @@ -5,36 +5,60 @@ * Covers explicit multipart part content types. */ import type { UploadEncodedAssetMultipartRequestBody } from '../models/UploadEncodedAssetMultipartRequestBody'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, RequiredError, ResponseError, VoidApiResponse, multipartHeaderValue, uploadFileData, uploadFileFilename } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + RequiredError, + ResponseError, + VoidApiResponse, + multipartHeaderValue, + uploadFileData, + uploadFileFilename, +} from '../runtime/runtime'; export interface ApiUploadEncodedAssetRequest { body: UploadEncodedAssetMultipartRequestBody; } export type UploadEncodedAssetRawResponse = - | VoidApiResponse & { status: 204 } - | VoidApiResponse & HttpSuccessResponse; + | (VoidApiResponse & { status: 204 }) + | (VoidApiResponse & HttpSuccessResponse); - -export type UploadEncodedAssetErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type UploadEncodedAssetErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class UploadEncodedAssetError extends ResponseError { readonly detail: UploadEncodedAssetErrorDetail; - constructor(response: Response, detail: UploadEncodedAssetErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: UploadEncodedAssetErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface TransferApiInterface { - uploadEncodedAssetRaw: (requestParameters: ApiUploadEncodedAssetRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - uploadEncodedAsset: (requestParameters: ApiUploadEncodedAssetRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + uploadEncodedAssetRaw: ( + requestParameters: ApiUploadEncodedAssetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + uploadEncodedAsset: ( + requestParameters: ApiUploadEncodedAssetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class TransferApi extends BaseAPI implements TransferApiInterface { @@ -45,12 +69,14 @@ export class TransferApi extends BaseAPI implements TransferApiInterface { super(configuration ?? DefaultConfig); } - async uploadEncodedAssetRaw(requestParameters: ApiUploadEncodedAssetRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async uploadEncodedAssetRaw( + requestParameters: ApiUploadEncodedAssetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling uploadEncodedAssetRaw().' + 'Required parameter "body" was null or undefined when calling uploadEncodedAssetRaw().', ); } // Build path with path parameters @@ -58,8 +84,7 @@ export class TransferApi extends BaseAPI implements TransferApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Prepare request body const multipartBoundary = '----openapi-nexus-' + Math.random().toString(16).slice(2); @@ -83,32 +108,44 @@ export class TransferApi extends BaseAPI implements TransferApiInterface { multipartChunks.push('--' + multipartBoundary + '--\r\n'); const requestBody = new Blob(multipartChunks); // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new UploadEncodedAssetError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new UploadEncodedAssetError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 204) { return new VoidApiResponse(response) as VoidApiResponse & { status: 204 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async uploadEncodedAsset(requestParameters: ApiUploadEncodedAssetRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async uploadEncodedAsset( + requestParameters: ApiUploadEncodedAssetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.uploadEncodedAssetRaw(requestParameters, initOverrides); return await response.value(); } diff --git a/tests/golden/typescript/typescript-fetch/multipart-explicit-encoding/package.json.golden b/tests/golden/typescript/typescript-fetch/multipart-explicit-encoding/package.json.golden index d6e22243e..f7a21f29b 100644 --- a/tests/golden/typescript/typescript-fetch/multipart-explicit-encoding/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/multipart-explicit-encoding/package.json.golden @@ -1,26 +1,26 @@ { + "name": "multipart-explicit-encoding", + "version": "1.0.0", "description": "Covers explicit multipart part content types.", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "multipart-explicit-encoding", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/multipart-explicit-encoding/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/multipart-explicit-encoding/runtime/runtime.ts.golden index 53278a127..723b7cd6c 100644 --- a/tests/golden/typescript/typescript-fetch/multipart-explicit-encoding/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/multipart-explicit-encoding/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Multipart Explicit Encoding — 1.0.0 * Covers explicit multipart part content types. */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -126,8 +129,10 @@ function isFile(value: UploadFileInput): value is File { * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -169,12 +174,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -184,7 +195,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -200,9 +211,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -217,13 +226,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -233,7 +244,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -243,10 +254,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -255,18 +267,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -274,16 +290,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -302,11 +319,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -316,7 +333,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -326,7 +343,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -340,12 +357,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -363,15 +398,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -447,16 +495,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -483,7 +621,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -510,7 +651,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -520,5 +661,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/multipart-explicit-encoding/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/multipart-explicit-encoding/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/multipart-explicit-encoding/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/multipart-explicit-encoding/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/multipart-explicit-encoding/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/multipart-explicit-encoding/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/multipart-explicit-encoding/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/multipart-explicit-encoding/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/multipart-nested-object-parts/README.md.golden b/tests/golden/typescript/typescript-fetch/multipart-nested-object-parts/README.md.golden index 031134492..a8bce99c3 100644 --- a/tests/golden/typescript/typescript-fetch/multipart-nested-object-parts/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/multipart-nested-object-parts/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, MultipartApi } from 'multipart-nested-object-parts'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'multipart-nested-object-parts'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/multipart-nested-object-parts/apis/MultipartApi.ts.golden b/tests/golden/typescript/typescript-fetch/multipart-nested-object-parts/apis/MultipartApi.ts.golden index 9749c7665..47d598092 100644 --- a/tests/golden/typescript/typescript-fetch/multipart-nested-object-parts/apis/MultipartApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/multipart-nested-object-parts/apis/MultipartApi.ts.golden @@ -5,36 +5,60 @@ * Covers multipart object parts whose wire names differ from ergonomic names. */ import type { SendNestedObjectPartMultipartRequestBody } from '../models/SendNestedObjectPartMultipartRequestBody'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, RequiredError, ResponseError, VoidApiResponse, multipartHeaderValue, uploadFileData, uploadFileFilename } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + RequiredError, + ResponseError, + VoidApiResponse, + multipartHeaderValue, + uploadFileData, + uploadFileFilename, +} from '../runtime/runtime'; export interface ApiSendNestedObjectPartRequest { body: SendNestedObjectPartMultipartRequestBody; } export type SendNestedObjectPartRawResponse = - | VoidApiResponse & { status: 204 } - | VoidApiResponse & HttpSuccessResponse; + | (VoidApiResponse & { status: 204 }) + | (VoidApiResponse & HttpSuccessResponse); - -export type SendNestedObjectPartErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type SendNestedObjectPartErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class SendNestedObjectPartError extends ResponseError { readonly detail: SendNestedObjectPartErrorDetail; - constructor(response: Response, detail: SendNestedObjectPartErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: SendNestedObjectPartErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface MultipartApiInterface { - sendNestedObjectPartRaw: (requestParameters: ApiSendNestedObjectPartRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - sendNestedObjectPart: (requestParameters: ApiSendNestedObjectPartRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + sendNestedObjectPartRaw: ( + requestParameters: ApiSendNestedObjectPartRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + sendNestedObjectPart: ( + requestParameters: ApiSendNestedObjectPartRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class MultipartApi extends BaseAPI implements MultipartApiInterface { @@ -45,12 +69,14 @@ export class MultipartApi extends BaseAPI implements MultipartApiInterface { super(configuration ?? DefaultConfig); } - async sendNestedObjectPartRaw(requestParameters: ApiSendNestedObjectPartRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async sendNestedObjectPartRaw( + requestParameters: ApiSendNestedObjectPartRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling sendNestedObjectPartRaw().' + 'Required parameter "body" was null or undefined when calling sendNestedObjectPartRaw().', ); } // Build path with path parameters @@ -58,8 +84,7 @@ export class MultipartApi extends BaseAPI implements MultipartApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Prepare request body const multipartBoundary = '----openapi-nexus-' + Math.random().toString(16).slice(2); @@ -77,32 +102,44 @@ export class MultipartApi extends BaseAPI implements MultipartApiInterface { multipartChunks.push('--' + multipartBoundary + '--\r\n'); const requestBody = new Blob(multipartChunks); // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new SendNestedObjectPartError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new SendNestedObjectPartError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 204) { return new VoidApiResponse(response) as VoidApiResponse & { status: 204 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async sendNestedObjectPart(requestParameters: ApiSendNestedObjectPartRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async sendNestedObjectPart( + requestParameters: ApiSendNestedObjectPartRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.sendNestedObjectPartRaw(requestParameters, initOverrides); return await response.value(); } diff --git a/tests/golden/typescript/typescript-fetch/multipart-nested-object-parts/package.json.golden b/tests/golden/typescript/typescript-fetch/multipart-nested-object-parts/package.json.golden index adfcebda6..c20db5337 100644 --- a/tests/golden/typescript/typescript-fetch/multipart-nested-object-parts/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/multipart-nested-object-parts/package.json.golden @@ -1,26 +1,26 @@ { + "name": "multipart-nested-object-parts", + "version": "1.0.0", "description": "Covers multipart object parts whose wire names differ from ergonomic names.", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "multipart-nested-object-parts", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/multipart-nested-object-parts/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/multipart-nested-object-parts/runtime/runtime.ts.golden index af4ec2675..1b4f8c0d8 100644 --- a/tests/golden/typescript/typescript-fetch/multipart-nested-object-parts/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/multipart-nested-object-parts/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Multipart Nested Object Parts — 1.0.0 * Covers multipart object parts whose wire names differ from ergonomic names. */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -126,8 +129,10 @@ function isFile(value: UploadFileInput): value is File { * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -169,12 +174,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -184,7 +195,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -200,9 +211,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -217,13 +226,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -233,7 +244,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -243,10 +254,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -255,18 +267,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -274,16 +290,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -302,11 +319,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -316,7 +333,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -326,7 +343,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -340,12 +357,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -363,15 +398,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -447,16 +495,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -483,7 +621,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -510,7 +651,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -520,5 +661,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/multipart-nested-object-parts/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/multipart-nested-object-parts/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/multipart-nested-object-parts/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/multipart-nested-object-parts/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/multipart-nested-object-parts/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/multipart-nested-object-parts/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/multipart-nested-object-parts/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/multipart-nested-object-parts/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/multipart-unsupported-schema/README.md.golden b/tests/golden/typescript/typescript-fetch/multipart-unsupported-schema/README.md.golden index 96ac4cce0..09057cf78 100644 --- a/tests/golden/typescript/typescript-fetch/multipart-unsupported-schema/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/multipart-unsupported-schema/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, TransferApi } from 'multipart-unsupported-schema'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'multipart-unsupported-schema'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/multipart-unsupported-schema/apis/TransferApi.ts.golden b/tests/golden/typescript/typescript-fetch/multipart-unsupported-schema/apis/TransferApi.ts.golden index 70f5a2448..c1c31920b 100644 --- a/tests/golden/typescript/typescript-fetch/multipart-unsupported-schema/apis/TransferApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/multipart-unsupported-schema/apis/TransferApi.ts.golden @@ -4,36 +4,57 @@ * Multipart Unsupported Schema — 1.0.0 * Covers multipart request bodies that are not object-shaped. */ -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, RequiredError, ResponseError, VoidApiResponse } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + RequiredError, + ResponseError, + VoidApiResponse, +} from '../runtime/runtime'; export interface ApiUploadRawMultipartRequest { body: unknown; } export type UploadRawMultipartRawResponse = - | VoidApiResponse & { status: 204 } - | VoidApiResponse & HttpSuccessResponse; + | (VoidApiResponse & { status: 204 }) + | (VoidApiResponse & HttpSuccessResponse); - -export type UploadRawMultipartErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type UploadRawMultipartErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class UploadRawMultipartError extends ResponseError { readonly detail: UploadRawMultipartErrorDetail; - constructor(response: Response, detail: UploadRawMultipartErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: UploadRawMultipartErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface TransferApiInterface { - uploadRawMultipartRaw: (requestParameters: ApiUploadRawMultipartRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - uploadRawMultipart: (requestParameters: ApiUploadRawMultipartRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + uploadRawMultipartRaw: ( + requestParameters: ApiUploadRawMultipartRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + uploadRawMultipart: ( + requestParameters: ApiUploadRawMultipartRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class TransferApi extends BaseAPI implements TransferApiInterface { @@ -44,12 +65,14 @@ export class TransferApi extends BaseAPI implements TransferApiInterface { super(configuration ?? DefaultConfig); } - async uploadRawMultipartRaw(requestParameters: ApiUploadRawMultipartRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async uploadRawMultipartRaw( + requestParameters: ApiUploadRawMultipartRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling uploadRawMultipartRaw().' + 'Required parameter "body" was null or undefined when calling uploadRawMultipartRaw().', ); } // Build path with path parameters @@ -57,38 +80,49 @@ export class TransferApi extends BaseAPI implements TransferApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Prepare request body const requestBody = (() => {throw new Error('unsupported multipart request body: schema must be object-shaped');})(); // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new UploadRawMultipartError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new UploadRawMultipartError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 204) { return new VoidApiResponse(response) as VoidApiResponse & { status: 204 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async uploadRawMultipart(requestParameters: ApiUploadRawMultipartRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async uploadRawMultipart( + requestParameters: ApiUploadRawMultipartRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.uploadRawMultipartRaw(requestParameters, initOverrides); return await response.value(); } diff --git a/tests/golden/typescript/typescript-fetch/multipart-unsupported-schema/package.json.golden b/tests/golden/typescript/typescript-fetch/multipart-unsupported-schema/package.json.golden index 82e0f3267..570572b48 100644 --- a/tests/golden/typescript/typescript-fetch/multipart-unsupported-schema/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/multipart-unsupported-schema/package.json.golden @@ -1,26 +1,26 @@ { + "name": "multipart-unsupported-schema", + "version": "1.0.0", "description": "Covers multipart request bodies that are not object-shaped.", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "multipart-unsupported-schema", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/multipart-unsupported-schema/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/multipart-unsupported-schema/runtime/runtime.ts.golden index cb1c49b86..97175cf48 100644 --- a/tests/golden/typescript/typescript-fetch/multipart-unsupported-schema/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/multipart-unsupported-schema/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Multipart Unsupported Schema — 1.0.0 * Covers multipart request bodies that are not object-shaped. */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/multipart-unsupported-schema/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/multipart-unsupported-schema/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/multipart-unsupported-schema/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/multipart-unsupported-schema/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/multipart-unsupported-schema/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/multipart-unsupported-schema/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/multipart-unsupported-schema/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/multipart-unsupported-schema/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/multiple-similar-request-schemas/README.md.golden b/tests/golden/typescript/typescript-fetch/multiple-similar-request-schemas/README.md.golden index ef0650850..fa2837ea8 100644 --- a/tests/golden/typescript/typescript-fetch/multiple-similar-request-schemas/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/multiple-similar-request-schemas/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, TestApiApi } from 'multiple-similar-request-schemas-api' const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'multiple-similar-request-schemas-a const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/multiple-similar-request-schemas/apis/TestApiApi.ts.golden b/tests/golden/typescript/typescript-fetch/multiple-similar-request-schemas/apis/TestApiApi.ts.golden index d1a745fb5..c977e160b 100644 --- a/tests/golden/typescript/typescript-fetch/multiple-similar-request-schemas/apis/TestApiApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/multiple-similar-request-schemas/apis/TestApiApi.ts.golden @@ -8,8 +8,19 @@ import type { CreateRequestTypeA } from '../models/CreateRequestTypeA'; import type { CreateRequestTypeB } from '../models/CreateRequestTypeB'; import type { ResourceTypeA } from '../models/ResourceTypeA'; import type { ResourceTypeB } from '../models/ResourceTypeB'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, +} from '../runtime/runtime'; export interface ApiCreateTypeARequest { body: CreateRequestTypeA; @@ -20,49 +31,69 @@ export interface ApiCreateTypeBRequest { } export type CreateTypeARawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type CreateTypeBRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); -export type CreateTypeAErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type CreateTypeAErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class CreateTypeAError extends ResponseError { readonly detail: CreateTypeAErrorDetail; - constructor(response: Response, detail: CreateTypeAErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: CreateTypeAErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type CreateTypeBErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type CreateTypeBErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class CreateTypeBError extends ResponseError { readonly detail: CreateTypeBErrorDetail; - constructor(response: Response, detail: CreateTypeBErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: CreateTypeBErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface TestApiApiInterface { - createTypeARaw: (requestParameters: ApiCreateTypeARequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - createTypeA: (requestParameters: ApiCreateTypeARequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - createTypeBRaw: (requestParameters: ApiCreateTypeBRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - createTypeB: (requestParameters: ApiCreateTypeBRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + createTypeARaw: ( + requestParameters: ApiCreateTypeARequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + createTypeA: ( + requestParameters: ApiCreateTypeARequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + createTypeBRaw: ( + requestParameters: ApiCreateTypeBRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + createTypeB: ( + requestParameters: ApiCreateTypeBRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class TestApiApi extends BaseAPI implements TestApiApiInterface { @@ -73,12 +104,14 @@ export class TestApiApi extends BaseAPI implements TestApiApiInterface { super(configuration ?? DefaultConfig); } - async createTypeARaw(requestParameters: ApiCreateTypeARequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createTypeARaw( + requestParameters: ApiCreateTypeARequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling createTypeARaw().' + 'Required parameter "body" was null or undefined when calling createTypeARaw().', ); } // Build path with path parameters @@ -93,42 +126,56 @@ export class TestApiApi extends BaseAPI implements TestApiApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new CreateTypeAError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new CreateTypeAError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async createTypeA(requestParameters: ApiCreateTypeARequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createTypeA( + requestParameters: ApiCreateTypeARequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.createTypeARaw(requestParameters, initOverrides); - return await response.value() as ResourceTypeA; + return (await response.value()) as ResourceTypeA; } - async createTypeBRaw(requestParameters: ApiCreateTypeBRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createTypeBRaw( + requestParameters: ApiCreateTypeBRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling createTypeBRaw().' + 'Required parameter "body" was null or undefined when calling createTypeBRaw().', ); } // Build path with path parameters @@ -143,33 +190,45 @@ export class TestApiApi extends BaseAPI implements TestApiApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new CreateTypeBError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new CreateTypeBError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async createTypeB(requestParameters: ApiCreateTypeBRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createTypeB( + requestParameters: ApiCreateTypeBRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.createTypeBRaw(requestParameters, initOverrides); - return await response.value() as ResourceTypeB; + return (await response.value()) as ResourceTypeB; } } diff --git a/tests/golden/typescript/typescript-fetch/multiple-similar-request-schemas/package.json.golden b/tests/golden/typescript/typescript-fetch/multiple-similar-request-schemas/package.json.golden index ba7b3e9f6..c729d063f 100644 --- a/tests/golden/typescript/typescript-fetch/multiple-similar-request-schemas/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/multiple-similar-request-schemas/package.json.golden @@ -1,26 +1,26 @@ { + "name": "multiple-similar-request-schemas-api", + "version": "1.0.0", "description": "Test API with multiple operations having similar request body schema names", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "multiple-similar-request-schemas-api", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/multiple-similar-request-schemas/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/multiple-similar-request-schemas/runtime/runtime.ts.golden index 5151c7e7e..b5ffb5a77 100644 --- a/tests/golden/typescript/typescript-fetch/multiple-similar-request-schemas/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/multiple-similar-request-schemas/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Multiple Similar Request Schemas API — 1.0.0 * Test API with multiple operations having similar request body schema names */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/multiple-similar-request-schemas/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/multiple-similar-request-schemas/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/multiple-similar-request-schemas/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/multiple-similar-request-schemas/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/multiple-similar-request-schemas/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/multiple-similar-request-schemas/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/multiple-similar-request-schemas/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/multiple-similar-request-schemas/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/naming-conventions/README.md.golden b/tests/golden/typescript/typescript-fetch/naming-conventions/README.md.golden index 565aefb6c..bc3ad7741 100644 --- a/tests/golden/typescript/typescript-fetch/naming-conventions/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/naming-conventions/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'naming-conventions-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'naming-conventions-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/naming-conventions/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/naming-conventions/apis/DefaultApi.ts.golden index 45c0503ed..f7adb8148 100644 --- a/tests/golden/typescript/typescript-fetch/naming-conventions/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/naming-conventions/apis/DefaultApi.ts.golden @@ -5,8 +5,20 @@ * Test fixture to verify language property naming conventions */ import type { NamingConventionTest } from '../models/NamingConventionTest'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError, VoidApiResponse } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, + VoidApiResponse, +} from '../runtime/runtime'; export interface ApiGetWithQueryParamsRequest { snakeCaseParam: string; @@ -28,49 +40,69 @@ export interface ApiTestNamingConventionsRequest { } export type GetWithQueryParamsRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); export type TestNamingConventionsRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); -export type GetWithQueryParamsErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type GetWithQueryParamsErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class GetWithQueryParamsError extends ResponseError { readonly detail: GetWithQueryParamsErrorDetail; - constructor(response: Response, detail: GetWithQueryParamsErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: GetWithQueryParamsErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type TestNamingConventionsErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestNamingConventionsErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestNamingConventionsError extends ResponseError { readonly detail: TestNamingConventionsErrorDetail; - constructor(response: Response, detail: TestNamingConventionsErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestNamingConventionsErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - getWithQueryParamsRaw: (requestParameters: ApiGetWithQueryParamsRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - getWithQueryParams: (requestParameters: ApiGetWithQueryParamsRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - testNamingConventionsRaw: (requestParameters: ApiTestNamingConventionsRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - testNamingConventions: (requestParameters: ApiTestNamingConventionsRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + getWithQueryParamsRaw: ( + requestParameters: ApiGetWithQueryParamsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + getWithQueryParams: ( + requestParameters: ApiGetWithQueryParamsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + testNamingConventionsRaw: ( + requestParameters: ApiTestNamingConventionsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + testNamingConventions: ( + requestParameters: ApiTestNamingConventionsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class DefaultApi extends BaseAPI implements DefaultApiInterface { @@ -81,12 +113,14 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async getWithQueryParamsRaw(requestParameters: ApiGetWithQueryParamsRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async getWithQueryParamsRaw( + requestParameters: ApiGetWithQueryParamsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.snakeCaseParam === undefined || requestParameters.snakeCaseParam === null) { throw new RequiredError( 'snakeCaseParam', - 'Required parameter "snakeCaseParam" was null or undefined when calling getWithQueryParamsRaw().' + 'Required parameter "snakeCaseParam" was null or undefined when calling getWithQueryParamsRaw().', ); } // Build path with path parameters @@ -130,46 +164,59 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { queryParameters['id'] = requestParameters.id; } // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new GetWithQueryParamsError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new GetWithQueryParamsError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async getWithQueryParams(requestParameters: ApiGetWithQueryParamsRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async getWithQueryParams( + requestParameters: ApiGetWithQueryParamsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.getWithQueryParamsRaw(requestParameters, initOverrides); return await response.value(); } - async testNamingConventionsRaw(requestParameters: ApiTestNamingConventionsRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async testNamingConventionsRaw( + requestParameters: ApiTestNamingConventionsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling testNamingConventionsRaw().' + 'Required parameter "body" was null or undefined when calling testNamingConventionsRaw().', ); } // Build path with path parameters @@ -184,33 +231,47 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestNamingConventionsError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestNamingConventionsError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response) as JSONApiResponse & { + status: 200; + }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async testNamingConventions(requestParameters: ApiTestNamingConventionsRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async testNamingConventions( + requestParameters: ApiTestNamingConventionsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.testNamingConventionsRaw(requestParameters, initOverrides); - return await response.value() as NamingConventionTest; + return (await response.value()) as NamingConventionTest; } } diff --git a/tests/golden/typescript/typescript-fetch/naming-conventions/package.json.golden b/tests/golden/typescript/typescript-fetch/naming-conventions/package.json.golden index 379d653c4..3351be2a4 100644 --- a/tests/golden/typescript/typescript-fetch/naming-conventions/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/naming-conventions/package.json.golden @@ -1,26 +1,26 @@ { + "name": "naming-conventions-test", + "version": "1.0.0", "description": "Test fixture to verify language property naming conventions", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "naming-conventions-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/naming-conventions/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/naming-conventions/runtime/runtime.ts.golden index 6defd7205..000eb9d38 100644 --- a/tests/golden/typescript/typescript-fetch/naming-conventions/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/naming-conventions/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Naming Conventions Test — 1.0.0 * Test fixture to verify language property naming conventions */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/naming-conventions/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/naming-conventions/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/naming-conventions/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/naming-conventions/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/naming-conventions/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/naming-conventions/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/naming-conventions/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/naming-conventions/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/nested-nullable/README.md.golden b/tests/golden/typescript/typescript-fetch/nested-nullable/README.md.golden index ff7db7b52..477aa1297 100644 --- a/tests/golden/typescript/typescript-fetch/nested-nullable/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/nested-nullable/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, ValuesApi } from 'nested-nullable-api'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'nested-nullable-api'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/nested-nullable/apis/ValuesApi.ts.golden b/tests/golden/typescript/typescript-fetch/nested-nullable/apis/ValuesApi.ts.golden index 08f53103a..5cc647c4e 100644 --- a/tests/golden/typescript/typescript-fetch/nested-nullable/apis/ValuesApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/nested-nullable/apis/ValuesApi.ts.golden @@ -5,38 +5,79 @@ */ import type { DetailAlias } from '../models/DetailAlias'; import type { NullablePayload } from '../models/NullablePayload'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; import { BaseAPI, DefaultConfig, JSONApiResponse, ResponseError } from '../runtime/runtime'; export type GetValuesRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type GetValuesErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise> } - | { kind: 'unauthorized'; status: 401; raw: Response; value(): Promise<(Record -| null)[]> } - | { kind: 'status402'; status: 402; raw: Response; value(): Promise } - | { kind: 'forbidden'; status: 403; raw: Response; value(): Promise> } - | { kind: 'notFound'; status: 404; raw: Response; value(): Promise } - | { kind: 'status410'; status: 410; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise>; + } + | { + kind: 'unauthorized'; + status: 401; + raw: Response; + value(): Promise<(Record | null)[]>; + } + | { + kind: 'status402'; + status: 402; + raw: Response; + value(): Promise; + } + | { + kind: 'forbidden'; + status: 403; + raw: Response; + value(): Promise>; + } + | { + kind: 'notFound'; + status: 404; + raw: Response; + value(): Promise; + } + | { + kind: 'status410'; + status: 410; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class GetValuesError extends ResponseError { readonly detail: GetValuesErrorDetail; - constructor(response: Response, detail: GetValuesErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: GetValuesErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface ValuesApiInterface { - getValuesRaw: (initOverrides?: RequestInit - | InitOverrideFunction) => Promise; + getValuesRaw: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; getValues: (initOverrides?: RequestInit | InitOverrideFunction) => Promise; } @@ -48,72 +89,119 @@ export class ValuesApi extends BaseAPI implements ValuesApiInterface { super(configuration ?? DefaultConfig); } - async getValuesRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getValuesRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/values`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise> | undefined; - throw new GetValuesError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new JSONApiResponse>(errorRaw.clone()).value() }); - } - else if (response.status === 401) { + throw new GetValuesError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse>(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 401) { let errorValue: Promise<(Record | null)[]> | undefined; - throw new GetValuesError(response, { kind: 'unauthorized', status: response.status as 401, raw: response, value: () => errorValue ??= new JSONApiResponse<(Record - | null)[]>(errorRaw.clone()).value() }); - } - else if (response.status === 402) { + throw new GetValuesError(response, { + kind: 'unauthorized', + status: response.status as 401, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse<(Record | null)[]>(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 402) { let errorValue: Promise | undefined; - throw new GetValuesError(response, { kind: 'status402', status: response.status as 402, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 403) { + throw new GetValuesError(response, { + kind: 'status402', + status: response.status as 402, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 403) { let errorValue: Promise> | undefined; - throw new GetValuesError(response, { kind: 'forbidden', status: response.status as 403, raw: response, value: () => errorValue ??= new JSONApiResponse>(errorRaw.clone()).value() }); - } - else if (response.status === 404) { + throw new GetValuesError(response, { + kind: 'forbidden', + status: response.status as 403, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse>(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 404) { let errorValue: Promise | undefined; - throw new GetValuesError(response, { kind: 'notFound', status: response.status as 404, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 410) { + throw new GetValuesError(response, { + kind: 'notFound', + status: response.status as 404, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 410) { let errorValue: Promise | undefined; - throw new GetValuesError(response, { kind: 'status410', status: response.status as 410, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone()).value() }); - } - else { + throw new GetValuesError(response, { + kind: 'status410', + status: response.status as 410, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new GetValuesError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new GetValuesError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } async getValues(initOverrides?: RequestInit | InitOverrideFunction): Promise { const response = await this.getValuesRaw(initOverrides); - return await response.value() as NullablePayload; + return (await response.value()) as NullablePayload; } } diff --git a/tests/golden/typescript/typescript-fetch/nested-nullable/package.json.golden b/tests/golden/typescript/typescript-fetch/nested-nullable/package.json.golden index 6e4680435..0af2b9406 100644 --- a/tests/golden/typescript/typescript-fetch/nested-nullable/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/nested-nullable/package.json.golden @@ -1,26 +1,26 @@ { + "name": "nested-nullable-api", + "version": "1.0.0", "description": "TypeScript client for Nested Nullable API", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "nested-nullable-api", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/nested-nullable/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/nested-nullable/runtime/runtime.ts.golden index 2cb8475dc..f9fcacf93 100644 --- a/tests/golden/typescript/typescript-fetch/nested-nullable/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/nested-nullable/runtime/runtime.ts.golden @@ -3,7 +3,7 @@ * * Nested Nullable API — 1.0.0 */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -13,7 +13,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -92,8 +95,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -135,12 +140,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -150,7 +161,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -166,9 +177,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -183,13 +192,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -199,7 +210,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -209,10 +220,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -221,18 +233,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -240,16 +256,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -268,11 +285,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -282,7 +299,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -292,7 +309,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -306,12 +323,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -329,15 +364,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -413,16 +461,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -449,7 +587,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -476,7 +617,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -486,5 +627,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/nested-nullable/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/nested-nullable/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/nested-nullable/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/nested-nullable/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/nested-nullable/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/nested-nullable/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/nested-nullable/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/nested-nullable/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/open-tagged-additional-properties/README.md.golden b/tests/golden/typescript/typescript-fetch/open-tagged-additional-properties/README.md.golden index e0027dc85..ccc522251 100644 --- a/tests/golden/typescript/typescript-fetch/open-tagged-additional-properties/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/open-tagged-additional-properties/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'open-tagged-additional-properties'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'open-tagged-additional-properties' const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/open-tagged-additional-properties/models/Event.ts.golden b/tests/golden/typescript/typescript-fetch/open-tagged-additional-properties/models/Event.ts.golden index d6a73ee03..8ec3839ac 100644 --- a/tests/golden/typescript/typescript-fetch/open-tagged-additional-properties/models/Event.ts.golden +++ b/tests/golden/typescript/typescript-fetch/open-tagged-additional-properties/models/Event.ts.golden @@ -6,4 +6,6 @@ import type { EventCompleted } from './EventCompleted'; import type { EventSearching } from './EventSearching'; -export type Event = ({ type: 'searching' } & EventSearching) | ({ type: 'completed' } & EventCompleted); +export type Event = + | ({ type: 'searching' } & EventSearching) + | ({ type: 'completed' } & EventCompleted); diff --git a/tests/golden/typescript/typescript-fetch/open-tagged-additional-properties/models/ExternalEvent.ts.golden b/tests/golden/typescript/typescript-fetch/open-tagged-additional-properties/models/ExternalEvent.ts.golden index b2e2c60fc..29ded2087 100644 --- a/tests/golden/typescript/typescript-fetch/open-tagged-additional-properties/models/ExternalEvent.ts.golden +++ b/tests/golden/typescript/typescript-fetch/open-tagged-additional-properties/models/ExternalEvent.ts.golden @@ -5,5 +5,6 @@ */ import type { Payload } from './Payload'; -export type ExternalEvent = Readonly> & Readonly> -| Readonly> & Readonly>; +export type ExternalEvent = + | (Readonly> & Readonly>) + | (Readonly> & Readonly>); diff --git a/tests/golden/typescript/typescript-fetch/open-tagged-additional-properties/package.json.golden b/tests/golden/typescript/typescript-fetch/open-tagged-additional-properties/package.json.golden index 0d7fbb4b9..61f577366 100644 --- a/tests/golden/typescript/typescript-fetch/open-tagged-additional-properties/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/open-tagged-additional-properties/package.json.golden @@ -1,26 +1,26 @@ { + "name": "open-tagged-additional-properties", + "version": "1.0.0", "description": "TypeScript client for Open tagged additional properties", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "open-tagged-additional-properties", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/open-tagged-additional-properties/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/open-tagged-additional-properties/runtime/runtime.ts.golden index fff1d7318..8ad3f9617 100644 --- a/tests/golden/typescript/typescript-fetch/open-tagged-additional-properties/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/open-tagged-additional-properties/runtime/runtime.ts.golden @@ -3,7 +3,7 @@ * * Open tagged additional properties — 1.0.0 */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -13,7 +13,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -92,8 +95,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -135,12 +140,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -150,7 +161,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -166,9 +177,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -183,13 +192,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -199,7 +210,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -209,10 +220,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -221,18 +233,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -240,16 +256,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -268,11 +285,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -282,7 +299,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -292,7 +309,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -306,12 +323,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -329,15 +364,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -413,16 +461,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -449,7 +587,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -476,7 +617,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -486,5 +627,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/open-tagged-additional-properties/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/open-tagged-additional-properties/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/open-tagged-additional-properties/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/open-tagged-additional-properties/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/open-tagged-additional-properties/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/open-tagged-additional-properties/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/open-tagged-additional-properties/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/open-tagged-additional-properties/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/optional-request-bodies/README.md.golden b/tests/golden/typescript/typescript-fetch/optional-request-bodies/README.md.golden index d25c6a066..e2d5818a0 100644 --- a/tests/golden/typescript/typescript-fetch/optional-request-bodies/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/optional-request-bodies/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'optional-request-bodies'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'optional-request-bodies'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/optional-request-bodies/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/optional-request-bodies/apis/DefaultApi.ts.golden index 62b8d2a9f..73585833c 100644 --- a/tests/golden/typescript/typescript-fetch/optional-request-bodies/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/optional-request-bodies/apis/DefaultApi.ts.golden @@ -5,8 +5,19 @@ * Covers optional non-multipart request bodies. */ import type { Payload } from '../models/Payload'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, RequiredError, ResponseError, VoidApiResponse } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + RequiredError, + ResponseError, + VoidApiResponse, +} from '../runtime/runtime'; export interface ApiSendOptionalBinaryRequest { body?: Blob | File; @@ -25,91 +36,131 @@ export interface ApiSendRequiredJsonRequest { } export type SendOptionalBinaryRawResponse = - | VoidApiResponse & { status: 204 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 204 }) + | (VoidApiResponse & HttpSuccessResponse); export type SendOptionalJsonRawResponse = - | VoidApiResponse & { status: 204 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 204 }) + | (VoidApiResponse & HttpSuccessResponse); export type SendOptionalTextRawResponse = - | VoidApiResponse & { status: 204 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 204 }) + | (VoidApiResponse & HttpSuccessResponse); export type SendRequiredJsonRawResponse = - | VoidApiResponse & { status: 204 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 204 }) + | (VoidApiResponse & HttpSuccessResponse); -export type SendOptionalBinaryErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type SendOptionalBinaryErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class SendOptionalBinaryError extends ResponseError { readonly detail: SendOptionalBinaryErrorDetail; - constructor(response: Response, detail: SendOptionalBinaryErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: SendOptionalBinaryErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type SendOptionalJsonErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type SendOptionalJsonErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class SendOptionalJsonError extends ResponseError { readonly detail: SendOptionalJsonErrorDetail; - constructor(response: Response, detail: SendOptionalJsonErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: SendOptionalJsonErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type SendOptionalTextErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type SendOptionalTextErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class SendOptionalTextError extends ResponseError { readonly detail: SendOptionalTextErrorDetail; - constructor(response: Response, detail: SendOptionalTextErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: SendOptionalTextErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type SendRequiredJsonErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type SendRequiredJsonErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class SendRequiredJsonError extends ResponseError { readonly detail: SendRequiredJsonErrorDetail; - constructor(response: Response, detail: SendRequiredJsonErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: SendRequiredJsonErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - sendOptionalBinaryRaw: (requestParameters: ApiSendOptionalBinaryRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - sendOptionalBinary: (requestParameters: ApiSendOptionalBinaryRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - sendOptionalJsonRaw: (requestParameters: ApiSendOptionalJsonRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - sendOptionalJson: (requestParameters: ApiSendOptionalJsonRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - sendOptionalTextRaw: (requestParameters: ApiSendOptionalTextRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - sendOptionalText: (requestParameters: ApiSendOptionalTextRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - sendRequiredJsonRaw: (requestParameters: ApiSendRequiredJsonRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - sendRequiredJson: (requestParameters: ApiSendRequiredJsonRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + sendOptionalBinaryRaw: ( + requestParameters: ApiSendOptionalBinaryRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + sendOptionalBinary: ( + requestParameters: ApiSendOptionalBinaryRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + sendOptionalJsonRaw: ( + requestParameters: ApiSendOptionalJsonRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + sendOptionalJson: ( + requestParameters: ApiSendOptionalJsonRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + sendOptionalTextRaw: ( + requestParameters: ApiSendOptionalTextRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + sendOptionalText: ( + requestParameters: ApiSendOptionalTextRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + sendRequiredJsonRaw: ( + requestParameters: ApiSendRequiredJsonRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + sendRequiredJson: ( + requestParameters: ApiSendRequiredJsonRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class DefaultApi extends BaseAPI implements DefaultApiInterface { @@ -120,8 +171,10 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async sendOptionalBinaryRaw(requestParameters: ApiSendOptionalBinaryRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async sendOptionalBinaryRaw( + requestParameters: ApiSendOptionalBinaryRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/optional-binary`; // Build query parameters @@ -134,38 +187,52 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new SendOptionalBinaryError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new SendOptionalBinaryError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 204) { return new VoidApiResponse(response) as VoidApiResponse & { status: 204 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async sendOptionalBinary(requestParameters: ApiSendOptionalBinaryRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async sendOptionalBinary( + requestParameters: ApiSendOptionalBinaryRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.sendOptionalBinaryRaw(requestParameters, initOverrides); return await response.value(); } - async sendOptionalJsonRaw(requestParameters: ApiSendOptionalJsonRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async sendOptionalJsonRaw( + requestParameters: ApiSendOptionalJsonRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/optional-json`; // Build query parameters @@ -178,38 +245,52 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new SendOptionalJsonError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new SendOptionalJsonError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 204) { return new VoidApiResponse(response) as VoidApiResponse & { status: 204 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async sendOptionalJson(requestParameters: ApiSendOptionalJsonRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async sendOptionalJson( + requestParameters: ApiSendOptionalJsonRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.sendOptionalJsonRaw(requestParameters, initOverrides); return await response.value(); } - async sendOptionalTextRaw(requestParameters: ApiSendOptionalTextRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async sendOptionalTextRaw( + requestParameters: ApiSendOptionalTextRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/optional-text`; // Build query parameters @@ -222,42 +303,56 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new SendOptionalTextError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new SendOptionalTextError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 204) { return new VoidApiResponse(response) as VoidApiResponse & { status: 204 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async sendOptionalText(requestParameters: ApiSendOptionalTextRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async sendOptionalText( + requestParameters: ApiSendOptionalTextRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.sendOptionalTextRaw(requestParameters, initOverrides); return await response.value(); } - async sendRequiredJsonRaw(requestParameters: ApiSendRequiredJsonRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async sendRequiredJsonRaw( + requestParameters: ApiSendRequiredJsonRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling sendRequiredJsonRaw().' + 'Required parameter "body" was null or undefined when calling sendRequiredJsonRaw().', ); } // Build path with path parameters @@ -272,32 +367,44 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new SendRequiredJsonError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new SendRequiredJsonError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 204) { return new VoidApiResponse(response) as VoidApiResponse & { status: 204 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async sendRequiredJson(requestParameters: ApiSendRequiredJsonRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async sendRequiredJson( + requestParameters: ApiSendRequiredJsonRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.sendRequiredJsonRaw(requestParameters, initOverrides); return await response.value(); } diff --git a/tests/golden/typescript/typescript-fetch/optional-request-bodies/package.json.golden b/tests/golden/typescript/typescript-fetch/optional-request-bodies/package.json.golden index 55aee9ccc..d70942690 100644 --- a/tests/golden/typescript/typescript-fetch/optional-request-bodies/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/optional-request-bodies/package.json.golden @@ -1,26 +1,26 @@ { + "name": "optional-request-bodies", + "version": "1.0.0", "description": "Covers optional non-multipart request bodies.", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "optional-request-bodies", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/optional-request-bodies/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/optional-request-bodies/runtime/runtime.ts.golden index d75f62bd9..827d8e485 100644 --- a/tests/golden/typescript/typescript-fetch/optional-request-bodies/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/optional-request-bodies/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Optional Request Bodies — 1.0.0 * Covers optional non-multipart request bodies. */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/optional-request-bodies/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/optional-request-bodies/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/optional-request-bodies/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/optional-request-bodies/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/optional-request-bodies/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/optional-request-bodies/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/optional-request-bodies/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/optional-request-bodies/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/petstore/README.md.golden b/tests/golden/typescript/typescript-fetch/petstore/README.md.golden index eff1583ac..6373d4d15 100644 --- a/tests/golden/typescript/typescript-fetch/petstore/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/petstore/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, PetApi } from 'petstore-api'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'petstore-api'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/petstore/apis/PetApi.ts.golden b/tests/golden/typescript/typescript-fetch/petstore/apis/PetApi.ts.golden index cb66ee12e..b16c06363 100644 --- a/tests/golden/typescript/typescript-fetch/petstore/apis/PetApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/petstore/apis/PetApi.ts.golden @@ -6,8 +6,20 @@ */ import type { Pet } from '../models/Pet'; import type { UploadResponse } from '../models/UploadResponse'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError, VoidApiResponse } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, + VoidApiResponse, +} from '../runtime/runtime'; export interface ApiUpdatePetRequest { body: Pet; @@ -72,186 +84,328 @@ export interface ApiUploadFileRequest { } export type UpdatePetRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type AddPetRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type FindPetsByStatusRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type FindPetsByTagsRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type GetPetByIdRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type UpdatePetWithFormRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type DeletePetRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); export type UploadFileRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type UpdatePetErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'notFound'; status: 404; raw: Response; value(): Promise } - | { kind: 'validation'; status: 422; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'notFound'; + status: 404; + raw: Response; + value(): Promise; + } + | { + kind: 'validation'; + status: 422; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class UpdatePetError extends ResponseError { readonly detail: UpdatePetErrorDetail; - constructor(response: Response, detail: UpdatePetErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: UpdatePetErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type AddPetErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'validation'; status: 422; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'validation'; + status: 422; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class AddPetError extends ResponseError { readonly detail: AddPetErrorDetail; - constructor(response: Response, detail: AddPetErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: AddPetErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type FindPetsByStatusErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class FindPetsByStatusError extends ResponseError { readonly detail: FindPetsByStatusErrorDetail; - constructor(response: Response, detail: FindPetsByStatusErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: FindPetsByStatusErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type FindPetsByTagsErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class FindPetsByTagsError extends ResponseError { readonly detail: FindPetsByTagsErrorDetail; - constructor(response: Response, detail: FindPetsByTagsErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: FindPetsByTagsErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type GetPetByIdErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'notFound'; status: 404; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'notFound'; + status: 404; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class GetPetByIdError extends ResponseError { readonly detail: GetPetByIdErrorDetail; - constructor(response: Response, detail: GetPetByIdErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: GetPetByIdErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type UpdatePetWithFormErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class UpdatePetWithFormError extends ResponseError { readonly detail: UpdatePetWithFormErrorDetail; - constructor(response: Response, detail: UpdatePetWithFormErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: UpdatePetWithFormErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type DeletePetErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class DeletePetError extends ResponseError { readonly detail: DeletePetErrorDetail; - constructor(response: Response, detail: DeletePetErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: DeletePetErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type UploadFileErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type UploadFileErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class UploadFileError extends ResponseError { readonly detail: UploadFileErrorDetail; - constructor(response: Response, detail: UploadFileErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: UploadFileErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface PetApiInterface { - updatePetRaw: (requestParameters: ApiUpdatePetRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - updatePet: (requestParameters: ApiUpdatePetRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - addPetRaw: (requestParameters: ApiAddPetRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - addPet: (requestParameters: ApiAddPetRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - findPetsByStatusRaw: (requestParameters: ApiFindPetsByStatusRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - findPetsByStatus: (requestParameters: ApiFindPetsByStatusRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - findPetsByTagsRaw: (requestParameters: ApiFindPetsByTagsRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - findPetsByTags: (requestParameters: ApiFindPetsByTagsRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - getPetByIdRaw: (requestParameters: ApiGetPetByIdRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - getPetById: (requestParameters: ApiGetPetByIdRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - updatePetWithFormRaw: (requestParameters: ApiUpdatePetWithFormRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - updatePetWithForm: (requestParameters: ApiUpdatePetWithFormRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - deletePetRaw: (requestParameters: ApiDeletePetRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - deletePet: (requestParameters: ApiDeletePetRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - uploadFileRaw: (requestParameters: ApiUploadFileRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - uploadFile: (requestParameters: ApiUploadFileRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + updatePetRaw: ( + requestParameters: ApiUpdatePetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + updatePet: ( + requestParameters: ApiUpdatePetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + addPetRaw: ( + requestParameters: ApiAddPetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + addPet: ( + requestParameters: ApiAddPetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + findPetsByStatusRaw: ( + requestParameters: ApiFindPetsByStatusRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + findPetsByStatus: ( + requestParameters: ApiFindPetsByStatusRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + findPetsByTagsRaw: ( + requestParameters: ApiFindPetsByTagsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + findPetsByTags: ( + requestParameters: ApiFindPetsByTagsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + getPetByIdRaw: ( + requestParameters: ApiGetPetByIdRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + getPetById: ( + requestParameters: ApiGetPetByIdRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + updatePetWithFormRaw: ( + requestParameters: ApiUpdatePetWithFormRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + updatePetWithForm: ( + requestParameters: ApiUpdatePetWithFormRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + deletePetRaw: ( + requestParameters: ApiDeletePetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + deletePet: ( + requestParameters: ApiDeletePetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + uploadFileRaw: ( + requestParameters: ApiUploadFileRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + uploadFile: ( + requestParameters: ApiUploadFileRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class PetApi extends BaseAPI implements PetApiInterface { @@ -262,12 +416,14 @@ export class PetApi extends BaseAPI implements PetApiInterface { super(configuration ?? DefaultConfig); } - async updatePetRaw(requestParameters: ApiUpdatePetRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async updatePetRaw( + requestParameters: ApiUpdatePetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling updatePetRaw().' + 'Required parameter "body" was null or undefined when calling updatePetRaw().', ); } // Build path with path parameters @@ -282,54 +438,89 @@ export class PetApi extends BaseAPI implements PetApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'PUT', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new UpdatePetError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 404) { + throw new UpdatePetError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 404) { let errorValue: Promise | undefined; - throw new UpdatePetError(response, { kind: 'notFound', status: response.status as 404, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 422) { + throw new UpdatePetError(response, { + kind: 'notFound', + status: response.status as 404, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 422) { let errorValue: Promise | undefined; - throw new UpdatePetError(response, { kind: 'validation', status: response.status as 422, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new UpdatePetError(response, { + kind: 'validation', + status: response.status as 422, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new UpdatePetError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new UpdatePetError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async updatePet(requestParameters: ApiUpdatePetRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async updatePet( + requestParameters: ApiUpdatePetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.updatePetRaw(requestParameters, initOverrides); - return await response.value() as Pet; + return (await response.value()) as Pet; } - async addPetRaw(requestParameters: ApiAddPetRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async addPetRaw( + requestParameters: ApiAddPetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling addPetRaw().' + 'Required parameter "body" was null or undefined when calling addPetRaw().', ); } // Build path with path parameters @@ -344,50 +535,78 @@ export class PetApi extends BaseAPI implements PetApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new AddPetError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 422) { + throw new AddPetError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 422) { let errorValue: Promise | undefined; - throw new AddPetError(response, { kind: 'validation', status: response.status as 422, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new AddPetError(response, { + kind: 'validation', + status: response.status as 422, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new AddPetError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new AddPetError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async addPet(requestParameters: ApiAddPetRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async addPet( + requestParameters: ApiAddPetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.addPetRaw(requestParameters, initOverrides); - return await response.value() as Pet; + return (await response.value()) as Pet; } - async findPetsByStatusRaw(requestParameters: ApiFindPetsByStatusRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async findPetsByStatusRaw( + requestParameters: ApiFindPetsByStatusRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.status === undefined || requestParameters.status === null) { throw new RequiredError( 'status', - 'Required parameter "status" was null or undefined when calling findPetsByStatusRaw().' + 'Required parameter "status" was null or undefined when calling findPetsByStatusRaw().', ); } // Build path with path parameters @@ -398,50 +617,70 @@ export class PetApi extends BaseAPI implements PetApiInterface { queryParameters['status'] = requestParameters.status; } // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new FindPetsByStatusError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new FindPetsByStatusError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new FindPetsByStatusError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new FindPetsByStatusError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async findPetsByStatus(requestParameters: ApiFindPetsByStatusRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async findPetsByStatus( + requestParameters: ApiFindPetsByStatusRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.findPetsByStatusRaw(requestParameters, initOverrides); - return await response.value() as Pet[]; + return (await response.value()) as Pet[]; } - async findPetsByTagsRaw(requestParameters: ApiFindPetsByTagsRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async findPetsByTagsRaw( + requestParameters: ApiFindPetsByTagsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.tags === undefined || requestParameters.tags === null) { throw new RequiredError( 'tags', - 'Required parameter "tags" was null or undefined when calling findPetsByTagsRaw().' + 'Required parameter "tags" was null or undefined when calling findPetsByTagsRaw().', ); } // Build path with path parameters @@ -452,50 +691,70 @@ export class PetApi extends BaseAPI implements PetApiInterface { queryParameters['tags'] = requestParameters.tags; } // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new FindPetsByTagsError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new FindPetsByTagsError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new FindPetsByTagsError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new FindPetsByTagsError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async findPetsByTags(requestParameters: ApiFindPetsByTagsRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async findPetsByTags( + requestParameters: ApiFindPetsByTagsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.findPetsByTagsRaw(requestParameters, initOverrides); - return await response.value() as Pet[]; + return (await response.value()) as Pet[]; } - async getPetByIdRaw(requestParameters: ApiGetPetByIdRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getPetByIdRaw( + requestParameters: ApiGetPetByIdRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.petId === undefined || requestParameters.petId === null) { throw new RequiredError( 'petId', - 'Required parameter "petId" was null or undefined when calling getPetByIdRaw().' + 'Required parameter "petId" was null or undefined when calling getPetByIdRaw().', ); } // Build path with path parameters @@ -504,54 +763,81 @@ export class PetApi extends BaseAPI implements PetApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new GetPetByIdError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 404) { + throw new GetPetByIdError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 404) { let errorValue: Promise | undefined; - throw new GetPetByIdError(response, { kind: 'notFound', status: response.status as 404, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new GetPetByIdError(response, { + kind: 'notFound', + status: response.status as 404, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new GetPetByIdError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new GetPetByIdError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async getPetById(requestParameters: ApiGetPetByIdRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getPetById( + requestParameters: ApiGetPetByIdRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.getPetByIdRaw(requestParameters, initOverrides); - return await response.value() as Pet; + return (await response.value()) as Pet; } - async updatePetWithFormRaw(requestParameters: ApiUpdatePetWithFormRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async updatePetWithFormRaw( + requestParameters: ApiUpdatePetWithFormRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.petId === undefined || requestParameters.petId === null) { throw new RequiredError( 'petId', - 'Required parameter "petId" was null or undefined when calling updatePetWithFormRaw().' + 'Required parameter "petId" was null or undefined when calling updatePetWithFormRaw().', ); } // Build path with path parameters @@ -566,50 +852,70 @@ export class PetApi extends BaseAPI implements PetApiInterface { queryParameters['status'] = requestParameters.status; } // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new UpdatePetWithFormError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new UpdatePetWithFormError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new UpdatePetWithFormError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new UpdatePetWithFormError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async updatePetWithForm(requestParameters: ApiUpdatePetWithFormRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async updatePetWithForm( + requestParameters: ApiUpdatePetWithFormRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.updatePetWithFormRaw(requestParameters, initOverrides); - return await response.value() as Pet; + return (await response.value()) as Pet; } - async deletePetRaw(requestParameters: ApiDeletePetRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async deletePetRaw( + requestParameters: ApiDeletePetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.petId === undefined || requestParameters.petId === null) { throw new RequiredError( 'petId', - 'Required parameter "petId" was null or undefined when calling deletePetRaw().' + 'Required parameter "petId" was null or undefined when calling deletePetRaw().', ); } // Build path with path parameters @@ -618,50 +924,70 @@ export class PetApi extends BaseAPI implements PetApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'DELETE', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new DeletePetError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new DeletePetError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new DeletePetError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new DeletePetError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async deletePet(requestParameters: ApiDeletePetRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async deletePet( + requestParameters: ApiDeletePetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.deletePetRaw(requestParameters, initOverrides); return await response.value(); } - async uploadFileRaw(requestParameters: ApiUploadFileRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async uploadFileRaw( + requestParameters: ApiUploadFileRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.petId === undefined || requestParameters.petId === null) { throw new RequiredError( 'petId', - 'Required parameter "petId" was null or undefined when calling uploadFileRaw().' + 'Required parameter "petId" was null or undefined when calling uploadFileRaw().', ); } // Build path with path parameters @@ -673,37 +999,48 @@ export class PetApi extends BaseAPI implements PetApiInterface { queryParameters['additionalMetadata'] = requestParameters.additionalMetadata; } // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new UploadFileError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new UploadFileError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async uploadFile(requestParameters: ApiUploadFileRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async uploadFile( + requestParameters: ApiUploadFileRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.uploadFileRaw(requestParameters, initOverrides); - return await response.value() as UploadResponse; + return (await response.value()) as UploadResponse; } } diff --git a/tests/golden/typescript/typescript-fetch/petstore/apis/StoreApi.ts.golden b/tests/golden/typescript/typescript-fetch/petstore/apis/StoreApi.ts.golden index 772202019..0b89a495c 100644 --- a/tests/golden/typescript/typescript-fetch/petstore/apis/StoreApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/petstore/apis/StoreApi.ts.golden @@ -5,8 +5,20 @@ * This is a sample Pet Store Server based on the OpenAPI 3.1 specification */ import type { Order } from '../models/Order'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError, VoidApiResponse } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, + VoidApiResponse, +} from '../runtime/runtime'; export interface ApiPlaceOrderRequest { body: Order; @@ -27,96 +39,162 @@ export interface ApiDeleteOrderRequest { } export type GetInventoryRawResponse = - | JSONApiResponse> & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse> & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type PlaceOrderRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type GetOrderByIdRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type DeleteOrderRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); -export type GetInventoryErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type GetInventoryErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class GetInventoryError extends ResponseError { readonly detail: GetInventoryErrorDetail; - constructor(response: Response, detail: GetInventoryErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: GetInventoryErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type PlaceOrderErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class PlaceOrderError extends ResponseError { readonly detail: PlaceOrderErrorDetail; - constructor(response: Response, detail: PlaceOrderErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: PlaceOrderErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type GetOrderByIdErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'notFound'; status: 404; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'notFound'; + status: 404; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class GetOrderByIdError extends ResponseError { readonly detail: GetOrderByIdErrorDetail; - constructor(response: Response, detail: GetOrderByIdErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: GetOrderByIdErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type DeleteOrderErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'notFound'; status: 404; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'notFound'; + status: 404; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class DeleteOrderError extends ResponseError { readonly detail: DeleteOrderErrorDetail; - constructor(response: Response, detail: DeleteOrderErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: DeleteOrderErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface StoreApiInterface { - getInventoryRaw: (initOverrides?: RequestInit - | InitOverrideFunction) => Promise; - getInventory: (initOverrides?: RequestInit | InitOverrideFunction) => Promise>; - placeOrderRaw: (requestParameters: ApiPlaceOrderRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - placeOrder: (requestParameters: ApiPlaceOrderRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - getOrderByIdRaw: (requestParameters: ApiGetOrderByIdRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - getOrderById: (requestParameters: ApiGetOrderByIdRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - deleteOrderRaw: (requestParameters: ApiDeleteOrderRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - deleteOrder: (requestParameters: ApiDeleteOrderRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + getInventoryRaw: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + getInventory: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise>; + placeOrderRaw: ( + requestParameters: ApiPlaceOrderRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + placeOrder: ( + requestParameters: ApiPlaceOrderRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + getOrderByIdRaw: ( + requestParameters: ApiGetOrderByIdRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + getOrderById: ( + requestParameters: ApiGetOrderByIdRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + deleteOrderRaw: ( + requestParameters: ApiDeleteOrderRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + deleteOrder: ( + requestParameters: ApiDeleteOrderRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class StoreApi extends BaseAPI implements StoreApiInterface { @@ -127,54 +205,68 @@ export class StoreApi extends BaseAPI implements StoreApiInterface { super(configuration ?? DefaultConfig); } - async getInventoryRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getInventoryRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/store/inventory`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new GetInventoryError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new GetInventoryError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response) as JSONApiResponse> & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response) as JSONApiResponse> & { + status: 200; + }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async getInventory(initOverrides?: RequestInit | InitOverrideFunction): Promise> { + async getInventory( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise> { const response = await this.getInventoryRaw(initOverrides); - return await response.value() as Record; + return (await response.value()) as Record; } - async placeOrderRaw(requestParameters: ApiPlaceOrderRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async placeOrderRaw( + requestParameters: ApiPlaceOrderRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling placeOrderRaw().' + 'Required parameter "body" was null or undefined when calling placeOrderRaw().', ); } // Build path with path parameters @@ -189,46 +281,67 @@ export class StoreApi extends BaseAPI implements StoreApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new PlaceOrderError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new PlaceOrderError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new PlaceOrderError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new PlaceOrderError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async placeOrder(requestParameters: ApiPlaceOrderRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async placeOrder( + requestParameters: ApiPlaceOrderRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.placeOrderRaw(requestParameters, initOverrides); - return await response.value() as Order; + return (await response.value()) as Order; } - async getOrderByIdRaw(requestParameters: ApiGetOrderByIdRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getOrderByIdRaw( + requestParameters: ApiGetOrderByIdRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.orderId === undefined || requestParameters.orderId === null) { throw new RequiredError( 'orderId', - 'Required parameter "orderId" was null or undefined when calling getOrderByIdRaw().' + 'Required parameter "orderId" was null or undefined when calling getOrderByIdRaw().', ); } // Build path with path parameters @@ -237,54 +350,81 @@ export class StoreApi extends BaseAPI implements StoreApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new GetOrderByIdError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 404) { + throw new GetOrderByIdError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 404) { let errorValue: Promise | undefined; - throw new GetOrderByIdError(response, { kind: 'notFound', status: response.status as 404, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new GetOrderByIdError(response, { + kind: 'notFound', + status: response.status as 404, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new GetOrderByIdError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new GetOrderByIdError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async getOrderById(requestParameters: ApiGetOrderByIdRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getOrderById( + requestParameters: ApiGetOrderByIdRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.getOrderByIdRaw(requestParameters, initOverrides); - return await response.value() as Order; + return (await response.value()) as Order; } - async deleteOrderRaw(requestParameters: ApiDeleteOrderRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async deleteOrderRaw( + requestParameters: ApiDeleteOrderRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.orderId === undefined || requestParameters.orderId === null) { throw new RequiredError( 'orderId', - 'Required parameter "orderId" was null or undefined when calling deleteOrderRaw().' + 'Required parameter "orderId" was null or undefined when calling deleteOrderRaw().', ); } // Build path with path parameters @@ -293,44 +433,69 @@ export class StoreApi extends BaseAPI implements StoreApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'DELETE', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new DeleteOrderError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 404) { + throw new DeleteOrderError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 404) { let errorValue: Promise | undefined; - throw new DeleteOrderError(response, { kind: 'notFound', status: response.status as 404, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new DeleteOrderError(response, { + kind: 'notFound', + status: response.status as 404, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new DeleteOrderError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new DeleteOrderError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async deleteOrder(requestParameters: ApiDeleteOrderRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async deleteOrder( + requestParameters: ApiDeleteOrderRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.deleteOrderRaw(requestParameters, initOverrides); return await response.value(); } diff --git a/tests/golden/typescript/typescript-fetch/petstore/apis/UserApi.ts.golden b/tests/golden/typescript/typescript-fetch/petstore/apis/UserApi.ts.golden index d3b26a158..dbbbcc76b 100644 --- a/tests/golden/typescript/typescript-fetch/petstore/apis/UserApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/petstore/apis/UserApi.ts.golden @@ -5,8 +5,20 @@ * This is a sample Pet Store Server based on the OpenAPI 3.1 specification */ import type { User } from '../models/User'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError, VoidApiResponse } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, + VoidApiResponse, +} from '../runtime/runtime'; export interface ApiCreateUserRequest { body: User; @@ -50,161 +62,266 @@ export interface ApiDeleteUserRequest { } export type CreateUserRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type CreateUsersWithListInputRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type LoginUserRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); export type LogoutUserRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); export type GetUserByNameRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type UpdateUserRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); export type DeleteUserRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); -export type CreateUserErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type CreateUserErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class CreateUserError extends ResponseError { readonly detail: CreateUserErrorDetail; - constructor(response: Response, detail: CreateUserErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: CreateUserErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type CreateUsersWithListInputErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type CreateUsersWithListInputErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class CreateUsersWithListInputError extends ResponseError { readonly detail: CreateUsersWithListInputErrorDetail; - constructor(response: Response, detail: CreateUsersWithListInputErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: CreateUsersWithListInputErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type LoginUserErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class LoginUserError extends ResponseError { readonly detail: LoginUserErrorDetail; - constructor(response: Response, detail: LoginUserErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: LoginUserErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type LogoutUserErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type LogoutUserErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class LogoutUserError extends ResponseError { readonly detail: LogoutUserErrorDetail; - constructor(response: Response, detail: LogoutUserErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: LogoutUserErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type GetUserByNameErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'notFound'; status: 404; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'notFound'; + status: 404; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class GetUserByNameError extends ResponseError { readonly detail: GetUserByNameErrorDetail; - constructor(response: Response, detail: GetUserByNameErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: GetUserByNameErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type UpdateUserErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'notFound'; status: 404; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'notFound'; + status: 404; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class UpdateUserError extends ResponseError { readonly detail: UpdateUserErrorDetail; - constructor(response: Response, detail: UpdateUserErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: UpdateUserErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type DeleteUserErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'notFound'; status: 404; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'notFound'; + status: 404; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class DeleteUserError extends ResponseError { readonly detail: DeleteUserErrorDetail; - constructor(response: Response, detail: DeleteUserErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: DeleteUserErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface UserApiInterface { - createUserRaw: (requestParameters: ApiCreateUserRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - createUser: (requestParameters: ApiCreateUserRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - createUsersWithListInputRaw: (requestParameters: ApiCreateUsersWithListInputRequest, - initOverrides?: RequestInit - | InitOverrideFunction) => Promise; - createUsersWithListInput: (requestParameters: ApiCreateUsersWithListInputRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - loginUserRaw: (requestParameters: ApiLoginUserRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - loginUser: (requestParameters: ApiLoginUserRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - logoutUserRaw: (initOverrides?: RequestInit - | InitOverrideFunction) => Promise; + createUserRaw: ( + requestParameters: ApiCreateUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + createUser: ( + requestParameters: ApiCreateUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + createUsersWithListInputRaw: ( + requestParameters: ApiCreateUsersWithListInputRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + createUsersWithListInput: ( + requestParameters: ApiCreateUsersWithListInputRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + loginUserRaw: ( + requestParameters: ApiLoginUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + loginUser: ( + requestParameters: ApiLoginUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + logoutUserRaw: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; logoutUser: (initOverrides?: RequestInit | InitOverrideFunction) => Promise; - getUserByNameRaw: (requestParameters: ApiGetUserByNameRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - getUserByName: (requestParameters: ApiGetUserByNameRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - updateUserRaw: (requestParameters: ApiUpdateUserRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - updateUser: (requestParameters: ApiUpdateUserRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - deleteUserRaw: (requestParameters: ApiDeleteUserRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - deleteUser: (requestParameters: ApiDeleteUserRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + getUserByNameRaw: ( + requestParameters: ApiGetUserByNameRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + getUserByName: ( + requestParameters: ApiGetUserByNameRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + updateUserRaw: ( + requestParameters: ApiUpdateUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + updateUser: ( + requestParameters: ApiUpdateUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + deleteUserRaw: ( + requestParameters: ApiDeleteUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + deleteUser: ( + requestParameters: ApiDeleteUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class UserApi extends BaseAPI implements UserApiInterface { @@ -215,12 +332,14 @@ export class UserApi extends BaseAPI implements UserApiInterface { super(configuration ?? DefaultConfig); } - async createUserRaw(requestParameters: ApiCreateUserRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createUserRaw( + requestParameters: ApiCreateUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling createUserRaw().' + 'Required parameter "body" was null or undefined when calling createUserRaw().', ); } // Build path with path parameters @@ -235,43 +354,56 @@ export class UserApi extends BaseAPI implements UserApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new CreateUserError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new CreateUserError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async createUser(requestParameters: ApiCreateUserRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createUser( + requestParameters: ApiCreateUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.createUserRaw(requestParameters, initOverrides); - return await response.value() as User; + return (await response.value()) as User; } - async createUsersWithListInputRaw(requestParameters: ApiCreateUsersWithListInputRequest, - initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createUsersWithListInputRaw( + requestParameters: ApiCreateUsersWithListInputRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling createUsersWithListInputRaw().' + 'Required parameter "body" was null or undefined when calling createUsersWithListInputRaw().', ); } // Build path with path parameters @@ -286,38 +418,52 @@ export class UserApi extends BaseAPI implements UserApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new CreateUsersWithListInputError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new CreateUsersWithListInputError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async createUsersWithListInput(requestParameters: ApiCreateUsersWithListInputRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async createUsersWithListInput( + requestParameters: ApiCreateUsersWithListInputRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.createUsersWithListInputRaw(requestParameters, initOverrides); - return await response.value() as User; + return (await response.value()) as User; } - async loginUserRaw(requestParameters: ApiLoginUserRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async loginUserRaw( + requestParameters: ApiLoginUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/user/login`; // Build query parameters @@ -329,75 +475,103 @@ export class UserApi extends BaseAPI implements UserApiInterface { queryParameters['password'] = requestParameters.password; } // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new LoginUserError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new LoginUserError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new LoginUserError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new LoginUserError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async loginUser(requestParameters: ApiLoginUserRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async loginUser( + requestParameters: ApiLoginUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.loginUserRaw(requestParameters, initOverrides); return await response.value(); } - async logoutUserRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async logoutUserRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/user/logout`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new LogoutUserError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new LogoutUserError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } @@ -407,12 +581,14 @@ export class UserApi extends BaseAPI implements UserApiInterface { return await response.value(); } - async getUserByNameRaw(requestParameters: ApiGetUserByNameRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getUserByNameRaw( + requestParameters: ApiGetUserByNameRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.username === undefined || requestParameters.username === null) { throw new RequiredError( 'username', - 'Required parameter "username" was null or undefined when calling getUserByNameRaw().' + 'Required parameter "username" was null or undefined when calling getUserByNameRaw().', ); } // Build path with path parameters @@ -421,60 +597,87 @@ export class UserApi extends BaseAPI implements UserApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new GetUserByNameError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 404) { + throw new GetUserByNameError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 404) { let errorValue: Promise | undefined; - throw new GetUserByNameError(response, { kind: 'notFound', status: response.status as 404, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new GetUserByNameError(response, { + kind: 'notFound', + status: response.status as 404, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new GetUserByNameError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new GetUserByNameError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async getUserByName(requestParameters: ApiGetUserByNameRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getUserByName( + requestParameters: ApiGetUserByNameRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.getUserByNameRaw(requestParameters, initOverrides); - return await response.value() as User; + return (await response.value()) as User; } - async updateUserRaw(requestParameters: ApiUpdateUserRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async updateUserRaw( + requestParameters: ApiUpdateUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.username === undefined || requestParameters.username === null) { throw new RequiredError( 'username', - 'Required parameter "username" was null or undefined when calling updateUserRaw().' + 'Required parameter "username" was null or undefined when calling updateUserRaw().', ); } if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling updateUserRaw().' + 'Required parameter "body" was null or undefined when calling updateUserRaw().', ); } // Build path with path parameters @@ -490,50 +693,78 @@ export class UserApi extends BaseAPI implements UserApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'PUT', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new UpdateUserError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 404) { + throw new UpdateUserError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 404) { let errorValue: Promise | undefined; - throw new UpdateUserError(response, { kind: 'notFound', status: response.status as 404, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new UpdateUserError(response, { + kind: 'notFound', + status: response.status as 404, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new UpdateUserError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new UpdateUserError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async updateUser(requestParameters: ApiUpdateUserRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async updateUser( + requestParameters: ApiUpdateUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.updateUserRaw(requestParameters, initOverrides); return await response.value(); } - async deleteUserRaw(requestParameters: ApiDeleteUserRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async deleteUserRaw( + requestParameters: ApiDeleteUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.username === undefined || requestParameters.username === null) { throw new RequiredError( 'username', - 'Required parameter "username" was null or undefined when calling deleteUserRaw().' + 'Required parameter "username" was null or undefined when calling deleteUserRaw().', ); } // Build path with path parameters @@ -542,44 +773,69 @@ export class UserApi extends BaseAPI implements UserApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'DELETE', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new DeleteUserError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 404) { + throw new DeleteUserError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 404) { let errorValue: Promise | undefined; - throw new DeleteUserError(response, { kind: 'notFound', status: response.status as 404, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new DeleteUserError(response, { + kind: 'notFound', + status: response.status as 404, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new DeleteUserError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new DeleteUserError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async deleteUser(requestParameters: ApiDeleteUserRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async deleteUser( + requestParameters: ApiDeleteUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.deleteUserRaw(requestParameters, initOverrides); return await response.value(); } diff --git a/tests/golden/typescript/typescript-fetch/petstore/package.json.golden b/tests/golden/typescript/typescript-fetch/petstore/package.json.golden index ccae2b401..76e865554 100644 --- a/tests/golden/typescript/typescript-fetch/petstore/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/petstore/package.json.golden @@ -1,27 +1,27 @@ { + "name": "petstore-api", + "version": "1.0.0", "description": "This is a sample Pet Store Server based on the OpenAPI 3.1 specification", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "license": "Apache 2.0", + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "license": "Apache 2.0", - "main": "./dist/index.js", - "name": "petstore-api", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/petstore/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/petstore/runtime/runtime.ts.golden index b36abbfbd..6ca6619b2 100644 --- a/tests/golden/typescript/typescript-fetch/petstore/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/petstore/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Petstore API — 1.0.0 * This is a sample Pet Store Server based on the OpenAPI 3.1 specification */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/petstore/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/petstore/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/petstore/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/petstore/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/petstore/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/petstore/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/petstore/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/petstore/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/query-param-enum/README.md.golden b/tests/golden/typescript/typescript-fetch/query-param-enum/README.md.golden index 23b08e71c..1663e1a51 100644 --- a/tests/golden/typescript/typescript-fetch/query-param-enum/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/query-param-enum/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, ItemsApi } from 'query-parameter-enum-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'query-parameter-enum-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/query-param-enum/apis/ItemsApi.ts.golden b/tests/golden/typescript/typescript-fetch/query-param-enum/apis/ItemsApi.ts.golden index ff1df7c1f..547c2f987 100644 --- a/tests/golden/typescript/typescript-fetch/query-param-enum/apis/ItemsApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/query-param-enum/apis/ItemsApi.ts.golden @@ -6,8 +6,19 @@ */ import type { FooStatus } from '../models/FooStatus'; import type { GetItemsResponse200 } from '../models/GetItemsResponse200'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, ResponseError, VoidApiResponse } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + ResponseError, + VoidApiResponse, +} from '../runtime/runtime'; export interface ApiGetItemsRequest { /** @@ -17,29 +28,45 @@ export interface ApiGetItemsRequest { } export type GetItemsRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type GetItemsErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class GetItemsError extends ResponseError { readonly detail: GetItemsErrorDetail; - constructor(response: Response, detail: GetItemsErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: GetItemsErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface ItemsApiInterface { - getItemsRaw: (requestParameters: ApiGetItemsRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - getItems: (requestParameters: ApiGetItemsRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + getItemsRaw: ( + requestParameters: ApiGetItemsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + getItems: ( + requestParameters: ApiGetItemsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class ItemsApi extends BaseAPI implements ItemsApiInterface { @@ -50,8 +77,10 @@ export class ItemsApi extends BaseAPI implements ItemsApiInterface { super(configuration ?? DefaultConfig); } - async getItemsRaw(requestParameters: ApiGetItemsRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getItemsRaw( + requestParameters: ApiGetItemsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/items`; // Build query parameters @@ -60,41 +89,61 @@ export class ItemsApi extends BaseAPI implements ItemsApiInterface { queryParameters['status'] = requestParameters.status; } // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new GetItemsError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new GetItemsError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new GetItemsError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new GetItemsError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response) as JSONApiResponse & { + status: 200; + }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async getItems(requestParameters: ApiGetItemsRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getItems( + requestParameters: ApiGetItemsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.getItemsRaw(requestParameters, initOverrides); - return await response.value() as GetItemsResponse200; + return (await response.value()) as GetItemsResponse200; } } diff --git a/tests/golden/typescript/typescript-fetch/query-param-enum/package.json.golden b/tests/golden/typescript/typescript-fetch/query-param-enum/package.json.golden index e19a7f899..ef86a0859 100644 --- a/tests/golden/typescript/typescript-fetch/query-param-enum/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/query-param-enum/package.json.golden @@ -1,26 +1,26 @@ { + "name": "query-parameter-enum-test", + "version": "1.0.0", "description": "Test case for query parameters that reference enum schemas", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "query-parameter-enum-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/query-param-enum/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/query-param-enum/runtime/runtime.ts.golden index 2b05d43c3..0f9ad31a0 100644 --- a/tests/golden/typescript/typescript-fetch/query-param-enum/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/query-param-enum/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Query Parameter Enum Test — 1.0.0 * Test case for query parameters that reference enum schemas */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/query-param-enum/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/query-param-enum/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/query-param-enum/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/query-param-enum/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/query-param-enum/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/query-param-enum/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/query-param-enum/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/query-param-enum/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-all-optional-properties/README.md.golden b/tests/golden/typescript/typescript-fetch/recursive-json-all-optional-properties/README.md.golden index ebab867af..153473d68 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-all-optional-properties/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-all-optional-properties/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'all-optional-properties-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'all-optional-properties-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-all-optional-properties/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-all-optional-properties/apis/DefaultApi.ts.golden index f8a399d74..a47e3ece1 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-all-optional-properties/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-all-optional-properties/apis/DefaultApi.ts.golden @@ -4,22 +4,33 @@ * All Optional Properties Test — 1.0.0 * Test case for object with all optional properties including arrays, references, and inline objects */ -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; import { BaseAPI, DefaultConfig, ResponseError, VoidApiResponse } from '../runtime/runtime'; export type TestRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); - -export type TestErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestError extends ResponseError { readonly detail: TestErrorDetail; - constructor(response: Response, detail: TestErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } @@ -44,30 +55,39 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-all-optional-properties/package.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-all-optional-properties/package.json.golden index 42230e2e5..f7f5d93cc 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-all-optional-properties/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-all-optional-properties/package.json.golden @@ -1,26 +1,26 @@ { + "name": "all-optional-properties-test", + "version": "1.0.0", "description": "Test case for object with all optional properties including arrays, references, and inline objects", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "all-optional-properties-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-all-optional-properties/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-all-optional-properties/runtime/runtime.ts.golden index 2d1f958ed..598289641 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-all-optional-properties/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-all-optional-properties/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * All Optional Properties Test — 1.0.0 * Test case for object with all optional properties including arrays, references, and inline objects */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-all-optional-properties/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-all-optional-properties/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-all-optional-properties/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-all-optional-properties/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-all-optional-properties/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-all-optional-properties/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-all-optional-properties/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-all-optional-properties/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-array-of-inline-objects/README.md.golden b/tests/golden/typescript/typescript-fetch/recursive-json-array-of-inline-objects/README.md.golden index f817ef15a..b48e54063 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-array-of-inline-objects/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-array-of-inline-objects/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'array-of-inline-objects-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'array-of-inline-objects-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-array-of-inline-objects/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-array-of-inline-objects/apis/DefaultApi.ts.golden index b3a69fb38..7434268ff 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-array-of-inline-objects/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-array-of-inline-objects/apis/DefaultApi.ts.golden @@ -4,22 +4,33 @@ * Array of Inline Objects Test — 1.0.0 * Test case for array of inline objects with snake_case to camelCase conversion (main case from user issue) */ -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; import { BaseAPI, DefaultConfig, ResponseError, VoidApiResponse } from '../runtime/runtime'; export type TestRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); - -export type TestErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestError extends ResponseError { readonly detail: TestErrorDetail; - constructor(response: Response, detail: TestErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } @@ -44,30 +55,39 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-array-of-inline-objects/package.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-array-of-inline-objects/package.json.golden index df98f3428..ef9eaa826 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-array-of-inline-objects/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-array-of-inline-objects/package.json.golden @@ -1,26 +1,26 @@ { + "name": "array-of-inline-objects-test", + "version": "1.0.0", "description": "Test case for array of inline objects with snake_case to camelCase conversion (main case from user issue)", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "array-of-inline-objects-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-array-of-inline-objects/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-array-of-inline-objects/runtime/runtime.ts.golden index 90893186e..eb5d3d29e 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-array-of-inline-objects/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-array-of-inline-objects/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Array of Inline Objects Test — 1.0.0 * Test case for array of inline objects with snake_case to camelCase conversion (main case from user issue) */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-array-of-inline-objects/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-array-of-inline-objects/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-array-of-inline-objects/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-array-of-inline-objects/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-array-of-inline-objects/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-array-of-inline-objects/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-array-of-inline-objects/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-array-of-inline-objects/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-array-of-referenced-types/README.md.golden b/tests/golden/typescript/typescript-fetch/recursive-json-array-of-referenced-types/README.md.golden index fc93f424d..6ed1cae0f 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-array-of-referenced-types/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-array-of-referenced-types/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'array-of-referenced-types-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'array-of-referenced-types-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-array-of-referenced-types/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-array-of-referenced-types/apis/DefaultApi.ts.golden index d3969cfe0..3578baf47 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-array-of-referenced-types/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-array-of-referenced-types/apis/DefaultApi.ts.golden @@ -4,22 +4,33 @@ * Array of Referenced Types Test — 1.0.0 * Test case for array of referenced model types with recursive FromJSON calls */ -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; import { BaseAPI, DefaultConfig, ResponseError, VoidApiResponse } from '../runtime/runtime'; export type TestRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); - -export type TestErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestError extends ResponseError { readonly detail: TestErrorDetail; - constructor(response: Response, detail: TestErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } @@ -44,30 +55,39 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-array-of-referenced-types/package.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-array-of-referenced-types/package.json.golden index 0f4b27469..2d69760ed 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-array-of-referenced-types/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-array-of-referenced-types/package.json.golden @@ -1,26 +1,26 @@ { + "name": "array-of-referenced-types-test", + "version": "1.0.0", "description": "Test case for array of referenced model types with recursive FromJSON calls", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "array-of-referenced-types-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-array-of-referenced-types/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-array-of-referenced-types/runtime/runtime.ts.golden index 10a5c386f..af98c37a3 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-array-of-referenced-types/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-array-of-referenced-types/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Array of Referenced Types Test — 1.0.0 * Test case for array of referenced model types with recursive FromJSON calls */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-array-of-referenced-types/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-array-of-referenced-types/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-array-of-referenced-types/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-array-of-referenced-types/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-array-of-referenced-types/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-array-of-referenced-types/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-array-of-referenced-types/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-array-of-referenced-types/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-array-with-reference-property/README.md.golden b/tests/golden/typescript/typescript-fetch/recursive-json-array-with-reference-property/README.md.golden index 67e680e2e..5faf57238 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-array-with-reference-property/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-array-with-reference-property/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'array-with-reference-property-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'array-with-reference-property-test const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-array-with-reference-property/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-array-with-reference-property/apis/DefaultApi.ts.golden index 06c1160b1..a57fde2dd 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-array-with-reference-property/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-array-with-reference-property/apis/DefaultApi.ts.golden @@ -4,22 +4,33 @@ * Array with Reference Property Test — 1.0.0 * Test case for array of inline objects that contain a reference property */ -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; import { BaseAPI, DefaultConfig, ResponseError, VoidApiResponse } from '../runtime/runtime'; export type TestRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); - -export type TestErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestError extends ResponseError { readonly detail: TestErrorDetail; - constructor(response: Response, detail: TestErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } @@ -44,30 +55,39 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-array-with-reference-property/package.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-array-with-reference-property/package.json.golden index 0b72b7597..ae518db6d 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-array-with-reference-property/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-array-with-reference-property/package.json.golden @@ -1,26 +1,26 @@ { + "name": "array-with-reference-property-test", + "version": "1.0.0", "description": "Test case for array of inline objects that contain a reference property", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "array-with-reference-property-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-array-with-reference-property/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-array-with-reference-property/runtime/runtime.ts.golden index d4de12550..dcae69e14 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-array-with-reference-property/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-array-with-reference-property/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Array with Reference Property Test — 1.0.0 * Test case for array of inline objects that contain a reference property */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-array-with-reference-property/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-array-with-reference-property/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-array-with-reference-property/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-array-with-reference-property/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-array-with-reference-property/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-array-with-reference-property/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-array-with-reference-property/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-array-with-reference-property/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-complex-array-structure/README.md.golden b/tests/golden/typescript/typescript-fetch/recursive-json-complex-array-structure/README.md.golden index fd5037117..d1959ecc6 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-complex-array-structure/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-complex-array-structure/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'complex-array-structure-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'complex-array-structure-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-complex-array-structure/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-complex-array-structure/apis/DefaultApi.ts.golden index 1bf64fd29..f9beb9106 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-complex-array-structure/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-complex-array-structure/apis/DefaultApi.ts.golden @@ -4,22 +4,33 @@ * Complex Array Structure Test — 1.0.0 * Test case for array of inline objects where each object has nested inline objects */ -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; import { BaseAPI, DefaultConfig, ResponseError, VoidApiResponse } from '../runtime/runtime'; export type TestRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); - -export type TestErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestError extends ResponseError { readonly detail: TestErrorDetail; - constructor(response: Response, detail: TestErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } @@ -44,30 +55,39 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-complex-array-structure/package.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-complex-array-structure/package.json.golden index 371429f8c..ddc3ed626 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-complex-array-structure/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-complex-array-structure/package.json.golden @@ -1,26 +1,26 @@ { + "name": "complex-array-structure-test", + "version": "1.0.0", "description": "Test case for array of inline objects where each object has nested inline objects", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "complex-array-structure-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-complex-array-structure/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-complex-array-structure/runtime/runtime.ts.golden index 6fcbb6374..3e8f1360b 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-complex-array-structure/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-complex-array-structure/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Complex Array Structure Test — 1.0.0 * Test case for array of inline objects where each object has nested inline objects */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-complex-array-structure/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-complex-array-structure/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-complex-array-structure/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-complex-array-structure/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-complex-array-structure/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-complex-array-structure/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-complex-array-structure/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-complex-array-structure/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-deeply-nested-inline/README.md.golden b/tests/golden/typescript/typescript-fetch/recursive-json-deeply-nested-inline/README.md.golden index afe682c54..4dfe6ee63 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-deeply-nested-inline/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-deeply-nested-inline/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'deeply-nested-inline-objects-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'deeply-nested-inline-objects-test' const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-deeply-nested-inline/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-deeply-nested-inline/apis/DefaultApi.ts.golden index 186d504ab..dfab319cf 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-deeply-nested-inline/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-deeply-nested-inline/apis/DefaultApi.ts.golden @@ -4,22 +4,33 @@ * Deeply Nested Inline Objects Test — 1.0.0 * Test case for three levels of nested inline objects */ -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; import { BaseAPI, DefaultConfig, ResponseError, VoidApiResponse } from '../runtime/runtime'; export type TestRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); - -export type TestErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestError extends ResponseError { readonly detail: TestErrorDetail; - constructor(response: Response, detail: TestErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } @@ -44,30 +55,39 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-deeply-nested-inline/package.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-deeply-nested-inline/package.json.golden index d2cf9e810..bd7819e6c 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-deeply-nested-inline/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-deeply-nested-inline/package.json.golden @@ -1,26 +1,26 @@ { + "name": "deeply-nested-inline-objects-test", + "version": "1.0.0", "description": "Test case for three levels of nested inline objects", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "deeply-nested-inline-objects-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-deeply-nested-inline/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-deeply-nested-inline/runtime/runtime.ts.golden index 4570baaad..3274c0098 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-deeply-nested-inline/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-deeply-nested-inline/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Deeply Nested Inline Objects Test — 1.0.0 * Test case for three levels of nested inline objects */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-deeply-nested-inline/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-deeply-nested-inline/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-deeply-nested-inline/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-deeply-nested-inline/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-deeply-nested-inline/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-deeply-nested-inline/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-deeply-nested-inline/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-deeply-nested-inline/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-empty-array/README.md.golden b/tests/golden/typescript/typescript-fetch/recursive-json-empty-array/README.md.golden index 2fb76d338..9e564b10f 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-empty-array/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-empty-array/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'empty-array-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'empty-array-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-empty-array/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-empty-array/apis/DefaultApi.ts.golden index 2f67ee349..8d13e840f 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-empty-array/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-empty-array/apis/DefaultApi.ts.golden @@ -4,22 +4,33 @@ * Empty Array Test — 1.0.0 * Test case for empty array handling */ -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; import { BaseAPI, DefaultConfig, ResponseError, VoidApiResponse } from '../runtime/runtime'; export type TestRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); - -export type TestErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestError extends ResponseError { readonly detail: TestErrorDetail; - constructor(response: Response, detail: TestErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } @@ -44,30 +55,39 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-empty-array/package.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-empty-array/package.json.golden index f74f05a90..bf2034dc3 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-empty-array/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-empty-array/package.json.golden @@ -1,26 +1,26 @@ { + "name": "empty-array-test", + "version": "1.0.0", "description": "Test case for empty array handling", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "empty-array-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-empty-array/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-empty-array/runtime/runtime.ts.golden index de2d542d3..ca9dfb390 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-empty-array/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-empty-array/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Empty Array Test — 1.0.0 * Test case for empty array handling */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-empty-array/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-empty-array/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-empty-array/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-empty-array/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-empty-array/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-empty-array/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-empty-array/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-empty-array/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-inline-object-with-array/README.md.golden b/tests/golden/typescript/typescript-fetch/recursive-json-inline-object-with-array/README.md.golden index f68ad04c9..09c72cab8 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-inline-object-with-array/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-inline-object-with-array/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'inline-object-with-array-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'inline-object-with-array-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-inline-object-with-array/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-inline-object-with-array/apis/DefaultApi.ts.golden index d667394d4..f5c9c5e28 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-inline-object-with-array/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-inline-object-with-array/apis/DefaultApi.ts.golden @@ -4,22 +4,33 @@ * Inline Object with Array Test — 1.0.0 * Test case for inline object containing an array of inline objects */ -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; import { BaseAPI, DefaultConfig, ResponseError, VoidApiResponse } from '../runtime/runtime'; export type TestRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); - -export type TestErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestError extends ResponseError { readonly detail: TestErrorDetail; - constructor(response: Response, detail: TestErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } @@ -44,30 +55,39 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-inline-object-with-array/package.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-inline-object-with-array/package.json.golden index a51af7711..b0dcf56d7 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-inline-object-with-array/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-inline-object-with-array/package.json.golden @@ -1,26 +1,26 @@ { + "name": "inline-object-with-array-test", + "version": "1.0.0", "description": "Test case for inline object containing an array of inline objects", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "inline-object-with-array-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-inline-object-with-array/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-inline-object-with-array/runtime/runtime.ts.golden index d3b57f44f..ef58fd124 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-inline-object-with-array/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-inline-object-with-array/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Inline Object with Array Test — 1.0.0 * Test case for inline object containing an array of inline objects */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-inline-object-with-array/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-inline-object-with-array/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-inline-object-with-array/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-inline-object-with-array/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-inline-object-with-array/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-inline-object-with-array/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-inline-object-with-array/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-inline-object-with-array/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-inline-object/README.md.golden b/tests/golden/typescript/typescript-fetch/recursive-json-inline-object/README.md.golden index 2cfbd13f2..d215c1ec9 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-inline-object/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-inline-object/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'inline-object-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'inline-object-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-inline-object/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-inline-object/apis/DefaultApi.ts.golden index b4f4f1aff..b47091cdf 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-inline-object/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-inline-object/apis/DefaultApi.ts.golden @@ -4,22 +4,33 @@ * Inline Object Test — 1.0.0 * Test case for inline objects (not arrays) with snake_case to camelCase conversion */ -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; import { BaseAPI, DefaultConfig, ResponseError, VoidApiResponse } from '../runtime/runtime'; export type TestRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); - -export type TestErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestError extends ResponseError { readonly detail: TestErrorDetail; - constructor(response: Response, detail: TestErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } @@ -44,30 +55,39 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-inline-object/package.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-inline-object/package.json.golden index 3108209f6..29708bc76 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-inline-object/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-inline-object/package.json.golden @@ -1,26 +1,26 @@ { + "name": "inline-object-test", + "version": "1.0.0", "description": "Test case for inline objects (not arrays) with snake_case to camelCase conversion", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "inline-object-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-inline-object/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-inline-object/runtime/runtime.ts.golden index 78abac8dd..b7cf87e68 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-inline-object/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-inline-object/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Inline Object Test — 1.0.0 * Test case for inline objects (not arrays) with snake_case to camelCase conversion */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-inline-object/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-inline-object/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-inline-object/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-inline-object/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-inline-object/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-inline-object/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-inline-object/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-inline-object/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-mixed-property-types/README.md.golden b/tests/golden/typescript/typescript-fetch/recursive-json-mixed-property-types/README.md.golden index 4a4b9cf99..30b5a25ff 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-mixed-property-types/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-mixed-property-types/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'mixed-property-types-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'mixed-property-types-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-mixed-property-types/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-mixed-property-types/apis/DefaultApi.ts.golden index d769d48ad..b504ed80f 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-mixed-property-types/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-mixed-property-types/apis/DefaultApi.ts.golden @@ -4,22 +4,33 @@ * Mixed Property Types Test — 1.0.0 * Test case for object with mix of simple types, arrays, references, and inline objects */ -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; import { BaseAPI, DefaultConfig, ResponseError, VoidApiResponse } from '../runtime/runtime'; export type TestRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); - -export type TestErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestError extends ResponseError { readonly detail: TestErrorDetail; - constructor(response: Response, detail: TestErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } @@ -44,30 +55,39 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-mixed-property-types/package.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-mixed-property-types/package.json.golden index 0445a57dd..c86fbda27 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-mixed-property-types/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-mixed-property-types/package.json.golden @@ -1,26 +1,26 @@ { + "name": "mixed-property-types-test", + "version": "1.0.0", "description": "Test case for object with mix of simple types, arrays, references, and inline objects", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "mixed-property-types-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-mixed-property-types/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-mixed-property-types/runtime/runtime.ts.golden index ac04cc5fe..80cd61ba5 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-mixed-property-types/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-mixed-property-types/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Mixed Property Types Test — 1.0.0 * Test case for object with mix of simple types, arrays, references, and inline objects */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-mixed-property-types/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-mixed-property-types/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-mixed-property-types/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-mixed-property-types/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-mixed-property-types/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-mixed-property-types/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-mixed-property-types/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-mixed-property-types/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-nested-object-reference/README.md.golden b/tests/golden/typescript/typescript-fetch/recursive-json-nested-object-reference/README.md.golden index 17d933479..031fad085 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-nested-object-reference/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-nested-object-reference/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'nested-object-reference-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'nested-object-reference-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-nested-object-reference/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-nested-object-reference/apis/DefaultApi.ts.golden index 9984b3307..0dfb076f0 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-nested-object-reference/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-nested-object-reference/apis/DefaultApi.ts.golden @@ -4,22 +4,33 @@ * Nested Object Reference Test — 1.0.0 * Test case for nested object reference with recursive FromJSON calls */ -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; import { BaseAPI, DefaultConfig, ResponseError, VoidApiResponse } from '../runtime/runtime'; export type TestRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); - -export type TestErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestError extends ResponseError { readonly detail: TestErrorDetail; - constructor(response: Response, detail: TestErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } @@ -44,30 +55,39 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-nested-object-reference/package.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-nested-object-reference/package.json.golden index eec71d444..b01719f74 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-nested-object-reference/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-nested-object-reference/package.json.golden @@ -1,26 +1,26 @@ { + "name": "nested-object-reference-test", + "version": "1.0.0", "description": "Test case for nested object reference with recursive FromJSON calls", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "nested-object-reference-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-nested-object-reference/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-nested-object-reference/runtime/runtime.ts.golden index 6725b09d3..c57c8dd98 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-nested-object-reference/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-nested-object-reference/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Nested Object Reference Test — 1.0.0 * Test case for nested object reference with recursive FromJSON calls */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-nested-object-reference/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-nested-object-reference/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-nested-object-reference/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-nested-object-reference/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-nested-object-reference/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-nested-object-reference/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-nested-object-reference/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-nested-object-reference/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-inline-objects/README.md.golden b/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-inline-objects/README.md.golden index d518fa8f0..7d7762c3d 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-inline-objects/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-inline-objects/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'optional-array-of-inline-objects-test const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'optional-array-of-inline-objects-t const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-inline-objects/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-inline-objects/apis/DefaultApi.ts.golden index b4d89d31a..87275cea5 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-inline-objects/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-inline-objects/apis/DefaultApi.ts.golden @@ -4,22 +4,33 @@ * Optional Array of Inline Objects Test — 1.0.0 * Test case for optional array of inline objects with snake_case to camelCase conversion */ -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; import { BaseAPI, DefaultConfig, ResponseError, VoidApiResponse } from '../runtime/runtime'; export type TestRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); - -export type TestErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestError extends ResponseError { readonly detail: TestErrorDetail; - constructor(response: Response, detail: TestErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } @@ -44,30 +55,39 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-inline-objects/package.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-inline-objects/package.json.golden index 64619000e..ab34f359f 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-inline-objects/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-inline-objects/package.json.golden @@ -1,26 +1,26 @@ { + "name": "optional-array-of-inline-objects-test", + "version": "1.0.0", "description": "Test case for optional array of inline objects with snake_case to camelCase conversion", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "optional-array-of-inline-objects-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-inline-objects/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-inline-objects/runtime/runtime.ts.golden index 0345a693b..5223e6375 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-inline-objects/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-inline-objects/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Optional Array of Inline Objects Test — 1.0.0 * Test case for optional array of inline objects with snake_case to camelCase conversion */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-inline-objects/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-inline-objects/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-inline-objects/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-inline-objects/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-inline-objects/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-inline-objects/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-inline-objects/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-inline-objects/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-referenced-types/README.md.golden b/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-referenced-types/README.md.golden index faab8f5a7..ee60b0a40 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-referenced-types/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-referenced-types/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'optional-array-of-referenced-types-te const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'optional-array-of-referenced-types const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-referenced-types/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-referenced-types/apis/DefaultApi.ts.golden index 6409f5c12..60d7c0155 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-referenced-types/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-referenced-types/apis/DefaultApi.ts.golden @@ -4,22 +4,33 @@ * Optional Array of Referenced Types Test — 1.0.0 * Test case for optional array of referenced model types */ -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; import { BaseAPI, DefaultConfig, ResponseError, VoidApiResponse } from '../runtime/runtime'; export type TestRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); - -export type TestErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestError extends ResponseError { readonly detail: TestErrorDetail; - constructor(response: Response, detail: TestErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } @@ -44,30 +55,39 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-referenced-types/package.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-referenced-types/package.json.golden index 22a258b2f..a003db4b1 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-referenced-types/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-referenced-types/package.json.golden @@ -1,26 +1,26 @@ { + "name": "optional-array-of-referenced-types-test", + "version": "1.0.0", "description": "Test case for optional array of referenced model types", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "optional-array-of-referenced-types-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-referenced-types/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-referenced-types/runtime/runtime.ts.golden index 568057820..e8e2cdcde 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-referenced-types/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-referenced-types/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Optional Array of Referenced Types Test — 1.0.0 * Test case for optional array of referenced model types */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-referenced-types/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-referenced-types/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-referenced-types/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-referenced-types/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-referenced-types/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-referenced-types/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-referenced-types/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-optional-array-of-referenced-types/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-optional-inline-object/README.md.golden b/tests/golden/typescript/typescript-fetch/recursive-json-optional-inline-object/README.md.golden index 63b281dbf..3a4e60525 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-optional-inline-object/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-optional-inline-object/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'optional-inline-object-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'optional-inline-object-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-optional-inline-object/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-optional-inline-object/apis/DefaultApi.ts.golden index d96c295f9..d677dfd93 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-optional-inline-object/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-optional-inline-object/apis/DefaultApi.ts.golden @@ -4,22 +4,33 @@ * Optional Inline Object Test — 1.0.0 * Test case for optional inline objects */ -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; import { BaseAPI, DefaultConfig, ResponseError, VoidApiResponse } from '../runtime/runtime'; export type TestRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); - -export type TestErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestError extends ResponseError { readonly detail: TestErrorDetail; - constructor(response: Response, detail: TestErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } @@ -44,30 +55,39 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-optional-inline-object/package.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-optional-inline-object/package.json.golden index ff018be5c..9caa9b66b 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-optional-inline-object/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-optional-inline-object/package.json.golden @@ -1,26 +1,26 @@ { + "name": "optional-inline-object-test", + "version": "1.0.0", "description": "Test case for optional inline objects", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "optional-inline-object-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-optional-inline-object/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-optional-inline-object/runtime/runtime.ts.golden index 119ca19e2..2bfe220e1 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-optional-inline-object/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-optional-inline-object/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Optional Inline Object Test — 1.0.0 * Test case for optional inline objects */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-optional-inline-object/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-optional-inline-object/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-optional-inline-object/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-optional-inline-object/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-optional-inline-object/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-optional-inline-object/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-optional-inline-object/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-optional-inline-object/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-optional-nested-object-reference/README.md.golden b/tests/golden/typescript/typescript-fetch/recursive-json-optional-nested-object-reference/README.md.golden index b07baad73..2e6593d85 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-optional-nested-object-reference/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-optional-nested-object-reference/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'optional-nested-object-reference-test const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'optional-nested-object-reference-t const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-optional-nested-object-reference/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-optional-nested-object-reference/apis/DefaultApi.ts.golden index 99f80a761..1371362b8 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-optional-nested-object-reference/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-optional-nested-object-reference/apis/DefaultApi.ts.golden @@ -4,22 +4,33 @@ * Optional Nested Object Reference Test — 1.0.0 * Test case for optional nested object reference */ -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; import { BaseAPI, DefaultConfig, ResponseError, VoidApiResponse } from '../runtime/runtime'; export type TestRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); - -export type TestErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestError extends ResponseError { readonly detail: TestErrorDetail; - constructor(response: Response, detail: TestErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } @@ -44,30 +55,39 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-optional-nested-object-reference/package.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-optional-nested-object-reference/package.json.golden index 8a6bcb3db..f03f219cb 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-optional-nested-object-reference/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-optional-nested-object-reference/package.json.golden @@ -1,26 +1,26 @@ { + "name": "optional-nested-object-reference-test", + "version": "1.0.0", "description": "Test case for optional nested object reference", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "optional-nested-object-reference-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-optional-nested-object-reference/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-optional-nested-object-reference/runtime/runtime.ts.golden index 0a6f7e81e..9040f1bd1 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-optional-nested-object-reference/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-optional-nested-object-reference/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Optional Nested Object Reference Test — 1.0.0 * Test case for optional nested object reference */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-optional-nested-object-reference/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-optional-nested-object-reference/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-optional-nested-object-reference/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-optional-nested-object-reference/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-optional-nested-object-reference/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-optional-nested-object-reference/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-optional-nested-object-reference/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-optional-nested-object-reference/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-primitive-array/README.md.golden b/tests/golden/typescript/typescript-fetch/recursive-json-primitive-array/README.md.golden index 354ce8908..b5f46112b 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-primitive-array/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-primitive-array/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'primitive-array-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'primitive-array-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-primitive-array/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-primitive-array/apis/DefaultApi.ts.golden index da18f253e..a94143f07 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-primitive-array/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-primitive-array/apis/DefaultApi.ts.golden @@ -4,22 +4,33 @@ * Primitive Array Test — 1.0.0 * Test case for arrays with primitive items (should not be affected by recursive parsing) */ -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; import { BaseAPI, DefaultConfig, ResponseError, VoidApiResponse } from '../runtime/runtime'; export type TestRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); - -export type TestErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestError extends ResponseError { readonly detail: TestErrorDetail; - constructor(response: Response, detail: TestErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } @@ -44,30 +55,39 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-primitive-array/package.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-primitive-array/package.json.golden index 7448e18e7..72a7b3fc4 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-primitive-array/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-primitive-array/package.json.golden @@ -1,26 +1,26 @@ { + "name": "primitive-array-test", + "version": "1.0.0", "description": "Test case for arrays with primitive items (should not be affected by recursive parsing)", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "primitive-array-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-primitive-array/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-primitive-array/runtime/runtime.ts.golden index 8bbc3ad5a..43ca326df 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-primitive-array/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-primitive-array/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Primitive Array Test — 1.0.0 * Test case for arrays with primitive items (should not be affected by recursive parsing) */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-primitive-array/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-primitive-array/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-primitive-array/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-primitive-array/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-primitive-array/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-primitive-array/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-primitive-array/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-primitive-array/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-self-referential-object/README.md.golden b/tests/golden/typescript/typescript-fetch/recursive-json-self-referential-object/README.md.golden index 8e372bc03..1c1dc5461 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-self-referential-object/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-self-referential-object/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'self-referential-object-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'self-referential-object-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-self-referential-object/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-self-referential-object/apis/DefaultApi.ts.golden index 0e9dd7645..e3e54bfdb 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-self-referential-object/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-self-referential-object/apis/DefaultApi.ts.golden @@ -4,22 +4,33 @@ * Self-Referential Object Test — 1.0.0 */ import type { Foo } from '../models/Foo'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; import { BaseAPI, DefaultConfig, JSONApiResponse, ResponseError } from '../runtime/runtime'; export type GetFooRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); - -export type GetFooErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type GetFooErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class GetFooError extends ResponseError { readonly detail: GetFooErrorDetail; - constructor(response: Response, detail: GetFooErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: GetFooErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } @@ -44,36 +55,45 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new GetFooError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new GetFooError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } async getFoo(initOverrides?: RequestInit | InitOverrideFunction): Promise { const response = await this.getFooRaw(initOverrides); - return await response.value() as Foo; + return (await response.value()) as Foo; } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-self-referential-object/package.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-self-referential-object/package.json.golden index 163c0b2f3..7aab13df5 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-self-referential-object/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-self-referential-object/package.json.golden @@ -1,26 +1,26 @@ { + "name": "self-referential-object-test", + "version": "1.0.0", "description": "TypeScript client for Self-Referential Object Test", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "self-referential-object-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-self-referential-object/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/recursive-json-self-referential-object/runtime/runtime.ts.golden index 70e5b239b..e177a1562 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-self-referential-object/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-self-referential-object/runtime/runtime.ts.golden @@ -3,7 +3,7 @@ * * Self-Referential Object Test — 1.0.0 */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -13,7 +13,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -92,8 +95,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -135,12 +140,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -150,7 +161,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -166,9 +177,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -183,13 +192,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -199,7 +210,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -209,10 +220,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -221,18 +233,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -240,16 +256,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -268,11 +285,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -282,7 +299,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -292,7 +309,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -306,12 +323,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -329,15 +364,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -413,16 +461,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -449,7 +587,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -476,7 +617,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -486,5 +627,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-self-referential-object/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-self-referential-object/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-self-referential-object/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-self-referential-object/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/recursive-json-self-referential-object/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/recursive-json-self-referential-object/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/recursive-json-self-referential-object/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/recursive-json-self-referential-object/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/request-body-content-types/README.md.golden b/tests/golden/typescript/typescript-fetch/request-body-content-types/README.md.golden index 5786e6021..f1e2218e6 100644 --- a/tests/golden/typescript/typescript-fetch/request-body-content-types/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/request-body-content-types/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'request-body-content-types'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'request-body-content-types'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/request-body-content-types/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/request-body-content-types/apis/DefaultApi.ts.golden index f39e71748..53ff91953 100644 --- a/tests/golden/typescript/typescript-fetch/request-body-content-types/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/request-body-content-types/apis/DefaultApi.ts.golden @@ -5,8 +5,21 @@ * Covers non-JSON request body media types to pin Content-Type emission. */ import type { Payload } from '../models/Payload'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError, TextApiResponse, VoidApiResponse } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, + TextApiResponse, + VoidApiResponse, +} from '../runtime/runtime'; export interface ApiPostBinaryRequest { body: Blob | File; @@ -37,173 +50,250 @@ export interface ApiPostXmlRequest { } export type PostBinaryRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); export type PostFormRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); export type PostJsonRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); export type PostJsonOrXmlRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); export type PatchMergeJsonRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); export type PostTextRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); export type PostXmlRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); export type GetXmlResponseRawResponse = - | TextApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; + | (TextApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); - -export type PostBinaryErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type PostBinaryErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class PostBinaryError extends ResponseError { readonly detail: PostBinaryErrorDetail; - constructor(response: Response, detail: PostBinaryErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: PostBinaryErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type PostFormErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type PostFormErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class PostFormError extends ResponseError { readonly detail: PostFormErrorDetail; - constructor(response: Response, detail: PostFormErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: PostFormErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type PostJsonErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type PostJsonErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class PostJsonError extends ResponseError { readonly detail: PostJsonErrorDetail; - constructor(response: Response, detail: PostJsonErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: PostJsonErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type PostJsonOrXmlErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type PostJsonOrXmlErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class PostJsonOrXmlError extends ResponseError { readonly detail: PostJsonOrXmlErrorDetail; - constructor(response: Response, detail: PostJsonOrXmlErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: PostJsonOrXmlErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type PatchMergeJsonErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type PatchMergeJsonErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class PatchMergeJsonError extends ResponseError { readonly detail: PatchMergeJsonErrorDetail; - constructor(response: Response, detail: PatchMergeJsonErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: PatchMergeJsonErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type PostTextErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type PostTextErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class PostTextError extends ResponseError { readonly detail: PostTextErrorDetail; - constructor(response: Response, detail: PostTextErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: PostTextErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type PostXmlErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type PostXmlErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class PostXmlError extends ResponseError { readonly detail: PostXmlErrorDetail; - constructor(response: Response, detail: PostXmlErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: PostXmlErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type GetXmlResponseErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type GetXmlResponseErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class GetXmlResponseError extends ResponseError { readonly detail: GetXmlResponseErrorDetail; - constructor(response: Response, detail: GetXmlResponseErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: GetXmlResponseErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - postBinaryRaw: (requestParameters: ApiPostBinaryRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - postBinary: (requestParameters: ApiPostBinaryRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - postFormRaw: (requestParameters: ApiPostFormRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - postForm: (requestParameters: ApiPostFormRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - postJsonRaw: (requestParameters: ApiPostJsonRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - postJson: (requestParameters: ApiPostJsonRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - postJsonOrXmlRaw: (requestParameters: ApiPostJsonOrXmlRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - postJsonOrXml: (requestParameters: ApiPostJsonOrXmlRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - patchMergeJsonRaw: (requestParameters: ApiPatchMergeJsonRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - patchMergeJson: (requestParameters: ApiPatchMergeJsonRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - postTextRaw: (requestParameters: ApiPostTextRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - postText: (requestParameters: ApiPostTextRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - postXmlRaw: (requestParameters: ApiPostXmlRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - postXml: (requestParameters: ApiPostXmlRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - getXmlResponseRaw: (initOverrides?: RequestInit - | InitOverrideFunction) => Promise; + postBinaryRaw: ( + requestParameters: ApiPostBinaryRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + postBinary: ( + requestParameters: ApiPostBinaryRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + postFormRaw: ( + requestParameters: ApiPostFormRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + postForm: ( + requestParameters: ApiPostFormRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + postJsonRaw: ( + requestParameters: ApiPostJsonRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + postJson: ( + requestParameters: ApiPostJsonRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + postJsonOrXmlRaw: ( + requestParameters: ApiPostJsonOrXmlRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + postJsonOrXml: ( + requestParameters: ApiPostJsonOrXmlRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + patchMergeJsonRaw: ( + requestParameters: ApiPatchMergeJsonRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + patchMergeJson: ( + requestParameters: ApiPatchMergeJsonRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + postTextRaw: ( + requestParameters: ApiPostTextRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + postText: ( + requestParameters: ApiPostTextRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + postXmlRaw: ( + requestParameters: ApiPostXmlRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + postXml: ( + requestParameters: ApiPostXmlRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + getXmlResponseRaw: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; getXmlResponse: (initOverrides?: RequestInit | InitOverrideFunction) => Promise; } @@ -215,12 +305,14 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async postBinaryRaw(requestParameters: ApiPostBinaryRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async postBinaryRaw( + requestParameters: ApiPostBinaryRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling postBinaryRaw().' + 'Required parameter "body" was null or undefined when calling postBinaryRaw().', ); } // Build path with path parameters @@ -235,42 +327,56 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new PostBinaryError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new PostBinaryError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async postBinary(requestParameters: ApiPostBinaryRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async postBinary( + requestParameters: ApiPostBinaryRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.postBinaryRaw(requestParameters, initOverrides); return await response.value(); } - async postFormRaw(requestParameters: ApiPostFormRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async postFormRaw( + requestParameters: ApiPostFormRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling postFormRaw().' + 'Required parameter "body" was null or undefined when calling postFormRaw().', ); } // Build path with path parameters @@ -285,42 +391,56 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = (() => {throw new Error('unsupported request body media type: application/x-www-form-urlencoded');})(); // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new PostFormError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new PostFormError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async postForm(requestParameters: ApiPostFormRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async postForm( + requestParameters: ApiPostFormRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.postFormRaw(requestParameters, initOverrides); return await response.value(); } - async postJsonRaw(requestParameters: ApiPostJsonRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async postJsonRaw( + requestParameters: ApiPostJsonRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling postJsonRaw().' + 'Required parameter "body" was null or undefined when calling postJsonRaw().', ); } // Build path with path parameters @@ -335,42 +455,56 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new PostJsonError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new PostJsonError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async postJson(requestParameters: ApiPostJsonRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async postJson( + requestParameters: ApiPostJsonRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.postJsonRaw(requestParameters, initOverrides); return await response.value(); } - async postJsonOrXmlRaw(requestParameters: ApiPostJsonOrXmlRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async postJsonOrXmlRaw( + requestParameters: ApiPostJsonOrXmlRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling postJsonOrXmlRaw().' + 'Required parameter "body" was null or undefined when calling postJsonOrXmlRaw().', ); } // Build path with path parameters @@ -385,42 +519,56 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new PostJsonOrXmlError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new PostJsonOrXmlError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async postJsonOrXml(requestParameters: ApiPostJsonOrXmlRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async postJsonOrXml( + requestParameters: ApiPostJsonOrXmlRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.postJsonOrXmlRaw(requestParameters, initOverrides); return await response.value(); } - async patchMergeJsonRaw(requestParameters: ApiPatchMergeJsonRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async patchMergeJsonRaw( + requestParameters: ApiPatchMergeJsonRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling patchMergeJsonRaw().' + 'Required parameter "body" was null or undefined when calling patchMergeJsonRaw().', ); } // Build path with path parameters @@ -435,42 +583,56 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'PATCH', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new PatchMergeJsonError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new PatchMergeJsonError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async patchMergeJson(requestParameters: ApiPatchMergeJsonRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async patchMergeJson( + requestParameters: ApiPatchMergeJsonRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.patchMergeJsonRaw(requestParameters, initOverrides); return await response.value(); } - async postTextRaw(requestParameters: ApiPostTextRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async postTextRaw( + requestParameters: ApiPostTextRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling postTextRaw().' + 'Required parameter "body" was null or undefined when calling postTextRaw().', ); } // Build path with path parameters @@ -485,42 +647,56 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new PostTextError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new PostTextError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async postText(requestParameters: ApiPostTextRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async postText( + requestParameters: ApiPostTextRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.postTextRaw(requestParameters, initOverrides); return await response.value(); } - async postXmlRaw(requestParameters: ApiPostXmlRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async postXmlRaw( + requestParameters: ApiPostXmlRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling postXmlRaw().' + 'Required parameter "body" was null or undefined when calling postXmlRaw().', ); } // Build path with path parameters @@ -535,73 +711,95 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = (() => {throw new Error('unsupported request body media type: application/xml');})(); // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new PostXmlError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new PostXmlError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async postXml(requestParameters: ApiPostXmlRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async postXml( + requestParameters: ApiPostXmlRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.postXmlRaw(requestParameters, initOverrides); return await response.value(); } - async getXmlResponseRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getXmlResponseRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/xml-response`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new GetXmlResponseError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new GetXmlResponseError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new TextApiResponse(response) as TextApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } async getXmlResponse(initOverrides?: RequestInit | InitOverrideFunction): Promise { const response = await this.getXmlResponseRaw(initOverrides); - return await response.value() as string; + return (await response.value()) as string; } } diff --git a/tests/golden/typescript/typescript-fetch/request-body-content-types/package.json.golden b/tests/golden/typescript/typescript-fetch/request-body-content-types/package.json.golden index a51acbda3..c471342c0 100644 --- a/tests/golden/typescript/typescript-fetch/request-body-content-types/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/request-body-content-types/package.json.golden @@ -1,26 +1,26 @@ { + "name": "request-body-content-types", + "version": "1.0.0", "description": "Covers non-JSON request body media types to pin Content-Type emission.", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "request-body-content-types", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/request-body-content-types/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/request-body-content-types/runtime/runtime.ts.golden index 29af9f560..bedc8e703 100644 --- a/tests/golden/typescript/typescript-fetch/request-body-content-types/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/request-body-content-types/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Request Body Content Types — 1.0.0 * Covers non-JSON request body media types to pin Content-Type emission. */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/request-body-content-types/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/request-body-content-types/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/request-body-content-types/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/request-body-content-types/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/request-body-content-types/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/request-body-content-types/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/request-body-content-types/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/request-body-content-types/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/response-body-default-and-exact/README.md.golden b/tests/golden/typescript/typescript-fetch/response-body-default-and-exact/README.md.golden index 3db049943..60d414a12 100644 --- a/tests/golden/typescript/typescript-fetch/response-body-default-and-exact/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/response-body-default-and-exact/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, WidgetApi } from 'default-and-exact-response-api'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'default-and-exact-response-api'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/response-body-default-and-exact/apis/WidgetApi.ts.golden b/tests/golden/typescript/typescript-fetch/response-body-default-and-exact/apis/WidgetApi.ts.golden index aee0dcc8d..fe3029ad8 100644 --- a/tests/golden/typescript/typescript-fetch/response-body-default-and-exact/apis/WidgetApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/response-body-default-and-exact/apis/WidgetApi.ts.golden @@ -5,31 +5,49 @@ */ import type { ErrorResponse } from '../models/ErrorResponse'; import type { Widget } from '../models/Widget'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; import { BaseAPI, DefaultConfig, JSONApiResponse, ResponseError } from '../runtime/runtime'; export type GetWidgetRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type GetWidgetErrorDetail = - { kind: 'default'; status: number; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'default'; + status: number; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class GetWidgetError extends ResponseError { readonly detail: GetWidgetErrorDetail; - constructor(response: Response, detail: GetWidgetErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: GetWidgetErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface WidgetApiInterface { - getWidgetRaw: (initOverrides?: RequestInit - | InitOverrideFunction) => Promise; + getWidgetRaw: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; getWidget: (initOverrides?: RequestInit | InitOverrideFunction) => Promise; } @@ -41,43 +59,53 @@ export class WidgetApi extends BaseAPI implements WidgetApiInterface { super(configuration ?? DefaultConfig); } - async getWidgetRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getWidgetRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/widgets`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new GetWidgetError(response, { kind: 'default', status: response.status, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone()).value() }); + throw new GetWidgetError(response, { + kind: 'default', + status: response.status, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } async getWidget(initOverrides?: RequestInit | InitOverrideFunction): Promise { const response = await this.getWidgetRaw(initOverrides); - return await response.value() as Widget; + return (await response.value()) as Widget; } } diff --git a/tests/golden/typescript/typescript-fetch/response-body-default-and-exact/package.json.golden b/tests/golden/typescript/typescript-fetch/response-body-default-and-exact/package.json.golden index ef7ffeca9..b7ec67d72 100644 --- a/tests/golden/typescript/typescript-fetch/response-body-default-and-exact/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/response-body-default-and-exact/package.json.golden @@ -1,26 +1,26 @@ { + "name": "default-and-exact-response-api", + "version": "1.0.0", "description": "TypeScript client for Default And Exact Response API", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "default-and-exact-response-api", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/response-body-default-and-exact/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/response-body-default-and-exact/runtime/runtime.ts.golden index 44ca8be87..55dfe1d7c 100644 --- a/tests/golden/typescript/typescript-fetch/response-body-default-and-exact/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/response-body-default-and-exact/runtime/runtime.ts.golden @@ -3,7 +3,7 @@ * * Default And Exact Response API — 1.0.0 */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -13,7 +13,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -92,8 +95,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -135,12 +140,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -150,7 +161,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -166,9 +177,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -183,13 +192,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -199,7 +210,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -209,10 +220,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -221,18 +233,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -240,16 +256,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -268,11 +285,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -282,7 +299,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -292,7 +309,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -306,12 +323,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -329,15 +364,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -413,16 +461,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -449,7 +587,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -476,7 +617,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -486,5 +627,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/response-body-default-and-exact/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/response-body-default-and-exact/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/response-body-default-and-exact/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/response-body-default-and-exact/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/response-body-default-and-exact/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/response-body-default-and-exact/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/response-body-default-and-exact/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/response-body-default-and-exact/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/response-body-fallback/README.md.golden b/tests/golden/typescript/typescript-fetch/response-body-fallback/README.md.golden index 4767d92ca..0f427b40f 100644 --- a/tests/golden/typescript/typescript-fetch/response-body-fallback/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/response-body-fallback/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'response-fallback-test-api'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'response-fallback-test-api'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/response-body-fallback/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/response-body-fallback/apis/DefaultApi.ts.golden index 391b7ee2d..59cf74385 100644 --- a/tests/golden/typescript/typescript-fetch/response-body-fallback/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/response-body-fallback/apis/DefaultApi.ts.golden @@ -4,54 +4,92 @@ * Response Fallback Test API — 1.0.0 */ import type { GetFallbackWithBodyResponse200 } from '../models/GetFallbackWithBodyResponse200'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, ResponseError, VoidApiResponse } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + ResponseError, + VoidApiResponse, +} from '../runtime/runtime'; export type GetFallbackNoBodyRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); export type GetFallbackWithBodyRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type GetFallbackNoBodyErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class GetFallbackNoBodyError extends ResponseError { readonly detail: GetFallbackNoBodyErrorDetail; - constructor(response: Response, detail: GetFallbackNoBodyErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: GetFallbackNoBodyErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type GetFallbackWithBodyErrorDetail = - { kind: 'notFound'; status: 404; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'notFound'; + status: 404; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class GetFallbackWithBodyError extends ResponseError { readonly detail: GetFallbackWithBodyErrorDetail; - constructor(response: Response, detail: GetFallbackWithBodyErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: GetFallbackWithBodyErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - getFallbackNoBodyRaw: (initOverrides?: RequestInit - | InitOverrideFunction) => Promise; + getFallbackNoBodyRaw: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; getFallbackNoBody: (initOverrides?: RequestInit | InitOverrideFunction) => Promise; - getFallbackWithBodyRaw: (initOverrides?: RequestInit - | InitOverrideFunction) => Promise; - getFallbackWithBody: (initOverrides?: RequestInit - | InitOverrideFunction) => Promise; + getFallbackWithBodyRaw: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + getFallbackWithBody: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class DefaultApi extends BaseAPI implements DefaultApiInterface { @@ -62,41 +100,58 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async getFallbackNoBodyRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getFallbackNoBodyRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/fallback/no-body`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new GetFallbackNoBodyError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new GetFallbackNoBodyError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new GetFallbackNoBodyError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new GetFallbackNoBodyError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } @@ -106,48 +161,68 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { return await response.value(); } - async getFallbackWithBodyRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getFallbackWithBodyRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/fallback/with-body`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 404) { let errorValue: Promise | undefined; - throw new GetFallbackWithBodyError(response, { kind: 'notFound', status: response.status as 404, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new GetFallbackWithBodyError(response, { + kind: 'notFound', + status: response.status as 404, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new GetFallbackWithBodyError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new GetFallbackWithBodyError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response) as JSONApiResponse & { + status: 200; + }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async getFallbackWithBody(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getFallbackWithBody( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.getFallbackWithBodyRaw(initOverrides); - return await response.value() as GetFallbackWithBodyResponse200; + return (await response.value()) as GetFallbackWithBodyResponse200; } } diff --git a/tests/golden/typescript/typescript-fetch/response-body-fallback/package.json.golden b/tests/golden/typescript/typescript-fetch/response-body-fallback/package.json.golden index 23fa6453a..c2af34178 100644 --- a/tests/golden/typescript/typescript-fetch/response-body-fallback/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/response-body-fallback/package.json.golden @@ -1,26 +1,26 @@ { + "name": "response-fallback-test-api", + "version": "1.0.0", "description": "TypeScript client for Response Fallback Test API", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "response-fallback-test-api", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/response-body-fallback/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/response-body-fallback/runtime/runtime.ts.golden index 4fbef3372..6a310eed8 100644 --- a/tests/golden/typescript/typescript-fetch/response-body-fallback/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/response-body-fallback/runtime/runtime.ts.golden @@ -3,7 +3,7 @@ * * Response Fallback Test API — 1.0.0 */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -13,7 +13,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -92,8 +95,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -135,12 +140,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -150,7 +161,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -166,9 +177,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -183,13 +192,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -199,7 +210,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -209,10 +220,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -221,18 +233,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -240,16 +256,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -268,11 +285,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -282,7 +299,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -292,7 +309,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -306,12 +323,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -329,15 +364,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -413,16 +461,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -449,7 +587,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -476,7 +617,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -486,5 +627,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/response-body-fallback/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/response-body-fallback/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/response-body-fallback/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/response-body-fallback/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/response-body-fallback/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/response-body-fallback/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/response-body-fallback/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/response-body-fallback/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/response-body-multi-status-responses/README.md.golden b/tests/golden/typescript/typescript-fetch/response-body-multi-status-responses/README.md.golden index 0cc0263f4..4df1e35af 100644 --- a/tests/golden/typescript/typescript-fetch/response-body-multi-status-responses/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/response-body-multi-status-responses/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, WidgetApi } from 'multi-status-api'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'multi-status-api'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/response-body-multi-status-responses/apis/WidgetApi.ts.golden b/tests/golden/typescript/typescript-fetch/response-body-multi-status-responses/apis/WidgetApi.ts.golden index 7088f68db..0971cb622 100644 --- a/tests/golden/typescript/typescript-fetch/response-body-multi-status-responses/apis/WidgetApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/response-body-multi-status-responses/apis/WidgetApi.ts.golden @@ -6,34 +6,53 @@ import type { ErrorResponse } from '../models/ErrorResponse'; import type { Widget } from '../models/Widget'; import type { WidgetListPartial } from '../models/WidgetListPartial'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; import { BaseAPI, DefaultConfig, JSONApiResponse, ResponseError } from '../runtime/runtime'; export type ListWidgetsRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & { status: 206 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & { status: 206 }) + | (JSONApiResponse & HttpSuccessResponse); export type ListWidgetsErrorDetail = - { kind: 'notFound'; status: 404; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'notFound'; + status: 404; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class ListWidgetsError extends ResponseError { readonly detail: ListWidgetsErrorDetail; - constructor(response: Response, detail: ListWidgetsErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: ListWidgetsErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface WidgetApiInterface { - listWidgetsRaw: (initOverrides?: RequestInit - | InitOverrideFunction) => Promise; - listWidgets: (initOverrides?: RequestInit | InitOverrideFunction) => Promise; + listWidgetsRaw: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + listWidgets: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class WidgetApi extends BaseAPI implements WidgetApiInterface { @@ -44,51 +63,68 @@ export class WidgetApi extends BaseAPI implements WidgetApiInterface { super(configuration ?? DefaultConfig); } - async listWidgetsRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async listWidgetsRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/widgets`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 404) { let errorValue: Promise | undefined; - throw new ListWidgetsError(response, { kind: 'notFound', status: response.status as 404, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone()).value() }); - } - else { + throw new ListWidgetsError(response, { + kind: 'notFound', + status: response.status as 404, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new ListWidgetsError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new ListWidgetsError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else if (response.status === 206) { + } else if (response.status === 206) { return new JSONApiResponse(response) as JSONApiResponse & { status: 206 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async listWidgets(initOverrides?: RequestInit | InitOverrideFunction): Promise { + async listWidgets( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.listWidgetsRaw(initOverrides); - return await response.value() as Widget[] | WidgetListPartial; + return (await response.value()) as Widget[] | WidgetListPartial; } } diff --git a/tests/golden/typescript/typescript-fetch/response-body-multi-status-responses/package.json.golden b/tests/golden/typescript/typescript-fetch/response-body-multi-status-responses/package.json.golden index 44a6d30c5..cca0ce2ac 100644 --- a/tests/golden/typescript/typescript-fetch/response-body-multi-status-responses/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/response-body-multi-status-responses/package.json.golden @@ -1,26 +1,26 @@ { + "name": "multi-status-api", + "version": "1.0.0", "description": "TypeScript client for Multi Status API", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "multi-status-api", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/response-body-multi-status-responses/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/response-body-multi-status-responses/runtime/runtime.ts.golden index 9c889c6b2..26bffb6ac 100644 --- a/tests/golden/typescript/typescript-fetch/response-body-multi-status-responses/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/response-body-multi-status-responses/runtime/runtime.ts.golden @@ -3,7 +3,7 @@ * * Multi Status API — 1.0.0 */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -13,7 +13,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -92,8 +95,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -135,12 +140,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -150,7 +161,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -166,9 +177,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -183,13 +192,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -199,7 +210,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -209,10 +220,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -221,18 +233,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -240,16 +256,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -268,11 +285,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -282,7 +299,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -292,7 +309,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -306,12 +323,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -329,15 +364,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -413,16 +461,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -449,7 +587,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -476,7 +617,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -486,5 +627,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/response-body-multi-status-responses/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/response-body-multi-status-responses/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/response-body-multi-status-responses/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/response-body-multi-status-responses/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/response-body-multi-status-responses/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/response-body-multi-status-responses/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/response-body-multi-status-responses/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/response-body-multi-status-responses/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/response-body-no-response-body/README.md.golden b/tests/golden/typescript/typescript-fetch/response-body-no-response-body/README.md.golden index 45667a1e4..9b2049eaa 100644 --- a/tests/golden/typescript/typescript-fetch/response-body-no-response-body/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/response-body-no-response-body/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, FooApi } from 'no-response-body-api'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'no-response-body-api'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/response-body-no-response-body/apis/FooApi.ts.golden b/tests/golden/typescript/typescript-fetch/response-body-no-response-body/apis/FooApi.ts.golden index 53947aad5..495087267 100644 --- a/tests/golden/typescript/typescript-fetch/response-body-no-response-body/apis/FooApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/response-body-no-response-body/apis/FooApi.ts.golden @@ -5,8 +5,20 @@ */ import type { ErrorResponse } from '../models/ErrorResponse'; import type { FooRequest } from '../models/FooRequest'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError, VoidApiResponse } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, + VoidApiResponse, +} from '../runtime/runtime'; export interface ApiUpdateFooBarRequest { fooId: string; @@ -14,30 +26,51 @@ export interface ApiUpdateFooBarRequest { } export type UpdateFooBarRawResponse = - | VoidApiResponse & { status: 204 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 204 }) + | (VoidApiResponse & HttpSuccessResponse); export type UpdateFooBarErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'internalServerError'; status: 500; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'internalServerError'; + status: 500; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class UpdateFooBarError extends ResponseError { readonly detail: UpdateFooBarErrorDetail; - constructor(response: Response, detail: UpdateFooBarErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: UpdateFooBarErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface FooApiInterface { - updateFooBarRaw: (requestParameters: ApiUpdateFooBarRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - updateFooBar: (requestParameters: ApiUpdateFooBarRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + updateFooBarRaw: ( + requestParameters: ApiUpdateFooBarRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + updateFooBar: ( + requestParameters: ApiUpdateFooBarRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class FooApi extends BaseAPI implements FooApiInterface { @@ -48,18 +81,20 @@ export class FooApi extends BaseAPI implements FooApiInterface { super(configuration ?? DefaultConfig); } - async updateFooBarRaw(requestParameters: ApiUpdateFooBarRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async updateFooBarRaw( + requestParameters: ApiUpdateFooBarRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.fooId === undefined || requestParameters.fooId === null) { throw new RequiredError( 'fooId', - 'Required parameter "fooId" was null or undefined when calling updateFooBarRaw().' + 'Required parameter "fooId" was null or undefined when calling updateFooBarRaw().', ); } if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling updateFooBarRaw().' + 'Required parameter "body" was null or undefined when calling updateFooBarRaw().', ); } // Build path with path parameters @@ -75,40 +110,66 @@ export class FooApi extends BaseAPI implements FooApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'PATCH', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new UpdateFooBarError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 500) { + throw new UpdateFooBarError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 500) { let errorValue: Promise | undefined; - throw new UpdateFooBarError(response, { kind: 'internalServerError', status: response.status as 500, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone()).value() }); - } - else { + throw new UpdateFooBarError(response, { + kind: 'internalServerError', + status: response.status as 500, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new UpdateFooBarError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new UpdateFooBarError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 204) { return new VoidApiResponse(response) as VoidApiResponse & { status: 204 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async updateFooBar(requestParameters: ApiUpdateFooBarRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async updateFooBar( + requestParameters: ApiUpdateFooBarRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.updateFooBarRaw(requestParameters, initOverrides); return await response.value(); } diff --git a/tests/golden/typescript/typescript-fetch/response-body-no-response-body/package.json.golden b/tests/golden/typescript/typescript-fetch/response-body-no-response-body/package.json.golden index 48c40691a..613037a96 100644 --- a/tests/golden/typescript/typescript-fetch/response-body-no-response-body/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/response-body-no-response-body/package.json.golden @@ -1,26 +1,26 @@ { + "name": "no-response-body-api", + "version": "1.0.0", "description": "TypeScript client for No Response Body API", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "no-response-body-api", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/response-body-no-response-body/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/response-body-no-response-body/runtime/runtime.ts.golden index 1f0f8fd63..37edf98c5 100644 --- a/tests/golden/typescript/typescript-fetch/response-body-no-response-body/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/response-body-no-response-body/runtime/runtime.ts.golden @@ -3,7 +3,7 @@ * * No Response Body API — 1.0.0 */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -13,7 +13,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -92,8 +95,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -135,12 +140,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -150,7 +161,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -166,9 +177,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -183,13 +192,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -199,7 +210,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -209,10 +220,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -221,18 +233,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -240,16 +256,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -268,11 +285,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -282,7 +299,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -292,7 +309,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -306,12 +323,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -329,15 +364,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -413,16 +461,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -449,7 +587,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -476,7 +617,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -486,5 +627,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/response-body-no-response-body/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/response-body-no-response-body/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/response-body-no-response-body/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/response-body-no-response-body/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/response-body-no-response-body/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/response-body-no-response-body/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/response-body-no-response-body/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/response-body-no-response-body/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/response-dispatch/README.md.golden b/tests/golden/typescript/typescript-fetch/response-dispatch/README.md.golden index 3e33d7b90..4c7c1e7fc 100644 --- a/tests/golden/typescript/typescript-fetch/response-dispatch/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/response-dispatch/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, ResponsesApi } from 'type-script-response-dispatch'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'type-script-response-dispatch'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/response-dispatch/apis/ResponsesApi.ts.golden b/tests/golden/typescript/typescript-fetch/response-dispatch/apis/ResponsesApi.ts.golden index 88a2dda77..0f34afe58 100644 --- a/tests/golden/typescript/typescript-fetch/response-dispatch/apis/ResponsesApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/response-dispatch/apis/ResponsesApi.ts.golden @@ -4,124 +4,230 @@ * TypeScript Response Dispatch — 1.0.0 */ import type { Detail } from '../models/Detail'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, BlobApiResponse, DefaultConfig, JSONApiResponse, ResponseError, TextApiResponse, VoidApiResponse } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + BlobApiResponse, + DefaultConfig, + JSONApiResponse, + ResponseError, + TextApiResponse, + VoidApiResponse, +} from '../runtime/runtime'; export type ReadDefaultRawResponse = VoidApiResponse & HttpSuccessResponse; - export type ReadErrorOnlyRawResponse = VoidApiResponse & HttpSuccessResponse; - export type ReadMixedRawResponse = - | JSONApiResponse & { status: 201 } - | TextApiResponse & { status: 202 } - | VoidApiResponse & { status: 204 } - | BlobApiResponse & { status: 206 } - | JSONApiResponse & { status: number } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 201 }) + | (TextApiResponse & { status: 202 }) + | (VoidApiResponse & { status: 204 }) + | (BlobApiResponse & { status: 206 }) + | (JSONApiResponse & { status: number }) + | (JSONApiResponse & HttpSuccessResponse); export type ReadSuccessOnlyRawResponse = - | VoidApiResponse & { status: 204 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 204 }) + | (VoidApiResponse & HttpSuccessResponse); export type ReadWildcardsRawResponse = - | VoidApiResponse & { status: number } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: number }) + | (VoidApiResponse & HttpSuccessResponse); export type ReadDefaultErrorDetail = - { kind: 'default'; status: number; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'default'; + status: number; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class ReadDefaultError extends ResponseError { readonly detail: ReadDefaultErrorDetail; - constructor(response: Response, detail: ReadDefaultErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: ReadDefaultErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type ReadErrorOnlyErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class ReadErrorOnlyError extends ResponseError { readonly detail: ReadErrorOnlyErrorDetail; - constructor(response: Response, detail: ReadErrorOnlyErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: ReadErrorOnlyErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type ReadMixedErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unauthorized'; status: 401; raw: Response; value(): Promise } - | { kind: 'conflict'; status: 409; raw: Response; value(): Promise } - | { kind: 'status410'; status: 410; raw: Response; value(): Promise } - | { kind: 'status415'; status: 415; raw: Response; value(): Promise } - | { kind: 'serverError'; status: number; raw: Response; value(): Promise } - | { kind: 'default'; status: number; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unauthorized'; + status: 401; + raw: Response; + value(): Promise; + } + | { + kind: 'conflict'; + status: 409; + raw: Response; + value(): Promise; + } + | { + kind: 'status410'; + status: 410; + raw: Response; + value(): Promise; + } + | { + kind: 'status415'; + status: 415; + raw: Response; + value(): Promise; + } + | { + kind: 'serverError'; + status: number; + raw: Response; + value(): Promise; + } + | { + kind: 'default'; + status: number; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class ReadMixedError extends ResponseError { readonly detail: ReadMixedErrorDetail; - constructor(response: Response, detail: ReadMixedErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: ReadMixedErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type ReadSuccessOnlyErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type ReadSuccessOnlyErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class ReadSuccessOnlyError extends ResponseError { readonly detail: ReadSuccessOnlyErrorDetail; - constructor(response: Response, detail: ReadSuccessOnlyErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: ReadSuccessOnlyErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type ReadWildcardsErrorDetail = - { kind: 'clientError'; status: number; raw: Response; value(): Promise } - | { kind: 'serverError'; status: number; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'clientError'; + status: number; + raw: Response; + value(): Promise; + } + | { + kind: 'serverError'; + status: number; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class ReadWildcardsError extends ResponseError { readonly detail: ReadWildcardsErrorDetail; - constructor(response: Response, detail: ReadWildcardsErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: ReadWildcardsErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface ResponsesApiInterface { - readDefaultRaw: (initOverrides?: RequestInit - | InitOverrideFunction) => Promise; + readDefaultRaw: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; readDefault: (initOverrides?: RequestInit | InitOverrideFunction) => Promise; - readErrorOnlyRaw: (initOverrides?: RequestInit - | InitOverrideFunction) => Promise; + readErrorOnlyRaw: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; readErrorOnly: (initOverrides?: RequestInit | InitOverrideFunction) => Promise; - readMixedRaw: (initOverrides?: RequestInit - | InitOverrideFunction) => Promise; - readMixed: (initOverrides?: RequestInit | InitOverrideFunction) => Promise; - readSuccessOnlyRaw: (initOverrides?: RequestInit - | InitOverrideFunction) => Promise; + readMixedRaw: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + readMixed: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + readSuccessOnlyRaw: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; readSuccessOnly: (initOverrides?: RequestInit | InitOverrideFunction) => Promise; - readWildcardsRaw: (initOverrides?: RequestInit - | InitOverrideFunction) => Promise; + readWildcardsRaw: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; readWildcards: (initOverrides?: RequestInit | InitOverrideFunction) => Promise; } @@ -133,31 +239,42 @@ export class ResponsesApi extends BaseAPI implements ResponsesApiInterface { super(configuration ?? DefaultConfig); } - async readDefaultRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async readDefaultRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/default`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new ReadDefaultError(response, { kind: 'default', status: response.status, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone()).value() }); + throw new ReadDefaultError(response, { + kind: 'default', + status: response.status, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); } } return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; @@ -168,35 +285,53 @@ export class ResponsesApi extends BaseAPI implements ResponsesApiInterface { return await response.value(); } - async readErrorOnlyRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async readErrorOnlyRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/error`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new ReadErrorOnlyError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new TextApiResponse(errorRaw.clone()).value() }); - } - else { + throw new ReadErrorOnlyError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new TextApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new ReadErrorOnlyError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new ReadErrorOnlyError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; @@ -207,116 +342,173 @@ export class ResponsesApi extends BaseAPI implements ResponsesApiInterface { return await response.value(); } - async readMixedRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async readMixedRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/mixed`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new ReadMixedError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 401) { + throw new ReadMixedError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 401) { let errorValue: Promise | undefined; - throw new ReadMixedError(response, { kind: 'unauthorized', status: response.status as 401, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 409) { + throw new ReadMixedError(response, { + kind: 'unauthorized', + status: response.status as 401, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 409) { let errorValue: Promise | undefined; - throw new ReadMixedError(response, { kind: 'conflict', status: response.status as 409, raw: response, value: () => errorValue ??= new TextApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 410) { + throw new ReadMixedError(response, { + kind: 'conflict', + status: response.status as 409, + raw: response, + value: () => { + errorValue ??= new TextApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 410) { let errorValue: Promise | undefined; - throw new ReadMixedError(response, { kind: 'status410', status: response.status as 410, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 415) { + throw new ReadMixedError(response, { + kind: 'status410', + status: response.status as 410, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 415) { let errorValue: Promise | undefined; - throw new ReadMixedError(response, { kind: 'status415', status: response.status as 415, raw: response, value: () => errorValue ??= new BlobApiResponse(errorRaw.clone()).value() }); - } - else if (response.status >= 500 && response.status < 600) { + throw new ReadMixedError(response, { + kind: 'status415', + status: response.status as 415, + raw: response, + value: () => { + errorValue ??= new BlobApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status >= 500 && response.status < 600) { let errorValue: Promise | undefined; - throw new ReadMixedError(response, { kind: 'serverError', status: response.status, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone()).value() }); - } - else { + throw new ReadMixedError(response, { + kind: 'serverError', + status: response.status, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new ReadMixedError(response, { kind: 'default', status: response.status, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone()).value() }); + throw new ReadMixedError(response, { + kind: 'default', + status: response.status, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); } } if (response.status === 201) { return new JSONApiResponse(response) as JSONApiResponse & { status: 201 }; - } - else if (response.status === 202) { + } else if (response.status === 202) { return new TextApiResponse(response) as TextApiResponse & { status: 202 }; - } - else if (response.status === 204) { + } else if (response.status === 204) { return new VoidApiResponse(response) as VoidApiResponse & { status: 204 }; - } - else if (response.status === 206) { + } else if (response.status === 206) { return new BlobApiResponse(response) as BlobApiResponse & { status: 206 }; - } - else if (response.status >= 200 && response.status < 300) { + } else if (response.status >= 200 && response.status < 300) { return new JSONApiResponse(response) as JSONApiResponse & { status: number }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async readMixed(initOverrides?: RequestInit | InitOverrideFunction): Promise { + async readMixed( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.readMixedRaw(initOverrides); - return await response.value() as Detail | string | Blob | Detail[]; + return (await response.value()) as Detail | string | Blob | Detail[]; } - async readSuccessOnlyRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async readSuccessOnlyRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/success`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new ReadSuccessOnlyError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new ReadSuccessOnlyError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 204) { return new VoidApiResponse(response) as VoidApiResponse & { status: 204 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } @@ -326,45 +518,69 @@ export class ResponsesApi extends BaseAPI implements ResponsesApiInterface { return await response.value(); } - async readWildcardsRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async readWildcardsRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/wildcards`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status >= 400 && response.status < 500) { let errorValue: Promise | undefined; - throw new ReadWildcardsError(response, { kind: 'clientError', status: response.status, raw: response, value: () => errorValue ??= new TextApiResponse(errorRaw.clone()).value() }); - } - else if (response.status >= 500 && response.status < 600) { + throw new ReadWildcardsError(response, { + kind: 'clientError', + status: response.status, + raw: response, + value: () => { + errorValue ??= new TextApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status >= 500 && response.status < 600) { let errorValue: Promise | undefined; - throw new ReadWildcardsError(response, { kind: 'serverError', status: response.status, raw: response, value: () => errorValue ??= new BlobApiResponse(errorRaw.clone()).value() }); - } - else { + throw new ReadWildcardsError(response, { + kind: 'serverError', + status: response.status, + raw: response, + value: () => { + errorValue ??= new BlobApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new ReadWildcardsError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new ReadWildcardsError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status >= 200 && response.status < 300) { return new VoidApiResponse(response) as VoidApiResponse & { status: number }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } diff --git a/tests/golden/typescript/typescript-fetch/response-dispatch/package.json.golden b/tests/golden/typescript/typescript-fetch/response-dispatch/package.json.golden index 59d6da387..1e410ab14 100644 --- a/tests/golden/typescript/typescript-fetch/response-dispatch/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/response-dispatch/package.json.golden @@ -1,26 +1,26 @@ { + "name": "type-script-response-dispatch", + "version": "1.0.0", "description": "TypeScript client for TypeScript Response Dispatch", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "type-script-response-dispatch", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/response-dispatch/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/response-dispatch/runtime/runtime.ts.golden index 62758288d..e148a93c5 100644 --- a/tests/golden/typescript/typescript-fetch/response-dispatch/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/response-dispatch/runtime/runtime.ts.golden @@ -3,7 +3,7 @@ * * TypeScript Response Dispatch — 1.0.0 */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -13,7 +13,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -92,8 +95,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -135,12 +140,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -150,7 +161,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -166,9 +177,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -183,13 +192,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -199,7 +210,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -209,10 +220,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -221,18 +233,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -240,16 +256,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -268,11 +285,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -282,7 +299,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -292,7 +309,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -306,12 +323,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -329,15 +364,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -413,16 +461,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -449,7 +587,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -476,7 +617,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -486,5 +627,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/response-dispatch/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/response-dispatch/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/response-dispatch/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/response-dispatch/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/response-dispatch/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/response-dispatch/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/response-dispatch/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/response-dispatch/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/server-object/README.md.golden b/tests/golden/typescript/typescript-fetch/server-object/README.md.golden index ec238c1f8..af01407f4 100644 --- a/tests/golden/typescript/typescript-fetch/server-object/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/server-object/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'test-api-with-server-objects'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'test-api-with-server-objects'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/server-object/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/server-object/apis/DefaultApi.ts.golden index 1a12ffbe7..2b5292135 100644 --- a/tests/golden/typescript/typescript-fetch/server-object/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/server-object/apis/DefaultApi.ts.golden @@ -7,8 +7,19 @@ import type { GetAllUsersResponse200Item } from '../models/GetAllUsersResponse200Item'; import type { GetUserByIdResponse200 } from '../models/GetUserByIdResponse200'; import type { GetUserByIdResponse404 } from '../models/GetUserByIdResponse404'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, +} from '../runtime/runtime'; export interface ApiGetUserByIdRequest { /** @@ -18,50 +29,74 @@ export interface ApiGetUserByIdRequest { } export type GetAllUsersRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type GetUserByIdRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); -export type GetAllUsersErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type GetAllUsersErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class GetAllUsersError extends ResponseError { readonly detail: GetAllUsersErrorDetail; - constructor(response: Response, detail: GetAllUsersErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: GetAllUsersErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type GetUserByIdErrorDetail = - { kind: 'notFound'; status: 404; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'notFound'; + status: 404; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class GetUserByIdError extends ResponseError { readonly detail: GetUserByIdErrorDetail; - constructor(response: Response, detail: GetUserByIdErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: GetUserByIdErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - getAllUsersRaw: (initOverrides?: RequestInit - | InitOverrideFunction) => Promise; - getAllUsers: (initOverrides?: RequestInit - | InitOverrideFunction) => Promise; - getUserByIdRaw: (requestParameters: ApiGetUserByIdRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - getUserById: (requestParameters: ApiGetUserByIdRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + getAllUsersRaw: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + getAllUsers: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + getUserByIdRaw: ( + requestParameters: ApiGetUserByIdRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + getUserById: ( + requestParameters: ApiGetUserByIdRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class DefaultApi extends BaseAPI implements DefaultApiInterface { @@ -72,53 +107,68 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async getAllUsersRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getAllUsersRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/users`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new GetAllUsersError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new GetAllUsersError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response) as JSONApiResponse & { + status: 200; + }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async getAllUsers(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getAllUsers( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.getAllUsersRaw(initOverrides); - return await response.value() as GetAllUsersResponse200Item[]; + return (await response.value()) as GetAllUsersResponse200Item[]; } - async getUserByIdRaw(requestParameters: ApiGetUserByIdRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getUserByIdRaw( + requestParameters: ApiGetUserByIdRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.id === undefined || requestParameters.id === null) { throw new RequiredError( 'id', - 'Required parameter "id" was null or undefined when calling getUserByIdRaw().' + 'Required parameter "id" was null or undefined when calling getUserByIdRaw().', ); } // Build path with path parameters @@ -127,41 +177,61 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 404) { let errorValue: Promise | undefined; - throw new GetUserByIdError(response, { kind: 'notFound', status: response.status as 404, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone()).value() }); - } - else { + throw new GetUserByIdError(response, { + kind: 'notFound', + status: response.status as 404, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new GetUserByIdError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new GetUserByIdError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response) as JSONApiResponse & { + status: 200; + }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async getUserById(requestParameters: ApiGetUserByIdRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getUserById( + requestParameters: ApiGetUserByIdRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.getUserByIdRaw(requestParameters, initOverrides); - return await response.value() as GetUserByIdResponse200; + return (await response.value()) as GetUserByIdResponse200; } } diff --git a/tests/golden/typescript/typescript-fetch/server-object/package.json.golden b/tests/golden/typescript/typescript-fetch/server-object/package.json.golden index 6668c7755..cf5e55f6c 100644 --- a/tests/golden/typescript/typescript-fetch/server-object/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/server-object/package.json.golden @@ -1,27 +1,27 @@ { + "name": "test-api-with-server-objects", + "version": "1.0.0", "description": "This is a test API specification that includes various server configurations", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "license": "MIT", + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "license": "MIT", - "main": "./dist/index.js", - "name": "test-api-with-server-objects", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/server-object/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/server-object/runtime/runtime.ts.golden index 927080311..d76c3c5ee 100644 --- a/tests/golden/typescript/typescript-fetch/server-object/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/server-object/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Test API with Server Objects — 1.0.0 * This is a test API specification that includes various server configurations */ -export const BASE_PATH = "https://api.example.com/v1".replace(/\/+$/, ""); +export const BASE_PATH = 'https://api.example.com/v1'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/server-object/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/server-object/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/server-object/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/server-object/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/server-object/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/server-object/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/server-object/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/server-object/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/server-path-prefix/README.md.golden b/tests/golden/typescript/typescript-fetch/server-path-prefix/README.md.golden index 9de3bfe57..eae167b5e 100644 --- a/tests/golden/typescript/typescript-fetch/server-path-prefix/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/server-path-prefix/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'server-path-prefix-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'server-path-prefix-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/server-path-prefix/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/server-path-prefix/apis/DefaultApi.ts.golden index 7ed25f106..7f70c5871 100644 --- a/tests/golden/typescript/typescript-fetch/server-path-prefix/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/server-path-prefix/apis/DefaultApi.ts.golden @@ -4,76 +4,111 @@ * Server Path Prefix Test — 1.0.0 * Test fixture for server URL path prefix stripping in operation paths. */ -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, RequiredError, ResponseError, VoidApiResponse } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + RequiredError, + ResponseError, + VoidApiResponse, +} from '../runtime/runtime'; export interface ApiGetUserRequest { userId: string; } export type HealthCheckRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); export type ListUsersRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); export type GetUserRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); -export type HealthCheckErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type HealthCheckErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class HealthCheckError extends ResponseError { readonly detail: HealthCheckErrorDetail; - constructor(response: Response, detail: HealthCheckErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: HealthCheckErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type ListUsersErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type ListUsersErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class ListUsersError extends ResponseError { readonly detail: ListUsersErrorDetail; - constructor(response: Response, detail: ListUsersErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: ListUsersErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type GetUserErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type GetUserErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class GetUserError extends ResponseError { readonly detail: GetUserErrorDetail; - constructor(response: Response, detail: GetUserErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: GetUserErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - healthCheckRaw: (initOverrides?: RequestInit - | InitOverrideFunction) => Promise; + healthCheckRaw: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; healthCheck: (initOverrides?: RequestInit | InitOverrideFunction) => Promise; - listUsersRaw: (initOverrides?: RequestInit - | InitOverrideFunction) => Promise; + listUsersRaw: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; listUsers: (initOverrides?: RequestInit | InitOverrideFunction) => Promise; - getUserRaw: (requestParameters: ApiGetUserRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - getUser: (requestParameters: ApiGetUserRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + getUserRaw: ( + requestParameters: ApiGetUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + getUser: ( + requestParameters: ApiGetUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class DefaultApi extends BaseAPI implements DefaultApiInterface { @@ -84,37 +119,47 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async healthCheckRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async healthCheckRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/health`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new HealthCheckError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new HealthCheckError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } @@ -124,37 +169,47 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { return await response.value(); } - async listUsersRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async listUsersRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/users`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new ListUsersError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new ListUsersError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } @@ -164,12 +219,14 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { return await response.value(); } - async getUserRaw(requestParameters: ApiGetUserRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getUserRaw( + requestParameters: ApiGetUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.userId === undefined || requestParameters.userId === null) { throw new RequiredError( 'userId', - 'Required parameter "userId" was null or undefined when calling getUserRaw().' + 'Required parameter "userId" was null or undefined when calling getUserRaw().', ); } // Build path with path parameters @@ -178,36 +235,47 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new GetUserError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new GetUserError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async getUser(requestParameters: ApiGetUserRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getUser( + requestParameters: ApiGetUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.getUserRaw(requestParameters, initOverrides); return await response.value(); } diff --git a/tests/golden/typescript/typescript-fetch/server-path-prefix/package.json.golden b/tests/golden/typescript/typescript-fetch/server-path-prefix/package.json.golden index 209dd3f2d..ac081afde 100644 --- a/tests/golden/typescript/typescript-fetch/server-path-prefix/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/server-path-prefix/package.json.golden @@ -1,26 +1,26 @@ { + "name": "server-path-prefix-test", + "version": "1.0.0", "description": "Test fixture for server URL path prefix stripping in operation paths.", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "server-path-prefix-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/server-path-prefix/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/server-path-prefix/runtime/runtime.ts.golden index d08637dd6..ddc184b1b 100644 --- a/tests/golden/typescript/typescript-fetch/server-path-prefix/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/server-path-prefix/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Server Path Prefix Test — 1.0.0 * Test fixture for server URL path prefix stripping in operation paths. */ -export const BASE_PATH = "https://api.example.com/v2".replace(/\/+$/, ""); +export const BASE_PATH = 'https://api.example.com/v2'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/server-path-prefix/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/server-path-prefix/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/server-path-prefix/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/server-path-prefix/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/server-path-prefix/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/server-path-prefix/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/server-path-prefix/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/server-path-prefix/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/ts-enum-const/README.md.golden b/tests/golden/typescript/typescript-fetch/ts-enum-const/README.md.golden index 5af19f041..777d7a6d5 100644 --- a/tests/golden/typescript/typescript-fetch/ts-enum-const/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/ts-enum-const/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'ts-enum-const-object-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'ts-enum-const-object-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/ts-enum-const/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/ts-enum-const/apis/DefaultApi.ts.golden index 8cb3ec6fd..43e19b8fc 100644 --- a/tests/golden/typescript/typescript-fetch/ts-enum-const/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-enum-const/apis/DefaultApi.ts.golden @@ -4,22 +4,33 @@ * TS Enum Const Object Test — 1.0.0 */ import type { Item } from '../models/Item'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; import { BaseAPI, DefaultConfig, JSONApiResponse, ResponseError } from '../runtime/runtime'; export type GetItemsRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); - -export type GetItemsErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type GetItemsErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class GetItemsError extends ResponseError { readonly detail: GetItemsErrorDetail; - constructor(response: Response, detail: GetItemsErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: GetItemsErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } @@ -38,43 +49,53 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async getItemsRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getItemsRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/items`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new GetItemsError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new GetItemsError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } async getItems(initOverrides?: RequestInit | InitOverrideFunction): Promise { const response = await this.getItemsRaw(initOverrides); - return await response.value() as Item; + return (await response.value()) as Item; } } diff --git a/tests/golden/typescript/typescript-fetch/ts-enum-const/package.json.golden b/tests/golden/typescript/typescript-fetch/ts-enum-const/package.json.golden index b0b808cec..f10433fae 100644 --- a/tests/golden/typescript/typescript-fetch/ts-enum-const/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-enum-const/package.json.golden @@ -1,26 +1,26 @@ { + "name": "ts-enum-const-object-test", + "version": "1.0.0", "description": "TypeScript client for TS Enum Const Object Test", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "ts-enum-const-object-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/ts-enum-const/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/ts-enum-const/runtime/runtime.ts.golden index 595f8fb98..72fe8cd74 100644 --- a/tests/golden/typescript/typescript-fetch/ts-enum-const/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-enum-const/runtime/runtime.ts.golden @@ -3,7 +3,7 @@ * * TS Enum Const Object Test — 1.0.0 */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -13,7 +13,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -92,8 +95,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -135,12 +140,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -150,7 +161,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -166,9 +177,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -183,13 +192,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -199,7 +210,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -209,10 +220,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -221,18 +233,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -240,16 +256,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -268,11 +285,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -282,7 +299,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -292,7 +309,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -306,12 +323,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -329,15 +364,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -413,16 +461,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -449,7 +587,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -476,7 +617,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -486,5 +627,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/ts-enum-const/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/ts-enum-const/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/ts-enum-const/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-enum-const/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/ts-enum-const/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/ts-enum-const/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/ts-enum-const/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-enum-const/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/README.md.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/README.md.golden index 893c067d5..4eecbe9d7 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'type-script-additional-property-prese const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -140,7 +140,11 @@ const config = new Configuration({ The client throws typed errors for different failure scenarios: ```typescript -import { ResponseError, FetchError, RequiredError } from 'type-script-additional-property-preservation'; +import { + ResponseError, + FetchError, + RequiredError, +} from 'type-script-additional-property-preservation'; try { const result = await api.someMethod(); @@ -190,6 +194,22 @@ To build ES modules: npm run build ``` +### Formatting and validation + +After generating or regenerating this client, install its development dependencies, +run all checks on the generated files and build the library: + +```bash +vp install +vp check +vp pack +``` + +The `check` and `build` npm scripts run the same Vite+ commands. +Use `vp fmt` (or the `fmt` script) to format any subsequent manual edits. +`vp check` validates formatting, lint rules, and types without modifying files. +Build output in `dist/` is excluded from formatting. + ## TypeScript Support This package includes TypeScript type definitions. No additional `@types` package is needed. @@ -214,7 +234,7 @@ import type { User, CreateUserRequest } from 'type-script-additional-property-pr const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AliasArrayMap.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AliasArrayMap.ts.golden index 8b013e7fa..ab6410932 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AliasArrayMap.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AliasArrayMap.ts.golden @@ -6,8 +6,9 @@ import type { DetailListAlias, DetailListAlias$Wire } from './DetailListAlias'; import { detailListAliasFromJSON, detailListAliasToJSON } from './DetailListAlias'; -export interface AliasArrayMap$Wire extends Readonly> { +export interface AliasArrayMap$Wire extends Readonly< + Record +> { readonly known_count: number; } @@ -16,25 +17,55 @@ export interface AliasArrayMap extends Readonly !['known_count'].includes(key)).map(([key, value]) => {const additionalValue = value as DetailListAlias$Wire; return [key, detailListAliasFromJSON(additionalValue)] as const;})); + const sourceEntries = Object.entries(json).filter(([key]) => { + return !['known_count'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as DetailListAlias$Wire; + return [key, detailListAliasFromJSON(additionalValue)] as const; + }), + ); + const visibleProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return !['knownCount'].includes(key); + }), + ); const result = { - ...Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => !['knownCount'].includes(key))), + ...visibleProperties, knownCount: json.known_count, }; - const shadowedProperties = Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => ['knownCount'].includes(key))); + const shadowedProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return ['knownCount'].includes(key); + }), + ); if (Object.keys(shadowedProperties).length > 0) { - Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), {value: shadowedProperties, enumerable: true,}); + Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), { + value: shadowedProperties, + enumerable: true, + }); } return result; } export function aliasArrayMapToJSON(value: AliasArrayMap): AliasArrayMap$Wire { - const retainedProperties = Object.getOwnPropertyDescriptor(value, Symbol.for('openapi-nexus.additionalProperties'))?.value as Record - | undefined; - const additionalProperties = Object.fromEntries(Object.entries({...Object.fromEntries(Object.entries(value) - .filter(([key]) => !['knownCount'].includes(key))),...retainedProperties}).map(([key, value]) => {const additionalValue = value as DetailListAlias; return [key, detailListAliasToJSON(additionalValue)] as const;})); + const retainedProperties = Object.getOwnPropertyDescriptor( + value, + Symbol.for('openapi-nexus.additionalProperties'), + )?.value as Record | undefined; + const sourceEntries = Object.entries(value).filter(([key]) => { + return !['knownCount'].includes(key); + }); + const sourceProperties = Object.fromEntries(sourceEntries); + const additionalEntries = Object.entries({ ...sourceProperties, ...retainedProperties }); + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as DetailListAlias; + return [key, detailListAliasToJSON(additionalValue)] as const; + }), + ); const result = { ...additionalProperties, known_count: value.knownCount, diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AliasMap.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AliasMap.ts.golden index 7b08ad241..d9665e877 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AliasMap.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AliasMap.ts.golden @@ -15,25 +15,55 @@ export interface AliasMap extends Readonly !['known_field'].includes(key)).map(([key, value]) => {const additionalValue = value as DetailAliasChain$Wire; return [key, detailAliasChainFromJSON(additionalValue)] as const;})); + const sourceEntries = Object.entries(json).filter(([key]) => { + return !['known_field'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as DetailAliasChain$Wire; + return [key, detailAliasChainFromJSON(additionalValue)] as const; + }), + ); + const visibleProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return !['knownField'].includes(key); + }), + ); const result = { - ...Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => !['knownField'].includes(key))), + ...visibleProperties, knownField: json.known_field, }; - const shadowedProperties = Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => ['knownField'].includes(key))); + const shadowedProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return ['knownField'].includes(key); + }), + ); if (Object.keys(shadowedProperties).length > 0) { - Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), {value: shadowedProperties, enumerable: true,}); + Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), { + value: shadowedProperties, + enumerable: true, + }); } return result; } export function aliasMapToJSON(value: AliasMap): AliasMap$Wire { - const retainedProperties = Object.getOwnPropertyDescriptor(value, Symbol.for('openapi-nexus.additionalProperties'))?.value as Record - | undefined; - const additionalProperties = Object.fromEntries(Object.entries({...Object.fromEntries(Object.entries(value) - .filter(([key]) => !['knownField'].includes(key))),...retainedProperties}).map(([key, value]) => {const additionalValue = value as DetailAliasChain; return [key, detailAliasChainToJSON(additionalValue)] as const;})); + const retainedProperties = Object.getOwnPropertyDescriptor( + value, + Symbol.for('openapi-nexus.additionalProperties'), + )?.value as Record | undefined; + const sourceEntries = Object.entries(value).filter(([key]) => { + return !['knownField'].includes(key); + }); + const sourceProperties = Object.fromEntries(sourceEntries); + const additionalEntries = Object.entries({ ...sourceProperties, ...retainedProperties }); + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as DetailAliasChain; + return [key, detailAliasChainToJSON(additionalValue)] as const; + }), + ); const result = { ...additionalProperties, known_field: value.knownField, diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AliasNullableMap.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AliasNullableMap.ts.golden index fa34cf2a4..bae54c33a 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AliasNullableMap.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AliasNullableMap.ts.golden @@ -6,8 +6,9 @@ import type { NullableDetailAlias, NullableDetailAlias$Wire } from './NullableDetailAlias'; import { nullableDetailAliasFromJSON, nullableDetailAliasToJSON } from './NullableDetailAlias'; -export interface AliasNullableMap$Wire extends Readonly> { +export interface AliasNullableMap$Wire extends Readonly< + Record +> { readonly known_count: number; } @@ -16,25 +17,55 @@ export interface AliasNullableMap extends Readonly !['known_count'].includes(key)).map(([key, value]) => {const additionalValue = value as NullableDetailAlias$Wire; return [key, nullableDetailAliasFromJSON(additionalValue)] as const;})); + const sourceEntries = Object.entries(json).filter(([key]) => { + return !['known_count'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as NullableDetailAlias$Wire; + return [key, nullableDetailAliasFromJSON(additionalValue)] as const; + }), + ); + const visibleProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return !['knownCount'].includes(key); + }), + ); const result = { - ...Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => !['knownCount'].includes(key))), + ...visibleProperties, knownCount: json.known_count, }; - const shadowedProperties = Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => ['knownCount'].includes(key))); + const shadowedProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return ['knownCount'].includes(key); + }), + ); if (Object.keys(shadowedProperties).length > 0) { - Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), {value: shadowedProperties, enumerable: true,}); + Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), { + value: shadowedProperties, + enumerable: true, + }); } return result; } export function aliasNullableMapToJSON(value: AliasNullableMap): AliasNullableMap$Wire { - const retainedProperties = Object.getOwnPropertyDescriptor(value, Symbol.for('openapi-nexus.additionalProperties'))?.value as Record - | undefined; - const additionalProperties = Object.fromEntries(Object.entries({...Object.fromEntries(Object.entries(value) - .filter(([key]) => !['knownCount'].includes(key))),...retainedProperties}).map(([key, value]) => {const additionalValue = value as NullableDetailAlias; return [key, nullableDetailAliasToJSON(additionalValue)] as const;})); + const retainedProperties = Object.getOwnPropertyDescriptor( + value, + Symbol.for('openapi-nexus.additionalProperties'), + )?.value as Record | undefined; + const sourceEntries = Object.entries(value).filter(([key]) => { + return !['knownCount'].includes(key); + }); + const sourceProperties = Object.fromEntries(sourceEntries); + const additionalEntries = Object.entries({ ...sourceProperties, ...retainedProperties }); + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as NullableDetailAlias; + return [key, nullableDetailAliasToJSON(additionalValue)] as const; + }), + ); const result = { ...additionalProperties, known_count: value.knownCount, diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AllOfJsonDictionary.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AllOfJsonDictionary.ts.golden index 783caff3c..86612d59d 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AllOfJsonDictionary.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AllOfJsonDictionary.ts.golden @@ -3,36 +3,71 @@ * * TypeScript additional property preservation — 1.0.0 */ -import type { AllOfJsonDictionaryAllOf1, AllOfJsonDictionaryAllOf1$Wire } from './AllOfJsonDictionaryAllOf1'; +import type { + AllOfJsonDictionaryAllOf1, + AllOfJsonDictionaryAllOf1$Wire, +} from './AllOfJsonDictionaryAllOf1'; import type { AnyJsonValue } from './AnyJsonValue'; import { detailFromJSON, detailToJSON } from './Detail'; -export type AllOfJsonDictionary$Wire = Readonly>; +export type AllOfJsonDictionary$Wire = Readonly< + AllOfJsonDictionaryAllOf1$Wire & Record +>; -export type AllOfJsonDictionary = Readonly>; +export type AllOfJsonDictionary = Readonly< + AllOfJsonDictionaryAllOf1 & Record +>; export function allOfJsonDictionaryFromJSON(json: AllOfJsonDictionary$Wire): AllOfJsonDictionary { - const additionalProperties = Object.fromEntries(Object.entries(json) - .filter(([key]) => !['known_item'].includes(key)).map(([key, value]) => {const additionalValue = value; return [key, additionalValue] as const;})); + const sourceEntries = Object.entries(json).filter(([key]) => { + return !['known_item'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value; + return [key, additionalValue] as const; + }), + ); + const visibleProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return !['knownItem'].includes(key); + }), + ); const result = { - ...Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => !['knownItem'].includes(key))), + ...visibleProperties, knownItem: detailFromJSON(json.known_item), }; - const shadowedProperties = Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => ['knownItem'].includes(key))); + const shadowedProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return ['knownItem'].includes(key); + }), + ); if (Object.keys(shadowedProperties).length > 0) { - Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), {value: shadowedProperties, enumerable: true,}); + Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), { + value: shadowedProperties, + enumerable: true, + }); } return result; } export function allOfJsonDictionaryToJSON(value: AllOfJsonDictionary): AllOfJsonDictionary$Wire { - const retainedProperties = Object.getOwnPropertyDescriptor(value, Symbol.for('openapi-nexus.additionalProperties'))?.value as Record - | undefined; - const additionalProperties = Object.fromEntries(Object.entries({...Object.fromEntries(Object.entries(value) - .filter(([key]) => !['knownItem'].includes(key))),...retainedProperties}).map(([key, value]) => {const additionalValue = value; return [key, additionalValue] as const;})); + const retainedProperties = Object.getOwnPropertyDescriptor( + value, + Symbol.for('openapi-nexus.additionalProperties'), + )?.value as Record | undefined; + const sourceEntries = Object.entries(value).filter(([key]) => { + return !['knownItem'].includes(key); + }); + const sourceProperties = Object.fromEntries(sourceEntries); + const additionalEntries = Object.entries({ ...sourceProperties, ...retainedProperties }); + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value; + return [key, additionalValue] as const; + }), + ); const result = { ...additionalProperties, known_item: detailToJSON(value.knownItem), diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AllOfJsonDictionaryAllOf1.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AllOfJsonDictionaryAllOf1.ts.golden index 6fa72ec6c..c99ad8563 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AllOfJsonDictionaryAllOf1.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AllOfJsonDictionaryAllOf1.ts.golden @@ -14,13 +14,17 @@ export interface AllOfJsonDictionaryAllOf1 { readonly knownItem: Detail; } -export function allOfJsonDictionaryAllOf1FromJSON(json: AllOfJsonDictionaryAllOf1$Wire): AllOfJsonDictionaryAllOf1 { +export function allOfJsonDictionaryAllOf1FromJSON( + json: AllOfJsonDictionaryAllOf1$Wire, +): AllOfJsonDictionaryAllOf1 { return { knownItem: detailFromJSON(json.known_item), }; } -export function allOfJsonDictionaryAllOf1ToJSON(value: AllOfJsonDictionaryAllOf1): AllOfJsonDictionaryAllOf1$Wire { +export function allOfJsonDictionaryAllOf1ToJSON( + value: AllOfJsonDictionaryAllOf1, +): AllOfJsonDictionaryAllOf1$Wire { return { known_item: detailToJSON(value.knownItem), }; diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AllOfMixedStringMap.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AllOfMixedStringMap.ts.golden index 5ec9aa7a0..aecfc7508 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AllOfMixedStringMap.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AllOfMixedStringMap.ts.golden @@ -3,29 +3,49 @@ * * TypeScript additional property preservation — 1.0.0 */ -import type { AllOfMixedStringMapAllOf1, AllOfMixedStringMapAllOf1$Wire } from './AllOfMixedStringMapAllOf1'; +import type { + AllOfMixedStringMapAllOf1, + AllOfMixedStringMapAllOf1$Wire, +} from './AllOfMixedStringMapAllOf1'; -export type AllOfMixedStringMap$Wire = Readonly>; +export type AllOfMixedStringMap$Wire = Readonly< + AllOfMixedStringMapAllOf1$Wire & Record +>; export type AllOfMixedStringMap = Readonly>; export function allOfMixedStringMapFromJSON(json: AllOfMixedStringMap$Wire): AllOfMixedStringMap { - const additionalProperties = Object.fromEntries(Object.entries(json) - .filter(([key]) => !['known'].includes(key)).map(([key, value]) => {const additionalValue = value as string; return [key, additionalValue] as const;})); + const sourceEntries = Object.entries(json).filter(([key]) => { + return !['known'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as string; + return [key, additionalValue] as const; + }), + ); const result = { ...additionalProperties, - ...(Object.prototype.hasOwnProperty.call(json, 'known') ? {known: json.known,} : {}), + ...(Object.prototype.hasOwnProperty.call(json, 'known') ? { known: json.known } : {}), }; return result; } export function allOfMixedStringMapToJSON(value: AllOfMixedStringMap): AllOfMixedStringMap$Wire { - const additionalProperties = Object.fromEntries(Object.entries(value) - .filter(([key]) => !['known'].includes(key)).map(([key, value]) => {const additionalValue = value as string; return [key, additionalValue] as const;})); + const sourceEntries = Object.entries(value).filter(([key]) => { + return !['known'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as string; + return [key, additionalValue] as const; + }), + ); const result = { ...additionalProperties, - ...(Object.prototype.hasOwnProperty.call(value, 'known') ? {known: value.known,} : {}), + ...(Object.prototype.hasOwnProperty.call(value, 'known') ? { known: value.known } : {}), }; return result; } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AllOfMixedStringMapAllOf1.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AllOfMixedStringMapAllOf1.ts.golden index 66061dd9f..511341fec 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AllOfMixedStringMapAllOf1.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AllOfMixedStringMapAllOf1.ts.golden @@ -11,13 +11,17 @@ export interface AllOfMixedStringMapAllOf1 { readonly known?: string; } -export function allOfMixedStringMapAllOf1FromJSON(json: AllOfMixedStringMapAllOf1$Wire): AllOfMixedStringMapAllOf1 { +export function allOfMixedStringMapAllOf1FromJSON( + json: AllOfMixedStringMapAllOf1$Wire, +): AllOfMixedStringMapAllOf1 { return { known: json.known, }; } -export function allOfMixedStringMapAllOf1ToJSON(value: AllOfMixedStringMapAllOf1): AllOfMixedStringMapAllOf1$Wire { +export function allOfMixedStringMapAllOf1ToJSON( + value: AllOfMixedStringMapAllOf1, +): AllOfMixedStringMapAllOf1$Wire { return { known: value.known, }; diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AllOfRenamedMap.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AllOfRenamedMap.ts.golden index 3f3c2b3bc..f824e5902 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AllOfRenamedMap.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AllOfRenamedMap.ts.golden @@ -17,30 +17,64 @@ export type AllOfRenamedMap$Wire = Readonly; export function allOfRenamedMapFromJSON(json: AllOfRenamedMap$Wire): AllOfRenamedMap { - const additionalProperties = Object.fromEntries(Object.entries(json) - .filter(([key]) => !['known_field', 'optional_field'].includes(key)).map(([key, value]) => {const additionalValue = value; return [key, additionalValue] as const;})); + const sourceEntries = Object.entries(json).filter(([key]) => { + return !['known_field', 'optional_field'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value; + return [key, additionalValue] as const; + }), + ); + const visibleProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return !['knownField', 'optionalField'].includes(key); + }), + ); const result = { - ...Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => !['knownField', 'optionalField'].includes(key))), + ...visibleProperties, knownField: json.known_field, - ...(Object.prototype.hasOwnProperty.call(json, 'optional_field') ? {optionalField: json.optional_field,} : {}), + ...(Object.prototype.hasOwnProperty.call(json, 'optional_field') + ? { optionalField: json.optional_field } + : {}), }; - const shadowedProperties = Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => ['knownField', 'optionalField'].includes(key))); + const shadowedProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return ['knownField', 'optionalField'].includes(key); + }), + ); if (Object.keys(shadowedProperties).length > 0) { - Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), {value: shadowedProperties, enumerable: true,}); + Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), { + value: shadowedProperties, + enumerable: true, + }); } return result; } export function allOfRenamedMapToJSON(value: AllOfRenamedMap): AllOfRenamedMap$Wire { - const retainedProperties = Object.getOwnPropertyDescriptor(value, Symbol.for('openapi-nexus.additionalProperties'))?.value as Record - | undefined; - const additionalProperties = Object.fromEntries(Object.entries({...Object.fromEntries(Object.entries(value) - .filter(([key]) => !['knownField', 'optionalField'].includes(key))),...retainedProperties}).map(([key, value]) => {const additionalValue = value; return [key, additionalValue] as const;})); + const retainedProperties = Object.getOwnPropertyDescriptor( + value, + Symbol.for('openapi-nexus.additionalProperties'), + )?.value as Record | undefined; + const sourceEntries = Object.entries(value).filter(([key]) => { + return !['knownField', 'optionalField'].includes(key); + }); + const sourceProperties = Object.fromEntries(sourceEntries); + const additionalEntries = Object.entries({ ...sourceProperties, ...retainedProperties }); + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value; + return [key, additionalValue] as const; + }), + ); const result = { ...additionalProperties, known_field: value.knownField, - ...(Object.prototype.hasOwnProperty.call(value, 'optionalField') ? {optional_field: value.optionalField,} : {}), + ...(Object.prototype.hasOwnProperty.call(value, 'optionalField') + ? { optional_field: value.optionalField } + : {}), }; return result; } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AllOfRenamedMapAllOf2.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AllOfRenamedMapAllOf2.ts.golden index 5c11b3e7a..24c1cf903 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AllOfRenamedMapAllOf2.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/AllOfRenamedMapAllOf2.ts.golden @@ -11,29 +11,67 @@ export interface AllOfRenamedMapAllOf2 extends Readonly> readonly knownField?: string; } -export function allOfRenamedMapAllOf2FromJSON(json: AllOfRenamedMapAllOf2$Wire): AllOfRenamedMapAllOf2 { - const additionalProperties = Object.fromEntries(Object.entries(json) - .filter(([key]) => !['known_field'].includes(key)).map(([key, value]) => {const additionalValue = value; return [key, additionalValue] as const;})); +export function allOfRenamedMapAllOf2FromJSON( + json: AllOfRenamedMapAllOf2$Wire, +): AllOfRenamedMapAllOf2 { + const sourceEntries = Object.entries(json).filter(([key]) => { + return !['known_field'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value; + return [key, additionalValue] as const; + }), + ); + const visibleProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return !['knownField'].includes(key); + }), + ); const result = { - ...Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => !['knownField'].includes(key))), - ...(Object.prototype.hasOwnProperty.call(json, 'known_field') ? {knownField: json.known_field,} : {}), + ...visibleProperties, + ...(Object.prototype.hasOwnProperty.call(json, 'known_field') + ? { knownField: json.known_field } + : {}), }; - const shadowedProperties = Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => ['knownField'].includes(key))); + const shadowedProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return ['knownField'].includes(key); + }), + ); if (Object.keys(shadowedProperties).length > 0) { - Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), {value: shadowedProperties, enumerable: true,}); + Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), { + value: shadowedProperties, + enumerable: true, + }); } return result; } -export function allOfRenamedMapAllOf2ToJSON(value: AllOfRenamedMapAllOf2): AllOfRenamedMapAllOf2$Wire { - const retainedProperties = Object.getOwnPropertyDescriptor(value, Symbol.for('openapi-nexus.additionalProperties'))?.value as Record - | undefined; - const additionalProperties = Object.fromEntries(Object.entries({...Object.fromEntries(Object.entries(value) - .filter(([key]) => !['knownField'].includes(key))),...retainedProperties}).map(([key, value]) => {const additionalValue = value; return [key, additionalValue] as const;})); +export function allOfRenamedMapAllOf2ToJSON( + value: AllOfRenamedMapAllOf2, +): AllOfRenamedMapAllOf2$Wire { + const retainedProperties = Object.getOwnPropertyDescriptor( + value, + Symbol.for('openapi-nexus.additionalProperties'), + )?.value as Record | undefined; + const sourceEntries = Object.entries(value).filter(([key]) => { + return !['knownField'].includes(key); + }); + const sourceProperties = Object.fromEntries(sourceEntries); + const additionalEntries = Object.entries({ ...sourceProperties, ...retainedProperties }); + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value; + return [key, additionalValue] as const; + }), + ); const result = { ...additionalProperties, - ...(Object.prototype.hasOwnProperty.call(value, 'knownField') ? {known_field: value.knownField,} : {}), + ...(Object.prototype.hasOwnProperty.call(value, 'knownField') + ? { known_field: value.knownField } + : {}), }; return result; } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/ArrayModelMap.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/ArrayModelMap.ts.golden index 4d47c82b8..085653a15 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/ArrayModelMap.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/ArrayModelMap.ts.golden @@ -6,8 +6,9 @@ import type { Detail, Detail$Wire } from './Detail'; import { detailFromJSON, detailToJSON } from './Detail'; -export interface ArrayModelMap$Wire extends Readonly> { +export interface ArrayModelMap$Wire extends Readonly< + Record +> { readonly known_count: number; } @@ -16,25 +17,55 @@ export interface ArrayModelMap extends Readonly !['known_count'].includes(key)).map(([key, value]) => {const additionalValue = value as readonly Detail$Wire[]; return [key, additionalValue.map((item) => detailFromJSON(item))] as const;})); + const sourceEntries = Object.entries(json).filter(([key]) => { + return !['known_count'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as readonly Detail$Wire[]; + return [key, additionalValue.map((item) => detailFromJSON(item))] as const; + }), + ); + const visibleProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return !['knownCount'].includes(key); + }), + ); const result = { - ...Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => !['knownCount'].includes(key))), + ...visibleProperties, knownCount: json.known_count, }; - const shadowedProperties = Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => ['knownCount'].includes(key))); + const shadowedProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return ['knownCount'].includes(key); + }), + ); if (Object.keys(shadowedProperties).length > 0) { - Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), {value: shadowedProperties, enumerable: true,}); + Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), { + value: shadowedProperties, + enumerable: true, + }); } return result; } export function arrayModelMapToJSON(value: ArrayModelMap): ArrayModelMap$Wire { - const retainedProperties = Object.getOwnPropertyDescriptor(value, Symbol.for('openapi-nexus.additionalProperties'))?.value as Record - | undefined; - const additionalProperties = Object.fromEntries(Object.entries({...Object.fromEntries(Object.entries(value) - .filter(([key]) => !['knownCount'].includes(key))),...retainedProperties}).map(([key, value]) => {const additionalValue = value as readonly Detail[]; return [key, additionalValue.map((item) => detailToJSON(item))] as const;})); + const retainedProperties = Object.getOwnPropertyDescriptor( + value, + Symbol.for('openapi-nexus.additionalProperties'), + )?.value as Record | undefined; + const sourceEntries = Object.entries(value).filter(([key]) => { + return !['knownCount'].includes(key); + }); + const sourceProperties = Object.fromEntries(sourceEntries); + const additionalEntries = Object.entries({ ...sourceProperties, ...retainedProperties }); + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as readonly Detail[]; + return [key, additionalValue.map((item) => detailToJSON(item))] as const; + }), + ); const result = { ...additionalProperties, known_count: value.knownCount, diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/ClosedExternalEvent.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/ClosedExternalEvent.ts.golden index 0f2702eec..42ffcc23b 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/ClosedExternalEvent.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/ClosedExternalEvent.ts.golden @@ -6,18 +6,18 @@ import type { Detail, Detail$Wire } from './Detail'; import { detailFromJSON, detailToJSON } from './Detail'; -export type ClosedExternalEvent$Wire = { 'started': Detail$Wire } | { 'finished': Detail$Wire }; +export type ClosedExternalEvent$Wire = { started: Detail$Wire } | { finished: Detail$Wire }; -export type ClosedExternalEvent = { 'started': Detail } | { 'finished': Detail }; +export type ClosedExternalEvent = { started: Detail } | { finished: Detail }; export function closedExternalEventFromJSON(json: ClosedExternalEvent$Wire): ClosedExternalEvent { - if ('started' in json) return { 'started': detailFromJSON(json['started']) }; - if ('finished' in json) return { 'finished': detailFromJSON(json['finished']) }; + if ('started' in json) return { started: detailFromJSON(json['started']) }; + if ('finished' in json) return { finished: detailFromJSON(json['finished']) }; throw new Error('Unknown variant'); } export function closedExternalEventToJSON(value: ClosedExternalEvent): ClosedExternalEvent$Wire { - if ('started' in value) return { 'started': detailToJSON(value['started']) }; - if ('finished' in value) return { 'finished': detailToJSON(value['finished']) }; + if ('started' in value) return { started: detailToJSON(value['started']) }; + if ('finished' in value) return { finished: detailToJSON(value['finished']) }; throw new Error('Unknown variant'); } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/HeterogeneousAllOf.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/HeterogeneousAllOf.ts.golden index 7b0a968ab..6073de3c4 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/HeterogeneousAllOf.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/HeterogeneousAllOf.ts.golden @@ -3,35 +3,72 @@ * * TypeScript additional property preservation — 1.0.0 */ -import type { HeterogeneousAllOfAllOf1, HeterogeneousAllOfAllOf1$Wire } from './HeterogeneousAllOfAllOf1'; -import type { HeterogeneousAllOfAllOf2, HeterogeneousAllOfAllOf2$Wire } from './HeterogeneousAllOfAllOf2'; +import type { + HeterogeneousAllOfAllOf1, + HeterogeneousAllOfAllOf1$Wire, +} from './HeterogeneousAllOfAllOf1'; +import type { + HeterogeneousAllOfAllOf2, + HeterogeneousAllOfAllOf2$Wire, +} from './HeterogeneousAllOfAllOf2'; -export type HeterogeneousAllOf$Wire = Readonly; +export type HeterogeneousAllOf$Wire = Readonly< + HeterogeneousAllOfAllOf1$Wire & HeterogeneousAllOfAllOf2$Wire +>; export type HeterogeneousAllOf = Readonly; export function heterogeneousAllOfFromJSON(json: HeterogeneousAllOf$Wire): HeterogeneousAllOf { - const additionalProperties = Object.fromEntries(Object.entries(json) - .filter(([key]) => !['known_field', 'other_field'].includes(key)).map(([key, value]) => {const additionalValue = value as string; return [key, additionalValue] as const;})); + const sourceEntries = Object.entries(json).filter(([key]) => { + return !['known_field', 'other_field'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as string; + return [key, additionalValue] as const; + }), + ); + const visibleProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return !['knownField', 'otherField'].includes(key); + }), + ); const result = { - ...Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => !['knownField', 'otherField'].includes(key))), + ...visibleProperties, knownField: json.known_field, otherField: json.other_field, }; - const shadowedProperties = Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => ['knownField', 'otherField'].includes(key))); + const shadowedProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return ['knownField', 'otherField'].includes(key); + }), + ); if (Object.keys(shadowedProperties).length > 0) { - Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), {value: shadowedProperties, enumerable: true,}); + Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), { + value: shadowedProperties, + enumerable: true, + }); } return result; } export function heterogeneousAllOfToJSON(value: HeterogeneousAllOf): HeterogeneousAllOf$Wire { - const retainedProperties = Object.getOwnPropertyDescriptor(value, Symbol.for('openapi-nexus.additionalProperties'))?.value as Record - | undefined; - const additionalProperties = Object.fromEntries(Object.entries({...Object.fromEntries(Object.entries(value) - .filter(([key]) => !['knownField', 'otherField'].includes(key))),...retainedProperties}).map(([key, value]) => {const additionalValue = value as string; return [key, additionalValue] as const;})); + const retainedProperties = Object.getOwnPropertyDescriptor( + value, + Symbol.for('openapi-nexus.additionalProperties'), + )?.value as Record | undefined; + const sourceEntries = Object.entries(value).filter(([key]) => { + return !['knownField', 'otherField'].includes(key); + }); + const sourceProperties = Object.fromEntries(sourceEntries); + const additionalEntries = Object.entries({ ...sourceProperties, ...retainedProperties }); + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as string; + return [key, additionalValue] as const; + }), + ); const result = { ...additionalProperties, known_field: value.knownField, diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/HeterogeneousAllOfAllOf1.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/HeterogeneousAllOfAllOf1.ts.golden index 0087947e9..3a072ff69 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/HeterogeneousAllOfAllOf1.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/HeterogeneousAllOfAllOf1.ts.golden @@ -11,26 +11,60 @@ export interface HeterogeneousAllOfAllOf1 extends Readonly !['known_field'].includes(key)).map(([key, value]) => {const additionalValue = value; return [key, additionalValue] as const;})); +export function heterogeneousAllOfAllOf1FromJSON( + json: HeterogeneousAllOfAllOf1$Wire, +): HeterogeneousAllOfAllOf1 { + const sourceEntries = Object.entries(json).filter(([key]) => { + return !['known_field'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value; + return [key, additionalValue] as const; + }), + ); + const visibleProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return !['knownField'].includes(key); + }), + ); const result = { - ...Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => !['knownField'].includes(key))), + ...visibleProperties, knownField: json.known_field, }; - const shadowedProperties = Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => ['knownField'].includes(key))); + const shadowedProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return ['knownField'].includes(key); + }), + ); if (Object.keys(shadowedProperties).length > 0) { - Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), {value: shadowedProperties, enumerable: true,}); + Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), { + value: shadowedProperties, + enumerable: true, + }); } return result; } -export function heterogeneousAllOfAllOf1ToJSON(value: HeterogeneousAllOfAllOf1): HeterogeneousAllOfAllOf1$Wire { - const retainedProperties = Object.getOwnPropertyDescriptor(value, Symbol.for('openapi-nexus.additionalProperties'))?.value as Record - | undefined; - const additionalProperties = Object.fromEntries(Object.entries({...Object.fromEntries(Object.entries(value) - .filter(([key]) => !['knownField'].includes(key))),...retainedProperties}).map(([key, value]) => {const additionalValue = value; return [key, additionalValue] as const;})); +export function heterogeneousAllOfAllOf1ToJSON( + value: HeterogeneousAllOfAllOf1, +): HeterogeneousAllOfAllOf1$Wire { + const retainedProperties = Object.getOwnPropertyDescriptor( + value, + Symbol.for('openapi-nexus.additionalProperties'), + )?.value as Record | undefined; + const sourceEntries = Object.entries(value).filter(([key]) => { + return !['knownField'].includes(key); + }); + const sourceProperties = Object.fromEntries(sourceEntries); + const additionalEntries = Object.entries({ ...sourceProperties, ...retainedProperties }); + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value; + return [key, additionalValue] as const; + }), + ); const result = { ...additionalProperties, known_field: value.knownField, diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/HeterogeneousAllOfAllOf2.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/HeterogeneousAllOfAllOf2.ts.golden index 98a85e58b..b15d960bb 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/HeterogeneousAllOfAllOf2.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/HeterogeneousAllOfAllOf2.ts.golden @@ -11,26 +11,60 @@ export interface HeterogeneousAllOfAllOf2 extends Readonly !['other_field'].includes(key)).map(([key, value]) => {const additionalValue = value as string; return [key, additionalValue] as const;})); +export function heterogeneousAllOfAllOf2FromJSON( + json: HeterogeneousAllOfAllOf2$Wire, +): HeterogeneousAllOfAllOf2 { + const sourceEntries = Object.entries(json).filter(([key]) => { + return !['other_field'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as string; + return [key, additionalValue] as const; + }), + ); + const visibleProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return !['otherField'].includes(key); + }), + ); const result = { - ...Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => !['otherField'].includes(key))), + ...visibleProperties, otherField: json.other_field, }; - const shadowedProperties = Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => ['otherField'].includes(key))); + const shadowedProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return ['otherField'].includes(key); + }), + ); if (Object.keys(shadowedProperties).length > 0) { - Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), {value: shadowedProperties, enumerable: true,}); + Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), { + value: shadowedProperties, + enumerable: true, + }); } return result; } -export function heterogeneousAllOfAllOf2ToJSON(value: HeterogeneousAllOfAllOf2): HeterogeneousAllOfAllOf2$Wire { - const retainedProperties = Object.getOwnPropertyDescriptor(value, Symbol.for('openapi-nexus.additionalProperties'))?.value as Record - | undefined; - const additionalProperties = Object.fromEntries(Object.entries({...Object.fromEntries(Object.entries(value) - .filter(([key]) => !['otherField'].includes(key))),...retainedProperties}).map(([key, value]) => {const additionalValue = value as string; return [key, additionalValue] as const;})); +export function heterogeneousAllOfAllOf2ToJSON( + value: HeterogeneousAllOfAllOf2, +): HeterogeneousAllOfAllOf2$Wire { + const retainedProperties = Object.getOwnPropertyDescriptor( + value, + Symbol.for('openapi-nexus.additionalProperties'), + )?.value as Record | undefined; + const sourceEntries = Object.entries(value).filter(([key]) => { + return !['otherField'].includes(key); + }); + const sourceProperties = Object.fromEntries(sourceEntries); + const additionalEntries = Object.entries({ ...sourceProperties, ...retainedProperties }); + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as string; + return [key, additionalValue] as const; + }), + ); const result = { ...additionalProperties, other_field: value.otherField, diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/JsonModelAllOf.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/JsonModelAllOf.ts.golden index 0d4027d76..fb9b9ec8a 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/JsonModelAllOf.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/JsonModelAllOf.ts.golden @@ -13,26 +13,56 @@ export type JsonModelAllOf$Wire = Readonly; export function jsonModelAllOfFromJSON(json: JsonModelAllOf$Wire): JsonModelAllOf { - const additionalProperties = Object.fromEntries(Object.entries(json) - .filter(([key]) => !['known_first', 'known_second'].includes(key)).map(([key, value]) => {const additionalValue = value as Detail$Wire; return [key, detailFromJSON(additionalValue)] as const;})); + const sourceEntries = Object.entries(json).filter(([key]) => { + return !['known_first', 'known_second'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as Detail$Wire; + return [key, detailFromJSON(additionalValue)] as const; + }), + ); + const visibleProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return !['knownFirst', 'knownSecond'].includes(key); + }), + ); const result = { - ...Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => !['knownFirst', 'knownSecond'].includes(key))), + ...visibleProperties, knownFirst: detailFromJSON(json.known_first), knownSecond: detailFromJSON(json.known_second), }; - const shadowedProperties = Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => ['knownFirst', 'knownSecond'].includes(key))); + const shadowedProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return ['knownFirst', 'knownSecond'].includes(key); + }), + ); if (Object.keys(shadowedProperties).length > 0) { - Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), {value: shadowedProperties, enumerable: true,}); + Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), { + value: shadowedProperties, + enumerable: true, + }); } return result; } export function jsonModelAllOfToJSON(value: JsonModelAllOf): JsonModelAllOf$Wire { - const retainedProperties = Object.getOwnPropertyDescriptor(value, Symbol.for('openapi-nexus.additionalProperties'))?.value as Record - | undefined; - const additionalProperties = Object.fromEntries(Object.entries({...Object.fromEntries(Object.entries(value) - .filter(([key]) => !['knownFirst', 'knownSecond'].includes(key))),...retainedProperties}).map(([key, value]) => {const additionalValue = value as Detail; return [key, detailToJSON(additionalValue)] as const;})); + const retainedProperties = Object.getOwnPropertyDescriptor( + value, + Symbol.for('openapi-nexus.additionalProperties'), + )?.value as Record | undefined; + const sourceEntries = Object.entries(value).filter(([key]) => { + return !['knownFirst', 'knownSecond'].includes(key); + }); + const sourceProperties = Object.fromEntries(sourceEntries); + const additionalEntries = Object.entries({ ...sourceProperties, ...retainedProperties }); + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as Detail; + return [key, detailToJSON(additionalValue)] as const; + }), + ); const result = { ...additionalProperties, known_first: detailToJSON(value.knownFirst), diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/JsonModelAllOfAllOf1.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/JsonModelAllOfAllOf1.ts.golden index 1c9cee754..7394b479a 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/JsonModelAllOfAllOf1.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/JsonModelAllOfAllOf1.ts.golden @@ -15,26 +15,58 @@ export interface JsonModelAllOfAllOf1 extends Readonly> readonly knownFirst: Detail; } -export function jsonModelAllOfAllOf1FromJSON(json: JsonModelAllOfAllOf1$Wire): JsonModelAllOfAllOf1 { - const additionalProperties = Object.fromEntries(Object.entries(json) - .filter(([key]) => !['known_first'].includes(key)).map(([key, value]) => {const additionalValue = value; return [key, additionalValue] as const;})); +export function jsonModelAllOfAllOf1FromJSON( + json: JsonModelAllOfAllOf1$Wire, +): JsonModelAllOfAllOf1 { + const sourceEntries = Object.entries(json).filter(([key]) => { + return !['known_first'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value; + return [key, additionalValue] as const; + }), + ); + const visibleProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return !['knownFirst'].includes(key); + }), + ); const result = { - ...Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => !['knownFirst'].includes(key))), + ...visibleProperties, knownFirst: detailFromJSON(json.known_first), }; - const shadowedProperties = Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => ['knownFirst'].includes(key))); + const shadowedProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return ['knownFirst'].includes(key); + }), + ); if (Object.keys(shadowedProperties).length > 0) { - Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), {value: shadowedProperties, enumerable: true,}); + Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), { + value: shadowedProperties, + enumerable: true, + }); } return result; } export function jsonModelAllOfAllOf1ToJSON(value: JsonModelAllOfAllOf1): JsonModelAllOfAllOf1$Wire { - const retainedProperties = Object.getOwnPropertyDescriptor(value, Symbol.for('openapi-nexus.additionalProperties'))?.value as Record - | undefined; - const additionalProperties = Object.fromEntries(Object.entries({...Object.fromEntries(Object.entries(value) - .filter(([key]) => !['knownFirst'].includes(key))),...retainedProperties}).map(([key, value]) => {const additionalValue = value; return [key, additionalValue] as const;})); + const retainedProperties = Object.getOwnPropertyDescriptor( + value, + Symbol.for('openapi-nexus.additionalProperties'), + )?.value as Record | undefined; + const sourceEntries = Object.entries(value).filter(([key]) => { + return !['knownFirst'].includes(key); + }); + const sourceProperties = Object.fromEntries(sourceEntries); + const additionalEntries = Object.entries({ ...sourceProperties, ...retainedProperties }); + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value; + return [key, additionalValue] as const; + }), + ); const result = { ...additionalProperties, known_first: detailToJSON(value.knownFirst), diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/JsonModelAllOfAllOf2.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/JsonModelAllOfAllOf2.ts.golden index cced38684..d2690205d 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/JsonModelAllOfAllOf2.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/JsonModelAllOfAllOf2.ts.golden @@ -14,26 +14,58 @@ export interface JsonModelAllOfAllOf2 extends Readonly> { readonly knownSecond: Detail; } -export function jsonModelAllOfAllOf2FromJSON(json: JsonModelAllOfAllOf2$Wire): JsonModelAllOfAllOf2 { - const additionalProperties = Object.fromEntries(Object.entries(json) - .filter(([key]) => !['known_second'].includes(key)).map(([key, value]) => {const additionalValue = value as Detail$Wire; return [key, detailFromJSON(additionalValue)] as const;})); +export function jsonModelAllOfAllOf2FromJSON( + json: JsonModelAllOfAllOf2$Wire, +): JsonModelAllOfAllOf2 { + const sourceEntries = Object.entries(json).filter(([key]) => { + return !['known_second'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as Detail$Wire; + return [key, detailFromJSON(additionalValue)] as const; + }), + ); + const visibleProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return !['knownSecond'].includes(key); + }), + ); const result = { - ...Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => !['knownSecond'].includes(key))), + ...visibleProperties, knownSecond: detailFromJSON(json.known_second), }; - const shadowedProperties = Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => ['knownSecond'].includes(key))); + const shadowedProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return ['knownSecond'].includes(key); + }), + ); if (Object.keys(shadowedProperties).length > 0) { - Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), {value: shadowedProperties, enumerable: true,}); + Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), { + value: shadowedProperties, + enumerable: true, + }); } return result; } export function jsonModelAllOfAllOf2ToJSON(value: JsonModelAllOfAllOf2): JsonModelAllOfAllOf2$Wire { - const retainedProperties = Object.getOwnPropertyDescriptor(value, Symbol.for('openapi-nexus.additionalProperties'))?.value as Record - | undefined; - const additionalProperties = Object.fromEntries(Object.entries({...Object.fromEntries(Object.entries(value) - .filter(([key]) => !['knownSecond'].includes(key))),...retainedProperties}).map(([key, value]) => {const additionalValue = value as Detail; return [key, detailToJSON(additionalValue)] as const;})); + const retainedProperties = Object.getOwnPropertyDescriptor( + value, + Symbol.for('openapi-nexus.additionalProperties'), + )?.value as Record | undefined; + const sourceEntries = Object.entries(value).filter(([key]) => { + return !['knownSecond'].includes(key); + }); + const sourceProperties = Object.fromEntries(sourceEntries); + const additionalEntries = Object.entries({ ...sourceProperties, ...retainedProperties }); + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as Detail; + return [key, detailToJSON(additionalValue)] as const; + }), + ); const result = { ...additionalProperties, known_second: detailToJSON(value.knownSecond), diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/MixedBooleanMap.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/MixedBooleanMap.ts.golden index 2ebb32bce..4b3870134 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/MixedBooleanMap.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/MixedBooleanMap.ts.golden @@ -12,21 +12,37 @@ export interface MixedBooleanMap extends Readonly> { } export function mixedBooleanMapFromJSON(json: MixedBooleanMap$Wire): MixedBooleanMap { - const additionalProperties = Object.fromEntries(Object.entries(json) - .filter(([key]) => !['known'].includes(key)).map(([key, value]) => {const additionalValue = value; return [key, additionalValue] as const;})); + const sourceEntries = Object.entries(json).filter(([key]) => { + return !['known'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value; + return [key, additionalValue] as const; + }), + ); const result = { ...additionalProperties, - ...(Object.prototype.hasOwnProperty.call(json, 'known') ? {known: json.known,} : {}), + ...(Object.prototype.hasOwnProperty.call(json, 'known') ? { known: json.known } : {}), }; return result; } export function mixedBooleanMapToJSON(value: MixedBooleanMap): MixedBooleanMap$Wire { - const additionalProperties = Object.fromEntries(Object.entries(value) - .filter(([key]) => !['known'].includes(key)).map(([key, value]) => {const additionalValue = value; return [key, additionalValue] as const;})); + const sourceEntries = Object.entries(value).filter(([key]) => { + return !['known'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value; + return [key, additionalValue] as const; + }), + ); const result = { ...additionalProperties, - ...(Object.prototype.hasOwnProperty.call(value, 'known') ? {known: value.known,} : {}), + ...(Object.prototype.hasOwnProperty.call(value, 'known') ? { known: value.known } : {}), }; return result; } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/MixedExternalEvent.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/MixedExternalEvent.ts.golden index 2f55e4074..23d7911d0 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/MixedExternalEvent.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/MixedExternalEvent.ts.golden @@ -6,23 +6,30 @@ import type { Detail, Detail$Wire } from './Detail'; import { detailFromJSON, detailToJSON } from './Detail'; -export type MixedExternalEvent$Wire = Readonly> -& Readonly> -| Readonly>; +export type MixedExternalEvent$Wire = + | (Readonly> & Readonly>) + | Readonly>; -export type MixedExternalEvent = Readonly> -& Readonly> -| Readonly>; +export type MixedExternalEvent = + | (Readonly> & Readonly>) + | Readonly>; export function mixedExternalEventFromJSON(json: MixedExternalEvent$Wire): MixedExternalEvent { if (Object.prototype.hasOwnProperty.call(json, 'started')) { const contentValue = (json as Record<'started', Detail$Wire>)['started']; - const additionalProperties = Object.fromEntries(Object.entries(json).filter(([key]) => key !== 'started').map(([key, value]) => {const additionalValue = value; return [key, additionalValue] as const;})); - return {...additionalProperties,['started']: detailFromJSON(contentValue),}; + const additionalProperties = Object.fromEntries( + Object.entries(json) + .filter(([key]) => key !== 'started') + .map(([key, value]) => { + const additionalValue = value; + return [key, additionalValue] as const; + }), + ); + return { ...additionalProperties, ['started']: detailFromJSON(contentValue) }; } if (Object.prototype.hasOwnProperty.call(json, 'finished')) { const contentValue = (json as Record<'finished', Detail$Wire>)['finished']; - return {['finished']: detailFromJSON(contentValue),}; + return { ['finished']: detailFromJSON(contentValue) }; } throw new Error('Unknown variant'); } @@ -30,12 +37,19 @@ export function mixedExternalEventFromJSON(json: MixedExternalEvent$Wire): Mixed export function mixedExternalEventToJSON(value: MixedExternalEvent): MixedExternalEvent$Wire { if (Object.prototype.hasOwnProperty.call(value, 'started')) { const contentValue = (value as Record<'started', Detail>)['started']; - const additionalProperties = Object.fromEntries(Object.entries(value).filter(([key]) => key !== 'started').map(([key, value]) => {const additionalValue = value; return [key, additionalValue] as const;})); - return {...additionalProperties,['started']: detailToJSON(contentValue),}; + const additionalProperties = Object.fromEntries( + Object.entries(value) + .filter(([key]) => key !== 'started') + .map(([key, value]) => { + const additionalValue = value; + return [key, additionalValue] as const; + }), + ); + return { ...additionalProperties, ['started']: detailToJSON(contentValue) }; } if (Object.prototype.hasOwnProperty.call(value, 'finished')) { const contentValue = (value as Record<'finished', Detail>)['finished']; - return {['finished']: detailToJSON(contentValue),}; + return { ['finished']: detailToJSON(contentValue) }; } throw new Error('Unknown variant'); } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/MixedInlineAnyMap.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/MixedInlineAnyMap.ts.golden index 6cd3f27c3..36696a863 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/MixedInlineAnyMap.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/MixedInlineAnyMap.ts.golden @@ -12,21 +12,37 @@ export interface MixedInlineAnyMap extends Readonly> { } export function mixedInlineAnyMapFromJSON(json: MixedInlineAnyMap$Wire): MixedInlineAnyMap { - const additionalProperties = Object.fromEntries(Object.entries(json) - .filter(([key]) => !['known'].includes(key)).map(([key, value]) => {const additionalValue = value; return [key, additionalValue] as const;})); + const sourceEntries = Object.entries(json).filter(([key]) => { + return !['known'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value; + return [key, additionalValue] as const; + }), + ); const result = { ...additionalProperties, - ...(Object.prototype.hasOwnProperty.call(json, 'known') ? {known: json.known,} : {}), + ...(Object.prototype.hasOwnProperty.call(json, 'known') ? { known: json.known } : {}), }; return result; } export function mixedInlineAnyMapToJSON(value: MixedInlineAnyMap): MixedInlineAnyMap$Wire { - const additionalProperties = Object.fromEntries(Object.entries(value) - .filter(([key]) => !['known'].includes(key)).map(([key, value]) => {const additionalValue = value; return [key, additionalValue] as const;})); + const sourceEntries = Object.entries(value).filter(([key]) => { + return !['known'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value; + return [key, additionalValue] as const; + }), + ); const result = { ...additionalProperties, - ...(Object.prototype.hasOwnProperty.call(value, 'known') ? {known: value.known,} : {}), + ...(Object.prototype.hasOwnProperty.call(value, 'known') ? { known: value.known } : {}), }; return result; } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/MixedJsonMap.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/MixedJsonMap.ts.golden index 3c0f58574..253b9f74c 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/MixedJsonMap.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/MixedJsonMap.ts.golden @@ -12,21 +12,37 @@ export interface MixedJsonMap extends Readonly> { } export function mixedJsonMapFromJSON(json: MixedJsonMap$Wire): MixedJsonMap { - const additionalProperties = Object.fromEntries(Object.entries(json) - .filter(([key]) => !['known'].includes(key)).map(([key, value]) => {const additionalValue = value; return [key, additionalValue] as const;})); + const sourceEntries = Object.entries(json).filter(([key]) => { + return !['known'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value; + return [key, additionalValue] as const; + }), + ); const result = { ...additionalProperties, - ...(Object.prototype.hasOwnProperty.call(json, 'known') ? {known: json.known,} : {}), + ...(Object.prototype.hasOwnProperty.call(json, 'known') ? { known: json.known } : {}), }; return result; } export function mixedJsonMapToJSON(value: MixedJsonMap): MixedJsonMap$Wire { - const additionalProperties = Object.fromEntries(Object.entries(value) - .filter(([key]) => !['known'].includes(key)).map(([key, value]) => {const additionalValue = value; return [key, additionalValue] as const;})); + const sourceEntries = Object.entries(value).filter(([key]) => { + return !['known'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value; + return [key, additionalValue] as const; + }), + ); const result = { ...additionalProperties, - ...(Object.prototype.hasOwnProperty.call(value, 'known') ? {known: value.known,} : {}), + ...(Object.prototype.hasOwnProperty.call(value, 'known') ? { known: value.known } : {}), }; return result; } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/MixedModelMap.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/MixedModelMap.ts.golden index 65826887d..7924f478d 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/MixedModelMap.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/MixedModelMap.ts.golden @@ -15,25 +15,55 @@ export interface MixedModelMap extends Readonly> } export function mixedModelMapFromJSON(json: MixedModelMap$Wire): MixedModelMap { - const additionalProperties = Object.fromEntries(Object.entries(json) - .filter(([key]) => !['known_count'].includes(key)).map(([key, value]) => {const additionalValue = value as Detail$Wire; return [key, detailFromJSON(additionalValue)] as const;})); + const sourceEntries = Object.entries(json).filter(([key]) => { + return !['known_count'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as Detail$Wire; + return [key, detailFromJSON(additionalValue)] as const; + }), + ); + const visibleProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return !['knownCount'].includes(key); + }), + ); const result = { - ...Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => !['knownCount'].includes(key))), + ...visibleProperties, knownCount: json.known_count, }; - const shadowedProperties = Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => ['knownCount'].includes(key))); + const shadowedProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return ['knownCount'].includes(key); + }), + ); if (Object.keys(shadowedProperties).length > 0) { - Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), {value: shadowedProperties, enumerable: true,}); + Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), { + value: shadowedProperties, + enumerable: true, + }); } return result; } export function mixedModelMapToJSON(value: MixedModelMap): MixedModelMap$Wire { - const retainedProperties = Object.getOwnPropertyDescriptor(value, Symbol.for('openapi-nexus.additionalProperties'))?.value as Record - | undefined; - const additionalProperties = Object.fromEntries(Object.entries({...Object.fromEntries(Object.entries(value) - .filter(([key]) => !['knownCount'].includes(key))),...retainedProperties}).map(([key, value]) => {const additionalValue = value as Detail; return [key, detailToJSON(additionalValue)] as const;})); + const retainedProperties = Object.getOwnPropertyDescriptor( + value, + Symbol.for('openapi-nexus.additionalProperties'), + )?.value as Record | undefined; + const sourceEntries = Object.entries(value).filter(([key]) => { + return !['knownCount'].includes(key); + }); + const sourceProperties = Object.fromEntries(sourceEntries); + const additionalEntries = Object.entries({ ...sourceProperties, ...retainedProperties }); + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as Detail; + return [key, detailToJSON(additionalValue)] as const; + }), + ); const result = { ...additionalProperties, known_count: value.knownCount, diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/MixedNumberMap.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/MixedNumberMap.ts.golden index 9277dd9a5..46d74b929 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/MixedNumberMap.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/MixedNumberMap.ts.golden @@ -12,21 +12,37 @@ export interface MixedNumberMap extends Readonly !['known'].includes(key)).map(([key, value]) => {const additionalValue = value as number; return [key, additionalValue] as const;})); + const sourceEntries = Object.entries(json).filter(([key]) => { + return !['known'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as number; + return [key, additionalValue] as const; + }), + ); const result = { ...additionalProperties, - ...(Object.prototype.hasOwnProperty.call(json, 'known') ? {known: json.known,} : {}), + ...(Object.prototype.hasOwnProperty.call(json, 'known') ? { known: json.known } : {}), }; return result; } export function mixedNumberMapToJSON(value: MixedNumberMap): MixedNumberMap$Wire { - const additionalProperties = Object.fromEntries(Object.entries(value) - .filter(([key]) => !['known'].includes(key)).map(([key, value]) => {const additionalValue = value as number; return [key, additionalValue] as const;})); + const sourceEntries = Object.entries(value).filter(([key]) => { + return !['known'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as number; + return [key, additionalValue] as const; + }), + ); const result = { ...additionalProperties, - ...(Object.prototype.hasOwnProperty.call(value, 'known') ? {known: value.known,} : {}), + ...(Object.prototype.hasOwnProperty.call(value, 'known') ? { known: value.known } : {}), }; return result; } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/MixedStringMap.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/MixedStringMap.ts.golden index 72495883b..4498ad4bb 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/MixedStringMap.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/MixedStringMap.ts.golden @@ -12,21 +12,37 @@ export interface MixedStringMap extends Readonly !['known'].includes(key)).map(([key, value]) => {const additionalValue = value as string; return [key, additionalValue] as const;})); + const sourceEntries = Object.entries(json).filter(([key]) => { + return !['known'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as string; + return [key, additionalValue] as const; + }), + ); const result = { ...additionalProperties, - ...(Object.prototype.hasOwnProperty.call(json, 'known') ? {known: json.known,} : {}), + ...(Object.prototype.hasOwnProperty.call(json, 'known') ? { known: json.known } : {}), }; return result; } export function mixedStringMapToJSON(value: MixedStringMap): MixedStringMap$Wire { - const additionalProperties = Object.fromEntries(Object.entries(value) - .filter(([key]) => !['known'].includes(key)).map(([key, value]) => {const additionalValue = value as string; return [key, additionalValue] as const;})); + const sourceEntries = Object.entries(value).filter(([key]) => { + return !['known'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as string; + return [key, additionalValue] as const; + }), + ); const result = { ...additionalProperties, - ...(Object.prototype.hasOwnProperty.call(value, 'known') ? {known: value.known,} : {}), + ...(Object.prototype.hasOwnProperty.call(value, 'known') ? { known: value.known } : {}), }; return result; } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/NestedModelMap.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/NestedModelMap.ts.golden index 61ddbd8e7..5424df00f 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/NestedModelMap.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/NestedModelMap.ts.golden @@ -6,8 +6,9 @@ import type { Detail, Detail$Wire } from './Detail'; import { detailFromJSON, detailToJSON } from './Detail'; -export interface NestedModelMap$Wire extends Readonly | number>> { +export interface NestedModelMap$Wire extends Readonly< + Record | number> +> { readonly known_count: number; } @@ -16,27 +17,61 @@ export interface NestedModelMap extends Readonly !['known_count'].includes(key)).map(([key, value]) => {const additionalValue = value as Record; return [key, Object.fromEntries(Object.entries(additionalValue ?? {}).map(([k, v]) => [k, detailFromJSON(v)]))] as const;})); + const sourceEntries = Object.entries(json).filter(([key]) => { + return !['known_count'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as Record; + const convertedValue = Object.fromEntries( + Object.entries(additionalValue ?? {}).map(([k, v]) => [k, detailFromJSON(v)]), + ); + return [key, convertedValue] as const; + }), + ); + const visibleProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return !['knownCount'].includes(key); + }), + ); const result = { - ...Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => !['knownCount'].includes(key))), + ...visibleProperties, knownCount: json.known_count, }; - const shadowedProperties = Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => ['knownCount'].includes(key))); + const shadowedProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return ['knownCount'].includes(key); + }), + ); if (Object.keys(shadowedProperties).length > 0) { - Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), {value: shadowedProperties, enumerable: true,}); + Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), { + value: shadowedProperties, + enumerable: true, + }); } return result; } export function nestedModelMapToJSON(value: NestedModelMap): NestedModelMap$Wire { - const retainedProperties = Object.getOwnPropertyDescriptor(value, Symbol.for('openapi-nexus.additionalProperties'))?.value as Record> - | undefined; - const additionalProperties = Object.fromEntries(Object.entries({...Object.fromEntries(Object.entries(value) - .filter(([key]) => !['knownCount'].includes(key))),...retainedProperties}).map(([key, value]) => {const additionalValue = value as Record; return [key, Object.fromEntries(Object.entries(additionalValue ?? {}).map(([k, v]) => [k, detailToJSON(v)]))] as const;})); + const retainedProperties = Object.getOwnPropertyDescriptor( + value, + Symbol.for('openapi-nexus.additionalProperties'), + )?.value as Record> | undefined; + const sourceEntries = Object.entries(value).filter(([key]) => { + return !['knownCount'].includes(key); + }); + const sourceProperties = Object.fromEntries(sourceEntries); + const additionalEntries = Object.entries({ ...sourceProperties, ...retainedProperties }); + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as Record; + const convertedValue = Object.fromEntries( + Object.entries(additionalValue ?? {}).map(([k, v]) => [k, detailToJSON(v)]), + ); + return [key, convertedValue] as const; + }), + ); const result = { ...additionalProperties, known_count: value.knownCount, diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/NullableModelMap.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/NullableModelMap.ts.golden index 91b2b9f6d..7a8a6b34f 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/NullableModelMap.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/NullableModelMap.ts.golden @@ -6,8 +6,9 @@ import type { Detail, Detail$Wire } from './Detail'; import { detailFromJSON, detailToJSON } from './Detail'; -export interface NullableModelMap$Wire extends Readonly> { +export interface NullableModelMap$Wire extends Readonly< + Record +> { readonly known_count: number; } @@ -16,27 +17,55 @@ export interface NullableModelMap extends Readonly !['known_count'].includes(key)).map(([key, value]) => {const additionalValue = value as Detail$Wire - | null; return [key, additionalValue != null ? detailFromJSON(additionalValue) : null] as const;})); + const sourceEntries = Object.entries(json).filter(([key]) => { + return !['known_count'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as Detail$Wire | null; + return [key, additionalValue != null ? detailFromJSON(additionalValue) : null] as const; + }), + ); + const visibleProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return !['knownCount'].includes(key); + }), + ); const result = { - ...Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => !['knownCount'].includes(key))), + ...visibleProperties, knownCount: json.known_count, }; - const shadowedProperties = Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => ['knownCount'].includes(key))); + const shadowedProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return ['knownCount'].includes(key); + }), + ); if (Object.keys(shadowedProperties).length > 0) { - Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), {value: shadowedProperties, enumerable: true,}); + Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), { + value: shadowedProperties, + enumerable: true, + }); } return result; } export function nullableModelMapToJSON(value: NullableModelMap): NullableModelMap$Wire { - const retainedProperties = Object.getOwnPropertyDescriptor(value, Symbol.for('openapi-nexus.additionalProperties'))?.value as Record - | undefined; - const additionalProperties = Object.fromEntries(Object.entries({...Object.fromEntries(Object.entries(value) - .filter(([key]) => !['knownCount'].includes(key))),...retainedProperties}).map(([key, value]) => {const additionalValue = value as Detail - | null; return [key, additionalValue != null ? detailToJSON(additionalValue) : null] as const;})); + const retainedProperties = Object.getOwnPropertyDescriptor( + value, + Symbol.for('openapi-nexus.additionalProperties'), + )?.value as Record | undefined; + const sourceEntries = Object.entries(value).filter(([key]) => { + return !['knownCount'].includes(key); + }); + const sourceProperties = Object.fromEntries(sourceEntries); + const additionalEntries = Object.entries({ ...sourceProperties, ...retainedProperties }); + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as Detail | null; + return [key, additionalValue != null ? detailToJSON(additionalValue) : null] as const; + }), + ); const result = { ...additionalProperties, known_count: value.knownCount, diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/OpenExternalEvent.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/OpenExternalEvent.ts.golden index 39515ca20..74d6e6352 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/OpenExternalEvent.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/OpenExternalEvent.ts.golden @@ -6,24 +6,38 @@ import type { Detail, Detail$Wire } from './Detail'; import { detailFromJSON, detailToJSON } from './Detail'; -export type OpenExternalEvent$Wire = Readonly> -& Readonly> -| Readonly> & Readonly>; +export type OpenExternalEvent$Wire = + | (Readonly> & Readonly>) + | (Readonly> & Readonly>); -export type OpenExternalEvent = Readonly> -& Readonly> -| Readonly> & Readonly>; +export type OpenExternalEvent = + | (Readonly> & Readonly>) + | (Readonly> & Readonly>); export function openExternalEventFromJSON(json: OpenExternalEvent$Wire): OpenExternalEvent { if (Object.prototype.hasOwnProperty.call(json, 'started')) { const contentValue = (json as Record<'started', Detail$Wire>)['started']; - const additionalProperties = Object.fromEntries(Object.entries(json).filter(([key]) => key !== 'started').map(([key, value]) => {const additionalValue = value; return [key, additionalValue] as const;})); - return {...additionalProperties,['started']: detailFromJSON(contentValue),}; + const additionalProperties = Object.fromEntries( + Object.entries(json) + .filter(([key]) => key !== 'started') + .map(([key, value]) => { + const additionalValue = value; + return [key, additionalValue] as const; + }), + ); + return { ...additionalProperties, ['started']: detailFromJSON(contentValue) }; } if (Object.prototype.hasOwnProperty.call(json, 'finished')) { const contentValue = (json as Record<'finished', Detail$Wire>)['finished']; - const additionalProperties = Object.fromEntries(Object.entries(json).filter(([key]) => key !== 'finished').map(([key, value]) => {const additionalValue = value; return [key, additionalValue] as const;})); - return {...additionalProperties,['finished']: detailFromJSON(contentValue),}; + const additionalProperties = Object.fromEntries( + Object.entries(json) + .filter(([key]) => key !== 'finished') + .map(([key, value]) => { + const additionalValue = value; + return [key, additionalValue] as const; + }), + ); + return { ...additionalProperties, ['finished']: detailFromJSON(contentValue) }; } throw new Error('Unknown variant'); } @@ -31,13 +45,27 @@ export function openExternalEventFromJSON(json: OpenExternalEvent$Wire): OpenExt export function openExternalEventToJSON(value: OpenExternalEvent): OpenExternalEvent$Wire { if (Object.prototype.hasOwnProperty.call(value, 'started')) { const contentValue = (value as Record<'started', Detail>)['started']; - const additionalProperties = Object.fromEntries(Object.entries(value).filter(([key]) => key !== 'started').map(([key, value]) => {const additionalValue = value; return [key, additionalValue] as const;})); - return {...additionalProperties,['started']: detailToJSON(contentValue),}; + const additionalProperties = Object.fromEntries( + Object.entries(value) + .filter(([key]) => key !== 'started') + .map(([key, value]) => { + const additionalValue = value; + return [key, additionalValue] as const; + }), + ); + return { ...additionalProperties, ['started']: detailToJSON(contentValue) }; } if (Object.prototype.hasOwnProperty.call(value, 'finished')) { const contentValue = (value as Record<'finished', Detail>)['finished']; - const additionalProperties = Object.fromEntries(Object.entries(value).filter(([key]) => key !== 'finished').map(([key, value]) => {const additionalValue = value; return [key, additionalValue] as const;})); - return {...additionalProperties,['finished']: detailToJSON(contentValue),}; + const additionalProperties = Object.fromEntries( + Object.entries(value) + .filter(([key]) => key !== 'finished') + .map(([key, value]) => { + const additionalValue = value; + return [key, additionalValue] as const; + }), + ); + return { ...additionalProperties, ['finished']: detailToJSON(contentValue) }; } throw new Error('Unknown variant'); } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/PlainJsonMap.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/PlainJsonMap.ts.golden index 96713a059..15836bd9f 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/PlainJsonMap.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/PlainJsonMap.ts.golden @@ -3,11 +3,9 @@ * * TypeScript additional property preservation — 1.0.0 */ -export interface PlainJsonMap$Wire extends Readonly> { -} +export interface PlainJsonMap$Wire extends Readonly> {} -export interface PlainJsonMap extends Readonly> { -} +export interface PlainJsonMap extends Readonly> {} export function plainJsonMapFromJSON(json: PlainJsonMap$Wire): PlainJsonMap { return json as unknown as PlainJsonMap; diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/PlainModelMap.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/PlainModelMap.ts.golden index 776841df4..2b1240cc6 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/PlainModelMap.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/PlainModelMap.ts.golden @@ -6,14 +6,19 @@ import type { Detail, Detail$Wire } from './Detail'; import { detailFromJSON, detailToJSON } from './Detail'; -export interface PlainModelMap$Wire extends Readonly> { -} +export interface PlainModelMap$Wire extends Readonly> {} -export interface PlainModelMap extends Readonly> { -} +export interface PlainModelMap extends Readonly> {} export function plainModelMapFromJSON(json: PlainModelMap$Wire): PlainModelMap { - const additionalProperties = Object.fromEntries(Object.entries(json).map(([key, value]) => {const additionalValue = value; return [key, detailFromJSON(additionalValue)] as const;})); + const sourceEntries = Object.entries(json); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value; + return [key, detailFromJSON(additionalValue)] as const; + }), + ); const result = { ...additionalProperties, }; @@ -21,7 +26,14 @@ export function plainModelMapFromJSON(json: PlainModelMap$Wire): PlainModelMap { } export function plainModelMapToJSON(value: PlainModelMap): PlainModelMap$Wire { - const additionalProperties = Object.fromEntries(Object.entries(value).map(([key, value]) => {const additionalValue = value; return [key, detailToJSON(additionalValue)] as const;})); + const sourceEntries = Object.entries(value); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value; + return [key, detailToJSON(additionalValue)] as const; + }), + ); const result = { ...additionalProperties, }; diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/PlainStringMap.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/PlainStringMap.ts.golden index 129d1b465..88d669479 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/PlainStringMap.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/PlainStringMap.ts.golden @@ -3,11 +3,9 @@ * * TypeScript additional property preservation — 1.0.0 */ -export interface PlainStringMap$Wire extends Readonly> { -} +export interface PlainStringMap$Wire extends Readonly> {} -export interface PlainStringMap extends Readonly> { -} +export interface PlainStringMap extends Readonly> {} export function plainStringMapFromJSON(json: PlainStringMap$Wire): PlainStringMap { return json as unknown as PlainStringMap; diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/QuotedMap.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/QuotedMap.ts.golden index 30481dff0..9f81958cc 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/QuotedMap.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/QuotedMap.ts.golden @@ -14,30 +14,66 @@ export interface QuotedMap extends Readonly> { } export function quotedMapFromJSON(json: QuotedMap$Wire): QuotedMap { - const additionalProperties = Object.fromEntries(Object.entries(json) - .filter(([key]) => !['__proto__', 'kebab-field'].includes(key)).map(([key, value]) => {const additionalValue = value; return [key, additionalValue] as const;})); + const sourceEntries = Object.entries(json).filter(([key]) => { + return !['__proto__', 'kebab-field'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value; + return [key, additionalValue] as const; + }), + ); + const visibleProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return !['proto', 'kebabField'].includes(key); + }), + ); const result = { - ...Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => !['proto', 'kebabField'].includes(key))), - ...(Object.prototype.hasOwnProperty.call(json, '__proto__') ? {proto: json['__proto__'],} : {}), - ...(Object.prototype.hasOwnProperty.call(json, 'kebab-field') ? {kebabField: json['kebab-field'],} : {}), + ...visibleProperties, + ...(Object.prototype.hasOwnProperty.call(json, '__proto__') + ? { proto: json['__proto__'] } + : {}), + ...(Object.prototype.hasOwnProperty.call(json, 'kebab-field') + ? { kebabField: json['kebab-field'] } + : {}), }; - const shadowedProperties = Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => ['proto', 'kebabField'].includes(key))); + const shadowedProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return ['proto', 'kebabField'].includes(key); + }), + ); if (Object.keys(shadowedProperties).length > 0) { - Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), {value: shadowedProperties, enumerable: true,}); + Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), { + value: shadowedProperties, + enumerable: true, + }); } return result; } export function quotedMapToJSON(value: QuotedMap): QuotedMap$Wire { - const retainedProperties = Object.getOwnPropertyDescriptor(value, Symbol.for('openapi-nexus.additionalProperties'))?.value as Record - | undefined; - const additionalProperties = Object.fromEntries(Object.entries({...Object.fromEntries(Object.entries(value) - .filter(([key]) => !['proto', 'kebabField'].includes(key))),...retainedProperties}).map(([key, value]) => {const additionalValue = value; return [key, additionalValue] as const;})); + const retainedProperties = Object.getOwnPropertyDescriptor( + value, + Symbol.for('openapi-nexus.additionalProperties'), + )?.value as Record | undefined; + const sourceEntries = Object.entries(value).filter(([key]) => { + return !['proto', 'kebabField'].includes(key); + }); + const sourceProperties = Object.fromEntries(sourceEntries); + const additionalEntries = Object.entries({ ...sourceProperties, ...retainedProperties }); + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value; + return [key, additionalValue] as const; + }), + ); const result = { ...additionalProperties, - ...(Object.prototype.hasOwnProperty.call(value, 'proto') ? {['__proto__']: value.proto,} : {}), - ...(Object.prototype.hasOwnProperty.call(value, 'kebabField') ? {'kebab-field': value.kebabField,} : {}), + ...(Object.prototype.hasOwnProperty.call(value, 'proto') ? { ['__proto__']: value.proto } : {}), + ...(Object.prototype.hasOwnProperty.call(value, 'kebabField') + ? { 'kebab-field': value.kebabField } + : {}), }; return result; } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/RecursiveMap.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/RecursiveMap.ts.golden index d055f79a0..c1ba603b9 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/RecursiveMap.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/RecursiveMap.ts.golden @@ -12,25 +12,55 @@ export interface RecursiveMap extends Readonly !['node_label'].includes(key)).map(([key, value]) => {const additionalValue = value as RecursiveMap$Wire; return [key, recursiveMapFromJSON(additionalValue)] as const;})); + const sourceEntries = Object.entries(json).filter(([key]) => { + return !['node_label'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as RecursiveMap$Wire; + return [key, recursiveMapFromJSON(additionalValue)] as const; + }), + ); + const visibleProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return !['nodeLabel'].includes(key); + }), + ); const result = { - ...Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => !['nodeLabel'].includes(key))), + ...visibleProperties, nodeLabel: json.node_label, }; - const shadowedProperties = Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => ['nodeLabel'].includes(key))); + const shadowedProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return ['nodeLabel'].includes(key); + }), + ); if (Object.keys(shadowedProperties).length > 0) { - Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), {value: shadowedProperties, enumerable: true,}); + Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), { + value: shadowedProperties, + enumerable: true, + }); } return result; } export function recursiveMapToJSON(value: RecursiveMap): RecursiveMap$Wire { - const retainedProperties = Object.getOwnPropertyDescriptor(value, Symbol.for('openapi-nexus.additionalProperties'))?.value as Record - | undefined; - const additionalProperties = Object.fromEntries(Object.entries({...Object.fromEntries(Object.entries(value) - .filter(([key]) => !['nodeLabel'].includes(key))),...retainedProperties}).map(([key, value]) => {const additionalValue = value as RecursiveMap; return [key, recursiveMapToJSON(additionalValue)] as const;})); + const retainedProperties = Object.getOwnPropertyDescriptor( + value, + Symbol.for('openapi-nexus.additionalProperties'), + )?.value as Record | undefined; + const sourceEntries = Object.entries(value).filter(([key]) => { + return !['nodeLabel'].includes(key); + }); + const sourceProperties = Object.fromEntries(sourceEntries); + const additionalEntries = Object.entries({ ...sourceProperties, ...retainedProperties }); + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as RecursiveMap; + return [key, recursiveMapToJSON(additionalValue)] as const; + }), + ); const result = { ...additionalProperties, node_label: value.nodeLabel, diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/RenamedMap.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/RenamedMap.ts.golden index 00ae8016f..e00cfd0a6 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/RenamedMap.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/RenamedMap.ts.golden @@ -14,30 +14,64 @@ export interface RenamedMap extends Readonly> { } export function renamedMapFromJSON(json: RenamedMap$Wire): RenamedMap { - const additionalProperties = Object.fromEntries(Object.entries(json) - .filter(([key]) => !['known_field', 'optional_field'].includes(key)).map(([key, value]) => {const additionalValue = value; return [key, additionalValue] as const;})); + const sourceEntries = Object.entries(json).filter(([key]) => { + return !['known_field', 'optional_field'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value; + return [key, additionalValue] as const; + }), + ); + const visibleProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return !['knownField', 'optionalField'].includes(key); + }), + ); const result = { - ...Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => !['knownField', 'optionalField'].includes(key))), + ...visibleProperties, knownField: json.known_field, - ...(Object.prototype.hasOwnProperty.call(json, 'optional_field') ? {optionalField: json.optional_field,} : {}), + ...(Object.prototype.hasOwnProperty.call(json, 'optional_field') + ? { optionalField: json.optional_field } + : {}), }; - const shadowedProperties = Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => ['knownField', 'optionalField'].includes(key))); + const shadowedProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return ['knownField', 'optionalField'].includes(key); + }), + ); if (Object.keys(shadowedProperties).length > 0) { - Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), {value: shadowedProperties, enumerable: true,}); + Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), { + value: shadowedProperties, + enumerable: true, + }); } return result; } export function renamedMapToJSON(value: RenamedMap): RenamedMap$Wire { - const retainedProperties = Object.getOwnPropertyDescriptor(value, Symbol.for('openapi-nexus.additionalProperties'))?.value as Record - | undefined; - const additionalProperties = Object.fromEntries(Object.entries({...Object.fromEntries(Object.entries(value) - .filter(([key]) => !['knownField', 'optionalField'].includes(key))),...retainedProperties}).map(([key, value]) => {const additionalValue = value; return [key, additionalValue] as const;})); + const retainedProperties = Object.getOwnPropertyDescriptor( + value, + Symbol.for('openapi-nexus.additionalProperties'), + )?.value as Record | undefined; + const sourceEntries = Object.entries(value).filter(([key]) => { + return !['knownField', 'optionalField'].includes(key); + }); + const sourceProperties = Object.fromEntries(sourceEntries); + const additionalEntries = Object.entries({ ...sourceProperties, ...retainedProperties }); + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value; + return [key, additionalValue] as const; + }), + ); const result = { ...additionalProperties, known_field: value.knownField, - ...(Object.prototype.hasOwnProperty.call(value, 'optionalField') ? {optional_field: value.optionalField,} : {}), + ...(Object.prototype.hasOwnProperty.call(value, 'optionalField') + ? { optional_field: value.optionalField } + : {}), }; return result; } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/SearchItem.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/SearchItem.ts.golden index 311dfebf4..470d0accf 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/SearchItem.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/SearchItem.ts.golden @@ -16,25 +16,41 @@ export interface SearchItem extends Readonly> { } export function searchItemFromJSON(json: SearchItem$Wire): SearchItem { - const additionalProperties = Object.fromEntries(Object.entries(json) - .filter(([key]) => !['id', 'status', 'type'].includes(key)).map(([key, value]) => {const additionalValue = value; return [key, additionalValue] as const;})); + const sourceEntries = Object.entries(json).filter(([key]) => { + return !['id', 'status', 'type'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value; + return [key, additionalValue] as const; + }), + ); const result = { ...additionalProperties, - ...(Object.prototype.hasOwnProperty.call(json, 'id') ? {id: json.id,} : {}), - ...(Object.prototype.hasOwnProperty.call(json, 'status') ? {status: json.status,} : {}), - 'type': json['type'], + ...(Object.prototype.hasOwnProperty.call(json, 'id') ? { id: json.id } : {}), + ...(Object.prototype.hasOwnProperty.call(json, 'status') ? { status: json.status } : {}), + type: json['type'], }; return result; } export function searchItemToJSON(value: SearchItem): SearchItem$Wire { - const additionalProperties = Object.fromEntries(Object.entries(value) - .filter(([key]) => !['id', 'status', 'type'].includes(key)).map(([key, value]) => {const additionalValue = value; return [key, additionalValue] as const;})); + const sourceEntries = Object.entries(value).filter(([key]) => { + return !['id', 'status', 'type'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value; + return [key, additionalValue] as const; + }), + ); const result = { ...additionalProperties, - ...(Object.prototype.hasOwnProperty.call(value, 'id') ? {id: value.id,} : {}), - ...(Object.prototype.hasOwnProperty.call(value, 'status') ? {status: value.status,} : {}), - 'type': value['type'], + ...(Object.prototype.hasOwnProperty.call(value, 'id') ? { id: value.id } : {}), + ...(Object.prototype.hasOwnProperty.call(value, 'status') ? { status: value.status } : {}), + type: value['type'], }; return result; } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/SearchStreamEvent.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/SearchStreamEvent.ts.golden index 6f333b6ea..e4a5a5e88 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/SearchStreamEvent.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/SearchStreamEvent.ts.golden @@ -3,23 +3,47 @@ * * TypeScript additional property preservation — 1.0.0 */ -import type { SearchStreamEventResponseWebSearchCallSearching, SearchStreamEventResponseWebSearchCallSearching$Wire } from './SearchStreamEventResponseWebSearchCallSearching'; -import { searchStreamEventResponseWebSearchCallSearchingFromJSON, searchStreamEventResponseWebSearchCallSearchingToJSON } from './SearchStreamEventResponseWebSearchCallSearching'; +import type { + SearchStreamEventResponseWebSearchCallSearching, + SearchStreamEventResponseWebSearchCallSearching$Wire, +} from './SearchStreamEventResponseWebSearchCallSearching'; +import { + searchStreamEventResponseWebSearchCallSearchingFromJSON, + searchStreamEventResponseWebSearchCallSearchingToJSON, +} from './SearchStreamEventResponseWebSearchCallSearching'; -export type SearchStreamEvent$Wire = ({ type: 'response.web_search_call.searching' } & SearchStreamEventResponseWebSearchCallSearching$Wire) | { type: 'response.completed' }; +export type SearchStreamEvent$Wire = + | ({ + type: 'response.web_search_call.searching'; + } & SearchStreamEventResponseWebSearchCallSearching$Wire) + | { type: 'response.completed' }; -export type SearchStreamEvent = ({ type: 'response.web_search_call.searching' } & SearchStreamEventResponseWebSearchCallSearching) | { type: 'response.completed' }; +export type SearchStreamEvent = + | ({ + type: 'response.web_search_call.searching'; + } & SearchStreamEventResponseWebSearchCallSearching) + | { type: 'response.completed' }; export function searchStreamEventFromJSON(json: SearchStreamEvent$Wire): SearchStreamEvent { switch (json.type) { - case 'response.web_search_call.searching': return { ...searchStreamEventResponseWebSearchCallSearchingFromJSON(json), type: 'response.web_search_call.searching' }; - case 'response.completed': return { type: 'response.completed' }; + case 'response.web_search_call.searching': + return { + ...searchStreamEventResponseWebSearchCallSearchingFromJSON(json), + type: 'response.web_search_call.searching', + }; + case 'response.completed': + return { type: 'response.completed' }; } } export function searchStreamEventToJSON(value: SearchStreamEvent): SearchStreamEvent$Wire { switch (value.type) { - case 'response.web_search_call.searching': return { ...searchStreamEventResponseWebSearchCallSearchingToJSON(value), type: 'response.web_search_call.searching' } as SearchStreamEvent$Wire; - case 'response.completed': return { type: 'response.completed' } as SearchStreamEvent$Wire; + case 'response.web_search_call.searching': + return { + ...searchStreamEventResponseWebSearchCallSearchingToJSON(value), + type: 'response.web_search_call.searching', + } as SearchStreamEvent$Wire; + case 'response.completed': + return { type: 'response.completed' } as SearchStreamEvent$Wire; } } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/SearchStreamEventResponseCompleted.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/SearchStreamEventResponseCompleted.ts.golden index c1479841c..d3be21bc1 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/SearchStreamEventResponseCompleted.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/SearchStreamEventResponseCompleted.ts.golden @@ -11,14 +11,18 @@ export interface SearchStreamEventResponseCompleted { readonly type: 'response.completed'; } -export function searchStreamEventResponseCompletedFromJSON(json: SearchStreamEventResponseCompleted$Wire): SearchStreamEventResponseCompleted { +export function searchStreamEventResponseCompletedFromJSON( + json: SearchStreamEventResponseCompleted$Wire, +): SearchStreamEventResponseCompleted { return { - 'type': json['type'], + type: json['type'], }; } -export function searchStreamEventResponseCompletedToJSON(value: SearchStreamEventResponseCompleted): SearchStreamEventResponseCompleted$Wire { +export function searchStreamEventResponseCompletedToJSON( + value: SearchStreamEventResponseCompleted, +): SearchStreamEventResponseCompleted$Wire { return { - 'type': value['type'], + type: value['type'], }; } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/SearchStreamEventResponseWebSearchCallSearching.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/SearchStreamEventResponseWebSearchCallSearching.ts.golden index 59efc8ca2..e99c2748f 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/SearchStreamEventResponseWebSearchCallSearching.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/SearchStreamEventResponseWebSearchCallSearching.ts.golden @@ -5,43 +5,79 @@ */ import type { AnyJsonValue } from './AnyJsonValue'; -export interface SearchStreamEventResponseWebSearchCallSearching$Wire extends Readonly> { +export interface SearchStreamEventResponseWebSearchCallSearching$Wire extends Readonly< + Record +> { readonly sequence_number: number; readonly type: 'response.web_search_call.searching'; } -export interface SearchStreamEventResponseWebSearchCallSearching extends Readonly> { +export interface SearchStreamEventResponseWebSearchCallSearching extends Readonly< + Record +> { readonly sequenceNumber: number; readonly type: 'response.web_search_call.searching'; } -export function searchStreamEventResponseWebSearchCallSearchingFromJSON(json: SearchStreamEventResponseWebSearchCallSearching$Wire): SearchStreamEventResponseWebSearchCallSearching { - const additionalProperties = Object.fromEntries(Object.entries(json) - .filter(([key]) => !['sequence_number', 'type'].includes(key)).map(([key, value]) => {const additionalValue = value; return [key, additionalValue] as const;})); +export function searchStreamEventResponseWebSearchCallSearchingFromJSON( + json: SearchStreamEventResponseWebSearchCallSearching$Wire, +): SearchStreamEventResponseWebSearchCallSearching { + const sourceEntries = Object.entries(json).filter(([key]) => { + return !['sequence_number', 'type'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value; + return [key, additionalValue] as const; + }), + ); + const visibleProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return !['sequenceNumber', 'type'].includes(key); + }), + ); const result = { - ...Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => !['sequenceNumber', 'type'].includes(key))), + ...visibleProperties, sequenceNumber: json.sequence_number, - 'type': json['type'], + type: json['type'], }; - const shadowedProperties = Object.fromEntries(Object.entries(additionalProperties).filter(([key]) => ['sequenceNumber', 'type'].includes(key))); + const shadowedProperties = Object.fromEntries( + Object.entries(additionalProperties).filter(([key]) => { + return ['sequenceNumber', 'type'].includes(key); + }), + ); if (Object.keys(shadowedProperties).length > 0) { - Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), {value: shadowedProperties, enumerable: true,}); + Object.defineProperty(result, Symbol.for('openapi-nexus.additionalProperties'), { + value: shadowedProperties, + enumerable: true, + }); } return result; } -export function searchStreamEventResponseWebSearchCallSearchingToJSON(value: SearchStreamEventResponseWebSearchCallSearching): SearchStreamEventResponseWebSearchCallSearching$Wire { - const retainedProperties = Object.getOwnPropertyDescriptor(value, Symbol.for('openapi-nexus.additionalProperties'))?.value as Record - | undefined; - const additionalProperties = Object.fromEntries(Object.entries({...Object.fromEntries(Object.entries(value) - .filter(([key]) => !['sequenceNumber', 'type'].includes(key))),...retainedProperties}).map(([key, value]) => {const additionalValue = value; return [key, additionalValue] as const;})); +export function searchStreamEventResponseWebSearchCallSearchingToJSON( + value: SearchStreamEventResponseWebSearchCallSearching, +): SearchStreamEventResponseWebSearchCallSearching$Wire { + const retainedProperties = Object.getOwnPropertyDescriptor( + value, + Symbol.for('openapi-nexus.additionalProperties'), + )?.value as Record | undefined; + const sourceEntries = Object.entries(value).filter(([key]) => { + return !['sequenceNumber', 'type'].includes(key); + }); + const sourceProperties = Object.fromEntries(sourceEntries); + const additionalEntries = Object.entries({ ...sourceProperties, ...retainedProperties }); + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value; + return [key, additionalValue] as const; + }), + ); const result = { ...additionalProperties, sequence_number: value.sequenceNumber, - 'type': value['type'], + type: value['type'], }; return result; } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/TypedExternalEvent.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/TypedExternalEvent.ts.golden index f6a657afe..723dd2ce9 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/TypedExternalEvent.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/TypedExternalEvent.ts.golden @@ -6,25 +6,40 @@ import type { DetailAliasChain, DetailAliasChain$Wire } from './DetailAliasChain'; import { detailAliasChainFromJSON, detailAliasChainToJSON } from './DetailAliasChain'; -export type TypedExternalEvent$Wire = Readonly> -& Readonly> -| Readonly> -& Readonly>; +export type TypedExternalEvent$Wire = + | (Readonly> & + Readonly>) + | (Readonly> & + Readonly>); -export type TypedExternalEvent = Readonly> -& Readonly> -| Readonly> & Readonly>; +export type TypedExternalEvent = + | (Readonly> & Readonly>) + | (Readonly> & Readonly>); export function typedExternalEventFromJSON(json: TypedExternalEvent$Wire): TypedExternalEvent { if (Object.prototype.hasOwnProperty.call(json, 'started')) { const contentValue = (json as Record<'started', DetailAliasChain$Wire>)['started']; - const additionalProperties = Object.fromEntries(Object.entries(json).filter(([key]) => key !== 'started').map(([key, value]) => {const additionalValue = value as DetailAliasChain$Wire; return [key, detailAliasChainFromJSON(additionalValue)] as const;})); - return {...additionalProperties,['started']: detailAliasChainFromJSON(contentValue),}; + const additionalProperties = Object.fromEntries( + Object.entries(json) + .filter(([key]) => key !== 'started') + .map(([key, value]) => { + const additionalValue = value as DetailAliasChain$Wire; + return [key, detailAliasChainFromJSON(additionalValue)] as const; + }), + ); + return { ...additionalProperties, ['started']: detailAliasChainFromJSON(contentValue) }; } if (Object.prototype.hasOwnProperty.call(json, 'finished')) { const contentValue = (json as Record<'finished', DetailAliasChain$Wire>)['finished']; - const additionalProperties = Object.fromEntries(Object.entries(json).filter(([key]) => key !== 'finished').map(([key, value]) => {const additionalValue = value as DetailAliasChain$Wire; return [key, detailAliasChainFromJSON(additionalValue)] as const;})); - return {...additionalProperties,['finished']: detailAliasChainFromJSON(contentValue),}; + const additionalProperties = Object.fromEntries( + Object.entries(json) + .filter(([key]) => key !== 'finished') + .map(([key, value]) => { + const additionalValue = value as DetailAliasChain$Wire; + return [key, detailAliasChainFromJSON(additionalValue)] as const; + }), + ); + return { ...additionalProperties, ['finished']: detailAliasChainFromJSON(contentValue) }; } throw new Error('Unknown variant'); } @@ -32,13 +47,27 @@ export function typedExternalEventFromJSON(json: TypedExternalEvent$Wire): Typed export function typedExternalEventToJSON(value: TypedExternalEvent): TypedExternalEvent$Wire { if (Object.prototype.hasOwnProperty.call(value, 'started')) { const contentValue = (value as Record<'started', DetailAliasChain>)['started']; - const additionalProperties = Object.fromEntries(Object.entries(value).filter(([key]) => key !== 'started').map(([key, value]) => {const additionalValue = value as DetailAliasChain; return [key, detailAliasChainToJSON(additionalValue)] as const;})); - return {...additionalProperties,['started']: detailAliasChainToJSON(contentValue),}; + const additionalProperties = Object.fromEntries( + Object.entries(value) + .filter(([key]) => key !== 'started') + .map(([key, value]) => { + const additionalValue = value as DetailAliasChain; + return [key, detailAliasChainToJSON(additionalValue)] as const; + }), + ); + return { ...additionalProperties, ['started']: detailAliasChainToJSON(contentValue) }; } if (Object.prototype.hasOwnProperty.call(value, 'finished')) { const contentValue = (value as Record<'finished', DetailAliasChain>)['finished']; - const additionalProperties = Object.fromEntries(Object.entries(value).filter(([key]) => key !== 'finished').map(([key, value]) => {const additionalValue = value as DetailAliasChain; return [key, detailAliasChainToJSON(additionalValue)] as const;})); - return {...additionalProperties,['finished']: detailAliasChainToJSON(contentValue),}; + const additionalProperties = Object.fromEntries( + Object.entries(value) + .filter(([key]) => key !== 'finished') + .map(([key, value]) => { + const additionalValue = value as DetailAliasChain; + return [key, detailAliasChainToJSON(additionalValue)] as const; + }), + ); + return { ...additionalProperties, ['finished']: detailAliasChainToJSON(contentValue) }; } throw new Error('Unknown variant'); } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/index.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/index.ts.golden index 344137577..4476a1421 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/index.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/models/index.ts.golden @@ -11,16 +11,31 @@ export type { AliasNullableMap, AliasNullableMap$Wire } from './AliasNullableMap export { aliasNullableMapFromJSON, aliasNullableMapToJSON } from './AliasNullableMap'; export type { AllOfJsonDictionary, AllOfJsonDictionary$Wire } from './AllOfJsonDictionary'; export { allOfJsonDictionaryFromJSON, allOfJsonDictionaryToJSON } from './AllOfJsonDictionary'; -export type { AllOfJsonDictionaryAllOf1, AllOfJsonDictionaryAllOf1$Wire } from './AllOfJsonDictionaryAllOf1'; -export { allOfJsonDictionaryAllOf1FromJSON, allOfJsonDictionaryAllOf1ToJSON } from './AllOfJsonDictionaryAllOf1'; +export type { + AllOfJsonDictionaryAllOf1, + AllOfJsonDictionaryAllOf1$Wire, +} from './AllOfJsonDictionaryAllOf1'; +export { + allOfJsonDictionaryAllOf1FromJSON, + allOfJsonDictionaryAllOf1ToJSON, +} from './AllOfJsonDictionaryAllOf1'; export type { AllOfMixedStringMap, AllOfMixedStringMap$Wire } from './AllOfMixedStringMap'; export { allOfMixedStringMapFromJSON, allOfMixedStringMapToJSON } from './AllOfMixedStringMap'; -export type { AllOfMixedStringMapAllOf1, AllOfMixedStringMapAllOf1$Wire } from './AllOfMixedStringMapAllOf1'; -export { allOfMixedStringMapAllOf1FromJSON, allOfMixedStringMapAllOf1ToJSON } from './AllOfMixedStringMapAllOf1'; +export type { + AllOfMixedStringMapAllOf1, + AllOfMixedStringMapAllOf1$Wire, +} from './AllOfMixedStringMapAllOf1'; +export { + allOfMixedStringMapAllOf1FromJSON, + allOfMixedStringMapAllOf1ToJSON, +} from './AllOfMixedStringMapAllOf1'; export type { AllOfRenamedMap, AllOfRenamedMap$Wire } from './AllOfRenamedMap'; export { allOfRenamedMapFromJSON, allOfRenamedMapToJSON } from './AllOfRenamedMap'; export type { AllOfRenamedMapAllOf2, AllOfRenamedMapAllOf2$Wire } from './AllOfRenamedMapAllOf2'; -export { allOfRenamedMapAllOf2FromJSON, allOfRenamedMapAllOf2ToJSON } from './AllOfRenamedMapAllOf2'; +export { + allOfRenamedMapAllOf2FromJSON, + allOfRenamedMapAllOf2ToJSON, +} from './AllOfRenamedMapAllOf2'; export type { AnyJsonValue } from './AnyJsonValue'; export type { ArrayModelMap, ArrayModelMap$Wire } from './ArrayModelMap'; export { arrayModelMapFromJSON, arrayModelMapToJSON } from './ArrayModelMap'; @@ -38,10 +53,22 @@ export type { DetailListAlias, DetailListAlias$Wire } from './DetailListAlias'; export { detailListAliasFromJSON, detailListAliasToJSON } from './DetailListAlias'; export type { HeterogeneousAllOf, HeterogeneousAllOf$Wire } from './HeterogeneousAllOf'; export { heterogeneousAllOfFromJSON, heterogeneousAllOfToJSON } from './HeterogeneousAllOf'; -export type { HeterogeneousAllOfAllOf1, HeterogeneousAllOfAllOf1$Wire } from './HeterogeneousAllOfAllOf1'; -export { heterogeneousAllOfAllOf1FromJSON, heterogeneousAllOfAllOf1ToJSON } from './HeterogeneousAllOfAllOf1'; -export type { HeterogeneousAllOfAllOf2, HeterogeneousAllOfAllOf2$Wire } from './HeterogeneousAllOfAllOf2'; -export { heterogeneousAllOfAllOf2FromJSON, heterogeneousAllOfAllOf2ToJSON } from './HeterogeneousAllOfAllOf2'; +export type { + HeterogeneousAllOfAllOf1, + HeterogeneousAllOfAllOf1$Wire, +} from './HeterogeneousAllOfAllOf1'; +export { + heterogeneousAllOfAllOf1FromJSON, + heterogeneousAllOfAllOf1ToJSON, +} from './HeterogeneousAllOfAllOf1'; +export type { + HeterogeneousAllOfAllOf2, + HeterogeneousAllOfAllOf2$Wire, +} from './HeterogeneousAllOfAllOf2'; +export { + heterogeneousAllOfAllOf2FromJSON, + heterogeneousAllOfAllOf2ToJSON, +} from './HeterogeneousAllOfAllOf2'; export type { JsonModelAllOf, JsonModelAllOf$Wire } from './JsonModelAllOf'; export { jsonModelAllOfFromJSON, jsonModelAllOfToJSON } from './JsonModelAllOf'; export type { JsonModelAllOfAllOf1, JsonModelAllOfAllOf1$Wire } from './JsonModelAllOfAllOf1'; @@ -90,9 +117,21 @@ export type { SearchItem, SearchItem$Wire } from './SearchItem'; export { searchItemFromJSON, searchItemToJSON } from './SearchItem'; export type { SearchStreamEvent, SearchStreamEvent$Wire } from './SearchStreamEvent'; export { searchStreamEventFromJSON, searchStreamEventToJSON } from './SearchStreamEvent'; -export type { SearchStreamEventResponseCompleted, SearchStreamEventResponseCompleted$Wire } from './SearchStreamEventResponseCompleted'; -export { searchStreamEventResponseCompletedFromJSON, searchStreamEventResponseCompletedToJSON } from './SearchStreamEventResponseCompleted'; -export type { SearchStreamEventResponseWebSearchCallSearching, SearchStreamEventResponseWebSearchCallSearching$Wire } from './SearchStreamEventResponseWebSearchCallSearching'; -export { searchStreamEventResponseWebSearchCallSearchingFromJSON, searchStreamEventResponseWebSearchCallSearchingToJSON } from './SearchStreamEventResponseWebSearchCallSearching'; +export type { + SearchStreamEventResponseCompleted, + SearchStreamEventResponseCompleted$Wire, +} from './SearchStreamEventResponseCompleted'; +export { + searchStreamEventResponseCompletedFromJSON, + searchStreamEventResponseCompletedToJSON, +} from './SearchStreamEventResponseCompleted'; +export type { + SearchStreamEventResponseWebSearchCallSearching, + SearchStreamEventResponseWebSearchCallSearching$Wire, +} from './SearchStreamEventResponseWebSearchCallSearching'; +export { + searchStreamEventResponseWebSearchCallSearchingFromJSON, + searchStreamEventResponseWebSearchCallSearchingToJSON, +} from './SearchStreamEventResponseWebSearchCallSearching'; export type { TypedExternalEvent, TypedExternalEvent$Wire } from './TypedExternalEvent'; export { typedExternalEventFromJSON, typedExternalEventToJSON } from './TypedExternalEvent'; diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/package.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/package.json.golden index 2b0acc16a..b2e998ea8 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/package.json.golden @@ -1,31 +1,32 @@ { + "name": "type-script-additional-property-preservation", + "version": "1.0.0", "description": "TypeScript client for TypeScript additional property preservation", - "devDependencies": { - "typescript": "^7.0.2", - "vite-plus": "^1.5.0" - }, + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.mjs", + "types": "./dist/index.d.mts", "exports": { ".": { "default": "./dist/index.mjs", "types": "./dist/index.d.mts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.mjs", - "name": "type-script-additional-property-preservation", "scripts": { "build": "vp pack", - "check": "vp check --no-fmt" + "check": "vp check", + "fmt": "vp fmt" }, - "type": "module", - "types": "./dist/index.d.mts", - "version": "1.0.0" -} \ No newline at end of file + "devDependencies": { + "typescript": "^7.0.2", + "vite-plus": "^1.5.0" + } +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/runtime/runtime.ts.golden index 800ffc9dd..d7c637a44 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/runtime/runtime.ts.golden @@ -3,7 +3,7 @@ * * TypeScript additional property preservation — 1.0.0 */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -13,7 +13,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -92,8 +95,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -135,12 +140,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -150,7 +161,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -166,9 +177,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -183,13 +192,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -199,7 +210,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -209,10 +220,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -221,18 +233,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -240,16 +256,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -268,11 +285,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -282,7 +299,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -292,7 +309,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -306,12 +323,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -329,15 +364,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -413,16 +461,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -449,7 +587,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -476,7 +617,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -486,5 +627,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/vite.config.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/vite.config.ts.golden index 250639b98..065569dd3 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/vite.config.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-additional-properties/vite.config.ts.golden @@ -1,6 +1,10 @@ import { defineConfig } from 'vite-plus'; export default defineConfig({ + fmt: { + singleQuote: true, + ignorePatterns: ['dist/**'], + }, lint: { options: { typeAware: true, diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-enum-ref/README.md.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-enum-ref/README.md.golden index 6fbe7e6ce..610b5b809 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-enum-ref/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-enum-ref/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'interface-with-enum-reference-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'interface-with-enum-reference-test const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-enum-ref/package.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-enum-ref/package.json.golden index 3365d12ea..9ae346ee9 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-enum-ref/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-enum-ref/package.json.golden @@ -1,26 +1,26 @@ { + "name": "interface-with-enum-reference-test", + "version": "1.0.0", "description": "Test case for interfaces that reference enum types", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "interface-with-enum-reference-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-enum-ref/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-enum-ref/runtime/runtime.ts.golden index c23d8f45b..e3b7205d3 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-enum-ref/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-enum-ref/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Interface with Enum Reference Test — 1.0.0 * Test case for interfaces that reference enum types */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-enum-ref/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-enum-ref/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-enum-ref/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-enum-ref/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-enum-ref/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-enum-ref/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-enum-ref/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-enum-ref/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-externally-tagged/README.md.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-externally-tagged/README.md.golden index d5a70a9d1..682d20b50 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-externally-tagged/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-externally-tagged/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'externally-tagged-union-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'externally-tagged-union-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-externally-tagged/models/ExternallyTaggedEnum.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-externally-tagged/models/ExternallyTaggedEnum.ts.golden index 3d1ee9607..f3e9d16b5 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-externally-tagged/models/ExternallyTaggedEnum.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-externally-tagged/models/ExternallyTaggedEnum.ts.golden @@ -11,18 +11,22 @@ import { variantBFromJSON, variantBToJSON } from './VariantB'; /** Externally tagged enum where the key determines the variant */ -export type ExternallyTaggedEnum$Wire = { 'EXTERNALLY_TAGGED_VARIANT_A': VariantA$Wire } | { 'EXTERNALLY_TAGGED_VARIANT_B': VariantB$Wire }; +export type ExternallyTaggedEnum$Wire = + | { EXTERNALLY_TAGGED_VARIANT_A: VariantA$Wire } + | { EXTERNALLY_TAGGED_VARIANT_B: VariantB$Wire }; -export type ExternallyTaggedEnum = { 'EXTERNALLY_TAGGED_VARIANT_A': VariantA } | { 'EXTERNALLY_TAGGED_VARIANT_B': VariantB }; +export type ExternallyTaggedEnum = + | { EXTERNALLY_TAGGED_VARIANT_A: VariantA } + | { EXTERNALLY_TAGGED_VARIANT_B: VariantB }; export function externallyTaggedEnumFromJSON(json: ExternallyTaggedEnum$Wire): ExternallyTaggedEnum { - if ('EXTERNALLY_TAGGED_VARIANT_A' in json) return { 'EXTERNALLY_TAGGED_VARIANT_A': variantAFromJSON(json['EXTERNALLY_TAGGED_VARIANT_A']) }; - if ('EXTERNALLY_TAGGED_VARIANT_B' in json) return { 'EXTERNALLY_TAGGED_VARIANT_B': variantBFromJSON(json['EXTERNALLY_TAGGED_VARIANT_B']) }; + if ('EXTERNALLY_TAGGED_VARIANT_A' in json) return { EXTERNALLY_TAGGED_VARIANT_A: variantAFromJSON(json['EXTERNALLY_TAGGED_VARIANT_A']) }; + if ('EXTERNALLY_TAGGED_VARIANT_B' in json) return { EXTERNALLY_TAGGED_VARIANT_B: variantBFromJSON(json['EXTERNALLY_TAGGED_VARIANT_B']) }; throw new Error('Unknown variant'); } export function externallyTaggedEnumToJSON(value: ExternallyTaggedEnum): ExternallyTaggedEnum$Wire { - if ('EXTERNALLY_TAGGED_VARIANT_A' in value) return { 'EXTERNALLY_TAGGED_VARIANT_A': variantAToJSON(value['EXTERNALLY_TAGGED_VARIANT_A']) }; - if ('EXTERNALLY_TAGGED_VARIANT_B' in value) return { 'EXTERNALLY_TAGGED_VARIANT_B': variantBToJSON(value['EXTERNALLY_TAGGED_VARIANT_B']) }; + if ('EXTERNALLY_TAGGED_VARIANT_A' in value) return { EXTERNALLY_TAGGED_VARIANT_A: variantAToJSON(value['EXTERNALLY_TAGGED_VARIANT_A']) }; + if ('EXTERNALLY_TAGGED_VARIANT_B' in value) return { EXTERNALLY_TAGGED_VARIANT_B: variantBToJSON(value['EXTERNALLY_TAGGED_VARIANT_B']) }; throw new Error('Unknown variant'); } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-externally-tagged/package.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-externally-tagged/package.json.golden index 6b3bbaa52..b3faa6c7e 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-externally-tagged/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-externally-tagged/package.json.golden @@ -1,26 +1,26 @@ { + "name": "externally-tagged-union-test", + "version": "1.0.0", "description": "Test case for externally-tagged discriminated unions with camelCase property naming", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "externally-tagged-union-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-externally-tagged/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-externally-tagged/runtime/runtime.ts.golden index c1321a10d..691a03844 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-externally-tagged/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-externally-tagged/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Externally Tagged Union Test — 1.0.0 * Test case for externally-tagged discriminated unions with camelCase property naming */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-externally-tagged/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-externally-tagged/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-externally-tagged/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-externally-tagged/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-externally-tagged/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-externally-tagged/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-externally-tagged/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-externally-tagged/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection-enum-ref/README.md.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection-enum-ref/README.md.golden index 8cff6fd0e..dede20db4 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection-enum-ref/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection-enum-ref/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'intersection-with-enum-reference-test const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'intersection-with-enum-reference-t const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection-enum-ref/package.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection-enum-ref/package.json.golden index 5c8d165c1..7ae6ec358 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection-enum-ref/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection-enum-ref/package.json.golden @@ -1,26 +1,26 @@ { + "name": "intersection-with-enum-reference-test", + "version": "1.0.0", "description": "Test case for allOf intersections mixing objects and enums", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "intersection-with-enum-reference-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection-enum-ref/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection-enum-ref/runtime/runtime.ts.golden index ca3b517c4..1c5eaf560 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection-enum-ref/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection-enum-ref/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Intersection with Enum Reference Test — 1.0.0 * Test case for allOf intersections mixing objects and enums */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection-enum-ref/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection-enum-ref/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection-enum-ref/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection-enum-ref/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection-enum-ref/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection-enum-ref/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection-enum-ref/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection-enum-ref/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection/README.md.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection/README.md.golden index 5e63e36ae..d8a69f807 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'intersection-type-all-of-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'intersection-type-all-of-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection/apis/DefaultApi.ts.golden index d9ed56d4b..34d226b51 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection/apis/DefaultApi.ts.golden @@ -6,36 +6,57 @@ */ import type { Foo, Foo$Wire } from '../models/Foo'; import { fooFromJSON, fooToJSON } from '../models/Foo'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, +} from '../runtime/runtime'; export interface ApiTestIntersectionRequest { body: Foo; } export type TestIntersectionRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); - -export type TestIntersectionErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestIntersectionErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestIntersectionError extends ResponseError { readonly detail: TestIntersectionErrorDetail; - constructor(response: Response, detail: TestIntersectionErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestIntersectionErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - testIntersectionRaw: (requestParameters: ApiTestIntersectionRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - testIntersection: (requestParameters: ApiTestIntersectionRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + testIntersectionRaw: ( + requestParameters: ApiTestIntersectionRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + testIntersection: ( + requestParameters: ApiTestIntersectionRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class DefaultApi extends BaseAPI implements DefaultApiInterface { @@ -46,12 +67,14 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async testIntersectionRaw(requestParameters: ApiTestIntersectionRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async testIntersectionRaw( + requestParameters: ApiTestIntersectionRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling testIntersectionRaw().' + 'Required parameter "body" was null or undefined when calling testIntersectionRaw().', ); } // Build path with path parameters @@ -66,33 +89,47 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = fooToJSON(requestParameters.body); // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestIntersectionError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestIntersectionError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response, (json) => fooFromJSON(json as Foo$Wire)) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response, (json) => { + return fooFromJSON(json as Foo$Wire); + }) as JSONApiResponse & { status: 200 }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async testIntersection(requestParameters: ApiTestIntersectionRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async testIntersection( + requestParameters: ApiTestIntersectionRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.testIntersectionRaw(requestParameters, initOverrides); - return await response.value() as Foo; + return (await response.value()) as Foo; } } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection/package.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection/package.json.golden index b416967ec..68c4d847f 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection/package.json.golden @@ -1,26 +1,26 @@ { + "name": "intersection-type-all-of-test", + "version": "1.0.0", "description": "Test fixture for allOf intersection types", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "intersection-type-all-of-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection/runtime/runtime.ts.golden index 5ea10eca4..d661eff77 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Intersection Type (allOf) Test — 1.0.0 * Test fixture for allOf intersection types */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-intersection/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-multipart-parts/README.md.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-multipart-parts/README.md.golden index 031134492..a8bce99c3 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-multipart-parts/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-multipart-parts/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, MultipartApi } from 'multipart-nested-object-parts'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'multipart-nested-object-parts'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-multipart-parts/apis/MultipartApi.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-multipart-parts/apis/MultipartApi.ts.golden index 3ffc789fb..a51c214dc 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-multipart-parts/apis/MultipartApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-multipart-parts/apis/MultipartApi.ts.golden @@ -6,36 +6,60 @@ */ import { itemConfigToJSON } from '../models/ItemConfig'; import type { SendNestedObjectPartMultipartRequestBody } from '../models/SendNestedObjectPartMultipartRequestBody'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, RequiredError, ResponseError, VoidApiResponse, multipartHeaderValue, uploadFileData, uploadFileFilename } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + RequiredError, + ResponseError, + VoidApiResponse, + multipartHeaderValue, + uploadFileData, + uploadFileFilename, +} from '../runtime/runtime'; export interface ApiSendNestedObjectPartRequest { body: SendNestedObjectPartMultipartRequestBody; } export type SendNestedObjectPartRawResponse = - | VoidApiResponse & { status: 204 } - | VoidApiResponse & HttpSuccessResponse; + | (VoidApiResponse & { status: 204 }) + | (VoidApiResponse & HttpSuccessResponse); - -export type SendNestedObjectPartErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type SendNestedObjectPartErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class SendNestedObjectPartError extends ResponseError { readonly detail: SendNestedObjectPartErrorDetail; - constructor(response: Response, detail: SendNestedObjectPartErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: SendNestedObjectPartErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface MultipartApiInterface { - sendNestedObjectPartRaw: (requestParameters: ApiSendNestedObjectPartRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - sendNestedObjectPart: (requestParameters: ApiSendNestedObjectPartRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + sendNestedObjectPartRaw: ( + requestParameters: ApiSendNestedObjectPartRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + sendNestedObjectPart: ( + requestParameters: ApiSendNestedObjectPartRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class MultipartApi extends BaseAPI implements MultipartApiInterface { @@ -46,12 +70,14 @@ export class MultipartApi extends BaseAPI implements MultipartApiInterface { super(configuration ?? DefaultConfig); } - async sendNestedObjectPartRaw(requestParameters: ApiSendNestedObjectPartRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async sendNestedObjectPartRaw( + requestParameters: ApiSendNestedObjectPartRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling sendNestedObjectPartRaw().' + 'Required parameter "body" was null or undefined when calling sendNestedObjectPartRaw().', ); } // Build path with path parameters @@ -59,8 +85,7 @@ export class MultipartApi extends BaseAPI implements MultipartApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Prepare request body const multipartBoundary = '----openapi-nexus-' + Math.random().toString(16).slice(2); @@ -78,32 +103,44 @@ export class MultipartApi extends BaseAPI implements MultipartApiInterface { multipartChunks.push('--' + multipartBoundary + '--\r\n'); const requestBody = new Blob(multipartChunks); // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new SendNestedObjectPartError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new SendNestedObjectPartError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 204) { return new VoidApiResponse(response) as VoidApiResponse & { status: 204 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async sendNestedObjectPart(requestParameters: ApiSendNestedObjectPartRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async sendNestedObjectPart( + requestParameters: ApiSendNestedObjectPartRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.sendNestedObjectPartRaw(requestParameters, initOverrides); return await response.value(); } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-multipart-parts/package.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-multipart-parts/package.json.golden index adfcebda6..c20db5337 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-multipart-parts/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-multipart-parts/package.json.golden @@ -1,26 +1,26 @@ { + "name": "multipart-nested-object-parts", + "version": "1.0.0", "description": "Covers multipart object parts whose wire names differ from ergonomic names.", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "multipart-nested-object-parts", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-multipart-parts/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-multipart-parts/runtime/runtime.ts.golden index af4ec2675..1b4f8c0d8 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-multipart-parts/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-multipart-parts/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Multipart Nested Object Parts — 1.0.0 * Covers multipart object parts whose wire names differ from ergonomic names. */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -126,8 +129,10 @@ function isFile(value: UploadFileInput): value is File { * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -169,12 +174,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -184,7 +195,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -200,9 +211,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -217,13 +226,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -233,7 +244,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -243,10 +254,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -255,18 +267,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -274,16 +290,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -302,11 +319,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -316,7 +333,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -326,7 +343,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -340,12 +357,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -363,15 +398,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -447,16 +495,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -483,7 +621,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -510,7 +651,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -520,5 +661,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-multipart-parts/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-multipart-parts/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-multipart-parts/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-multipart-parts/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-multipart-parts/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-multipart-parts/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-multipart-parts/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-multipart-parts/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-dispatch/README.md.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-dispatch/README.md.golden index 3e33d7b90..4c7c1e7fc 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-dispatch/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-dispatch/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, ResponsesApi } from 'type-script-response-dispatch'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'type-script-response-dispatch'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-dispatch/apis/ResponsesApi.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-dispatch/apis/ResponsesApi.ts.golden index 96110e106..51cb5a497 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-dispatch/apis/ResponsesApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-dispatch/apis/ResponsesApi.ts.golden @@ -5,124 +5,230 @@ */ import type { Detail, Detail$Wire } from '../models/Detail'; import { detailFromJSON } from '../models/Detail'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, BlobApiResponse, DefaultConfig, JSONApiResponse, ResponseError, TextApiResponse, VoidApiResponse } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + BlobApiResponse, + DefaultConfig, + JSONApiResponse, + ResponseError, + TextApiResponse, + VoidApiResponse, +} from '../runtime/runtime'; export type ReadDefaultRawResponse = VoidApiResponse & HttpSuccessResponse; - export type ReadErrorOnlyRawResponse = VoidApiResponse & HttpSuccessResponse; - export type ReadMixedRawResponse = - | JSONApiResponse & { status: 201 } - | TextApiResponse & { status: 202 } - | VoidApiResponse & { status: 204 } - | BlobApiResponse & { status: 206 } - | JSONApiResponse & { status: number } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 201 }) + | (TextApiResponse & { status: 202 }) + | (VoidApiResponse & { status: 204 }) + | (BlobApiResponse & { status: 206 }) + | (JSONApiResponse & { status: number }) + | (JSONApiResponse & HttpSuccessResponse); export type ReadSuccessOnlyRawResponse = - | VoidApiResponse & { status: 204 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 204 }) + | (VoidApiResponse & HttpSuccessResponse); export type ReadWildcardsRawResponse = - | VoidApiResponse & { status: number } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: number }) + | (VoidApiResponse & HttpSuccessResponse); export type ReadDefaultErrorDetail = - { kind: 'default'; status: number; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'default'; + status: number; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class ReadDefaultError extends ResponseError { readonly detail: ReadDefaultErrorDetail; - constructor(response: Response, detail: ReadDefaultErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: ReadDefaultErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type ReadErrorOnlyErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class ReadErrorOnlyError extends ResponseError { readonly detail: ReadErrorOnlyErrorDetail; - constructor(response: Response, detail: ReadErrorOnlyErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: ReadErrorOnlyErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type ReadMixedErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unauthorized'; status: 401; raw: Response; value(): Promise } - | { kind: 'conflict'; status: 409; raw: Response; value(): Promise } - | { kind: 'status410'; status: 410; raw: Response; value(): Promise } - | { kind: 'status415'; status: 415; raw: Response; value(): Promise } - | { kind: 'serverError'; status: number; raw: Response; value(): Promise } - | { kind: 'default'; status: number; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unauthorized'; + status: 401; + raw: Response; + value(): Promise; + } + | { + kind: 'conflict'; + status: 409; + raw: Response; + value(): Promise; + } + | { + kind: 'status410'; + status: 410; + raw: Response; + value(): Promise; + } + | { + kind: 'status415'; + status: 415; + raw: Response; + value(): Promise; + } + | { + kind: 'serverError'; + status: number; + raw: Response; + value(): Promise; + } + | { + kind: 'default'; + status: number; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class ReadMixedError extends ResponseError { readonly detail: ReadMixedErrorDetail; - constructor(response: Response, detail: ReadMixedErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: ReadMixedErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type ReadSuccessOnlyErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type ReadSuccessOnlyErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class ReadSuccessOnlyError extends ResponseError { readonly detail: ReadSuccessOnlyErrorDetail; - constructor(response: Response, detail: ReadSuccessOnlyErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: ReadSuccessOnlyErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type ReadWildcardsErrorDetail = - { kind: 'clientError'; status: number; raw: Response; value(): Promise } - | { kind: 'serverError'; status: number; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'clientError'; + status: number; + raw: Response; + value(): Promise; + } + | { + kind: 'serverError'; + status: number; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class ReadWildcardsError extends ResponseError { readonly detail: ReadWildcardsErrorDetail; - constructor(response: Response, detail: ReadWildcardsErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: ReadWildcardsErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface ResponsesApiInterface { - readDefaultRaw: (initOverrides?: RequestInit - | InitOverrideFunction) => Promise; + readDefaultRaw: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; readDefault: (initOverrides?: RequestInit | InitOverrideFunction) => Promise; - readErrorOnlyRaw: (initOverrides?: RequestInit - | InitOverrideFunction) => Promise; + readErrorOnlyRaw: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; readErrorOnly: (initOverrides?: RequestInit | InitOverrideFunction) => Promise; - readMixedRaw: (initOverrides?: RequestInit - | InitOverrideFunction) => Promise; - readMixed: (initOverrides?: RequestInit | InitOverrideFunction) => Promise; - readSuccessOnlyRaw: (initOverrides?: RequestInit - | InitOverrideFunction) => Promise; + readMixedRaw: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + readMixed: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + readSuccessOnlyRaw: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; readSuccessOnly: (initOverrides?: RequestInit | InitOverrideFunction) => Promise; - readWildcardsRaw: (initOverrides?: RequestInit - | InitOverrideFunction) => Promise; + readWildcardsRaw: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; readWildcards: (initOverrides?: RequestInit | InitOverrideFunction) => Promise; } @@ -134,31 +240,44 @@ export class ResponsesApi extends BaseAPI implements ResponsesApiInterface { super(configuration ?? DefaultConfig); } - async readDefaultRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async readDefaultRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/default`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new ReadDefaultError(response, { kind: 'default', status: response.status, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone(), (json) => detailFromJSON(json as Detail$Wire)).value() }); + throw new ReadDefaultError(response, { + kind: 'default', + status: response.status, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone(), (json) => { + return detailFromJSON(json as Detail$Wire); + }).value(); + return errorValue; + }, + }); } } return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; @@ -169,35 +288,53 @@ export class ResponsesApi extends BaseAPI implements ResponsesApiInterface { return await response.value(); } - async readErrorOnlyRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async readErrorOnlyRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/error`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new ReadErrorOnlyError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new TextApiResponse(errorRaw.clone()).value() }); - } - else { + throw new ReadErrorOnlyError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new TextApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new ReadErrorOnlyError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new ReadErrorOnlyError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; @@ -208,116 +345,183 @@ export class ResponsesApi extends BaseAPI implements ResponsesApiInterface { return await response.value(); } - async readMixedRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async readMixedRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/mixed`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new ReadMixedError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone(), (json) => detailFromJSON(json as Detail$Wire)).value() }); - } - else if (response.status === 401) { + throw new ReadMixedError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone(), (json) => { + return detailFromJSON(json as Detail$Wire); + }).value(); + return errorValue; + }, + }); + } else if (response.status === 401) { let errorValue: Promise | undefined; - throw new ReadMixedError(response, { kind: 'unauthorized', status: response.status as 401, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone(), (json) => (json as Detail$Wire[]).map(detailFromJSON)).value() }); - } - else if (response.status === 409) { + throw new ReadMixedError(response, { + kind: 'unauthorized', + status: response.status as 401, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone(), (json) => { + return (json as Detail$Wire[]).map(detailFromJSON); + }).value(); + return errorValue; + }, + }); + } else if (response.status === 409) { let errorValue: Promise | undefined; - throw new ReadMixedError(response, { kind: 'conflict', status: response.status as 409, raw: response, value: () => errorValue ??= new TextApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 410) { + throw new ReadMixedError(response, { + kind: 'conflict', + status: response.status as 409, + raw: response, + value: () => { + errorValue ??= new TextApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 410) { let errorValue: Promise | undefined; - throw new ReadMixedError(response, { kind: 'status410', status: response.status as 410, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 415) { + throw new ReadMixedError(response, { + kind: 'status410', + status: response.status as 410, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 415) { let errorValue: Promise | undefined; - throw new ReadMixedError(response, { kind: 'status415', status: response.status as 415, raw: response, value: () => errorValue ??= new BlobApiResponse(errorRaw.clone()).value() }); - } - else if (response.status >= 500 && response.status < 600) { + throw new ReadMixedError(response, { + kind: 'status415', + status: response.status as 415, + raw: response, + value: () => { + errorValue ??= new BlobApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status >= 500 && response.status < 600) { let errorValue: Promise | undefined; - throw new ReadMixedError(response, { kind: 'serverError', status: response.status, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone(), (json) => detailFromJSON(json as Detail$Wire)).value() }); - } - else { + throw new ReadMixedError(response, { + kind: 'serverError', + status: response.status, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone(), (json) => { + return detailFromJSON(json as Detail$Wire); + }).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new ReadMixedError(response, { kind: 'default', status: response.status, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone()).value() }); + throw new ReadMixedError(response, { + kind: 'default', + status: response.status, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); } } if (response.status === 201) { - return new JSONApiResponse(response, (json) => detailFromJSON(json as Detail$Wire)) as JSONApiResponse & { status: 201 }; - } - else if (response.status === 202) { + return new JSONApiResponse(response, (json) => { + return detailFromJSON(json as Detail$Wire); + }) as JSONApiResponse & { status: 201 }; + } else if (response.status === 202) { return new TextApiResponse(response) as TextApiResponse & { status: 202 }; - } - else if (response.status === 204) { + } else if (response.status === 204) { return new VoidApiResponse(response) as VoidApiResponse & { status: 204 }; - } - else if (response.status === 206) { + } else if (response.status === 206) { return new BlobApiResponse(response) as BlobApiResponse & { status: 206 }; - } - else if (response.status >= 200 && response.status < 300) { - return new JSONApiResponse(response, (json) => (json as Detail$Wire[]).map(detailFromJSON)) as JSONApiResponse & { status: number }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else if (response.status >= 200 && response.status < 300) { + return new JSONApiResponse(response, (json) => { + return (json as Detail$Wire[]).map(detailFromJSON); + }) as JSONApiResponse & { status: number }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async readMixed(initOverrides?: RequestInit | InitOverrideFunction): Promise { + async readMixed( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.readMixedRaw(initOverrides); - return await response.value() as Detail | string | Blob | Detail[]; + return (await response.value()) as Detail | string | Blob | Detail[]; } - async readSuccessOnlyRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async readSuccessOnlyRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/success`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new ReadSuccessOnlyError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new ReadSuccessOnlyError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 204) { return new VoidApiResponse(response) as VoidApiResponse & { status: 204 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } @@ -327,45 +531,69 @@ export class ResponsesApi extends BaseAPI implements ResponsesApiInterface { return await response.value(); } - async readWildcardsRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async readWildcardsRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/wildcards`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status >= 400 && response.status < 500) { let errorValue: Promise | undefined; - throw new ReadWildcardsError(response, { kind: 'clientError', status: response.status, raw: response, value: () => errorValue ??= new TextApiResponse(errorRaw.clone()).value() }); - } - else if (response.status >= 500 && response.status < 600) { + throw new ReadWildcardsError(response, { + kind: 'clientError', + status: response.status, + raw: response, + value: () => { + errorValue ??= new TextApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status >= 500 && response.status < 600) { let errorValue: Promise | undefined; - throw new ReadWildcardsError(response, { kind: 'serverError', status: response.status, raw: response, value: () => errorValue ??= new BlobApiResponse(errorRaw.clone()).value() }); - } - else { + throw new ReadWildcardsError(response, { + kind: 'serverError', + status: response.status, + raw: response, + value: () => { + errorValue ??= new BlobApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new ReadWildcardsError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new ReadWildcardsError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status >= 200 && response.status < 300) { return new VoidApiResponse(response) as VoidApiResponse & { status: number }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-dispatch/package.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-dispatch/package.json.golden index 59d6da387..1e410ab14 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-dispatch/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-dispatch/package.json.golden @@ -1,26 +1,26 @@ { + "name": "type-script-response-dispatch", + "version": "1.0.0", "description": "TypeScript client for TypeScript Response Dispatch", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "type-script-response-dispatch", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-dispatch/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-dispatch/runtime/runtime.ts.golden index 62758288d..e148a93c5 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-dispatch/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-dispatch/runtime/runtime.ts.golden @@ -3,7 +3,7 @@ * * TypeScript Response Dispatch — 1.0.0 */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -13,7 +13,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -92,8 +95,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -135,12 +140,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -150,7 +161,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -166,9 +177,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -183,13 +192,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -199,7 +210,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -209,10 +220,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -221,18 +233,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -240,16 +256,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -268,11 +285,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -282,7 +299,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -292,7 +309,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -306,12 +323,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -329,15 +364,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -413,16 +461,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -449,7 +587,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -476,7 +617,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -486,5 +627,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-dispatch/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-dispatch/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-dispatch/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-dispatch/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-dispatch/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-dispatch/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-dispatch/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-dispatch/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/README.md.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/README.md.golden index ff149e7a1..43696a245 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, TestResourceApi } from 'test-api-with-delete-response-sc const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'test-api-with-delete-response-sche const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/apis/TestResourceApi.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/apis/TestResourceApi.ts.golden index 9eb773001..549b754ed 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/apis/TestResourceApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/apis/TestResourceApi.ts.golden @@ -5,14 +5,31 @@ * Test fixture for DELETE operations with JSON response schemas and type alias request bodies */ import type { CreateTestResourceRequest } from '../models/CreateTestResourceRequest'; -import type { CreateTestResourceResponse, CreateTestResourceResponse$Wire } from '../models/CreateTestResourceResponse'; +import type { + CreateTestResourceResponse, + CreateTestResourceResponse$Wire, +} from '../models/CreateTestResourceResponse'; import { createTestResourceResponseFromJSON } from '../models/CreateTestResourceResponse'; -import type { DeleteTestResourceResponse, DeleteTestResourceResponse$Wire } from '../models/DeleteTestResourceResponse'; +import type { + DeleteTestResourceResponse, + DeleteTestResourceResponse$Wire, +} from '../models/DeleteTestResourceResponse'; import { deleteTestResourceResponseFromJSON } from '../models/DeleteTestResourceResponse'; import type { HttpErrorResponse, HttpErrorResponse$Wire } from '../models/HttpErrorResponse'; import { httpErrorResponseFromJSON } from '../models/HttpErrorResponse'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, +} from '../runtime/runtime'; export interface ApiCreateTestResourceRequest { body: CreateTestResourceRequest; @@ -26,51 +43,82 @@ export interface ApiDeleteTestResourceRequest { } export type CreateTestResourceRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type DeleteTestResourceRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); -export type CreateTestResourceErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type CreateTestResourceErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class CreateTestResourceError extends ResponseError { readonly detail: CreateTestResourceErrorDetail; - constructor(response: Response, detail: CreateTestResourceErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: CreateTestResourceErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type DeleteTestResourceErrorDetail = - { kind: 'clientError'; status: number; raw: Response; value(): Promise } - | { kind: 'serverError'; status: number; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'clientError'; + status: number; + raw: Response; + value(): Promise; + } + | { + kind: 'serverError'; + status: number; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class DeleteTestResourceError extends ResponseError { readonly detail: DeleteTestResourceErrorDetail; - constructor(response: Response, detail: DeleteTestResourceErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: DeleteTestResourceErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface TestResourceApiInterface { - createTestResourceRaw: (requestParameters: ApiCreateTestResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - createTestResource: (requestParameters: ApiCreateTestResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - deleteTestResourceRaw: (requestParameters: ApiDeleteTestResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - deleteTestResource: (requestParameters: ApiDeleteTestResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + createTestResourceRaw: ( + requestParameters: ApiCreateTestResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + createTestResource: ( + requestParameters: ApiCreateTestResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + deleteTestResourceRaw: ( + requestParameters: ApiDeleteTestResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + deleteTestResource: ( + requestParameters: ApiDeleteTestResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class TestResourceApi extends BaseAPI implements TestResourceApiInterface { @@ -81,12 +129,14 @@ export class TestResourceApi extends BaseAPI implements TestResourceApiInterface super(configuration ?? DefaultConfig); } - async createTestResourceRaw(requestParameters: ApiCreateTestResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async createTestResourceRaw( + requestParameters: ApiCreateTestResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling createTestResourceRaw().' + 'Required parameter "body" was null or undefined when calling createTestResourceRaw().', ); } // Build path with path parameters @@ -101,89 +151,139 @@ export class TestResourceApi extends BaseAPI implements TestResourceApiInterface // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new CreateTestResourceError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new CreateTestResourceError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response, (json) => createTestResourceResponseFromJSON(json as CreateTestResourceResponse$Wire)) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response, (json) => { + return createTestResourceResponseFromJSON(json as CreateTestResourceResponse$Wire); + }) as JSONApiResponse & { status: 200 }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async createTestResource(requestParameters: ApiCreateTestResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async createTestResource( + requestParameters: ApiCreateTestResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.createTestResourceRaw(requestParameters, initOverrides); - return await response.value() as CreateTestResourceResponse; + return (await response.value()) as CreateTestResourceResponse; } - async deleteTestResourceRaw(requestParameters: ApiDeleteTestResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async deleteTestResourceRaw( + requestParameters: ApiDeleteTestResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.resourceId === undefined || requestParameters.resourceId === null) { throw new RequiredError( 'resourceId', - 'Required parameter "resourceId" was null or undefined when calling deleteTestResourceRaw().' + 'Required parameter "resourceId" was null or undefined when calling deleteTestResourceRaw().', ); } // Build path with path parameters let urlPath = `/v1/api/test-resource/{resource_id}`; - urlPath = urlPath.replace(`{resource_id}`, encodeURIComponent(String(requestParameters.resourceId))); + urlPath = urlPath.replace( + `{resource_id}`, + encodeURIComponent(String(requestParameters.resourceId)), + ); // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'DELETE', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status >= 400 && response.status < 500) { let errorValue: Promise | undefined; - throw new DeleteTestResourceError(response, { kind: 'clientError', status: response.status, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone(), (json) => httpErrorResponseFromJSON(json as HttpErrorResponse$Wire)).value() }); - } - else if (response.status >= 500 && response.status < 600) { + throw new DeleteTestResourceError(response, { + kind: 'clientError', + status: response.status, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone(), (json) => { + return httpErrorResponseFromJSON(json as HttpErrorResponse$Wire); + }).value(); + return errorValue; + }, + }); + } else if (response.status >= 500 && response.status < 600) { let errorValue: Promise | undefined; - throw new DeleteTestResourceError(response, { kind: 'serverError', status: response.status, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone(), (json) => httpErrorResponseFromJSON(json as HttpErrorResponse$Wire)).value() }); - } - else { + throw new DeleteTestResourceError(response, { + kind: 'serverError', + status: response.status, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone(), (json) => { + return httpErrorResponseFromJSON(json as HttpErrorResponse$Wire); + }).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new DeleteTestResourceError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new DeleteTestResourceError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response, (json) => deleteTestResourceResponseFromJSON(json as DeleteTestResourceResponse$Wire)) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response, (json) => { + return deleteTestResourceResponseFromJSON(json as DeleteTestResourceResponse$Wire); + }) as JSONApiResponse & { status: 200 }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async deleteTestResource(requestParameters: ApiDeleteTestResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async deleteTestResource( + requestParameters: ApiDeleteTestResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.deleteTestResourceRaw(requestParameters, initOverrides); - return await response.value() as DeleteTestResourceResponse; + return (await response.value()) as DeleteTestResourceResponse; } } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/models/CreateTestResourceResponse.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/models/CreateTestResourceResponse.ts.golden index 26e584e4f..ca370daa9 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/models/CreateTestResourceResponse.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/models/CreateTestResourceResponse.ts.golden @@ -18,13 +18,17 @@ export interface CreateTestResourceResponse { readonly resourceId: string; } -export function createTestResourceResponseFromJSON(json: CreateTestResourceResponse$Wire): CreateTestResourceResponse { +export function createTestResourceResponseFromJSON( + json: CreateTestResourceResponse$Wire, +): CreateTestResourceResponse { return { resourceId: json.resource_id, }; } -export function createTestResourceResponseToJSON(value: CreateTestResourceResponse): CreateTestResourceResponse$Wire { +export function createTestResourceResponseToJSON( + value: CreateTestResourceResponse, +): CreateTestResourceResponse$Wire { return { resource_id: value.resourceId, }; diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/models/DeleteTestResourceResponse.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/models/DeleteTestResourceResponse.ts.golden index f40262c95..d8eab9557 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/models/DeleteTestResourceResponse.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/models/DeleteTestResourceResponse.ts.golden @@ -20,14 +20,18 @@ export interface DeleteTestResourceResponse { readonly success: boolean; } -export function deleteTestResourceResponseFromJSON(json: DeleteTestResourceResponse$Wire): DeleteTestResourceResponse { +export function deleteTestResourceResponseFromJSON( + json: DeleteTestResourceResponse$Wire, +): DeleteTestResourceResponse { return { message: json.message, success: json.success, }; } -export function deleteTestResourceResponseToJSON(value: DeleteTestResourceResponse): DeleteTestResourceResponse$Wire { +export function deleteTestResourceResponseToJSON( + value: DeleteTestResourceResponse, +): DeleteTestResourceResponse$Wire { return { message: value.message, success: value.success, diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/models/index.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/models/index.ts.golden index 9c28f97a6..0b2e377cb 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/models/index.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/models/index.ts.golden @@ -5,9 +5,21 @@ * Test fixture for DELETE operations with JSON response schemas and type alias request bodies */ export type { CreateTestResourceRequest } from './CreateTestResourceRequest'; -export type { CreateTestResourceResponse, CreateTestResourceResponse$Wire } from './CreateTestResourceResponse'; -export { createTestResourceResponseFromJSON, createTestResourceResponseToJSON } from './CreateTestResourceResponse'; -export type { DeleteTestResourceResponse, DeleteTestResourceResponse$Wire } from './DeleteTestResourceResponse'; -export { deleteTestResourceResponseFromJSON, deleteTestResourceResponseToJSON } from './DeleteTestResourceResponse'; +export type { + CreateTestResourceResponse, + CreateTestResourceResponse$Wire, +} from './CreateTestResourceResponse'; +export { + createTestResourceResponseFromJSON, + createTestResourceResponseToJSON, +} from './CreateTestResourceResponse'; +export type { + DeleteTestResourceResponse, + DeleteTestResourceResponse$Wire, +} from './DeleteTestResourceResponse'; +export { + deleteTestResourceResponseFromJSON, + deleteTestResourceResponseToJSON, +} from './DeleteTestResourceResponse'; export type { HttpErrorResponse, HttpErrorResponse$Wire } from './HttpErrorResponse'; export { httpErrorResponseFromJSON, httpErrorResponseToJSON } from './HttpErrorResponse'; diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/package.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/package.json.golden index 7309084d9..1a5e1912a 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/package.json.golden @@ -1,26 +1,26 @@ { + "name": "test-api-with-delete-response-schema", + "version": "1.0.0", "description": "Test fixture for DELETE operations with JSON response schemas and type alias request bodies", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "test-api-with-delete-response-schema", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/runtime/runtime.ts.golden index 37c19d852..827aebb74 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Test API with DELETE Response Schema — 1.0.0 * Test fixture for DELETE operations with JSON response schemas and type alias request bodies */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-response-only-types/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/README.md.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/README.md.golden index 7a9ba9626..3e0566aec 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/README.md.golden @@ -3,7 +3,6 @@ Internally tagged oneOf whose inline variant objects carry the required discriminator plus their content properties directly (no allOf wrapper). - **Version:** 1.0.0 ## Overview @@ -54,8 +53,8 @@ import { Configuration, DefaultApi } from 'discriminated-union-plain-internal-ta const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -103,9 +102,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -128,12 +127,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -142,7 +141,11 @@ const config = new Configuration({ The client throws typed errors for different failure scenarios: ```typescript -import { ResponseError, FetchError, RequiredError } from 'discriminated-union-plain-internal-tagging-test'; +import { + ResponseError, + FetchError, + RequiredError, +} from 'discriminated-union-plain-internal-tagging-test'; try { const result = await api.someMethod(); @@ -216,7 +219,7 @@ import type { User, CreateUserRequest } from 'discriminated-union-plain-internal const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/apis/DefaultApi.ts.golden index d65e084f5..82b9761d0 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/apis/DefaultApi.ts.golden @@ -7,36 +7,57 @@ */ import type { PreviewRequest, PreviewRequest$Wire } from '../models/PreviewRequest'; import { previewRequestFromJSON, previewRequestToJSON } from '../models/PreviewRequest'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, +} from '../runtime/runtime'; export interface ApiPreviewRequest { body: PreviewRequest; } export type PreviewRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); - -export type PreviewErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type PreviewErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class PreviewError extends ResponseError { readonly detail: PreviewErrorDetail; - constructor(response: Response, detail: PreviewErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: PreviewErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - previewRaw: (requestParameters: ApiPreviewRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - preview: (requestParameters: ApiPreviewRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + previewRaw: ( + requestParameters: ApiPreviewRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + preview: ( + requestParameters: ApiPreviewRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class DefaultApi extends BaseAPI implements DefaultApiInterface { @@ -47,12 +68,14 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async previewRaw(requestParameters: ApiPreviewRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async previewRaw( + requestParameters: ApiPreviewRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling previewRaw().' + 'Required parameter "body" was null or undefined when calling previewRaw().', ); } // Build path with path parameters @@ -67,33 +90,47 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = previewRequestToJSON(requestParameters.body); // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new PreviewError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new PreviewError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response, (json) => previewRequestFromJSON(json as PreviewRequest$Wire)) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response, (json) => { + return previewRequestFromJSON(json as PreviewRequest$Wire); + }) as JSONApiResponse & { status: 200 }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async preview(requestParameters: ApiPreviewRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async preview( + requestParameters: ApiPreviewRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.previewRaw(requestParameters, initOverrides); - return await response.value() as PreviewRequest; + return (await response.value()) as PreviewRequest; } } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/models/ScheduleRule.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/models/ScheduleRule.ts.golden index 776c62e72..e42161d3b 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/models/ScheduleRule.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/models/ScheduleRule.ts.golden @@ -12,22 +12,34 @@ import { scheduleRuleIntervalFromJSON, scheduleRuleIntervalToJSON } from './Sche import type { ScheduleRuleOnce, ScheduleRuleOnce$Wire } from './ScheduleRuleOnce'; import { scheduleRuleOnceFromJSON, scheduleRuleOnceToJSON } from './ScheduleRuleOnce'; -export type ScheduleRule$Wire = ({ type: 'once' } & ScheduleRuleOnce$Wire) | ({ type: 'interval' } & ScheduleRuleInterval$Wire) | ({ type: 'cron' } & ScheduleRuleCron$Wire); +export type ScheduleRule$Wire = + | ({ type: 'once' } & ScheduleRuleOnce$Wire) + | ({ type: 'interval' } & ScheduleRuleInterval$Wire) + | ({ type: 'cron' } & ScheduleRuleCron$Wire); -export type ScheduleRule = ({ type: 'once' } & ScheduleRuleOnce) | ({ type: 'interval' } & ScheduleRuleInterval) | ({ type: 'cron' } & ScheduleRuleCron); +export type ScheduleRule = + | ({ type: 'once' } & ScheduleRuleOnce) + | ({ type: 'interval' } & ScheduleRuleInterval) + | ({ type: 'cron' } & ScheduleRuleCron); export function scheduleRuleFromJSON(json: ScheduleRule$Wire): ScheduleRule { switch (json.type) { - case 'once': return { ...scheduleRuleOnceFromJSON(json), type: 'once' }; - case 'interval': return { ...scheduleRuleIntervalFromJSON(json), type: 'interval' }; - case 'cron': return { ...scheduleRuleCronFromJSON(json), type: 'cron' }; + case 'once': + return { ...scheduleRuleOnceFromJSON(json), type: 'once' }; + case 'interval': + return { ...scheduleRuleIntervalFromJSON(json), type: 'interval' }; + case 'cron': + return { ...scheduleRuleCronFromJSON(json), type: 'cron' }; } } export function scheduleRuleToJSON(value: ScheduleRule): ScheduleRule$Wire { switch (value.type) { - case 'once': return { ...scheduleRuleOnceToJSON(value), type: 'once' } as ScheduleRule$Wire; - case 'interval': return { ...scheduleRuleIntervalToJSON(value), type: 'interval' } as ScheduleRule$Wire; - case 'cron': return { ...scheduleRuleCronToJSON(value), type: 'cron' } as ScheduleRule$Wire; + case 'once': + return { ...scheduleRuleOnceToJSON(value), type: 'once' } as ScheduleRule$Wire; + case 'interval': + return { ...scheduleRuleIntervalToJSON(value), type: 'interval' } as ScheduleRule$Wire; + case 'cron': + return { ...scheduleRuleCronToJSON(value), type: 'cron' } as ScheduleRule$Wire; } } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/models/ScheduleRuleCron.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/models/ScheduleRuleCron.ts.golden index ce32e0c70..8f013d157 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/models/ScheduleRuleCron.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/models/ScheduleRuleCron.ts.golden @@ -21,7 +21,7 @@ export function scheduleRuleCronFromJSON(json: ScheduleRuleCron$Wire): ScheduleR return { expression: json.expression, timezone: json.timezone, - 'type': json['type'], + type: json['type'], }; } @@ -29,6 +29,6 @@ export function scheduleRuleCronToJSON(value: ScheduleRuleCron): ScheduleRuleCro return { expression: value.expression, timezone: value.timezone, - 'type': value['type'], + type: value['type'], }; } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/models/ScheduleRuleInterval.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/models/ScheduleRuleInterval.ts.golden index f486258d7..2ccdf4997 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/models/ScheduleRuleInterval.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/models/ScheduleRuleInterval.ts.golden @@ -17,11 +17,13 @@ export interface ScheduleRuleInterval { readonly type: 'interval'; } -export function scheduleRuleIntervalFromJSON(json: ScheduleRuleInterval$Wire): ScheduleRuleInterval { +export function scheduleRuleIntervalFromJSON( + json: ScheduleRuleInterval$Wire, +): ScheduleRuleInterval { return { anchorAt: json.anchor_at, everyMinutes: json.every_minutes, - 'type': json['type'], + type: json['type'], }; } @@ -29,6 +31,6 @@ export function scheduleRuleIntervalToJSON(value: ScheduleRuleInterval): Schedul return { anchor_at: value.anchorAt, every_minutes: value.everyMinutes, - 'type': value['type'], + type: value['type'], }; } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/models/ScheduleRuleOnce.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/models/ScheduleRuleOnce.ts.golden index f2e8ec4cd..a75e33665 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/models/ScheduleRuleOnce.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/models/ScheduleRuleOnce.ts.golden @@ -18,13 +18,13 @@ export interface ScheduleRuleOnce { export function scheduleRuleOnceFromJSON(json: ScheduleRuleOnce$Wire): ScheduleRuleOnce { return { at: json.at, - 'type': json['type'], + type: json['type'], }; } export function scheduleRuleOnceToJSON(value: ScheduleRuleOnce): ScheduleRuleOnce$Wire { return { at: value.at, - 'type': value['type'], + type: value['type'], }; } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/package.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/package.json.golden index 4cd616457..d97a8886a 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/package.json.golden @@ -1,26 +1,26 @@ { + "name": "discriminated-union-plain-internal-tagging-test", + "version": "1.0.0", "description": "Internally tagged oneOf whose inline variant objects carry the required\ndiscriminator plus their content properties directly (no allOf wrapper).\n", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "discriminated-union-plain-internal-tagging-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/runtime/runtime.ts.golden index 7582dcd92..1ff2f5f36 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/runtime/runtime.ts.golden @@ -5,7 +5,7 @@ * Internally tagged oneOf whose inline variant objects carry the required * discriminator plus their content properties directly (no allOf wrapper). */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -15,7 +15,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -94,8 +97,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -137,12 +142,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -152,7 +163,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -168,9 +179,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -185,13 +194,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -201,7 +212,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -211,10 +222,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -223,18 +235,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -242,16 +258,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -270,11 +287,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -284,7 +301,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -294,7 +311,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -308,12 +325,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -331,15 +366,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -415,16 +463,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -451,7 +589,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -478,7 +619,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -488,5 +629,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-plain-internal/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-variant-with-discriminator/README.md.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-variant-with-discriminator/README.md.golden index 306c1282f..cddd1c6d7 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-variant-with-discriminator/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-variant-with-discriminator/README.md.golden @@ -5,7 +5,6 @@ properties. This is the pattern that triggers TS2783 if the fromJSON/toJSON func put the discriminator literal BEFORE the spread (since the spread would overwrite it). The fix is to put the spread first, then the discriminator literal last so it wins. - **Version:** 1.0.0 ## Overview @@ -50,14 +49,17 @@ npm install ## Quick Start ```typescript -import { Configuration, DefaultApi } from 'discriminated-union-variant-includes-discriminator-field'; +import { + Configuration, + DefaultApi, +} from 'discriminated-union-variant-includes-discriminator-field'; // Create a configuration const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -105,9 +107,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -116,7 +118,10 @@ const config = new Configuration({ Add custom middleware to intercept requests and responses: ```typescript -import { Configuration, Middleware } from 'discriminated-union-variant-includes-discriminator-field'; +import { + Configuration, + Middleware, +} from 'discriminated-union-variant-includes-discriminator-field'; const loggingMiddleware: Middleware = { pre: async (context) => { @@ -130,12 +135,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -144,7 +149,11 @@ const config = new Configuration({ The client throws typed errors for different failure scenarios: ```typescript -import { ResponseError, FetchError, RequiredError } from 'discriminated-union-variant-includes-discriminator-field'; +import { + ResponseError, + FetchError, + RequiredError, +} from 'discriminated-union-variant-includes-discriminator-field'; try { const result = await api.someMethod(); @@ -213,12 +222,15 @@ This package works with standard TypeScript configurations. If you're using a bu ### Type Imports ```typescript -import type { User, CreateUserRequest } from 'discriminated-union-variant-includes-discriminator-field'; +import type { + User, + CreateUserRequest, +} from 'discriminated-union-variant-includes-discriminator-field'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-variant-with-discriminator/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-variant-with-discriminator/apis/DefaultApi.ts.golden index 0422a439a..34218d92d 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-variant-with-discriminator/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-variant-with-discriminator/apis/DefaultApi.ts.golden @@ -9,36 +9,57 @@ */ import type { Setup, Setup$Wire } from '../models/Setup'; import { setupFromJSON, setupToJSON } from '../models/Setup'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, +} from '../runtime/runtime'; export interface ApiCreateSetupRequest { body: Setup; } export type CreateSetupRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); - -export type CreateSetupErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type CreateSetupErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class CreateSetupError extends ResponseError { readonly detail: CreateSetupErrorDetail; - constructor(response: Response, detail: CreateSetupErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: CreateSetupErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - createSetupRaw: (requestParameters: ApiCreateSetupRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - createSetup: (requestParameters: ApiCreateSetupRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + createSetupRaw: ( + requestParameters: ApiCreateSetupRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + createSetup: ( + requestParameters: ApiCreateSetupRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class DefaultApi extends BaseAPI implements DefaultApiInterface { @@ -49,12 +70,14 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async createSetupRaw(requestParameters: ApiCreateSetupRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createSetupRaw( + requestParameters: ApiCreateSetupRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling createSetupRaw().' + 'Required parameter "body" was null or undefined when calling createSetupRaw().', ); } // Build path with path parameters @@ -69,33 +92,47 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = setupToJSON(requestParameters.body); // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new CreateSetupError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new CreateSetupError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response, (json) => setupFromJSON(json as Setup$Wire)) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response, (json) => { + return setupFromJSON(json as Setup$Wire); + }) as JSONApiResponse & { status: 200 }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async createSetup(requestParameters: ApiCreateSetupRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createSetup( + requestParameters: ApiCreateSetupRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.createSetupRaw(requestParameters, initOverrides); - return await response.value() as Setup; + return (await response.value()) as Setup; } } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-variant-with-discriminator/models/Setup.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-variant-with-discriminator/models/Setup.ts.golden index a470a6790..d80d4d95a 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-variant-with-discriminator/models/Setup.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-variant-with-discriminator/models/Setup.ts.golden @@ -14,22 +14,34 @@ import { setupManualFromJSON, setupManualToJSON } from './SetupManual'; import type { SetupUnspecified, SetupUnspecified$Wire } from './SetupUnspecified'; import { setupUnspecifiedFromJSON, setupUnspecifiedToJSON } from './SetupUnspecified'; -export type Setup$Wire = ({ kind: 'SETUP_UNSPECIFIED' } & SetupUnspecified$Wire) | ({ kind: 'SETUP_AUTOMATIC' } & SetupAutomatic$Wire) | ({ kind: 'SETUP_MANUAL' } & SetupManual$Wire); +export type Setup$Wire = + | ({ kind: 'SETUP_UNSPECIFIED' } & SetupUnspecified$Wire) + | ({ kind: 'SETUP_AUTOMATIC' } & SetupAutomatic$Wire) + | ({ kind: 'SETUP_MANUAL' } & SetupManual$Wire); -export type Setup = ({ kind: 'SETUP_UNSPECIFIED' } & SetupUnspecified) | ({ kind: 'SETUP_AUTOMATIC' } & SetupAutomatic) | ({ kind: 'SETUP_MANUAL' } & SetupManual); +export type Setup = + | ({ kind: 'SETUP_UNSPECIFIED' } & SetupUnspecified) + | ({ kind: 'SETUP_AUTOMATIC' } & SetupAutomatic) + | ({ kind: 'SETUP_MANUAL' } & SetupManual); export function setupFromJSON(json: Setup$Wire): Setup { switch (json.kind) { - case 'SETUP_UNSPECIFIED': return { ...setupUnspecifiedFromJSON(json), kind: 'SETUP_UNSPECIFIED' }; - case 'SETUP_AUTOMATIC': return { ...setupAutomaticFromJSON(json), kind: 'SETUP_AUTOMATIC' }; - case 'SETUP_MANUAL': return { ...setupManualFromJSON(json), kind: 'SETUP_MANUAL' }; + case 'SETUP_UNSPECIFIED': + return { ...setupUnspecifiedFromJSON(json), kind: 'SETUP_UNSPECIFIED' }; + case 'SETUP_AUTOMATIC': + return { ...setupAutomaticFromJSON(json), kind: 'SETUP_AUTOMATIC' }; + case 'SETUP_MANUAL': + return { ...setupManualFromJSON(json), kind: 'SETUP_MANUAL' }; } } export function setupToJSON(value: Setup): Setup$Wire { switch (value.kind) { - case 'SETUP_UNSPECIFIED': return { ...setupUnspecifiedToJSON(value), kind: 'SETUP_UNSPECIFIED' } as Setup$Wire; - case 'SETUP_AUTOMATIC': return { ...setupAutomaticToJSON(value), kind: 'SETUP_AUTOMATIC' } as Setup$Wire; - case 'SETUP_MANUAL': return { ...setupManualToJSON(value), kind: 'SETUP_MANUAL' } as Setup$Wire; + case 'SETUP_UNSPECIFIED': + return { ...setupUnspecifiedToJSON(value), kind: 'SETUP_UNSPECIFIED' } as Setup$Wire; + case 'SETUP_AUTOMATIC': + return { ...setupAutomaticToJSON(value), kind: 'SETUP_AUTOMATIC' } as Setup$Wire; + case 'SETUP_MANUAL': + return { ...setupManualToJSON(value), kind: 'SETUP_MANUAL' } as Setup$Wire; } } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-variant-with-discriminator/package.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-variant-with-discriminator/package.json.golden index 83ea9b28a..a87130f1c 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-variant-with-discriminator/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-variant-with-discriminator/package.json.golden @@ -1,26 +1,26 @@ { + "name": "discriminated-union-variant-includes-discriminator-field", + "version": "1.0.0", "description": "Test fixture where variant schemas include the discriminator property in their own\nproperties. This is the pattern that triggers TS2783 if the fromJSON/toJSON functions\nput the discriminator literal BEFORE the spread (since the spread would overwrite it).\nThe fix is to put the spread first, then the discriminator literal last so it wins.\n", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "discriminated-union-variant-includes-discriminator-field", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-variant-with-discriminator/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-variant-with-discriminator/runtime/runtime.ts.golden index 085ae7cbf..239e94458 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-variant-with-discriminator/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-variant-with-discriminator/runtime/runtime.ts.golden @@ -7,7 +7,7 @@ * put the discriminator literal BEFORE the spread (since the spread would overwrite it). * The fix is to put the spread first, then the discriminator literal last so it wins. */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -17,7 +17,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -96,8 +99,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -139,12 +144,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -154,7 +165,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -170,9 +181,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -187,13 +196,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -203,7 +214,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -213,10 +224,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -225,18 +237,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -244,16 +260,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -272,11 +289,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -286,7 +303,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -296,7 +313,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -310,12 +327,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -333,15 +368,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -417,16 +465,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -453,7 +591,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -480,7 +621,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -490,5 +631,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-variant-with-discriminator/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-variant-with-discriminator/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-variant-with-discriminator/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-variant-with-discriminator/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-variant-with-discriminator/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-variant-with-discriminator/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-variant-with-discriminator/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union-variant-with-discriminator/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/README.md.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/README.md.golden index dafe063f0..cd36d2d79 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/README.md.golden @@ -3,7 +3,6 @@ Test fixture for discriminated union where variants are references to component schemas. This is similar to the ContainerImage pattern in the infiron API. - **Version:** 1.0.0 ## Overview @@ -54,8 +53,8 @@ import { Configuration, DefaultApi } from 'discriminated-union-with-references-t const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -103,9 +102,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -128,12 +127,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -216,7 +215,7 @@ import type { User, CreateUserRequest } from 'discriminated-union-with-reference const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/apis/DefaultApi.ts.golden index 945e25638..2663e85c5 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/apis/DefaultApi.ts.golden @@ -7,36 +7,57 @@ */ import type { ContainerImage, ContainerImage$Wire } from '../models/ContainerImage'; import { containerImageFromJSON, containerImageToJSON } from '../models/ContainerImage'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, +} from '../runtime/runtime'; export interface ApiCreateContainerRequest { body: ContainerImage; } export type CreateContainerRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); - -export type CreateContainerErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type CreateContainerErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class CreateContainerError extends ResponseError { readonly detail: CreateContainerErrorDetail; - constructor(response: Response, detail: CreateContainerErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: CreateContainerErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - createContainerRaw: (requestParameters: ApiCreateContainerRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - createContainer: (requestParameters: ApiCreateContainerRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + createContainerRaw: ( + requestParameters: ApiCreateContainerRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + createContainer: ( + requestParameters: ApiCreateContainerRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class DefaultApi extends BaseAPI implements DefaultApiInterface { @@ -47,12 +68,14 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async createContainerRaw(requestParameters: ApiCreateContainerRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createContainerRaw( + requestParameters: ApiCreateContainerRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling createContainerRaw().' + 'Required parameter "body" was null or undefined when calling createContainerRaw().', ); } // Build path with path parameters @@ -67,33 +90,47 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = containerImageToJSON(requestParameters.body); // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new CreateContainerError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new CreateContainerError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response, (json) => containerImageFromJSON(json as ContainerImage$Wire)) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response, (json) => { + return containerImageFromJSON(json as ContainerImage$Wire); + }) as JSONApiResponse & { status: 200 }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async createContainer(requestParameters: ApiCreateContainerRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createContainer( + requestParameters: ApiCreateContainerRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.createContainerRaw(requestParameters, initOverrides); - return await response.value() as ContainerImage; + return (await response.value()) as ContainerImage; } } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/models/ContainerImage.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/models/ContainerImage.ts.golden index d77c1ee9e..4a3fb4001 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/models/ContainerImage.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/models/ContainerImage.ts.golden @@ -8,22 +8,39 @@ import type { ContainerImageCustom, ContainerImageCustom$Wire } from './ContainerImageCustom'; import { containerImageCustomFromJSON, containerImageCustomToJSON } from './ContainerImageCustom'; import type { ContainerImageManaged, ContainerImageManaged$Wire } from './ContainerImageManaged'; -import { containerImageManagedFromJSON, containerImageManagedToJSON } from './ContainerImageManaged'; +import { + containerImageManagedFromJSON, + containerImageManagedToJSON, +} from './ContainerImageManaged'; -export type ContainerImage$Wire = ({ kind: 'CONTAINER_IMAGE_MANAGED' } & ContainerImageManaged$Wire) | ({ kind: 'CONTAINER_IMAGE_CUSTOM' } & ContainerImageCustom$Wire); +export type ContainerImage$Wire = + | ({ kind: 'CONTAINER_IMAGE_MANAGED' } & ContainerImageManaged$Wire) + | ({ kind: 'CONTAINER_IMAGE_CUSTOM' } & ContainerImageCustom$Wire); -export type ContainerImage = ({ kind: 'CONTAINER_IMAGE_MANAGED' } & ContainerImageManaged) | ({ kind: 'CONTAINER_IMAGE_CUSTOM' } & ContainerImageCustom); +export type ContainerImage = + | ({ kind: 'CONTAINER_IMAGE_MANAGED' } & ContainerImageManaged) + | ({ kind: 'CONTAINER_IMAGE_CUSTOM' } & ContainerImageCustom); export function containerImageFromJSON(json: ContainerImage$Wire): ContainerImage { switch (json.kind) { - case 'CONTAINER_IMAGE_MANAGED': return { ...containerImageManagedFromJSON(json), kind: 'CONTAINER_IMAGE_MANAGED' }; - case 'CONTAINER_IMAGE_CUSTOM': return { ...containerImageCustomFromJSON(json), kind: 'CONTAINER_IMAGE_CUSTOM' }; + case 'CONTAINER_IMAGE_MANAGED': + return { ...containerImageManagedFromJSON(json), kind: 'CONTAINER_IMAGE_MANAGED' }; + case 'CONTAINER_IMAGE_CUSTOM': + return { ...containerImageCustomFromJSON(json), kind: 'CONTAINER_IMAGE_CUSTOM' }; } } export function containerImageToJSON(value: ContainerImage): ContainerImage$Wire { switch (value.kind) { - case 'CONTAINER_IMAGE_MANAGED': return { ...containerImageManagedToJSON(value), kind: 'CONTAINER_IMAGE_MANAGED' } as ContainerImage$Wire; - case 'CONTAINER_IMAGE_CUSTOM': return { ...containerImageCustomToJSON(value), kind: 'CONTAINER_IMAGE_CUSTOM' } as ContainerImage$Wire; + case 'CONTAINER_IMAGE_MANAGED': + return { + ...containerImageManagedToJSON(value), + kind: 'CONTAINER_IMAGE_MANAGED', + } as ContainerImage$Wire; + case 'CONTAINER_IMAGE_CUSTOM': + return { + ...containerImageCustomToJSON(value), + kind: 'CONTAINER_IMAGE_CUSTOM', + } as ContainerImage$Wire; } } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/models/ContainerImageCustom.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/models/ContainerImageCustom.ts.golden index cf8f037e4..b4d4ca906 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/models/ContainerImageCustom.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/models/ContainerImageCustom.ts.golden @@ -13,7 +13,9 @@ export interface ContainerImageCustom { readonly customField: string; } -export function containerImageCustomFromJSON(json: ContainerImageCustom$Wire): ContainerImageCustom { +export function containerImageCustomFromJSON( + json: ContainerImageCustom$Wire, +): ContainerImageCustom { return { customField: json.customField, }; diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/models/ContainerImageManaged.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/models/ContainerImageManaged.ts.golden index 553c00a70..d1ad83dc8 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/models/ContainerImageManaged.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/models/ContainerImageManaged.ts.golden @@ -13,13 +13,17 @@ export interface ContainerImageManaged { readonly managedField: string; } -export function containerImageManagedFromJSON(json: ContainerImageManaged$Wire): ContainerImageManaged { +export function containerImageManagedFromJSON( + json: ContainerImageManaged$Wire, +): ContainerImageManaged { return { managedField: json.managedField, }; } -export function containerImageManagedToJSON(value: ContainerImageManaged): ContainerImageManaged$Wire { +export function containerImageManagedToJSON( + value: ContainerImageManaged, +): ContainerImageManaged$Wire { return { managedField: value.managedField, }; diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/models/index.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/models/index.ts.golden index 0c7aefcf8..ebe940734 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/models/index.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/models/index.ts.golden @@ -10,4 +10,7 @@ export { containerImageFromJSON, containerImageToJSON } from './ContainerImage'; export type { ContainerImageCustom, ContainerImageCustom$Wire } from './ContainerImageCustom'; export { containerImageCustomFromJSON, containerImageCustomToJSON } from './ContainerImageCustom'; export type { ContainerImageManaged, ContainerImageManaged$Wire } from './ContainerImageManaged'; -export { containerImageManagedFromJSON, containerImageManagedToJSON } from './ContainerImageManaged'; +export { + containerImageManagedFromJSON, + containerImageManagedToJSON, +} from './ContainerImageManaged'; diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/package.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/package.json.golden index 2192b29f9..26997847b 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/package.json.golden @@ -1,26 +1,26 @@ { + "name": "discriminated-union-with-references-test", + "version": "1.0.0", "description": "Test fixture for discriminated union where variants are references to component schemas.\nThis is similar to the ContainerImage pattern in the infiron API.\n", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "discriminated-union-with-references-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/runtime/runtime.ts.golden index 878305890..d10377f26 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/runtime/runtime.ts.golden @@ -5,7 +5,7 @@ * Test fixture for discriminated union where variants are references to component schemas. * This is similar to the ContainerImage pattern in the infiron API. */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -15,7 +15,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -94,8 +97,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -137,12 +142,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -152,7 +163,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -168,9 +179,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -185,13 +194,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -201,7 +212,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -211,10 +222,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -223,18 +235,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -242,16 +258,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -270,11 +287,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -284,7 +301,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -294,7 +311,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -308,12 +325,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -331,15 +366,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -415,16 +463,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -451,7 +589,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -478,7 +619,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -488,5 +629,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-tagged-union/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/README.md.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/README.md.golden index dd13e00a8..33a68db9a 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'union-type-with-interfaces-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'union-type-with-interfaces-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/apis/DefaultApi.ts.golden index 747ac8e3f..69b808293 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/apis/DefaultApi.ts.golden @@ -6,36 +6,57 @@ */ import type { Foo, Foo$Wire } from '../models/Foo'; import { fooFromJSON, fooToJSON } from '../models/Foo'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, +} from '../runtime/runtime'; export interface ApiTestUnionRequest { body: Foo; } export type TestUnionRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); - -export type TestUnionErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestUnionErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestUnionError extends ResponseError { readonly detail: TestUnionErrorDetail; - constructor(response: Response, detail: TestUnionErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestUnionErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - testUnionRaw: (requestParameters: ApiTestUnionRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - testUnion: (requestParameters: ApiTestUnionRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + testUnionRaw: ( + requestParameters: ApiTestUnionRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + testUnion: ( + requestParameters: ApiTestUnionRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class DefaultApi extends BaseAPI implements DefaultApiInterface { @@ -46,12 +67,14 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async testUnionRaw(requestParameters: ApiTestUnionRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async testUnionRaw( + requestParameters: ApiTestUnionRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling testUnionRaw().' + 'Required parameter "body" was null or undefined when calling testUnionRaw().', ); } // Build path with path parameters @@ -66,33 +89,47 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = fooToJSON(requestParameters.body); // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestUnionError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestUnionError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response, (json) => fooFromJSON(json as Foo$Wire)) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response, (json) => { + return fooFromJSON(json as Foo$Wire); + }) as JSONApiResponse & { status: 200 }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async testUnion(requestParameters: ApiTestUnionRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async testUnion( + requestParameters: ApiTestUnionRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.testUnionRaw(requestParameters, initOverrides); - return await response.value() as Foo; + return (await response.value()) as Foo; } } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/models/Bar.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/models/Bar.ts.golden index a0e770523..ee00864d7 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/models/Bar.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/models/Bar.ts.golden @@ -20,7 +20,7 @@ export function barFromJSON(json: Bar$Wire): Bar { return { bucket: json.bucket, endpoint: json.endpoint, - 'type': json['type'], + type: json['type'], }; } @@ -28,6 +28,6 @@ export function barToJSON(value: Bar): Bar$Wire { return { bucket: value.bucket, endpoint: value.endpoint, - 'type': value['type'], + type: value['type'], }; } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/models/Baz.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/models/Baz.ts.golden index 607bdd09c..6e1e5fe18 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/models/Baz.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/models/Baz.ts.golden @@ -17,13 +17,13 @@ export interface Baz { export function bazFromJSON(json: Baz$Wire): Baz { return { path: json.path, - 'type': json['type'], + type: json['type'], }; } export function bazToJSON(value: Baz): Baz$Wire { return { path: value.path, - 'type': value['type'], + type: value['type'], }; } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/models/Qux.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/models/Qux.ts.golden index 8dc3812d8..9e2376885 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/models/Qux.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/models/Qux.ts.golden @@ -18,16 +18,16 @@ export interface Qux { export function quxFromJSON(json: Qux$Wire): Qux { return { - 'namespace': json['namespace'], - 'type': json['type'], + namespace: json['namespace'], + type: json['type'], url: json.url, }; } export function quxToJSON(value: Qux): Qux$Wire { return { - 'namespace': value['namespace'], - 'type': value['type'], + namespace: value['namespace'], + type: value['type'], url: value.url, }; } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/package.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/package.json.golden index 537713784..b00330362 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/package.json.golden @@ -1,26 +1,26 @@ { + "name": "union-type-with-interfaces-test", + "version": "1.0.0", "description": "Test fixture for oneOf/anyOf union types with interface members", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "union-type-with-interfaces-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/runtime/runtime.ts.golden index dbca9c450..501a9c0a3 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Union Type with Interfaces Test — 1.0.0 * Test fixture for oneOf/anyOf union types with interface members */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case-union/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/README.md.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/README.md.golden index 565aefb6c..bc3ad7741 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'naming-conventions-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'naming-conventions-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/apis/DefaultApi.ts.golden index d4b1c67d4..33d4b3bd1 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/apis/DefaultApi.ts.golden @@ -4,10 +4,28 @@ * Naming Conventions Test — 1.0.0 * Test fixture to verify language property naming conventions */ -import type { NamingConventionTest, NamingConventionTest$Wire } from '../models/NamingConventionTest'; -import { namingConventionTestFromJSON, namingConventionTestToJSON } from '../models/NamingConventionTest'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError, VoidApiResponse } from '../runtime/runtime'; +import type { + NamingConventionTest, + NamingConventionTest$Wire, +} from '../models/NamingConventionTest'; +import { + namingConventionTestFromJSON, + namingConventionTestToJSON, +} from '../models/NamingConventionTest'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, + VoidApiResponse, +} from '../runtime/runtime'; export interface ApiGetWithQueryParamsRequest { snakeCaseParam: string; @@ -29,49 +47,69 @@ export interface ApiTestNamingConventionsRequest { } export type GetWithQueryParamsRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); export type TestNamingConventionsRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); -export type GetWithQueryParamsErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type GetWithQueryParamsErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class GetWithQueryParamsError extends ResponseError { readonly detail: GetWithQueryParamsErrorDetail; - constructor(response: Response, detail: GetWithQueryParamsErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: GetWithQueryParamsErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type TestNamingConventionsErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestNamingConventionsErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestNamingConventionsError extends ResponseError { readonly detail: TestNamingConventionsErrorDetail; - constructor(response: Response, detail: TestNamingConventionsErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestNamingConventionsErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - getWithQueryParamsRaw: (requestParameters: ApiGetWithQueryParamsRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - getWithQueryParams: (requestParameters: ApiGetWithQueryParamsRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - testNamingConventionsRaw: (requestParameters: ApiTestNamingConventionsRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - testNamingConventions: (requestParameters: ApiTestNamingConventionsRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + getWithQueryParamsRaw: ( + requestParameters: ApiGetWithQueryParamsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + getWithQueryParams: ( + requestParameters: ApiGetWithQueryParamsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + testNamingConventionsRaw: ( + requestParameters: ApiTestNamingConventionsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + testNamingConventions: ( + requestParameters: ApiTestNamingConventionsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class DefaultApi extends BaseAPI implements DefaultApiInterface { @@ -82,12 +120,14 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async getWithQueryParamsRaw(requestParameters: ApiGetWithQueryParamsRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async getWithQueryParamsRaw( + requestParameters: ApiGetWithQueryParamsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.snakeCaseParam === undefined || requestParameters.snakeCaseParam === null) { throw new RequiredError( 'snakeCaseParam', - 'Required parameter "snakeCaseParam" was null or undefined when calling getWithQueryParamsRaw().' + 'Required parameter "snakeCaseParam" was null or undefined when calling getWithQueryParamsRaw().', ); } // Build path with path parameters @@ -131,46 +171,59 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { queryParameters['id'] = requestParameters.id; } // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new GetWithQueryParamsError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new GetWithQueryParamsError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async getWithQueryParams(requestParameters: ApiGetWithQueryParamsRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async getWithQueryParams( + requestParameters: ApiGetWithQueryParamsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.getWithQueryParamsRaw(requestParameters, initOverrides); return await response.value(); } - async testNamingConventionsRaw(requestParameters: ApiTestNamingConventionsRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async testNamingConventionsRaw( + requestParameters: ApiTestNamingConventionsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling testNamingConventionsRaw().' + 'Required parameter "body" was null or undefined when calling testNamingConventionsRaw().', ); } // Build path with path parameters @@ -185,33 +238,47 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = namingConventionTestToJSON(requestParameters.body); // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestNamingConventionsError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestNamingConventionsError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response, (json) => namingConventionTestFromJSON(json as NamingConventionTest$Wire)) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response, (json) => { + return namingConventionTestFromJSON(json as NamingConventionTest$Wire); + }) as JSONApiResponse & { status: 200 }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async testNamingConventions(requestParameters: ApiTestNamingConventionsRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async testNamingConventions( + requestParameters: ApiTestNamingConventionsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.testNamingConventionsRaw(requestParameters, initOverrides); - return await response.value() as NamingConventionTest; + return (await response.value()) as NamingConventionTest; } } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/models/NamingConventionTest.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/models/NamingConventionTest.ts.golden index b1735c147..818e52eb3 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/models/NamingConventionTest.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/models/NamingConventionTest.ts.golden @@ -4,12 +4,30 @@ * Naming Conventions Test — 1.0.0 * Test fixture to verify language property naming conventions */ -import type { NamingConventionTestItemsArrayItem, NamingConventionTestItemsArrayItem$Wire } from './NamingConventionTestItemsArrayItem'; -import { namingConventionTestItemsArrayItemFromJSON, namingConventionTestItemsArrayItemToJSON } from './NamingConventionTestItemsArrayItem'; -import type { NamingConventionTestNestedObject, NamingConventionTestNestedObject$Wire } from './NamingConventionTestNestedObject'; -import { namingConventionTestNestedObjectFromJSON, namingConventionTestNestedObjectToJSON } from './NamingConventionTestNestedObject'; -import type { NamingConventionTestPascalCaseObject, NamingConventionTestPascalCaseObject$Wire } from './NamingConventionTestPascalCaseObject'; -import { namingConventionTestPascalCaseObjectFromJSON, namingConventionTestPascalCaseObjectToJSON } from './NamingConventionTestPascalCaseObject'; +import type { + NamingConventionTestItemsArrayItem, + NamingConventionTestItemsArrayItem$Wire, +} from './NamingConventionTestItemsArrayItem'; +import { + namingConventionTestItemsArrayItemFromJSON, + namingConventionTestItemsArrayItemToJSON, +} from './NamingConventionTestItemsArrayItem'; +import type { + NamingConventionTestNestedObject, + NamingConventionTestNestedObject$Wire, +} from './NamingConventionTestNestedObject'; +import { + namingConventionTestNestedObjectFromJSON, + namingConventionTestNestedObjectToJSON, +} from './NamingConventionTestNestedObject'; +import type { + NamingConventionTestPascalCaseObject, + NamingConventionTestPascalCaseObject$Wire, +} from './NamingConventionTestPascalCaseObject'; +import { + namingConventionTestPascalCaseObjectFromJSON, + namingConventionTestPascalCaseObjectToJSON, +} from './NamingConventionTestPascalCaseObject'; export interface NamingConventionTest$Wire { /** @@ -111,19 +129,24 @@ export interface NamingConventionTest { readonly snakeCaseNumber?: number; } -export function namingConventionTestFromJSON(json: NamingConventionTest$Wire): NamingConventionTest { +export function namingConventionTestFromJSON( + json: NamingConventionTest$Wire, +): NamingConventionTest { return { pascalCaseField: json.PascalCaseField, - pascalCaseObject: json.PascalCaseObject !== undefined ? namingConventionTestPascalCaseObjectFromJSON(json.PascalCaseObject) : undefined, + pascalCaseObject: + json.PascalCaseObject !== undefined ? namingConventionTestPascalCaseObjectFromJSON(json.PascalCaseObject) : undefined, screamingNumber: json.SCREAMING_NUMBER, screamingSnakeCase: json.SCREAMING_SNAKE_CASE, camelCaseField: json.camelCaseField, camelCaseNumber: json.camelCaseNumber, id: json.id, - itemsArray: json.items_array !== undefined ? json.items_array.map((item) => namingConventionTestItemsArrayItemFromJSON(item)) : undefined, + itemsArray: + json.items_array !== undefined ? json.items_array.map((item) => namingConventionTestItemsArrayItemFromJSON(item)) : undefined, kebabCaseArray: json['kebab-case-array'], kebabCaseField: json['kebab-case-field'], - nestedObject: json.nested_object !== undefined ? namingConventionTestNestedObjectFromJSON(json.nested_object) : undefined, + nestedObject: + json.nested_object !== undefined ? namingConventionTestNestedObjectFromJSON(json.nested_object) : undefined, singleword: json.singleword, snakeCaseField: json.snake_case_field, snakeCaseNumber: json.snake_case_number, @@ -133,16 +156,19 @@ export function namingConventionTestFromJSON(json: NamingConventionTest$Wire): N export function namingConventionTestToJSON(value: NamingConventionTest): NamingConventionTest$Wire { return { PascalCaseField: value.pascalCaseField, - PascalCaseObject: value.pascalCaseObject !== undefined ? namingConventionTestPascalCaseObjectToJSON(value.pascalCaseObject) : undefined, + PascalCaseObject: + value.pascalCaseObject !== undefined ? namingConventionTestPascalCaseObjectToJSON(value.pascalCaseObject) : undefined, SCREAMING_NUMBER: value.screamingNumber, SCREAMING_SNAKE_CASE: value.screamingSnakeCase, camelCaseField: value.camelCaseField, camelCaseNumber: value.camelCaseNumber, id: value.id, - items_array: value.itemsArray !== undefined ? value.itemsArray.map((item) => namingConventionTestItemsArrayItemToJSON(item)) : undefined, + items_array: + value.itemsArray !== undefined ? value.itemsArray.map((item) => namingConventionTestItemsArrayItemToJSON(item)) : undefined, 'kebab-case-array': value.kebabCaseArray, 'kebab-case-field': value.kebabCaseField, - nested_object: value.nestedObject !== undefined ? namingConventionTestNestedObjectToJSON(value.nestedObject) : undefined, + nested_object: + value.nestedObject !== undefined ? namingConventionTestNestedObjectToJSON(value.nestedObject) : undefined, singleword: value.singleword, snake_case_field: value.snakeCaseField, snake_case_number: value.snakeCaseNumber, diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/models/NamingConventionTestItemsArrayItem.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/models/NamingConventionTestItemsArrayItem.ts.golden index 20fc49da9..e3f8d7211 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/models/NamingConventionTestItemsArrayItem.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/models/NamingConventionTestItemsArrayItem.ts.golden @@ -18,7 +18,9 @@ export interface NamingConventionTestItemsArrayItem { readonly itemSnakeCase?: string; } -export function namingConventionTestItemsArrayItemFromJSON(json: NamingConventionTestItemsArrayItem$Wire): NamingConventionTestItemsArrayItem { +export function namingConventionTestItemsArrayItemFromJSON( + json: NamingConventionTestItemsArrayItem$Wire, +): NamingConventionTestItemsArrayItem { return { itemPascalCase: json.ItemPascalCase, itemKebabCase: json['item-kebab-case'], @@ -27,7 +29,9 @@ export function namingConventionTestItemsArrayItemFromJSON(json: NamingConventio }; } -export function namingConventionTestItemsArrayItemToJSON(value: NamingConventionTestItemsArrayItem): NamingConventionTestItemsArrayItem$Wire { +export function namingConventionTestItemsArrayItemToJSON( + value: NamingConventionTestItemsArrayItem, +): NamingConventionTestItemsArrayItem$Wire { return { ItemPascalCase: value.itemPascalCase, 'item-kebab-case': value.itemKebabCase, diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/models/NamingConventionTestNestedObject.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/models/NamingConventionTestNestedObject.ts.golden index 0c5359668..d01c3890f 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/models/NamingConventionTestNestedObject.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/models/NamingConventionTestNestedObject.ts.golden @@ -18,7 +18,9 @@ export interface NamingConventionTestNestedObject { readonly nestedSnakeCase: string; } -export function namingConventionTestNestedObjectFromJSON(json: NamingConventionTestNestedObject$Wire): NamingConventionTestNestedObject { +export function namingConventionTestNestedObjectFromJSON( + json: NamingConventionTestNestedObject$Wire, +): NamingConventionTestNestedObject { return { nestedPascalCase: json.NestedPascalCase, nestedKebabCase: json['nested-kebab-case'], @@ -27,7 +29,9 @@ export function namingConventionTestNestedObjectFromJSON(json: NamingConventionT }; } -export function namingConventionTestNestedObjectToJSON(value: NamingConventionTestNestedObject): NamingConventionTestNestedObject$Wire { +export function namingConventionTestNestedObjectToJSON( + value: NamingConventionTestNestedObject, +): NamingConventionTestNestedObject$Wire { return { NestedPascalCase: value.nestedPascalCase, 'nested-kebab-case': value.nestedKebabCase, diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/models/NamingConventionTestPascalCaseObject.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/models/NamingConventionTestPascalCaseObject.ts.golden index 18dac6ab0..567679386 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/models/NamingConventionTestPascalCaseObject.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/models/NamingConventionTestPascalCaseObject.ts.golden @@ -12,13 +12,17 @@ export interface NamingConventionTestPascalCaseObject { readonly nestedProperty?: string; } -export function namingConventionTestPascalCaseObjectFromJSON(json: NamingConventionTestPascalCaseObject$Wire): NamingConventionTestPascalCaseObject { +export function namingConventionTestPascalCaseObjectFromJSON( + json: NamingConventionTestPascalCaseObject$Wire, +): NamingConventionTestPascalCaseObject { return { nestedProperty: json.nested_property, }; } -export function namingConventionTestPascalCaseObjectToJSON(value: NamingConventionTestPascalCaseObject): NamingConventionTestPascalCaseObject$Wire { +export function namingConventionTestPascalCaseObjectToJSON( + value: NamingConventionTestPascalCaseObject, +): NamingConventionTestPascalCaseObject$Wire { return { nested_property: value.nestedProperty, }; diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/models/index.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/models/index.ts.golden index 37b2d9571..7bc3f7c27 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/models/index.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/models/index.ts.golden @@ -6,9 +6,27 @@ */ export type { NamingConventionTest, NamingConventionTest$Wire } from './NamingConventionTest'; export { namingConventionTestFromJSON, namingConventionTestToJSON } from './NamingConventionTest'; -export type { NamingConventionTestItemsArrayItem, NamingConventionTestItemsArrayItem$Wire } from './NamingConventionTestItemsArrayItem'; -export { namingConventionTestItemsArrayItemFromJSON, namingConventionTestItemsArrayItemToJSON } from './NamingConventionTestItemsArrayItem'; -export type { NamingConventionTestNestedObject, NamingConventionTestNestedObject$Wire } from './NamingConventionTestNestedObject'; -export { namingConventionTestNestedObjectFromJSON, namingConventionTestNestedObjectToJSON } from './NamingConventionTestNestedObject'; -export type { NamingConventionTestPascalCaseObject, NamingConventionTestPascalCaseObject$Wire } from './NamingConventionTestPascalCaseObject'; -export { namingConventionTestPascalCaseObjectFromJSON, namingConventionTestPascalCaseObjectToJSON } from './NamingConventionTestPascalCaseObject'; +export type { + NamingConventionTestItemsArrayItem, + NamingConventionTestItemsArrayItem$Wire, +} from './NamingConventionTestItemsArrayItem'; +export { + namingConventionTestItemsArrayItemFromJSON, + namingConventionTestItemsArrayItemToJSON, +} from './NamingConventionTestItemsArrayItem'; +export type { + NamingConventionTestNestedObject, + NamingConventionTestNestedObject$Wire, +} from './NamingConventionTestNestedObject'; +export { + namingConventionTestNestedObjectFromJSON, + namingConventionTestNestedObjectToJSON, +} from './NamingConventionTestNestedObject'; +export type { + NamingConventionTestPascalCaseObject, + NamingConventionTestPascalCaseObject$Wire, +} from './NamingConventionTestPascalCaseObject'; +export { + namingConventionTestPascalCaseObjectFromJSON, + namingConventionTestPascalCaseObjectToJSON, +} from './NamingConventionTestPascalCaseObject'; diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/package.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/package.json.golden index 379d653c4..3351be2a4 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/package.json.golden @@ -1,26 +1,26 @@ { + "name": "naming-conventions-test", + "version": "1.0.0", "description": "Test fixture to verify language property naming conventions", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "naming-conventions-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/runtime/runtime.ts.golden index 6defd7205..000eb9d38 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Naming Conventions Test — 1.0.0 * Test fixture to verify language property naming conventions */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-property-naming-camel-case/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/README.md.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/README.md.golden index cab814d00..a59736937 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'type-script-fetch-vp-camel-case-maske const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -140,7 +140,11 @@ const config = new Configuration({ The client throws typed errors for different failure scenarios: ```typescript -import { ResponseError, FetchError, RequiredError } from 'type-script-fetch-vp-camel-case-masked-regression-test'; +import { + ResponseError, + FetchError, + RequiredError, +} from 'type-script-fetch-vp-camel-case-masked-regression-test'; try { const result = await api.someMethod(); @@ -190,6 +194,22 @@ To build ES modules: npm run build ``` +### Formatting and validation + +After generating or regenerating this client, install its development dependencies, +run all checks on the generated files and build the library: + +```bash +vp install +vp check +vp pack +``` + +The `check` and `build` npm scripts run the same Vite+ commands. +Use `vp fmt` (or the `fmt` script) to format any subsequent manual edits. +`vp check` validates formatting, lint rules, and types without modifying files. +Build output in `dist/` is excluded from formatting. + ## TypeScript Support This package includes TypeScript type definitions. No additional `@types` package is needed. @@ -209,12 +229,15 @@ This package works with standard TypeScript configurations. If you're using a bu ### Type Imports ```typescript -import type { User, CreateUserRequest } from 'type-script-fetch-vp-camel-case-masked-regression-test'; +import type { + User, + CreateUserRequest, +} from 'type-script-fetch-vp-camel-case-masked-regression-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/apis/DefaultApi.ts.golden index ee1e90912..f77f02ace 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/apis/DefaultApi.ts.golden @@ -6,36 +6,57 @@ */ import type { FooEnvelope, FooEnvelope$Wire } from '../models/FooEnvelope'; import { fooEnvelopeFromJSON, fooEnvelopeToJSON } from '../models/FooEnvelope'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, +} from '../runtime/runtime'; export interface ApiCreateFooEnvelopeRequest { body: FooEnvelope; } export type CreateFooEnvelopeRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); - -export type CreateFooEnvelopeErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type CreateFooEnvelopeErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class CreateFooEnvelopeError extends ResponseError { readonly detail: CreateFooEnvelopeErrorDetail; - constructor(response: Response, detail: CreateFooEnvelopeErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: CreateFooEnvelopeErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - createFooEnvelopeRaw: (requestParameters: ApiCreateFooEnvelopeRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - createFooEnvelope: (requestParameters: ApiCreateFooEnvelopeRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + createFooEnvelopeRaw: ( + requestParameters: ApiCreateFooEnvelopeRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + createFooEnvelope: ( + requestParameters: ApiCreateFooEnvelopeRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class DefaultApi extends BaseAPI implements DefaultApiInterface { @@ -46,12 +67,14 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async createFooEnvelopeRaw(requestParameters: ApiCreateFooEnvelopeRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async createFooEnvelopeRaw( + requestParameters: ApiCreateFooEnvelopeRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling createFooEnvelopeRaw().' + 'Required parameter "body" was null or undefined when calling createFooEnvelopeRaw().', ); } // Build path with path parameters @@ -66,33 +89,47 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = fooEnvelopeToJSON(requestParameters.body); // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new CreateFooEnvelopeError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new CreateFooEnvelopeError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response, (json) => fooEnvelopeFromJSON(json as FooEnvelope$Wire)) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response, (json) => { + return fooEnvelopeFromJSON(json as FooEnvelope$Wire); + }) as JSONApiResponse & { status: 200 }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async createFooEnvelope(requestParameters: ApiCreateFooEnvelopeRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async createFooEnvelope( + requestParameters: ApiCreateFooEnvelopeRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.createFooEnvelopeRaw(requestParameters, initOverrides); - return await response.value() as FooEnvelope; + return (await response.value()) as FooEnvelope; } } diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooAdjacentPayload.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooAdjacentPayload.ts.golden index 4b8eee5ec..919a7370d 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooAdjacentPayload.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooAdjacentPayload.ts.golden @@ -4,41 +4,84 @@ * TypeScript Fetch VP CamelCase Masked Regression Test — 1.0.0 * Masked fixture for TypeScript Fetch camelCase regression coverage. */ -import type { FooAdjacentPayloadFooInlineObjectPayloadValue, FooAdjacentPayloadFooInlineObjectPayloadValue$Wire } from './FooAdjacentPayloadFooInlineObjectPayloadValue'; -import { fooAdjacentPayloadFooInlineObjectPayloadValueFromJSON, fooAdjacentPayloadFooInlineObjectPayloadValueToJSON } from './FooAdjacentPayloadFooInlineObjectPayloadValue'; +import type { + FooAdjacentPayloadFooInlineObjectPayloadValue, + FooAdjacentPayloadFooInlineObjectPayloadValue$Wire, +} from './FooAdjacentPayloadFooInlineObjectPayloadValue'; +import { + fooAdjacentPayloadFooInlineObjectPayloadValueFromJSON, + fooAdjacentPayloadFooInlineObjectPayloadValueToJSON, +} from './FooAdjacentPayloadFooInlineObjectPayloadValue'; import type { FooArrayPart, FooArrayPart$Wire } from './FooArrayPart'; import { fooArrayPartFromJSON, fooArrayPartToJSON } from './FooArrayPart'; -export type FooAdjacentPayload$Wire = { type: 'foo_inline_none' } | { type: 'foo_inline_text'; payload_value: string } | { type: 'foo_inline_object'; payload_value: FooAdjacentPayloadFooInlineObjectPayloadValue$Wire } | { type: 'foo_inline_list'; payload_value: readonly FooArrayPart$Wire[] }; +export type FooAdjacentPayload$Wire = + | { type: 'foo_inline_none' } + | { type: 'foo_inline_text'; payload_value: string } + | { type: 'foo_inline_object'; payload_value: FooAdjacentPayloadFooInlineObjectPayloadValue$Wire } + | { type: 'foo_inline_list'; payload_value: readonly FooArrayPart$Wire[] }; -export type FooAdjacentPayload = { type: 'foo_inline_none' } | { type: 'foo_inline_text'; payloadValue: string } | { type: 'foo_inline_object'; payloadValue: FooAdjacentPayloadFooInlineObjectPayloadValue } | { type: 'foo_inline_list'; payloadValue: readonly FooArrayPart[] }; +export type FooAdjacentPayload = + | { type: 'foo_inline_none' } + | { type: 'foo_inline_text'; payloadValue: string } + | { type: 'foo_inline_object'; payloadValue: FooAdjacentPayloadFooInlineObjectPayloadValue } + | { type: 'foo_inline_list'; payloadValue: readonly FooArrayPart[] }; export function fooAdjacentPayloadFromJSON(json: FooAdjacentPayload$Wire): FooAdjacentPayload { switch (json.type) { - case 'foo_inline_none': return { type: 'foo_inline_none' }; - case 'foo_inline_text': return { type: 'foo_inline_text', payloadValue: json.payload_value }; - case 'foo_inline_object': return { type: 'foo_inline_object', payloadValue: fooAdjacentPayloadFooInlineObjectPayloadValueFromJSON(json.payload_value) }; - case 'foo_inline_list': return { type: 'foo_inline_list', payloadValue: json.payload_value.map((item) => fooArrayPartFromJSON(item)) }; + case 'foo_inline_none': + return { type: 'foo_inline_none' }; + case 'foo_inline_text': + return { type: 'foo_inline_text', payloadValue: json.payload_value }; + case 'foo_inline_object': + return { + type: 'foo_inline_object', + payloadValue: fooAdjacentPayloadFooInlineObjectPayloadValueFromJSON(json.payload_value), + }; + case 'foo_inline_list': + return { + type: 'foo_inline_list', + payloadValue: json.payload_value.map((item) => fooArrayPartFromJSON(item)), + }; } } export function fooAdjacentPayloadToJSON(value: FooAdjacentPayload): FooAdjacentPayload$Wire { switch (value.type) { - case 'foo_inline_none': return { type: 'foo_inline_none' }; - case 'foo_inline_text': return { type: 'foo_inline_text', payload_value: value.payloadValue }; - case 'foo_inline_object': return { type: 'foo_inline_object', payload_value: fooAdjacentPayloadFooInlineObjectPayloadValueToJSON(value.payloadValue) }; - case 'foo_inline_list': return { type: 'foo_inline_list', payload_value: value.payloadValue.map((item) => fooArrayPartToJSON(item)) }; + case 'foo_inline_none': + return { type: 'foo_inline_none' }; + case 'foo_inline_text': + return { type: 'foo_inline_text', payload_value: value.payloadValue }; + case 'foo_inline_object': + return { + type: 'foo_inline_object', + payload_value: fooAdjacentPayloadFooInlineObjectPayloadValueToJSON(value.payloadValue), + }; + case 'foo_inline_list': + return { + type: 'foo_inline_list', + payload_value: value.payloadValue.map((item) => fooArrayPartToJSON(item)), + }; } } -export function isFooInlineText(value: FooAdjacentPayload): value is { type: 'foo_inline_text'; payloadValue: string } { +export function isFooInlineText(value: FooAdjacentPayload): value is { + type: 'foo_inline_text'; + payloadValue: string; +} { return value.type === 'foo_inline_text'; } -export function isFooInlineObject(value: FooAdjacentPayload): value is { type: 'foo_inline_object'; payloadValue: FooAdjacentPayloadFooInlineObjectPayloadValue } { +export function isFooInlineObject(value: FooAdjacentPayload): value is { + type: 'foo_inline_object'; + payloadValue: FooAdjacentPayloadFooInlineObjectPayloadValue; +} { return value.type === 'foo_inline_object'; } -export function isFooInlineList(value: FooAdjacentPayload): value is { type: 'foo_inline_list'; payloadValue: readonly FooArrayPart[] } { +export function isFooInlineList(value: FooAdjacentPayload): value is { + type: 'foo_inline_list'; + payloadValue: readonly FooArrayPart[]; +} { return value.type === 'foo_inline_list'; } diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooAdjacentPayloadFooInlineNone.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooAdjacentPayloadFooInlineNone.ts.golden index d1fc211ae..eaa991efa 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooAdjacentPayloadFooInlineNone.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooAdjacentPayloadFooInlineNone.ts.golden @@ -12,14 +12,18 @@ export interface FooAdjacentPayloadFooInlineNone { readonly type: 'foo_inline_none'; } -export function fooAdjacentPayloadFooInlineNoneFromJSON(json: FooAdjacentPayloadFooInlineNone$Wire): FooAdjacentPayloadFooInlineNone { +export function fooAdjacentPayloadFooInlineNoneFromJSON( + json: FooAdjacentPayloadFooInlineNone$Wire, +): FooAdjacentPayloadFooInlineNone { return { - 'type': json['type'], + type: json['type'], }; } -export function fooAdjacentPayloadFooInlineNoneToJSON(value: FooAdjacentPayloadFooInlineNone): FooAdjacentPayloadFooInlineNone$Wire { +export function fooAdjacentPayloadFooInlineNoneToJSON( + value: FooAdjacentPayloadFooInlineNone, +): FooAdjacentPayloadFooInlineNone$Wire { return { - 'type': value['type'], + type: value['type'], }; } diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooAdjacentPayloadFooInlineObjectPayloadValue.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooAdjacentPayloadFooInlineObjectPayloadValue.ts.golden index 79b0ab894..859620c56 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooAdjacentPayloadFooInlineObjectPayloadValue.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooAdjacentPayloadFooInlineObjectPayloadValue.ts.golden @@ -12,13 +12,17 @@ export interface FooAdjacentPayloadFooInlineObjectPayloadValue { readonly barValue: string; } -export function fooAdjacentPayloadFooInlineObjectPayloadValueFromJSON(json: FooAdjacentPayloadFooInlineObjectPayloadValue$Wire): FooAdjacentPayloadFooInlineObjectPayloadValue { +export function fooAdjacentPayloadFooInlineObjectPayloadValueFromJSON( + json: FooAdjacentPayloadFooInlineObjectPayloadValue$Wire, +): FooAdjacentPayloadFooInlineObjectPayloadValue { return { barValue: json.bar_value, }; } -export function fooAdjacentPayloadFooInlineObjectPayloadValueToJSON(value: FooAdjacentPayloadFooInlineObjectPayloadValue): FooAdjacentPayloadFooInlineObjectPayloadValue$Wire { +export function fooAdjacentPayloadFooInlineObjectPayloadValueToJSON( + value: FooAdjacentPayloadFooInlineObjectPayloadValue, +): FooAdjacentPayloadFooInlineObjectPayloadValue$Wire { return { bar_value: value.barValue, }; diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooClosedVariant.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooClosedVariant.ts.golden index d81c139f5..0497403d9 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooClosedVariant.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooClosedVariant.ts.golden @@ -14,12 +14,12 @@ export interface FooClosedVariant { export function fooClosedVariantFromJSON(json: FooClosedVariant$Wire): FooClosedVariant { return { - 'type': json['type'], + type: json['type'], }; } export function fooClosedVariantToJSON(value: FooClosedVariant): FooClosedVariant$Wire { return { - 'type': value['type'], + type: value['type'], }; } diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooMappedTagUnion.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooMappedTagUnion.ts.golden index 4c874bbf9..4a1e9d909 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooMappedTagUnion.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooMappedTagUnion.ts.golden @@ -7,24 +7,34 @@ import type { FooOpenVariant, FooOpenVariant$Wire } from './FooOpenVariant'; import { fooOpenVariantFromJSON, fooOpenVariantToJSON } from './FooOpenVariant'; -export type FooMappedTagUnion$Wire = { type: 'foo_closed_variant' } | ({ type: 'foo_open_variant' } & FooOpenVariant$Wire); +export type FooMappedTagUnion$Wire = + | { type: 'foo_closed_variant' } + | ({ type: 'foo_open_variant' } & FooOpenVariant$Wire); -export type FooMappedTagUnion = { type: 'foo_closed_variant' } | ({ type: 'foo_open_variant' } & FooOpenVariant); +export type FooMappedTagUnion = + | { type: 'foo_closed_variant' } + | ({ type: 'foo_open_variant' } & FooOpenVariant); export function fooMappedTagUnionFromJSON(json: FooMappedTagUnion$Wire): FooMappedTagUnion { switch (json.type) { - case 'foo_closed_variant': return { type: 'foo_closed_variant' }; - case 'foo_open_variant': return { ...fooOpenVariantFromJSON(json), type: 'foo_open_variant' }; + case 'foo_closed_variant': + return { type: 'foo_closed_variant' }; + case 'foo_open_variant': + return { ...fooOpenVariantFromJSON(json), type: 'foo_open_variant' }; } } export function fooMappedTagUnionToJSON(value: FooMappedTagUnion): FooMappedTagUnion$Wire { switch (value.type) { - case 'foo_closed_variant': return { type: 'foo_closed_variant' } as FooMappedTagUnion$Wire; - case 'foo_open_variant': return { ...fooOpenVariantToJSON(value), type: 'foo_open_variant' } as FooMappedTagUnion$Wire; + case 'foo_closed_variant': + return { type: 'foo_closed_variant' } as FooMappedTagUnion$Wire; + case 'foo_open_variant': + return { ...fooOpenVariantToJSON(value), type: 'foo_open_variant' } as FooMappedTagUnion$Wire; } } -export function isFooOpenVariant(value: FooMappedTagUnion): value is ({ type: 'foo_open_variant' } & FooOpenVariant) { +export function isFooOpenVariant(value: FooMappedTagUnion): value is { + type: 'foo_open_variant'; +} & FooOpenVariant { return value.type === 'foo_open_variant'; } diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooNullableItems.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooNullableItems.ts.golden index c0f1b8764..667268bd5 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooNullableItems.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooNullableItems.ts.golden @@ -17,12 +17,14 @@ export interface FooNullableItems { export function fooNullableItemsFromJSON(json: FooNullableItems$Wire): FooNullableItems { return { - content: json.content === null ? null : json.content.map((item) => fooNullableItemFromJSON(item)), + content: + json.content === null ? null : json.content.map((item) => fooNullableItemFromJSON(item)), }; } export function fooNullableItemsToJSON(value: FooNullableItems): FooNullableItems$Wire { return { - content: value.content === null ? null : value.content.map((item) => fooNullableItemToJSON(item)), + content: + value.content === null ? null : value.content.map((item) => fooNullableItemToJSON(item)), }; } diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooNullableRefHolder.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooNullableRefHolder.ts.golden index 57bf2fd58..b703ef94c 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooNullableRefHolder.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooNullableRefHolder.ts.golden @@ -15,7 +15,9 @@ export interface FooNullableRefHolder { readonly maybeItems: FooNullableItems | null; } -export function fooNullableRefHolderFromJSON(json: FooNullableRefHolder$Wire): FooNullableRefHolder { +export function fooNullableRefHolderFromJSON( + json: FooNullableRefHolder$Wire, +): FooNullableRefHolder { return { maybeItems: json.maybe_items === null ? null : fooNullableItemsFromJSON(json.maybe_items), }; diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooOpenVariant.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooOpenVariant.ts.golden index 198fcc03b..fcc234f4f 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooOpenVariant.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooOpenVariant.ts.golden @@ -13,21 +13,37 @@ export interface FooOpenVariant extends Readonly !['type'].includes(key)).map(([key, value]) => {const additionalValue = value as string; return [key, additionalValue] as const;})); + const sourceEntries = Object.entries(json).filter(([key]) => { + return !['type'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as string; + return [key, additionalValue] as const; + }), + ); const result = { ...additionalProperties, - 'type': json['type'], + type: json['type'], }; return result; } export function fooOpenVariantToJSON(value: FooOpenVariant): FooOpenVariant$Wire { - const additionalProperties = Object.fromEntries(Object.entries(value) - .filter(([key]) => !['type'].includes(key)).map(([key, value]) => {const additionalValue = value as string; return [key, additionalValue] as const;})); + const sourceEntries = Object.entries(value).filter(([key]) => { + return !['type'].includes(key); + }); + const additionalEntries = sourceEntries; + const additionalProperties = Object.fromEntries( + additionalEntries.map(([key, value]) => { + const additionalValue = value as string; + return [key, additionalValue] as const; + }), + ); const result = { ...additionalProperties, - 'type': value['type'], + type: value['type'], }; return result; } diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooTagOnlyUnion.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooTagOnlyUnion.ts.golden index 573e386a7..f47cbd138 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooTagOnlyUnion.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooTagOnlyUnion.ts.golden @@ -7,26 +7,47 @@ import type { FooObjectPayload, FooObjectPayload$Wire } from './FooObjectPayload'; import { fooObjectPayloadFromJSON, fooObjectPayloadToJSON } from './FooObjectPayload'; -export type FooTagOnlyUnion$Wire = { type: 'foo_unit_alpha' } | { type: 'foo_unit_beta' } | { type: 'foo_object_payload'; object_payload: FooObjectPayload$Wire }; +export type FooTagOnlyUnion$Wire = + | { type: 'foo_unit_alpha' } + | { type: 'foo_unit_beta' } + | { type: 'foo_object_payload'; object_payload: FooObjectPayload$Wire }; -export type FooTagOnlyUnion = { type: 'foo_unit_alpha' } | { type: 'foo_unit_beta' } | { type: 'foo_object_payload'; objectPayload: FooObjectPayload }; +export type FooTagOnlyUnion = + | { type: 'foo_unit_alpha' } + | { type: 'foo_unit_beta' } + | { type: 'foo_object_payload'; objectPayload: FooObjectPayload }; export function fooTagOnlyUnionFromJSON(json: FooTagOnlyUnion$Wire): FooTagOnlyUnion { switch (json.type) { - case 'foo_unit_alpha': return { type: 'foo_unit_alpha' }; - case 'foo_unit_beta': return { type: 'foo_unit_beta' }; - case 'foo_object_payload': return { type: 'foo_object_payload', objectPayload: fooObjectPayloadFromJSON(json.object_payload) }; + case 'foo_unit_alpha': + return { type: 'foo_unit_alpha' }; + case 'foo_unit_beta': + return { type: 'foo_unit_beta' }; + case 'foo_object_payload': + return { + type: 'foo_object_payload', + objectPayload: fooObjectPayloadFromJSON(json.object_payload), + }; } } export function fooTagOnlyUnionToJSON(value: FooTagOnlyUnion): FooTagOnlyUnion$Wire { switch (value.type) { - case 'foo_unit_alpha': return { type: 'foo_unit_alpha' }; - case 'foo_unit_beta': return { type: 'foo_unit_beta' }; - case 'foo_object_payload': return { type: 'foo_object_payload', object_payload: fooObjectPayloadToJSON(value.objectPayload) }; + case 'foo_unit_alpha': + return { type: 'foo_unit_alpha' }; + case 'foo_unit_beta': + return { type: 'foo_unit_beta' }; + case 'foo_object_payload': + return { + type: 'foo_object_payload', + object_payload: fooObjectPayloadToJSON(value.objectPayload), + }; } } -export function isFooObjectPayload(value: FooTagOnlyUnion): value is { type: 'foo_object_payload'; objectPayload: FooObjectPayload } { +export function isFooObjectPayload(value: FooTagOnlyUnion): value is { + type: 'foo_object_payload'; + objectPayload: FooObjectPayload; +} { return value.type === 'foo_object_payload'; } diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooTagOnlyUnionFooUnitAlpha.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooTagOnlyUnionFooUnitAlpha.ts.golden index 1efba860e..05eabe6e7 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooTagOnlyUnionFooUnitAlpha.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooTagOnlyUnionFooUnitAlpha.ts.golden @@ -12,14 +12,18 @@ export interface FooTagOnlyUnionFooUnitAlpha { readonly type: 'foo_unit_alpha'; } -export function fooTagOnlyUnionFooUnitAlphaFromJSON(json: FooTagOnlyUnionFooUnitAlpha$Wire): FooTagOnlyUnionFooUnitAlpha { +export function fooTagOnlyUnionFooUnitAlphaFromJSON( + json: FooTagOnlyUnionFooUnitAlpha$Wire, +): FooTagOnlyUnionFooUnitAlpha { return { - 'type': json['type'], + type: json['type'], }; } -export function fooTagOnlyUnionFooUnitAlphaToJSON(value: FooTagOnlyUnionFooUnitAlpha): FooTagOnlyUnionFooUnitAlpha$Wire { +export function fooTagOnlyUnionFooUnitAlphaToJSON( + value: FooTagOnlyUnionFooUnitAlpha, +): FooTagOnlyUnionFooUnitAlpha$Wire { return { - 'type': value['type'], + type: value['type'], }; } diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooTagOnlyUnionFooUnitBeta.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooTagOnlyUnionFooUnitBeta.ts.golden index 09d4bb4c1..fd6ec9663 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooTagOnlyUnionFooUnitBeta.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooTagOnlyUnionFooUnitBeta.ts.golden @@ -12,14 +12,18 @@ export interface FooTagOnlyUnionFooUnitBeta { readonly type: 'foo_unit_beta'; } -export function fooTagOnlyUnionFooUnitBetaFromJSON(json: FooTagOnlyUnionFooUnitBeta$Wire): FooTagOnlyUnionFooUnitBeta { +export function fooTagOnlyUnionFooUnitBetaFromJSON( + json: FooTagOnlyUnionFooUnitBeta$Wire, +): FooTagOnlyUnionFooUnitBeta { return { - 'type': json['type'], + type: json['type'], }; } -export function fooTagOnlyUnionFooUnitBetaToJSON(value: FooTagOnlyUnionFooUnitBeta): FooTagOnlyUnionFooUnitBeta$Wire { +export function fooTagOnlyUnionFooUnitBetaToJSON( + value: FooTagOnlyUnionFooUnitBeta, +): FooTagOnlyUnionFooUnitBeta$Wire { return { - 'type': value['type'], + type: value['type'], }; } diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooTaggedRef.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooTaggedRef.ts.golden index fbea7f9ba..ebd0ad992 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooTaggedRef.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/FooTaggedRef.ts.golden @@ -13,16 +13,21 @@ export type FooTaggedRef = { type: 'foo_ref_payload'; barPayload: FooPayloadBody export function fooTaggedRefFromJSON(json: FooTaggedRef$Wire): FooTaggedRef { switch (json.type) { - case 'foo_ref_payload': return { type: 'foo_ref_payload', barPayload: fooPayloadBodyFromJSON(json.bar_payload) }; + case 'foo_ref_payload': + return { type: 'foo_ref_payload', barPayload: fooPayloadBodyFromJSON(json.bar_payload) }; } } export function fooTaggedRefToJSON(value: FooTaggedRef): FooTaggedRef$Wire { switch (value.type) { - case 'foo_ref_payload': return { type: 'foo_ref_payload', bar_payload: fooPayloadBodyToJSON(value.barPayload) }; + case 'foo_ref_payload': + return { type: 'foo_ref_payload', bar_payload: fooPayloadBodyToJSON(value.barPayload) }; } } -export function isFooRefPayload(value: FooTaggedRef): value is { type: 'foo_ref_payload'; barPayload: FooPayloadBody } { +export function isFooRefPayload(value: FooTaggedRef): value is { + type: 'foo_ref_payload'; + barPayload: FooPayloadBody; +} { return value.type === 'foo_ref_payload'; } diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/index.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/index.ts.golden index a5d0e0589..c48c1239d 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/index.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/models/index.ts.golden @@ -5,11 +5,29 @@ * Masked fixture for TypeScript Fetch camelCase regression coverage. */ export type { FooAdjacentPayload, FooAdjacentPayload$Wire } from './FooAdjacentPayload'; -export { fooAdjacentPayloadFromJSON, fooAdjacentPayloadToJSON, isFooInlineText, isFooInlineObject, isFooInlineList } from './FooAdjacentPayload'; -export type { FooAdjacentPayloadFooInlineNone, FooAdjacentPayloadFooInlineNone$Wire } from './FooAdjacentPayloadFooInlineNone'; -export { fooAdjacentPayloadFooInlineNoneFromJSON, fooAdjacentPayloadFooInlineNoneToJSON } from './FooAdjacentPayloadFooInlineNone'; -export type { FooAdjacentPayloadFooInlineObjectPayloadValue, FooAdjacentPayloadFooInlineObjectPayloadValue$Wire } from './FooAdjacentPayloadFooInlineObjectPayloadValue'; -export { fooAdjacentPayloadFooInlineObjectPayloadValueFromJSON, fooAdjacentPayloadFooInlineObjectPayloadValueToJSON } from './FooAdjacentPayloadFooInlineObjectPayloadValue'; +export { + fooAdjacentPayloadFromJSON, + fooAdjacentPayloadToJSON, + isFooInlineText, + isFooInlineObject, + isFooInlineList, +} from './FooAdjacentPayload'; +export type { + FooAdjacentPayloadFooInlineNone, + FooAdjacentPayloadFooInlineNone$Wire, +} from './FooAdjacentPayloadFooInlineNone'; +export { + fooAdjacentPayloadFooInlineNoneFromJSON, + fooAdjacentPayloadFooInlineNoneToJSON, +} from './FooAdjacentPayloadFooInlineNone'; +export type { + FooAdjacentPayloadFooInlineObjectPayloadValue, + FooAdjacentPayloadFooInlineObjectPayloadValue$Wire, +} from './FooAdjacentPayloadFooInlineObjectPayloadValue'; +export { + fooAdjacentPayloadFooInlineObjectPayloadValueFromJSON, + fooAdjacentPayloadFooInlineObjectPayloadValueToJSON, +} from './FooAdjacentPayloadFooInlineObjectPayloadValue'; export type { FooAnyValue } from './FooAnyValue'; export type { FooArrayPart, FooArrayPart$Wire } from './FooArrayPart'; export { fooArrayPartFromJSON, fooArrayPartToJSON } from './FooArrayPart'; @@ -18,7 +36,11 @@ export { fooClosedVariantFromJSON, fooClosedVariantToJSON } from './FooClosedVar export type { FooEnvelope, FooEnvelope$Wire } from './FooEnvelope'; export { fooEnvelopeFromJSON, fooEnvelopeToJSON } from './FooEnvelope'; export type { FooMappedTagUnion, FooMappedTagUnion$Wire } from './FooMappedTagUnion'; -export { fooMappedTagUnionFromJSON, fooMappedTagUnionToJSON, isFooOpenVariant } from './FooMappedTagUnion'; +export { + fooMappedTagUnionFromJSON, + fooMappedTagUnionToJSON, + isFooOpenVariant, +} from './FooMappedTagUnion'; export type { FooNullableItem, FooNullableItem$Wire } from './FooNullableItem'; export { fooNullableItemFromJSON, fooNullableItemToJSON } from './FooNullableItem'; export type { FooNullableItems, FooNullableItems$Wire } from './FooNullableItems'; @@ -32,11 +54,27 @@ export { fooOpenVariantFromJSON, fooOpenVariantToJSON } from './FooOpenVariant'; export type { FooPayloadBody, FooPayloadBody$Wire } from './FooPayloadBody'; export { fooPayloadBodyFromJSON, fooPayloadBodyToJSON } from './FooPayloadBody'; export type { FooTagOnlyUnion, FooTagOnlyUnion$Wire } from './FooTagOnlyUnion'; -export { fooTagOnlyUnionFromJSON, fooTagOnlyUnionToJSON, isFooObjectPayload } from './FooTagOnlyUnion'; -export type { FooTagOnlyUnionFooUnitAlpha, FooTagOnlyUnionFooUnitAlpha$Wire } from './FooTagOnlyUnionFooUnitAlpha'; -export { fooTagOnlyUnionFooUnitAlphaFromJSON, fooTagOnlyUnionFooUnitAlphaToJSON } from './FooTagOnlyUnionFooUnitAlpha'; -export type { FooTagOnlyUnionFooUnitBeta, FooTagOnlyUnionFooUnitBeta$Wire } from './FooTagOnlyUnionFooUnitBeta'; -export { fooTagOnlyUnionFooUnitBetaFromJSON, fooTagOnlyUnionFooUnitBetaToJSON } from './FooTagOnlyUnionFooUnitBeta'; +export { + fooTagOnlyUnionFromJSON, + fooTagOnlyUnionToJSON, + isFooObjectPayload, +} from './FooTagOnlyUnion'; +export type { + FooTagOnlyUnionFooUnitAlpha, + FooTagOnlyUnionFooUnitAlpha$Wire, +} from './FooTagOnlyUnionFooUnitAlpha'; +export { + fooTagOnlyUnionFooUnitAlphaFromJSON, + fooTagOnlyUnionFooUnitAlphaToJSON, +} from './FooTagOnlyUnionFooUnitAlpha'; +export type { + FooTagOnlyUnionFooUnitBeta, + FooTagOnlyUnionFooUnitBeta$Wire, +} from './FooTagOnlyUnionFooUnitBeta'; +export { + fooTagOnlyUnionFooUnitBetaFromJSON, + fooTagOnlyUnionFooUnitBetaToJSON, +} from './FooTagOnlyUnionFooUnitBeta'; export type { FooTaggedRef, FooTaggedRef$Wire } from './FooTaggedRef'; export { fooTaggedRefFromJSON, fooTaggedRefToJSON, isFooRefPayload } from './FooTaggedRef'; export type { FooUnionContent, FooUnionContent$Wire } from './FooUnionContent'; diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/package.json.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/package.json.golden index 8a092f4ec..e945f058d 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/package.json.golden @@ -1,31 +1,32 @@ { + "name": "type-script-fetch-vp-camel-case-masked-regression-test", + "version": "1.0.0", "description": "Masked fixture for TypeScript Fetch camelCase regression coverage.", - "devDependencies": { - "typescript": "^7.0.2", - "vite-plus": "^1.5.0" - }, + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.mjs", + "types": "./dist/index.d.mts", "exports": { ".": { "default": "./dist/index.mjs", "types": "./dist/index.d.mts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.mjs", - "name": "type-script-fetch-vp-camel-case-masked-regression-test", "scripts": { "build": "vp pack", - "check": "vp check --no-fmt" + "check": "vp check", + "fmt": "vp fmt" }, - "type": "module", - "types": "./dist/index.d.mts", - "version": "1.0.0" -} \ No newline at end of file + "devDependencies": { + "typescript": "^7.0.2", + "vite-plus": "^1.5.0" + } +} diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/runtime/runtime.ts.golden index 4a9694e39..6f380b437 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * TypeScript Fetch VP CamelCase Masked Regression Test — 1.0.0 * Masked fixture for TypeScript Fetch camelCase regression coverage. */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/vite.config.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/vite.config.ts.golden index 250639b98..065569dd3 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/vite.config.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-camel-case-tagged-nullable-unions/vite.config.ts.golden @@ -1,6 +1,10 @@ import { defineConfig } from 'vite-plus'; export default defineConfig({ + fmt: { + singleQuote: true, + ignorePatterns: ['dist/**'], + }, lint: { options: { typeAware: true, diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/README.md.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/README.md.golden index 4764722a0..3f4de1867 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'comprehensive-schema-types-example'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -190,6 +190,22 @@ To build ES modules: npm run build ``` +### Formatting and validation + +After generating or regenerating this client, install its development dependencies, +run all checks on the generated files and build the library: + +```bash +vp install +vp check +vp pack +``` + +The `check` and `build` npm scripts run the same Vite+ commands. +Use `vp fmt` (or the `fmt` script) to format any subsequent manual edits. +`vp check` validates formatting, lint rules, and types without modifying files. +Build output in `dist/` is excluded from formatting. + ## TypeScript Support This package includes TypeScript type definitions. No additional `@types` package is needed. @@ -214,7 +230,7 @@ import type { User, CreateUserRequest } from 'comprehensive-schema-types-example const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/apis/DefaultApi.ts.golden index 7ab3facda..6b3aaae1d 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/apis/DefaultApi.ts.golden @@ -4,22 +4,33 @@ * Comprehensive Schema Types Example — 1.0.0 * Comprehensive test for all OpenAPI v3.1.2 schema types */ -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; import { BaseAPI, DefaultConfig, ResponseError, VoidApiResponse } from '../runtime/runtime'; export type TestRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); - -export type TestErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestError extends ResponseError { readonly detail: TestErrorDetail; - constructor(response: Response, detail: TestErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } @@ -44,30 +55,39 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/models/ObjectWithTypedAdditionalProperties.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/models/ObjectWithTypedAdditionalProperties.ts.golden index 294ca5fb8..925919d94 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/models/ObjectWithTypedAdditionalProperties.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/models/ObjectWithTypedAdditionalProperties.ts.golden @@ -7,7 +7,8 @@ /** * Object with typed additional properties */ -export interface ObjectWithTypedAdditionalProperties extends Readonly> { +export interface ObjectWithTypedAdditionalProperties extends Readonly< + Record +> { readonly name: string; } diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/package.json.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/package.json.golden index 424e93d5b..bc8c775ad 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/package.json.golden @@ -1,31 +1,32 @@ { + "name": "comprehensive-schema-types-example", + "version": "1.0.0", "description": "Comprehensive test for all OpenAPI v3.1.2 schema types", - "devDependencies": { - "typescript": "^7.0.2", - "vite-plus": "^1.5.0" - }, + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.mjs", + "types": "./dist/index.d.mts", "exports": { ".": { "default": "./dist/index.mjs", "types": "./dist/index.d.mts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.mjs", - "name": "comprehensive-schema-types-example", "scripts": { "build": "vp pack", - "check": "vp check --no-fmt" + "check": "vp check", + "fmt": "vp fmt" }, - "type": "module", - "types": "./dist/index.d.mts", - "version": "1.0.0" -} \ No newline at end of file + "devDependencies": { + "typescript": "^7.0.2", + "vite-plus": "^1.5.0" + } +} diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/runtime/runtime.ts.golden index f0efc3478..cec4a3bfd 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Comprehensive Schema Types Example — 1.0.0 * Comprehensive test for all OpenAPI v3.1.2 schema types */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/vite.config.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/vite.config.ts.golden index 250639b98..065569dd3 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/vite.config.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-comprehensive/vite.config.ts.golden @@ -1,6 +1,10 @@ import { defineConfig } from 'vite-plus'; export default defineConfig({ + fmt: { + singleQuote: true, + ignorePatterns: ['dist/**'], + }, lint: { options: { typeAware: true, diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/README.md.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/README.md.golden index ff149e7a1..bdaa37dcb 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, TestResourceApi } from 'test-api-with-delete-response-sc const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -190,6 +190,22 @@ To build ES modules: npm run build ``` +### Formatting and validation + +After generating or regenerating this client, install its development dependencies, +run all checks on the generated files and build the library: + +```bash +vp install +vp check +vp pack +``` + +The `check` and `build` npm scripts run the same Vite+ commands. +Use `vp fmt` (or the `fmt` script) to format any subsequent manual edits. +`vp check` validates formatting, lint rules, and types without modifying files. +Build output in `dist/` is excluded from formatting. + ## TypeScript Support This package includes TypeScript type definitions. No additional `@types` package is needed. @@ -214,7 +230,7 @@ import type { User, CreateUserRequest } from 'test-api-with-delete-response-sche const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/apis/TestResourceApi.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/apis/TestResourceApi.ts.golden index 9eb773001..549b754ed 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/apis/TestResourceApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/apis/TestResourceApi.ts.golden @@ -5,14 +5,31 @@ * Test fixture for DELETE operations with JSON response schemas and type alias request bodies */ import type { CreateTestResourceRequest } from '../models/CreateTestResourceRequest'; -import type { CreateTestResourceResponse, CreateTestResourceResponse$Wire } from '../models/CreateTestResourceResponse'; +import type { + CreateTestResourceResponse, + CreateTestResourceResponse$Wire, +} from '../models/CreateTestResourceResponse'; import { createTestResourceResponseFromJSON } from '../models/CreateTestResourceResponse'; -import type { DeleteTestResourceResponse, DeleteTestResourceResponse$Wire } from '../models/DeleteTestResourceResponse'; +import type { + DeleteTestResourceResponse, + DeleteTestResourceResponse$Wire, +} from '../models/DeleteTestResourceResponse'; import { deleteTestResourceResponseFromJSON } from '../models/DeleteTestResourceResponse'; import type { HttpErrorResponse, HttpErrorResponse$Wire } from '../models/HttpErrorResponse'; import { httpErrorResponseFromJSON } from '../models/HttpErrorResponse'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, +} from '../runtime/runtime'; export interface ApiCreateTestResourceRequest { body: CreateTestResourceRequest; @@ -26,51 +43,82 @@ export interface ApiDeleteTestResourceRequest { } export type CreateTestResourceRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type DeleteTestResourceRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); -export type CreateTestResourceErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type CreateTestResourceErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class CreateTestResourceError extends ResponseError { readonly detail: CreateTestResourceErrorDetail; - constructor(response: Response, detail: CreateTestResourceErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: CreateTestResourceErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type DeleteTestResourceErrorDetail = - { kind: 'clientError'; status: number; raw: Response; value(): Promise } - | { kind: 'serverError'; status: number; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'clientError'; + status: number; + raw: Response; + value(): Promise; + } + | { + kind: 'serverError'; + status: number; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class DeleteTestResourceError extends ResponseError { readonly detail: DeleteTestResourceErrorDetail; - constructor(response: Response, detail: DeleteTestResourceErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: DeleteTestResourceErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface TestResourceApiInterface { - createTestResourceRaw: (requestParameters: ApiCreateTestResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - createTestResource: (requestParameters: ApiCreateTestResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - deleteTestResourceRaw: (requestParameters: ApiDeleteTestResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - deleteTestResource: (requestParameters: ApiDeleteTestResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + createTestResourceRaw: ( + requestParameters: ApiCreateTestResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + createTestResource: ( + requestParameters: ApiCreateTestResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + deleteTestResourceRaw: ( + requestParameters: ApiDeleteTestResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + deleteTestResource: ( + requestParameters: ApiDeleteTestResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class TestResourceApi extends BaseAPI implements TestResourceApiInterface { @@ -81,12 +129,14 @@ export class TestResourceApi extends BaseAPI implements TestResourceApiInterface super(configuration ?? DefaultConfig); } - async createTestResourceRaw(requestParameters: ApiCreateTestResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async createTestResourceRaw( + requestParameters: ApiCreateTestResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling createTestResourceRaw().' + 'Required parameter "body" was null or undefined when calling createTestResourceRaw().', ); } // Build path with path parameters @@ -101,89 +151,139 @@ export class TestResourceApi extends BaseAPI implements TestResourceApiInterface // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new CreateTestResourceError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new CreateTestResourceError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response, (json) => createTestResourceResponseFromJSON(json as CreateTestResourceResponse$Wire)) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response, (json) => { + return createTestResourceResponseFromJSON(json as CreateTestResourceResponse$Wire); + }) as JSONApiResponse & { status: 200 }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async createTestResource(requestParameters: ApiCreateTestResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async createTestResource( + requestParameters: ApiCreateTestResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.createTestResourceRaw(requestParameters, initOverrides); - return await response.value() as CreateTestResourceResponse; + return (await response.value()) as CreateTestResourceResponse; } - async deleteTestResourceRaw(requestParameters: ApiDeleteTestResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async deleteTestResourceRaw( + requestParameters: ApiDeleteTestResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.resourceId === undefined || requestParameters.resourceId === null) { throw new RequiredError( 'resourceId', - 'Required parameter "resourceId" was null or undefined when calling deleteTestResourceRaw().' + 'Required parameter "resourceId" was null or undefined when calling deleteTestResourceRaw().', ); } // Build path with path parameters let urlPath = `/v1/api/test-resource/{resource_id}`; - urlPath = urlPath.replace(`{resource_id}`, encodeURIComponent(String(requestParameters.resourceId))); + urlPath = urlPath.replace( + `{resource_id}`, + encodeURIComponent(String(requestParameters.resourceId)), + ); // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'DELETE', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status >= 400 && response.status < 500) { let errorValue: Promise | undefined; - throw new DeleteTestResourceError(response, { kind: 'clientError', status: response.status, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone(), (json) => httpErrorResponseFromJSON(json as HttpErrorResponse$Wire)).value() }); - } - else if (response.status >= 500 && response.status < 600) { + throw new DeleteTestResourceError(response, { + kind: 'clientError', + status: response.status, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone(), (json) => { + return httpErrorResponseFromJSON(json as HttpErrorResponse$Wire); + }).value(); + return errorValue; + }, + }); + } else if (response.status >= 500 && response.status < 600) { let errorValue: Promise | undefined; - throw new DeleteTestResourceError(response, { kind: 'serverError', status: response.status, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone(), (json) => httpErrorResponseFromJSON(json as HttpErrorResponse$Wire)).value() }); - } - else { + throw new DeleteTestResourceError(response, { + kind: 'serverError', + status: response.status, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone(), (json) => { + return httpErrorResponseFromJSON(json as HttpErrorResponse$Wire); + }).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new DeleteTestResourceError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new DeleteTestResourceError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response, (json) => deleteTestResourceResponseFromJSON(json as DeleteTestResourceResponse$Wire)) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response, (json) => { + return deleteTestResourceResponseFromJSON(json as DeleteTestResourceResponse$Wire); + }) as JSONApiResponse & { status: 200 }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async deleteTestResource(requestParameters: ApiDeleteTestResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async deleteTestResource( + requestParameters: ApiDeleteTestResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.deleteTestResourceRaw(requestParameters, initOverrides); - return await response.value() as DeleteTestResourceResponse; + return (await response.value()) as DeleteTestResourceResponse; } } diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/models/CreateTestResourceResponse.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/models/CreateTestResourceResponse.ts.golden index 26e584e4f..ca370daa9 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/models/CreateTestResourceResponse.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/models/CreateTestResourceResponse.ts.golden @@ -18,13 +18,17 @@ export interface CreateTestResourceResponse { readonly resourceId: string; } -export function createTestResourceResponseFromJSON(json: CreateTestResourceResponse$Wire): CreateTestResourceResponse { +export function createTestResourceResponseFromJSON( + json: CreateTestResourceResponse$Wire, +): CreateTestResourceResponse { return { resourceId: json.resource_id, }; } -export function createTestResourceResponseToJSON(value: CreateTestResourceResponse): CreateTestResourceResponse$Wire { +export function createTestResourceResponseToJSON( + value: CreateTestResourceResponse, +): CreateTestResourceResponse$Wire { return { resource_id: value.resourceId, }; diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/models/DeleteTestResourceResponse.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/models/DeleteTestResourceResponse.ts.golden index f40262c95..d8eab9557 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/models/DeleteTestResourceResponse.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/models/DeleteTestResourceResponse.ts.golden @@ -20,14 +20,18 @@ export interface DeleteTestResourceResponse { readonly success: boolean; } -export function deleteTestResourceResponseFromJSON(json: DeleteTestResourceResponse$Wire): DeleteTestResourceResponse { +export function deleteTestResourceResponseFromJSON( + json: DeleteTestResourceResponse$Wire, +): DeleteTestResourceResponse { return { message: json.message, success: json.success, }; } -export function deleteTestResourceResponseToJSON(value: DeleteTestResourceResponse): DeleteTestResourceResponse$Wire { +export function deleteTestResourceResponseToJSON( + value: DeleteTestResourceResponse, +): DeleteTestResourceResponse$Wire { return { message: value.message, success: value.success, diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/models/index.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/models/index.ts.golden index 9c28f97a6..0b2e377cb 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/models/index.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/models/index.ts.golden @@ -5,9 +5,21 @@ * Test fixture for DELETE operations with JSON response schemas and type alias request bodies */ export type { CreateTestResourceRequest } from './CreateTestResourceRequest'; -export type { CreateTestResourceResponse, CreateTestResourceResponse$Wire } from './CreateTestResourceResponse'; -export { createTestResourceResponseFromJSON, createTestResourceResponseToJSON } from './CreateTestResourceResponse'; -export type { DeleteTestResourceResponse, DeleteTestResourceResponse$Wire } from './DeleteTestResourceResponse'; -export { deleteTestResourceResponseFromJSON, deleteTestResourceResponseToJSON } from './DeleteTestResourceResponse'; +export type { + CreateTestResourceResponse, + CreateTestResourceResponse$Wire, +} from './CreateTestResourceResponse'; +export { + createTestResourceResponseFromJSON, + createTestResourceResponseToJSON, +} from './CreateTestResourceResponse'; +export type { + DeleteTestResourceResponse, + DeleteTestResourceResponse$Wire, +} from './DeleteTestResourceResponse'; +export { + deleteTestResourceResponseFromJSON, + deleteTestResourceResponseToJSON, +} from './DeleteTestResourceResponse'; export type { HttpErrorResponse, HttpErrorResponse$Wire } from './HttpErrorResponse'; export { httpErrorResponseFromJSON, httpErrorResponseToJSON } from './HttpErrorResponse'; diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/package.json.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/package.json.golden index 7a9327070..9ed69693a 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/package.json.golden @@ -1,31 +1,32 @@ { + "name": "test-api-with-delete-response-schema", + "version": "1.0.0", "description": "Test fixture for DELETE operations with JSON response schemas and type alias request bodies", - "devDependencies": { - "typescript": "^7.0.2", - "vite-plus": "^1.5.0" - }, + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.mjs", + "types": "./dist/index.d.mts", "exports": { ".": { "default": "./dist/index.mjs", "types": "./dist/index.d.mts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.mjs", - "name": "test-api-with-delete-response-schema", "scripts": { "build": "vp pack", - "check": "vp check --no-fmt" + "check": "vp check", + "fmt": "vp fmt" }, - "type": "module", - "types": "./dist/index.d.mts", - "version": "1.0.0" -} \ No newline at end of file + "devDependencies": { + "typescript": "^7.0.2", + "vite-plus": "^1.5.0" + } +} diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/runtime/runtime.ts.golden index 37c19d852..827aebb74 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Test API with DELETE Response Schema — 1.0.0 * Test fixture for DELETE operations with JSON response schemas and type alias request bodies */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/vite.config.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/vite.config.ts.golden index 250639b98..065569dd3 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/vite.config.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-delete-response/vite.config.ts.golden @@ -1,6 +1,10 @@ import { defineConfig } from 'vite-plus'; export default defineConfig({ + fmt: { + singleQuote: true, + ignorePatterns: ['dist/**'], + }, lint: { options: { typeAware: true, diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/README.md.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/README.md.golden index 40aa603eb..d7a753d74 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, EnumReprApi } from 'enum-representation-api'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -190,6 +190,22 @@ To build ES modules: npm run build ``` +### Formatting and validation + +After generating or regenerating this client, install its development dependencies, +run all checks on the generated files and build the library: + +```bash +vp install +vp check +vp pack +``` + +The `check` and `build` npm scripts run the same Vite+ commands. +Use `vp fmt` (or the `fmt` script) to format any subsequent manual edits. +`vp check` validates formatting, lint rules, and types without modifying files. +Build output in `dist/` is excluded from formatting. + ## TypeScript Support This package includes TypeScript type definitions. No additional `@types` package is needed. @@ -214,7 +230,7 @@ import type { User, CreateUserRequest } from 'enum-representation-api'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/apis/EnumReprApi.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/apis/EnumReprApi.ts.golden index abf9597ce..5cdd1da80 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/apis/EnumReprApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/apis/EnumReprApi.ts.golden @@ -9,8 +9,20 @@ import type { ExternallyTaggedEnum } from '../models/ExternallyTaggedEnum'; import type { InternallyTaggedEnum } from '../models/InternallyTaggedEnum'; import type { MixedEnum } from '../models/MixedEnum'; import type { UntaggedEnum } from '../models/UntaggedEnum'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError, VoidApiResponse } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, + VoidApiResponse, +} from '../runtime/runtime'; export interface ApiHandleAdjacentlyTaggedRequest { body: AdjacentlyTaggedEnum; @@ -33,117 +45,197 @@ export interface ApiHandleUntaggedRequest { } export type HandleAdjacentlyTaggedRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type HandleExternallyTaggedRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type HandleInternallyTaggedRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type HandleMixedRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type HandleUntaggedRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type HandleAdjacentlyTaggedErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class HandleAdjacentlyTaggedError extends ResponseError { readonly detail: HandleAdjacentlyTaggedErrorDetail; - constructor(response: Response, detail: HandleAdjacentlyTaggedErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: HandleAdjacentlyTaggedErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type HandleExternallyTaggedErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class HandleExternallyTaggedError extends ResponseError { readonly detail: HandleExternallyTaggedErrorDetail; - constructor(response: Response, detail: HandleExternallyTaggedErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: HandleExternallyTaggedErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type HandleInternallyTaggedErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class HandleInternallyTaggedError extends ResponseError { readonly detail: HandleInternallyTaggedErrorDetail; - constructor(response: Response, detail: HandleInternallyTaggedErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: HandleInternallyTaggedErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type HandleMixedErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class HandleMixedError extends ResponseError { readonly detail: HandleMixedErrorDetail; - constructor(response: Response, detail: HandleMixedErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: HandleMixedErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type HandleUntaggedErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class HandleUntaggedError extends ResponseError { readonly detail: HandleUntaggedErrorDetail; - constructor(response: Response, detail: HandleUntaggedErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: HandleUntaggedErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface EnumReprApiInterface { - handleAdjacentlyTaggedRaw: (requestParameters: ApiHandleAdjacentlyTaggedRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - handleAdjacentlyTagged: (requestParameters: ApiHandleAdjacentlyTaggedRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - handleExternallyTaggedRaw: (requestParameters: ApiHandleExternallyTaggedRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - handleExternallyTagged: (requestParameters: ApiHandleExternallyTaggedRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - handleInternallyTaggedRaw: (requestParameters: ApiHandleInternallyTaggedRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - handleInternallyTagged: (requestParameters: ApiHandleInternallyTaggedRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - handleMixedRaw: (requestParameters: ApiHandleMixedRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - handleMixed: (requestParameters: ApiHandleMixedRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - handleUntaggedRaw: (requestParameters: ApiHandleUntaggedRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - handleUntagged: (requestParameters: ApiHandleUntaggedRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + handleAdjacentlyTaggedRaw: ( + requestParameters: ApiHandleAdjacentlyTaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + handleAdjacentlyTagged: ( + requestParameters: ApiHandleAdjacentlyTaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + handleExternallyTaggedRaw: ( + requestParameters: ApiHandleExternallyTaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + handleExternallyTagged: ( + requestParameters: ApiHandleExternallyTaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + handleInternallyTaggedRaw: ( + requestParameters: ApiHandleInternallyTaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + handleInternallyTagged: ( + requestParameters: ApiHandleInternallyTaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + handleMixedRaw: ( + requestParameters: ApiHandleMixedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + handleMixed: ( + requestParameters: ApiHandleMixedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + handleUntaggedRaw: ( + requestParameters: ApiHandleUntaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + handleUntagged: ( + requestParameters: ApiHandleUntaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class EnumReprApi extends BaseAPI implements EnumReprApiInterface { @@ -154,13 +246,14 @@ export class EnumReprApi extends BaseAPI implements EnumReprApiInterface { super(configuration ?? DefaultConfig); } - async handleAdjacentlyTaggedRaw(requestParameters: ApiHandleAdjacentlyTaggedRequest, - initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async handleAdjacentlyTaggedRaw( + requestParameters: ApiHandleAdjacentlyTaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling handleAdjacentlyTaggedRaw().' + 'Required parameter "body" was null or undefined when calling handleAdjacentlyTaggedRaw().', ); } // Build path with path parameters @@ -175,47 +268,69 @@ export class EnumReprApi extends BaseAPI implements EnumReprApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new HandleAdjacentlyTaggedError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new HandleAdjacentlyTaggedError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new HandleAdjacentlyTaggedError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new HandleAdjacentlyTaggedError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response) as JSONApiResponse & { + status: 200; + }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async handleAdjacentlyTagged(requestParameters: ApiHandleAdjacentlyTaggedRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async handleAdjacentlyTagged( + requestParameters: ApiHandleAdjacentlyTaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.handleAdjacentlyTaggedRaw(requestParameters, initOverrides); - return await response.value() as AdjacentlyTaggedEnum; + return (await response.value()) as AdjacentlyTaggedEnum; } - async handleExternallyTaggedRaw(requestParameters: ApiHandleExternallyTaggedRequest, - initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async handleExternallyTaggedRaw( + requestParameters: ApiHandleExternallyTaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling handleExternallyTaggedRaw().' + 'Required parameter "body" was null or undefined when calling handleExternallyTaggedRaw().', ); } // Build path with path parameters @@ -230,47 +345,69 @@ export class EnumReprApi extends BaseAPI implements EnumReprApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new HandleExternallyTaggedError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new HandleExternallyTaggedError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new HandleExternallyTaggedError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new HandleExternallyTaggedError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response) as JSONApiResponse & { + status: 200; + }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async handleExternallyTagged(requestParameters: ApiHandleExternallyTaggedRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async handleExternallyTagged( + requestParameters: ApiHandleExternallyTaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.handleExternallyTaggedRaw(requestParameters, initOverrides); - return await response.value() as ExternallyTaggedEnum; + return (await response.value()) as ExternallyTaggedEnum; } - async handleInternallyTaggedRaw(requestParameters: ApiHandleInternallyTaggedRequest, - initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async handleInternallyTaggedRaw( + requestParameters: ApiHandleInternallyTaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling handleInternallyTaggedRaw().' + 'Required parameter "body" was null or undefined when calling handleInternallyTaggedRaw().', ); } // Build path with path parameters @@ -285,46 +422,69 @@ export class EnumReprApi extends BaseAPI implements EnumReprApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new HandleInternallyTaggedError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new HandleInternallyTaggedError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new HandleInternallyTaggedError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new HandleInternallyTaggedError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response) as JSONApiResponse & { + status: 200; + }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async handleInternallyTagged(requestParameters: ApiHandleInternallyTaggedRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async handleInternallyTagged( + requestParameters: ApiHandleInternallyTaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.handleInternallyTaggedRaw(requestParameters, initOverrides); - return await response.value() as InternallyTaggedEnum; + return (await response.value()) as InternallyTaggedEnum; } - async handleMixedRaw(requestParameters: ApiHandleMixedRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async handleMixedRaw( + requestParameters: ApiHandleMixedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling handleMixedRaw().' + 'Required parameter "body" was null or undefined when calling handleMixedRaw().', ); } // Build path with path parameters @@ -339,46 +499,67 @@ export class EnumReprApi extends BaseAPI implements EnumReprApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new HandleMixedError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new HandleMixedError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new HandleMixedError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new HandleMixedError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async handleMixed(requestParameters: ApiHandleMixedRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async handleMixed( + requestParameters: ApiHandleMixedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.handleMixedRaw(requestParameters, initOverrides); - return await response.value() as MixedEnum; + return (await response.value()) as MixedEnum; } - async handleUntaggedRaw(requestParameters: ApiHandleUntaggedRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async handleUntaggedRaw( + requestParameters: ApiHandleUntaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling handleUntaggedRaw().' + 'Required parameter "body" was null or undefined when calling handleUntaggedRaw().', ); } // Build path with path parameters @@ -393,37 +574,56 @@ export class EnumReprApi extends BaseAPI implements EnumReprApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new HandleUntaggedError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new HandleUntaggedError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new HandleUntaggedError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new HandleUntaggedError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async handleUntagged(requestParameters: ApiHandleUntaggedRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async handleUntagged( + requestParameters: ApiHandleUntaggedRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.handleUntaggedRaw(requestParameters, initOverrides); - return await response.value() as UntaggedEnum; + return (await response.value()) as UntaggedEnum; } } diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/models/AdjacentlyTaggedEnum.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/models/AdjacentlyTaggedEnum.ts.golden index b2b831564..af385123d 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/models/AdjacentlyTaggedEnum.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/models/AdjacentlyTaggedEnum.ts.golden @@ -12,4 +12,6 @@ import type { VariantB } from './VariantB'; The tag and content are separate fields: `{"ty": "VariantA", "data": {"field1": "...", "field2": 123}}` */ -export type AdjacentlyTaggedEnum = { ty: 'ADJACENTLY_TAGGED_ENUM_VARIANT_A'; data: VariantA } | { ty: 'ADJACENTLY_TAGGED_ENUM_VARIANT_B'; data: VariantB }; +export type AdjacentlyTaggedEnum = + | { ty: 'ADJACENTLY_TAGGED_ENUM_VARIANT_A'; data: VariantA } + | { ty: 'ADJACENTLY_TAGGED_ENUM_VARIANT_B'; data: VariantB }; diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/models/ExternallyTaggedEnum.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/models/ExternallyTaggedEnum.ts.golden index 51446f1fa..09dc7debe 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/models/ExternallyTaggedEnum.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/models/ExternallyTaggedEnum.ts.golden @@ -12,4 +12,6 @@ import type { VariantB } from './VariantB'; This is the default representation where the variant name is the key and the content is the value: `{"VariantA": {"field1": "...", "field2": 123}}` */ -export type ExternallyTaggedEnum = { 'EXTERNALLY_TAGGED_ENUM_VARIANT_A': VariantA } | { 'EXTERNALLY_TAGGED_ENUM_VARIANT_B': VariantB }; +export type ExternallyTaggedEnum = + | { EXTERNALLY_TAGGED_ENUM_VARIANT_A: VariantA } + | { EXTERNALLY_TAGGED_ENUM_VARIANT_B: VariantB }; diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/models/InternallyTaggedEnum.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/models/InternallyTaggedEnum.ts.golden index b7c003a81..75b637a62 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/models/InternallyTaggedEnum.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/models/InternallyTaggedEnum.ts.golden @@ -12,4 +12,6 @@ import type { VariantB } from './VariantB'; The tag is a field inside the object alongside other fields: `{"ty": "VariantA", "field1": "...", "field2": 123}` */ -export type InternallyTaggedEnum = ({ ty: 'INTERNALLY_TAGGED_ENUM_VARIANT_A' } & VariantA) | ({ ty: 'INTERNALLY_TAGGED_ENUM_VARIANT_B' } & VariantB); +export type InternallyTaggedEnum = + | ({ ty: 'INTERNALLY_TAGGED_ENUM_VARIANT_A' } & VariantA) + | ({ ty: 'INTERNALLY_TAGGED_ENUM_VARIANT_B' } & VariantB); diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/package.json.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/package.json.golden index 63aa8ed5e..ce4d174cd 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/package.json.golden @@ -1,32 +1,33 @@ { + "name": "enum-representation-api", + "version": "1.0.0", "description": "This API demonstrates all 4 kinds of enum representation types: Externally Tagged, Internally Tagged, Adjacently Tagged, and Untagged", - "devDependencies": { - "typescript": "^7.0.2", - "vite-plus": "^1.5.0" - }, + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "license": "MIT OR Apache-2.0", + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.mjs", + "types": "./dist/index.d.mts", "exports": { ".": { "default": "./dist/index.mjs", "types": "./dist/index.d.mts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "license": "MIT OR Apache-2.0", - "main": "./dist/index.mjs", - "name": "enum-representation-api", "scripts": { "build": "vp pack", - "check": "vp check --no-fmt" + "check": "vp check", + "fmt": "vp fmt" }, - "type": "module", - "types": "./dist/index.d.mts", - "version": "1.0.0" -} \ No newline at end of file + "devDependencies": { + "typescript": "^7.0.2", + "vite-plus": "^1.5.0" + } +} diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/runtime/runtime.ts.golden index b8ea08e2f..03d20b4a2 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Enum Representation API — 1.0.0 * This API demonstrates all 4 kinds of enum representation types: Externally Tagged, Internally Tagged, Adjacently Tagged, and Untagged */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/vite.config.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/vite.config.ts.golden index 250639b98..065569dd3 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/vite.config.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-enum-repr/vite.config.ts.golden @@ -1,6 +1,10 @@ import { defineConfig } from 'vite-plus'; export default defineConfig({ + fmt: { + singleQuote: true, + ignorePatterns: ['dist/**'], + }, lint: { options: { typeAware: true, diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/README.md.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/README.md.golden index eff1583ac..1cf88e697 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, PetApi } from 'petstore-api'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -190,6 +190,22 @@ To build ES modules: npm run build ``` +### Formatting and validation + +After generating or regenerating this client, install its development dependencies, +run all checks on the generated files and build the library: + +```bash +vp install +vp check +vp pack +``` + +The `check` and `build` npm scripts run the same Vite+ commands. +Use `vp fmt` (or the `fmt` script) to format any subsequent manual edits. +`vp check` validates formatting, lint rules, and types without modifying files. +Build output in `dist/` is excluded from formatting. + ## TypeScript Support This package includes TypeScript type definitions. No additional `@types` package is needed. @@ -214,7 +230,7 @@ import type { User, CreateUserRequest } from 'petstore-api'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/apis/PetApi.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/apis/PetApi.ts.golden index cb66ee12e..b16c06363 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/apis/PetApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/apis/PetApi.ts.golden @@ -6,8 +6,20 @@ */ import type { Pet } from '../models/Pet'; import type { UploadResponse } from '../models/UploadResponse'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError, VoidApiResponse } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, + VoidApiResponse, +} from '../runtime/runtime'; export interface ApiUpdatePetRequest { body: Pet; @@ -72,186 +84,328 @@ export interface ApiUploadFileRequest { } export type UpdatePetRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type AddPetRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type FindPetsByStatusRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type FindPetsByTagsRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type GetPetByIdRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type UpdatePetWithFormRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type DeletePetRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); export type UploadFileRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type UpdatePetErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'notFound'; status: 404; raw: Response; value(): Promise } - | { kind: 'validation'; status: 422; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'notFound'; + status: 404; + raw: Response; + value(): Promise; + } + | { + kind: 'validation'; + status: 422; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class UpdatePetError extends ResponseError { readonly detail: UpdatePetErrorDetail; - constructor(response: Response, detail: UpdatePetErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: UpdatePetErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type AddPetErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'validation'; status: 422; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'validation'; + status: 422; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class AddPetError extends ResponseError { readonly detail: AddPetErrorDetail; - constructor(response: Response, detail: AddPetErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: AddPetErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type FindPetsByStatusErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class FindPetsByStatusError extends ResponseError { readonly detail: FindPetsByStatusErrorDetail; - constructor(response: Response, detail: FindPetsByStatusErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: FindPetsByStatusErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type FindPetsByTagsErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class FindPetsByTagsError extends ResponseError { readonly detail: FindPetsByTagsErrorDetail; - constructor(response: Response, detail: FindPetsByTagsErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: FindPetsByTagsErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type GetPetByIdErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'notFound'; status: 404; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'notFound'; + status: 404; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class GetPetByIdError extends ResponseError { readonly detail: GetPetByIdErrorDetail; - constructor(response: Response, detail: GetPetByIdErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: GetPetByIdErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type UpdatePetWithFormErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class UpdatePetWithFormError extends ResponseError { readonly detail: UpdatePetWithFormErrorDetail; - constructor(response: Response, detail: UpdatePetWithFormErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: UpdatePetWithFormErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type DeletePetErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class DeletePetError extends ResponseError { readonly detail: DeletePetErrorDetail; - constructor(response: Response, detail: DeletePetErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: DeletePetErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type UploadFileErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type UploadFileErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class UploadFileError extends ResponseError { readonly detail: UploadFileErrorDetail; - constructor(response: Response, detail: UploadFileErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: UploadFileErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface PetApiInterface { - updatePetRaw: (requestParameters: ApiUpdatePetRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - updatePet: (requestParameters: ApiUpdatePetRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - addPetRaw: (requestParameters: ApiAddPetRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - addPet: (requestParameters: ApiAddPetRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - findPetsByStatusRaw: (requestParameters: ApiFindPetsByStatusRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - findPetsByStatus: (requestParameters: ApiFindPetsByStatusRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - findPetsByTagsRaw: (requestParameters: ApiFindPetsByTagsRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - findPetsByTags: (requestParameters: ApiFindPetsByTagsRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - getPetByIdRaw: (requestParameters: ApiGetPetByIdRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - getPetById: (requestParameters: ApiGetPetByIdRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - updatePetWithFormRaw: (requestParameters: ApiUpdatePetWithFormRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - updatePetWithForm: (requestParameters: ApiUpdatePetWithFormRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - deletePetRaw: (requestParameters: ApiDeletePetRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - deletePet: (requestParameters: ApiDeletePetRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - uploadFileRaw: (requestParameters: ApiUploadFileRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - uploadFile: (requestParameters: ApiUploadFileRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + updatePetRaw: ( + requestParameters: ApiUpdatePetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + updatePet: ( + requestParameters: ApiUpdatePetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + addPetRaw: ( + requestParameters: ApiAddPetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + addPet: ( + requestParameters: ApiAddPetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + findPetsByStatusRaw: ( + requestParameters: ApiFindPetsByStatusRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + findPetsByStatus: ( + requestParameters: ApiFindPetsByStatusRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + findPetsByTagsRaw: ( + requestParameters: ApiFindPetsByTagsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + findPetsByTags: ( + requestParameters: ApiFindPetsByTagsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + getPetByIdRaw: ( + requestParameters: ApiGetPetByIdRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + getPetById: ( + requestParameters: ApiGetPetByIdRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + updatePetWithFormRaw: ( + requestParameters: ApiUpdatePetWithFormRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + updatePetWithForm: ( + requestParameters: ApiUpdatePetWithFormRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + deletePetRaw: ( + requestParameters: ApiDeletePetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + deletePet: ( + requestParameters: ApiDeletePetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + uploadFileRaw: ( + requestParameters: ApiUploadFileRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + uploadFile: ( + requestParameters: ApiUploadFileRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class PetApi extends BaseAPI implements PetApiInterface { @@ -262,12 +416,14 @@ export class PetApi extends BaseAPI implements PetApiInterface { super(configuration ?? DefaultConfig); } - async updatePetRaw(requestParameters: ApiUpdatePetRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async updatePetRaw( + requestParameters: ApiUpdatePetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling updatePetRaw().' + 'Required parameter "body" was null or undefined when calling updatePetRaw().', ); } // Build path with path parameters @@ -282,54 +438,89 @@ export class PetApi extends BaseAPI implements PetApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'PUT', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new UpdatePetError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 404) { + throw new UpdatePetError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 404) { let errorValue: Promise | undefined; - throw new UpdatePetError(response, { kind: 'notFound', status: response.status as 404, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 422) { + throw new UpdatePetError(response, { + kind: 'notFound', + status: response.status as 404, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 422) { let errorValue: Promise | undefined; - throw new UpdatePetError(response, { kind: 'validation', status: response.status as 422, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new UpdatePetError(response, { + kind: 'validation', + status: response.status as 422, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new UpdatePetError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new UpdatePetError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async updatePet(requestParameters: ApiUpdatePetRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async updatePet( + requestParameters: ApiUpdatePetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.updatePetRaw(requestParameters, initOverrides); - return await response.value() as Pet; + return (await response.value()) as Pet; } - async addPetRaw(requestParameters: ApiAddPetRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async addPetRaw( + requestParameters: ApiAddPetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling addPetRaw().' + 'Required parameter "body" was null or undefined when calling addPetRaw().', ); } // Build path with path parameters @@ -344,50 +535,78 @@ export class PetApi extends BaseAPI implements PetApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new AddPetError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 422) { + throw new AddPetError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 422) { let errorValue: Promise | undefined; - throw new AddPetError(response, { kind: 'validation', status: response.status as 422, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new AddPetError(response, { + kind: 'validation', + status: response.status as 422, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new AddPetError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new AddPetError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async addPet(requestParameters: ApiAddPetRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async addPet( + requestParameters: ApiAddPetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.addPetRaw(requestParameters, initOverrides); - return await response.value() as Pet; + return (await response.value()) as Pet; } - async findPetsByStatusRaw(requestParameters: ApiFindPetsByStatusRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async findPetsByStatusRaw( + requestParameters: ApiFindPetsByStatusRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.status === undefined || requestParameters.status === null) { throw new RequiredError( 'status', - 'Required parameter "status" was null or undefined when calling findPetsByStatusRaw().' + 'Required parameter "status" was null or undefined when calling findPetsByStatusRaw().', ); } // Build path with path parameters @@ -398,50 +617,70 @@ export class PetApi extends BaseAPI implements PetApiInterface { queryParameters['status'] = requestParameters.status; } // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new FindPetsByStatusError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new FindPetsByStatusError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new FindPetsByStatusError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new FindPetsByStatusError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async findPetsByStatus(requestParameters: ApiFindPetsByStatusRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async findPetsByStatus( + requestParameters: ApiFindPetsByStatusRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.findPetsByStatusRaw(requestParameters, initOverrides); - return await response.value() as Pet[]; + return (await response.value()) as Pet[]; } - async findPetsByTagsRaw(requestParameters: ApiFindPetsByTagsRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async findPetsByTagsRaw( + requestParameters: ApiFindPetsByTagsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.tags === undefined || requestParameters.tags === null) { throw new RequiredError( 'tags', - 'Required parameter "tags" was null or undefined when calling findPetsByTagsRaw().' + 'Required parameter "tags" was null or undefined when calling findPetsByTagsRaw().', ); } // Build path with path parameters @@ -452,50 +691,70 @@ export class PetApi extends BaseAPI implements PetApiInterface { queryParameters['tags'] = requestParameters.tags; } // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new FindPetsByTagsError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new FindPetsByTagsError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new FindPetsByTagsError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new FindPetsByTagsError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async findPetsByTags(requestParameters: ApiFindPetsByTagsRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async findPetsByTags( + requestParameters: ApiFindPetsByTagsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.findPetsByTagsRaw(requestParameters, initOverrides); - return await response.value() as Pet[]; + return (await response.value()) as Pet[]; } - async getPetByIdRaw(requestParameters: ApiGetPetByIdRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getPetByIdRaw( + requestParameters: ApiGetPetByIdRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.petId === undefined || requestParameters.petId === null) { throw new RequiredError( 'petId', - 'Required parameter "petId" was null or undefined when calling getPetByIdRaw().' + 'Required parameter "petId" was null or undefined when calling getPetByIdRaw().', ); } // Build path with path parameters @@ -504,54 +763,81 @@ export class PetApi extends BaseAPI implements PetApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new GetPetByIdError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 404) { + throw new GetPetByIdError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 404) { let errorValue: Promise | undefined; - throw new GetPetByIdError(response, { kind: 'notFound', status: response.status as 404, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new GetPetByIdError(response, { + kind: 'notFound', + status: response.status as 404, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new GetPetByIdError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new GetPetByIdError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async getPetById(requestParameters: ApiGetPetByIdRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getPetById( + requestParameters: ApiGetPetByIdRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.getPetByIdRaw(requestParameters, initOverrides); - return await response.value() as Pet; + return (await response.value()) as Pet; } - async updatePetWithFormRaw(requestParameters: ApiUpdatePetWithFormRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async updatePetWithFormRaw( + requestParameters: ApiUpdatePetWithFormRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.petId === undefined || requestParameters.petId === null) { throw new RequiredError( 'petId', - 'Required parameter "petId" was null or undefined when calling updatePetWithFormRaw().' + 'Required parameter "petId" was null or undefined when calling updatePetWithFormRaw().', ); } // Build path with path parameters @@ -566,50 +852,70 @@ export class PetApi extends BaseAPI implements PetApiInterface { queryParameters['status'] = requestParameters.status; } // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new UpdatePetWithFormError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new UpdatePetWithFormError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new UpdatePetWithFormError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new UpdatePetWithFormError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async updatePetWithForm(requestParameters: ApiUpdatePetWithFormRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async updatePetWithForm( + requestParameters: ApiUpdatePetWithFormRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.updatePetWithFormRaw(requestParameters, initOverrides); - return await response.value() as Pet; + return (await response.value()) as Pet; } - async deletePetRaw(requestParameters: ApiDeletePetRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async deletePetRaw( + requestParameters: ApiDeletePetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.petId === undefined || requestParameters.petId === null) { throw new RequiredError( 'petId', - 'Required parameter "petId" was null or undefined when calling deletePetRaw().' + 'Required parameter "petId" was null or undefined when calling deletePetRaw().', ); } // Build path with path parameters @@ -618,50 +924,70 @@ export class PetApi extends BaseAPI implements PetApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'DELETE', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new DeletePetError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new DeletePetError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new DeletePetError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new DeletePetError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async deletePet(requestParameters: ApiDeletePetRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async deletePet( + requestParameters: ApiDeletePetRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.deletePetRaw(requestParameters, initOverrides); return await response.value(); } - async uploadFileRaw(requestParameters: ApiUploadFileRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async uploadFileRaw( + requestParameters: ApiUploadFileRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.petId === undefined || requestParameters.petId === null) { throw new RequiredError( 'petId', - 'Required parameter "petId" was null or undefined when calling uploadFileRaw().' + 'Required parameter "petId" was null or undefined when calling uploadFileRaw().', ); } // Build path with path parameters @@ -673,37 +999,48 @@ export class PetApi extends BaseAPI implements PetApiInterface { queryParameters['additionalMetadata'] = requestParameters.additionalMetadata; } // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new UploadFileError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new UploadFileError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async uploadFile(requestParameters: ApiUploadFileRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async uploadFile( + requestParameters: ApiUploadFileRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.uploadFileRaw(requestParameters, initOverrides); - return await response.value() as UploadResponse; + return (await response.value()) as UploadResponse; } } diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/apis/StoreApi.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/apis/StoreApi.ts.golden index 772202019..0b89a495c 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/apis/StoreApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/apis/StoreApi.ts.golden @@ -5,8 +5,20 @@ * This is a sample Pet Store Server based on the OpenAPI 3.1 specification */ import type { Order } from '../models/Order'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError, VoidApiResponse } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, + VoidApiResponse, +} from '../runtime/runtime'; export interface ApiPlaceOrderRequest { body: Order; @@ -27,96 +39,162 @@ export interface ApiDeleteOrderRequest { } export type GetInventoryRawResponse = - | JSONApiResponse> & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse> & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type PlaceOrderRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type GetOrderByIdRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type DeleteOrderRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); -export type GetInventoryErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type GetInventoryErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class GetInventoryError extends ResponseError { readonly detail: GetInventoryErrorDetail; - constructor(response: Response, detail: GetInventoryErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: GetInventoryErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type PlaceOrderErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class PlaceOrderError extends ResponseError { readonly detail: PlaceOrderErrorDetail; - constructor(response: Response, detail: PlaceOrderErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: PlaceOrderErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type GetOrderByIdErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'notFound'; status: 404; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'notFound'; + status: 404; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class GetOrderByIdError extends ResponseError { readonly detail: GetOrderByIdErrorDetail; - constructor(response: Response, detail: GetOrderByIdErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: GetOrderByIdErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type DeleteOrderErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'notFound'; status: 404; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'notFound'; + status: 404; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class DeleteOrderError extends ResponseError { readonly detail: DeleteOrderErrorDetail; - constructor(response: Response, detail: DeleteOrderErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: DeleteOrderErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface StoreApiInterface { - getInventoryRaw: (initOverrides?: RequestInit - | InitOverrideFunction) => Promise; - getInventory: (initOverrides?: RequestInit | InitOverrideFunction) => Promise>; - placeOrderRaw: (requestParameters: ApiPlaceOrderRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - placeOrder: (requestParameters: ApiPlaceOrderRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - getOrderByIdRaw: (requestParameters: ApiGetOrderByIdRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - getOrderById: (requestParameters: ApiGetOrderByIdRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - deleteOrderRaw: (requestParameters: ApiDeleteOrderRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - deleteOrder: (requestParameters: ApiDeleteOrderRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + getInventoryRaw: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + getInventory: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise>; + placeOrderRaw: ( + requestParameters: ApiPlaceOrderRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + placeOrder: ( + requestParameters: ApiPlaceOrderRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + getOrderByIdRaw: ( + requestParameters: ApiGetOrderByIdRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + getOrderById: ( + requestParameters: ApiGetOrderByIdRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + deleteOrderRaw: ( + requestParameters: ApiDeleteOrderRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + deleteOrder: ( + requestParameters: ApiDeleteOrderRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class StoreApi extends BaseAPI implements StoreApiInterface { @@ -127,54 +205,68 @@ export class StoreApi extends BaseAPI implements StoreApiInterface { super(configuration ?? DefaultConfig); } - async getInventoryRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getInventoryRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/store/inventory`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new GetInventoryError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new GetInventoryError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response) as JSONApiResponse> & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response) as JSONApiResponse> & { + status: 200; + }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async getInventory(initOverrides?: RequestInit | InitOverrideFunction): Promise> { + async getInventory( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise> { const response = await this.getInventoryRaw(initOverrides); - return await response.value() as Record; + return (await response.value()) as Record; } - async placeOrderRaw(requestParameters: ApiPlaceOrderRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async placeOrderRaw( + requestParameters: ApiPlaceOrderRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling placeOrderRaw().' + 'Required parameter "body" was null or undefined when calling placeOrderRaw().', ); } // Build path with path parameters @@ -189,46 +281,67 @@ export class StoreApi extends BaseAPI implements StoreApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new PlaceOrderError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new PlaceOrderError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new PlaceOrderError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new PlaceOrderError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async placeOrder(requestParameters: ApiPlaceOrderRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async placeOrder( + requestParameters: ApiPlaceOrderRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.placeOrderRaw(requestParameters, initOverrides); - return await response.value() as Order; + return (await response.value()) as Order; } - async getOrderByIdRaw(requestParameters: ApiGetOrderByIdRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getOrderByIdRaw( + requestParameters: ApiGetOrderByIdRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.orderId === undefined || requestParameters.orderId === null) { throw new RequiredError( 'orderId', - 'Required parameter "orderId" was null or undefined when calling getOrderByIdRaw().' + 'Required parameter "orderId" was null or undefined when calling getOrderByIdRaw().', ); } // Build path with path parameters @@ -237,54 +350,81 @@ export class StoreApi extends BaseAPI implements StoreApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new GetOrderByIdError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 404) { + throw new GetOrderByIdError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 404) { let errorValue: Promise | undefined; - throw new GetOrderByIdError(response, { kind: 'notFound', status: response.status as 404, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new GetOrderByIdError(response, { + kind: 'notFound', + status: response.status as 404, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new GetOrderByIdError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new GetOrderByIdError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async getOrderById(requestParameters: ApiGetOrderByIdRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getOrderById( + requestParameters: ApiGetOrderByIdRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.getOrderByIdRaw(requestParameters, initOverrides); - return await response.value() as Order; + return (await response.value()) as Order; } - async deleteOrderRaw(requestParameters: ApiDeleteOrderRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async deleteOrderRaw( + requestParameters: ApiDeleteOrderRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.orderId === undefined || requestParameters.orderId === null) { throw new RequiredError( 'orderId', - 'Required parameter "orderId" was null or undefined when calling deleteOrderRaw().' + 'Required parameter "orderId" was null or undefined when calling deleteOrderRaw().', ); } // Build path with path parameters @@ -293,44 +433,69 @@ export class StoreApi extends BaseAPI implements StoreApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'DELETE', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new DeleteOrderError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 404) { + throw new DeleteOrderError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 404) { let errorValue: Promise | undefined; - throw new DeleteOrderError(response, { kind: 'notFound', status: response.status as 404, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new DeleteOrderError(response, { + kind: 'notFound', + status: response.status as 404, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new DeleteOrderError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new DeleteOrderError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async deleteOrder(requestParameters: ApiDeleteOrderRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async deleteOrder( + requestParameters: ApiDeleteOrderRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.deleteOrderRaw(requestParameters, initOverrides); return await response.value(); } diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/apis/UserApi.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/apis/UserApi.ts.golden index d3b26a158..dbbbcc76b 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/apis/UserApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/apis/UserApi.ts.golden @@ -5,8 +5,20 @@ * This is a sample Pet Store Server based on the OpenAPI 3.1 specification */ import type { User } from '../models/User'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError, VoidApiResponse } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, + VoidApiResponse, +} from '../runtime/runtime'; export interface ApiCreateUserRequest { body: User; @@ -50,161 +62,266 @@ export interface ApiDeleteUserRequest { } export type CreateUserRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type CreateUsersWithListInputRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type LoginUserRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); export type LogoutUserRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); export type GetUserByNameRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type UpdateUserRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); export type DeleteUserRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); -export type CreateUserErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type CreateUserErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class CreateUserError extends ResponseError { readonly detail: CreateUserErrorDetail; - constructor(response: Response, detail: CreateUserErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: CreateUserErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type CreateUsersWithListInputErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type CreateUsersWithListInputErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class CreateUsersWithListInputError extends ResponseError { readonly detail: CreateUsersWithListInputErrorDetail; - constructor(response: Response, detail: CreateUsersWithListInputErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: CreateUsersWithListInputErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type LoginUserErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class LoginUserError extends ResponseError { readonly detail: LoginUserErrorDetail; - constructor(response: Response, detail: LoginUserErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: LoginUserErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type LogoutUserErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type LogoutUserErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class LogoutUserError extends ResponseError { readonly detail: LogoutUserErrorDetail; - constructor(response: Response, detail: LogoutUserErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: LogoutUserErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type GetUserByNameErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'notFound'; status: 404; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'notFound'; + status: 404; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class GetUserByNameError extends ResponseError { readonly detail: GetUserByNameErrorDetail; - constructor(response: Response, detail: GetUserByNameErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: GetUserByNameErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type UpdateUserErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'notFound'; status: 404; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'notFound'; + status: 404; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class UpdateUserError extends ResponseError { readonly detail: UpdateUserErrorDetail; - constructor(response: Response, detail: UpdateUserErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: UpdateUserErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export type DeleteUserErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'notFound'; status: 404; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'notFound'; + status: 404; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class DeleteUserError extends ResponseError { readonly detail: DeleteUserErrorDetail; - constructor(response: Response, detail: DeleteUserErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: DeleteUserErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface UserApiInterface { - createUserRaw: (requestParameters: ApiCreateUserRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - createUser: (requestParameters: ApiCreateUserRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - createUsersWithListInputRaw: (requestParameters: ApiCreateUsersWithListInputRequest, - initOverrides?: RequestInit - | InitOverrideFunction) => Promise; - createUsersWithListInput: (requestParameters: ApiCreateUsersWithListInputRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - loginUserRaw: (requestParameters: ApiLoginUserRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - loginUser: (requestParameters: ApiLoginUserRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - logoutUserRaw: (initOverrides?: RequestInit - | InitOverrideFunction) => Promise; + createUserRaw: ( + requestParameters: ApiCreateUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + createUser: ( + requestParameters: ApiCreateUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + createUsersWithListInputRaw: ( + requestParameters: ApiCreateUsersWithListInputRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + createUsersWithListInput: ( + requestParameters: ApiCreateUsersWithListInputRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + loginUserRaw: ( + requestParameters: ApiLoginUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + loginUser: ( + requestParameters: ApiLoginUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + logoutUserRaw: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; logoutUser: (initOverrides?: RequestInit | InitOverrideFunction) => Promise; - getUserByNameRaw: (requestParameters: ApiGetUserByNameRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - getUserByName: (requestParameters: ApiGetUserByNameRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - updateUserRaw: (requestParameters: ApiUpdateUserRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - updateUser: (requestParameters: ApiUpdateUserRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - deleteUserRaw: (requestParameters: ApiDeleteUserRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - deleteUser: (requestParameters: ApiDeleteUserRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + getUserByNameRaw: ( + requestParameters: ApiGetUserByNameRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + getUserByName: ( + requestParameters: ApiGetUserByNameRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + updateUserRaw: ( + requestParameters: ApiUpdateUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + updateUser: ( + requestParameters: ApiUpdateUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + deleteUserRaw: ( + requestParameters: ApiDeleteUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + deleteUser: ( + requestParameters: ApiDeleteUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class UserApi extends BaseAPI implements UserApiInterface { @@ -215,12 +332,14 @@ export class UserApi extends BaseAPI implements UserApiInterface { super(configuration ?? DefaultConfig); } - async createUserRaw(requestParameters: ApiCreateUserRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createUserRaw( + requestParameters: ApiCreateUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling createUserRaw().' + 'Required parameter "body" was null or undefined when calling createUserRaw().', ); } // Build path with path parameters @@ -235,43 +354,56 @@ export class UserApi extends BaseAPI implements UserApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new CreateUserError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new CreateUserError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async createUser(requestParameters: ApiCreateUserRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createUser( + requestParameters: ApiCreateUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.createUserRaw(requestParameters, initOverrides); - return await response.value() as User; + return (await response.value()) as User; } - async createUsersWithListInputRaw(requestParameters: ApiCreateUsersWithListInputRequest, - initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createUsersWithListInputRaw( + requestParameters: ApiCreateUsersWithListInputRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling createUsersWithListInputRaw().' + 'Required parameter "body" was null or undefined when calling createUsersWithListInputRaw().', ); } // Build path with path parameters @@ -286,38 +418,52 @@ export class UserApi extends BaseAPI implements UserApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new CreateUsersWithListInputError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new CreateUsersWithListInputError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async createUsersWithListInput(requestParameters: ApiCreateUsersWithListInputRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async createUsersWithListInput( + requestParameters: ApiCreateUsersWithListInputRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.createUsersWithListInputRaw(requestParameters, initOverrides); - return await response.value() as User; + return (await response.value()) as User; } - async loginUserRaw(requestParameters: ApiLoginUserRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async loginUserRaw( + requestParameters: ApiLoginUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/user/login`; // Build query parameters @@ -329,75 +475,103 @@ export class UserApi extends BaseAPI implements UserApiInterface { queryParameters['password'] = requestParameters.password; } // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new LoginUserError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new LoginUserError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new LoginUserError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new LoginUserError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async loginUser(requestParameters: ApiLoginUserRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async loginUser( + requestParameters: ApiLoginUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.loginUserRaw(requestParameters, initOverrides); return await response.value(); } - async logoutUserRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async logoutUserRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/user/logout`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new LogoutUserError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new LogoutUserError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } @@ -407,12 +581,14 @@ export class UserApi extends BaseAPI implements UserApiInterface { return await response.value(); } - async getUserByNameRaw(requestParameters: ApiGetUserByNameRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getUserByNameRaw( + requestParameters: ApiGetUserByNameRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.username === undefined || requestParameters.username === null) { throw new RequiredError( 'username', - 'Required parameter "username" was null or undefined when calling getUserByNameRaw().' + 'Required parameter "username" was null or undefined when calling getUserByNameRaw().', ); } // Build path with path parameters @@ -421,60 +597,87 @@ export class UserApi extends BaseAPI implements UserApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new GetUserByNameError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 404) { + throw new GetUserByNameError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 404) { let errorValue: Promise | undefined; - throw new GetUserByNameError(response, { kind: 'notFound', status: response.status as 404, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new GetUserByNameError(response, { + kind: 'notFound', + status: response.status as 404, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new GetUserByNameError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new GetUserByNameError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async getUserByName(requestParameters: ApiGetUserByNameRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getUserByName( + requestParameters: ApiGetUserByNameRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.getUserByNameRaw(requestParameters, initOverrides); - return await response.value() as User; + return (await response.value()) as User; } - async updateUserRaw(requestParameters: ApiUpdateUserRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async updateUserRaw( + requestParameters: ApiUpdateUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.username === undefined || requestParameters.username === null) { throw new RequiredError( 'username', - 'Required parameter "username" was null or undefined when calling updateUserRaw().' + 'Required parameter "username" was null or undefined when calling updateUserRaw().', ); } if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling updateUserRaw().' + 'Required parameter "body" was null or undefined when calling updateUserRaw().', ); } // Build path with path parameters @@ -490,50 +693,78 @@ export class UserApi extends BaseAPI implements UserApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'PUT', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new UpdateUserError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 404) { + throw new UpdateUserError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 404) { let errorValue: Promise | undefined; - throw new UpdateUserError(response, { kind: 'notFound', status: response.status as 404, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new UpdateUserError(response, { + kind: 'notFound', + status: response.status as 404, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new UpdateUserError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new UpdateUserError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async updateUser(requestParameters: ApiUpdateUserRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async updateUser( + requestParameters: ApiUpdateUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.updateUserRaw(requestParameters, initOverrides); return await response.value(); } - async deleteUserRaw(requestParameters: ApiDeleteUserRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async deleteUserRaw( + requestParameters: ApiDeleteUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.username === undefined || requestParameters.username === null) { throw new RequiredError( 'username', - 'Required parameter "username" was null or undefined when calling deleteUserRaw().' + 'Required parameter "username" was null or undefined when calling deleteUserRaw().', ); } // Build path with path parameters @@ -542,44 +773,69 @@ export class UserApi extends BaseAPI implements UserApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'DELETE', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new DeleteUserError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 404) { + throw new DeleteUserError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 404) { let errorValue: Promise | undefined; - throw new DeleteUserError(response, { kind: 'notFound', status: response.status as 404, raw: response, value: () => errorValue ??= new VoidApiResponse(errorRaw.clone()).value() }); - } - else { + throw new DeleteUserError(response, { + kind: 'notFound', + status: response.status as 404, + raw: response, + value: () => { + errorValue ??= new VoidApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new DeleteUserError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new DeleteUserError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async deleteUser(requestParameters: ApiDeleteUserRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async deleteUser( + requestParameters: ApiDeleteUserRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.deleteUserRaw(requestParameters, initOverrides); return await response.value(); } diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/package.json.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/package.json.golden index cfafa60c1..d2ae75421 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/package.json.golden @@ -1,32 +1,33 @@ { + "name": "petstore-api", + "version": "1.0.0", "description": "This is a sample Pet Store Server based on the OpenAPI 3.1 specification", - "devDependencies": { - "typescript": "^7.0.2", - "vite-plus": "^1.5.0" - }, + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "license": "Apache 2.0", + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.mjs", + "types": "./dist/index.d.mts", "exports": { ".": { "default": "./dist/index.mjs", "types": "./dist/index.d.mts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "license": "Apache 2.0", - "main": "./dist/index.mjs", - "name": "petstore-api", "scripts": { "build": "vp pack", - "check": "vp check --no-fmt" + "check": "vp check", + "fmt": "vp fmt" }, - "type": "module", - "types": "./dist/index.d.mts", - "version": "1.0.0" -} \ No newline at end of file + "devDependencies": { + "typescript": "^7.0.2", + "vite-plus": "^1.5.0" + } +} diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/runtime/runtime.ts.golden index b36abbfbd..6ca6619b2 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Petstore API — 1.0.0 * This is a sample Pet Store Server based on the OpenAPI 3.1 specification */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/vite.config.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/vite.config.ts.golden index 250639b98..065569dd3 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/vite.config.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-petstore/vite.config.ts.golden @@ -1,6 +1,10 @@ import { defineConfig } from 'vite-plus'; export default defineConfig({ + fmt: { + singleQuote: true, + ignorePatterns: ['dist/**'], + }, lint: { options: { typeAware: true, diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/README.md.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/README.md.golden index 8e372bc03..1a7e99277 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'self-referential-object-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -190,6 +190,22 @@ To build ES modules: npm run build ``` +### Formatting and validation + +After generating or regenerating this client, install its development dependencies, +run all checks on the generated files and build the library: + +```bash +vp install +vp check +vp pack +``` + +The `check` and `build` npm scripts run the same Vite+ commands. +Use `vp fmt` (or the `fmt` script) to format any subsequent manual edits. +`vp check` validates formatting, lint rules, and types without modifying files. +Build output in `dist/` is excluded from formatting. + ## TypeScript Support This package includes TypeScript type definitions. No additional `@types` package is needed. @@ -214,7 +230,7 @@ import type { User, CreateUserRequest } from 'self-referential-object-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/apis/DefaultApi.ts.golden index 50e822cc7..312337a0f 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/apis/DefaultApi.ts.golden @@ -5,22 +5,33 @@ */ import type { Foo, Foo$Wire } from '../models/Foo'; import { fooFromJSON } from '../models/Foo'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; import { BaseAPI, DefaultConfig, JSONApiResponse, ResponseError } from '../runtime/runtime'; export type GetFooRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); - -export type GetFooErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type GetFooErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class GetFooError extends ResponseError { readonly detail: GetFooErrorDetail; - constructor(response: Response, detail: GetFooErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: GetFooErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } @@ -45,36 +56,47 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new GetFooError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new GetFooError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response, (json) => fooFromJSON(json as Foo$Wire)) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response, (json) => { + return fooFromJSON(json as Foo$Wire); + }) as JSONApiResponse & { status: 200 }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } async getFoo(initOverrides?: RequestInit | InitOverrideFunction): Promise { const response = await this.getFooRaw(initOverrides); - return await response.value() as Foo; + return (await response.value()) as Foo; } } diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/models/Foo.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/models/Foo.ts.golden index c41bb424b..8dfe8a6bf 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/models/Foo.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/models/Foo.ts.golden @@ -18,14 +18,16 @@ export interface Foo { export function fooFromJSON(json: Foo$Wire): Foo { return { - children: json.children !== undefined ? json.children.map((item) => fooFromJSON(item)) : undefined, + children: + json.children !== undefined ? json.children.map((item) => fooFromJSON(item)) : undefined, relatedBar: barFromJSON(json.related_bar), }; } export function fooToJSON(value: Foo): Foo$Wire { return { - children: value.children !== undefined ? value.children.map((item) => fooToJSON(item)) : undefined, + children: + value.children !== undefined ? value.children.map((item) => fooToJSON(item)) : undefined, related_bar: barToJSON(value.relatedBar), }; } diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/package.json.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/package.json.golden index 90161f364..80132bb97 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/package.json.golden @@ -1,31 +1,32 @@ { + "name": "self-referential-object-test", + "version": "1.0.0", "description": "TypeScript client for Self-Referential Object Test", - "devDependencies": { - "typescript": "^7.0.2", - "vite-plus": "^1.5.0" - }, + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.mjs", + "types": "./dist/index.d.mts", "exports": { ".": { "default": "./dist/index.mjs", "types": "./dist/index.d.mts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.mjs", - "name": "self-referential-object-test", "scripts": { "build": "vp pack", - "check": "vp check --no-fmt" + "check": "vp check", + "fmt": "vp fmt" }, - "type": "module", - "types": "./dist/index.d.mts", - "version": "1.0.0" -} \ No newline at end of file + "devDependencies": { + "typescript": "^7.0.2", + "vite-plus": "^1.5.0" + } +} diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/runtime/runtime.ts.golden index 70e5b239b..e177a1562 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/runtime/runtime.ts.golden @@ -3,7 +3,7 @@ * * Self-Referential Object Test — 1.0.0 */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -13,7 +13,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -92,8 +95,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -135,12 +140,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -150,7 +161,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -166,9 +177,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -183,13 +192,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -199,7 +210,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -209,10 +220,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -221,18 +233,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -240,16 +256,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -268,11 +285,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -282,7 +299,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -292,7 +309,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -306,12 +323,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -329,15 +364,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -413,16 +461,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -449,7 +587,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -476,7 +617,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -486,5 +627,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/vite.config.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/vite.config.ts.golden index 250639b98..065569dd3 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/vite.config.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp-self-referential-object/vite.config.ts.golden @@ -1,6 +1,10 @@ import { defineConfig } from 'vite-plus'; export default defineConfig({ + fmt: { + singleQuote: true, + ignorePatterns: ['dist/**'], + }, lint: { options: { typeAware: true, diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/README.md.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/README.md.golden index dafe063f0..69fe30127 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/README.md.golden @@ -3,7 +3,6 @@ Test fixture for discriminated union where variants are references to component schemas. This is similar to the ContainerImage pattern in the infiron API. - **Version:** 1.0.0 ## Overview @@ -54,8 +53,8 @@ import { Configuration, DefaultApi } from 'discriminated-union-with-references-t const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -103,9 +102,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -128,12 +127,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -192,6 +191,22 @@ To build ES modules: npm run build ``` +### Formatting and validation + +After generating or regenerating this client, install its development dependencies, +run all checks on the generated files and build the library: + +```bash +vp install +vp check +vp pack +``` + +The `check` and `build` npm scripts run the same Vite+ commands. +Use `vp fmt` (or the `fmt` script) to format any subsequent manual edits. +`vp check` validates formatting, lint rules, and types without modifying files. +Build output in `dist/` is excluded from formatting. + ## TypeScript Support This package includes TypeScript type definitions. No additional `@types` package is needed. @@ -216,7 +231,7 @@ import type { User, CreateUserRequest } from 'discriminated-union-with-reference const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/apis/DefaultApi.ts.golden index 945e25638..2663e85c5 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/apis/DefaultApi.ts.golden @@ -7,36 +7,57 @@ */ import type { ContainerImage, ContainerImage$Wire } from '../models/ContainerImage'; import { containerImageFromJSON, containerImageToJSON } from '../models/ContainerImage'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, +} from '../runtime/runtime'; export interface ApiCreateContainerRequest { body: ContainerImage; } export type CreateContainerRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); - -export type CreateContainerErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type CreateContainerErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class CreateContainerError extends ResponseError { readonly detail: CreateContainerErrorDetail; - constructor(response: Response, detail: CreateContainerErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: CreateContainerErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - createContainerRaw: (requestParameters: ApiCreateContainerRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - createContainer: (requestParameters: ApiCreateContainerRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + createContainerRaw: ( + requestParameters: ApiCreateContainerRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + createContainer: ( + requestParameters: ApiCreateContainerRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class DefaultApi extends BaseAPI implements DefaultApiInterface { @@ -47,12 +68,14 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async createContainerRaw(requestParameters: ApiCreateContainerRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createContainerRaw( + requestParameters: ApiCreateContainerRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling createContainerRaw().' + 'Required parameter "body" was null or undefined when calling createContainerRaw().', ); } // Build path with path parameters @@ -67,33 +90,47 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = containerImageToJSON(requestParameters.body); // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new CreateContainerError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new CreateContainerError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response, (json) => containerImageFromJSON(json as ContainerImage$Wire)) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response, (json) => { + return containerImageFromJSON(json as ContainerImage$Wire); + }) as JSONApiResponse & { status: 200 }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async createContainer(requestParameters: ApiCreateContainerRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createContainer( + requestParameters: ApiCreateContainerRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.createContainerRaw(requestParameters, initOverrides); - return await response.value() as ContainerImage; + return (await response.value()) as ContainerImage; } } diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/models/ContainerImage.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/models/ContainerImage.ts.golden index d77c1ee9e..4a3fb4001 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/models/ContainerImage.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/models/ContainerImage.ts.golden @@ -8,22 +8,39 @@ import type { ContainerImageCustom, ContainerImageCustom$Wire } from './ContainerImageCustom'; import { containerImageCustomFromJSON, containerImageCustomToJSON } from './ContainerImageCustom'; import type { ContainerImageManaged, ContainerImageManaged$Wire } from './ContainerImageManaged'; -import { containerImageManagedFromJSON, containerImageManagedToJSON } from './ContainerImageManaged'; +import { + containerImageManagedFromJSON, + containerImageManagedToJSON, +} from './ContainerImageManaged'; -export type ContainerImage$Wire = ({ kind: 'CONTAINER_IMAGE_MANAGED' } & ContainerImageManaged$Wire) | ({ kind: 'CONTAINER_IMAGE_CUSTOM' } & ContainerImageCustom$Wire); +export type ContainerImage$Wire = + | ({ kind: 'CONTAINER_IMAGE_MANAGED' } & ContainerImageManaged$Wire) + | ({ kind: 'CONTAINER_IMAGE_CUSTOM' } & ContainerImageCustom$Wire); -export type ContainerImage = ({ kind: 'CONTAINER_IMAGE_MANAGED' } & ContainerImageManaged) | ({ kind: 'CONTAINER_IMAGE_CUSTOM' } & ContainerImageCustom); +export type ContainerImage = + | ({ kind: 'CONTAINER_IMAGE_MANAGED' } & ContainerImageManaged) + | ({ kind: 'CONTAINER_IMAGE_CUSTOM' } & ContainerImageCustom); export function containerImageFromJSON(json: ContainerImage$Wire): ContainerImage { switch (json.kind) { - case 'CONTAINER_IMAGE_MANAGED': return { ...containerImageManagedFromJSON(json), kind: 'CONTAINER_IMAGE_MANAGED' }; - case 'CONTAINER_IMAGE_CUSTOM': return { ...containerImageCustomFromJSON(json), kind: 'CONTAINER_IMAGE_CUSTOM' }; + case 'CONTAINER_IMAGE_MANAGED': + return { ...containerImageManagedFromJSON(json), kind: 'CONTAINER_IMAGE_MANAGED' }; + case 'CONTAINER_IMAGE_CUSTOM': + return { ...containerImageCustomFromJSON(json), kind: 'CONTAINER_IMAGE_CUSTOM' }; } } export function containerImageToJSON(value: ContainerImage): ContainerImage$Wire { switch (value.kind) { - case 'CONTAINER_IMAGE_MANAGED': return { ...containerImageManagedToJSON(value), kind: 'CONTAINER_IMAGE_MANAGED' } as ContainerImage$Wire; - case 'CONTAINER_IMAGE_CUSTOM': return { ...containerImageCustomToJSON(value), kind: 'CONTAINER_IMAGE_CUSTOM' } as ContainerImage$Wire; + case 'CONTAINER_IMAGE_MANAGED': + return { + ...containerImageManagedToJSON(value), + kind: 'CONTAINER_IMAGE_MANAGED', + } as ContainerImage$Wire; + case 'CONTAINER_IMAGE_CUSTOM': + return { + ...containerImageCustomToJSON(value), + kind: 'CONTAINER_IMAGE_CUSTOM', + } as ContainerImage$Wire; } } diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/models/ContainerImageCustom.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/models/ContainerImageCustom.ts.golden index cf8f037e4..b4d4ca906 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/models/ContainerImageCustom.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/models/ContainerImageCustom.ts.golden @@ -13,7 +13,9 @@ export interface ContainerImageCustom { readonly customField: string; } -export function containerImageCustomFromJSON(json: ContainerImageCustom$Wire): ContainerImageCustom { +export function containerImageCustomFromJSON( + json: ContainerImageCustom$Wire, +): ContainerImageCustom { return { customField: json.customField, }; diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/models/ContainerImageManaged.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/models/ContainerImageManaged.ts.golden index 553c00a70..d1ad83dc8 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/models/ContainerImageManaged.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/models/ContainerImageManaged.ts.golden @@ -13,13 +13,17 @@ export interface ContainerImageManaged { readonly managedField: string; } -export function containerImageManagedFromJSON(json: ContainerImageManaged$Wire): ContainerImageManaged { +export function containerImageManagedFromJSON( + json: ContainerImageManaged$Wire, +): ContainerImageManaged { return { managedField: json.managedField, }; } -export function containerImageManagedToJSON(value: ContainerImageManaged): ContainerImageManaged$Wire { +export function containerImageManagedToJSON( + value: ContainerImageManaged, +): ContainerImageManaged$Wire { return { managedField: value.managedField, }; diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/models/index.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/models/index.ts.golden index 0c7aefcf8..ebe940734 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/models/index.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/models/index.ts.golden @@ -10,4 +10,7 @@ export { containerImageFromJSON, containerImageToJSON } from './ContainerImage'; export type { ContainerImageCustom, ContainerImageCustom$Wire } from './ContainerImageCustom'; export { containerImageCustomFromJSON, containerImageCustomToJSON } from './ContainerImageCustom'; export type { ContainerImageManaged, ContainerImageManaged$Wire } from './ContainerImageManaged'; -export { containerImageManagedFromJSON, containerImageManagedToJSON } from './ContainerImageManaged'; +export { + containerImageManagedFromJSON, + containerImageManagedToJSON, +} from './ContainerImageManaged'; diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/package.json.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/package.json.golden index 0520f24e4..a82cc22ce 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/package.json.golden @@ -1,31 +1,32 @@ { + "name": "discriminated-union-with-references-test", + "version": "1.0.0", "description": "Test fixture for discriminated union where variants are references to component schemas.\nThis is similar to the ContainerImage pattern in the infiron API.\n", - "devDependencies": { - "typescript": "^7.0.2", - "vite-plus": "^1.5.0" - }, + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.mjs", + "types": "./dist/index.d.mts", "exports": { ".": { "default": "./dist/index.mjs", "types": "./dist/index.d.mts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.mjs", - "name": "discriminated-union-with-references-test", "scripts": { "build": "vp pack", - "check": "vp check --no-fmt" + "check": "vp check", + "fmt": "vp fmt" }, - "type": "module", - "types": "./dist/index.d.mts", - "version": "1.0.0" -} \ No newline at end of file + "devDependencies": { + "typescript": "^7.0.2", + "vite-plus": "^1.5.0" + } +} diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/runtime/runtime.ts.golden index 878305890..d10377f26 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/runtime/runtime.ts.golden @@ -5,7 +5,7 @@ * Test fixture for discriminated union where variants are references to component schemas. * This is similar to the ContainerImage pattern in the infiron API. */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -15,7 +15,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -94,8 +97,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -137,12 +142,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -152,7 +163,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -168,9 +179,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -185,13 +194,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -201,7 +212,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -211,10 +222,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -223,18 +235,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -242,16 +258,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -270,11 +287,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -284,7 +301,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -294,7 +311,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -308,12 +325,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -331,15 +366,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -415,16 +463,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -451,7 +589,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -478,7 +619,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -488,5 +629,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/vite.config.ts.golden b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/vite.config.ts.golden index 250639b98..065569dd3 100644 --- a/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/vite.config.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-toolchain-vp/vite.config.ts.golden @@ -1,6 +1,10 @@ import { defineConfig } from 'vite-plus'; export default defineConfig({ + fmt: { + singleQuote: true, + ignorePatterns: ['dist/**'], + }, lint: { options: { typeAware: true, diff --git a/tests/golden/typescript/typescript-fetch/ts-type-guards/README.md.golden b/tests/golden/typescript/typescript-fetch/ts-type-guards/README.md.golden index 6cea2ff91..44c239938 100644 --- a/tests/golden/typescript/typescript-fetch/ts-type-guards/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/ts-type-guards/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'ts-type-guard-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'ts-type-guard-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/ts-type-guards/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/ts-type-guards/apis/DefaultApi.ts.golden index 9bdb2bffd..42d66ddd5 100644 --- a/tests/golden/typescript/typescript-fetch/ts-type-guards/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-type-guards/apis/DefaultApi.ts.golden @@ -4,36 +4,57 @@ * TS Type Guard Test — 1.0.0 */ import type { AppEvent } from '../models/AppEvent'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, RequiredError, ResponseError, VoidApiResponse } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + RequiredError, + ResponseError, + VoidApiResponse, +} from '../runtime/runtime'; export interface ApiHandleEventRequest { body: AppEvent; } export type HandleEventRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); - -export type HandleEventErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type HandleEventErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class HandleEventError extends ResponseError { readonly detail: HandleEventErrorDetail; - constructor(response: Response, detail: HandleEventErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: HandleEventErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - handleEventRaw: (requestParameters: ApiHandleEventRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - handleEvent: (requestParameters: ApiHandleEventRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + handleEventRaw: ( + requestParameters: ApiHandleEventRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + handleEvent: ( + requestParameters: ApiHandleEventRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class DefaultApi extends BaseAPI implements DefaultApiInterface { @@ -44,12 +65,14 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async handleEventRaw(requestParameters: ApiHandleEventRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async handleEventRaw( + requestParameters: ApiHandleEventRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling handleEventRaw().' + 'Required parameter "body" was null or undefined when calling handleEventRaw().', ); } // Build path with path parameters @@ -64,32 +87,44 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new HandleEventError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new HandleEventError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } - async handleEvent(requestParameters: ApiHandleEventRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async handleEvent( + requestParameters: ApiHandleEventRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.handleEventRaw(requestParameters, initOverrides); return await response.value(); } diff --git a/tests/golden/typescript/typescript-fetch/ts-type-guards/models/AppEvent.ts.golden b/tests/golden/typescript/typescript-fetch/ts-type-guards/models/AppEvent.ts.golden index 964738c92..a225cbedc 100644 --- a/tests/golden/typescript/typescript-fetch/ts-type-guards/models/AppEvent.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-type-guards/models/AppEvent.ts.golden @@ -9,16 +9,25 @@ import type { ScrollEvent } from './ScrollEvent'; /** An application event */ -export type AppEvent = ({ eventType: 'ClickEvent' } & ClickEvent) | ({ eventType: 'ScrollEvent' } & ScrollEvent) | ({ eventType: 'KeyEvent' } & KeyEvent); +export type AppEvent = + | ({ eventType: 'ClickEvent' } & ClickEvent) + | ({ eventType: 'ScrollEvent' } & ScrollEvent) + | ({ eventType: 'KeyEvent' } & KeyEvent); -export function isClickEvent(value: AppEvent): value is ({ eventType: 'ClickEvent' } & ClickEvent) { +export function isClickEvent(value: AppEvent): value is { + eventType: 'ClickEvent'; +} & ClickEvent { return value.eventType === 'ClickEvent'; } -export function isScrollEvent(value: AppEvent): value is ({ eventType: 'ScrollEvent' } & ScrollEvent) { +export function isScrollEvent(value: AppEvent): value is { + eventType: 'ScrollEvent'; +} & ScrollEvent { return value.eventType === 'ScrollEvent'; } -export function isKeyEvent(value: AppEvent): value is ({ eventType: 'KeyEvent' } & KeyEvent) { +export function isKeyEvent(value: AppEvent): value is { + eventType: 'KeyEvent'; +} & KeyEvent { return value.eventType === 'KeyEvent'; } diff --git a/tests/golden/typescript/typescript-fetch/ts-type-guards/models/Shape.ts.golden b/tests/golden/typescript/typescript-fetch/ts-type-guards/models/Shape.ts.golden index 65fd3c165..c4e55e785 100644 --- a/tests/golden/typescript/typescript-fetch/ts-type-guards/models/Shape.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-type-guards/models/Shape.ts.golden @@ -10,10 +10,14 @@ import type { Rectangle } from './Rectangle'; export type Shape = ({ kind: 'circle' } & Circle) | ({ kind: 'rectangle' } & Rectangle); -export function isCircle(value: Shape): value is ({ kind: 'circle' } & Circle) { +export function isCircle(value: Shape): value is { + kind: 'circle'; +} & Circle { return value.kind === 'circle'; } -export function isRectangle(value: Shape): value is ({ kind: 'rectangle' } & Rectangle) { +export function isRectangle(value: Shape): value is { + kind: 'rectangle'; +} & Rectangle { return value.kind === 'rectangle'; } diff --git a/tests/golden/typescript/typescript-fetch/ts-type-guards/package.json.golden b/tests/golden/typescript/typescript-fetch/ts-type-guards/package.json.golden index fb4f41199..a0d01b121 100644 --- a/tests/golden/typescript/typescript-fetch/ts-type-guards/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-type-guards/package.json.golden @@ -1,26 +1,26 @@ { + "name": "ts-type-guard-test", + "version": "1.0.0", "description": "TypeScript client for TS Type Guard Test", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "ts-type-guard-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/ts-type-guards/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/ts-type-guards/runtime/runtime.ts.golden index 380a62d19..78d5255dd 100644 --- a/tests/golden/typescript/typescript-fetch/ts-type-guards/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/ts-type-guards/runtime/runtime.ts.golden @@ -3,7 +3,7 @@ * * TS Type Guard Test — 1.0.0 */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -13,7 +13,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -92,8 +95,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -135,12 +140,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -150,7 +161,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -166,9 +177,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -183,13 +192,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -199,7 +210,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -209,10 +220,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -221,18 +233,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -240,16 +256,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -268,11 +285,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -282,7 +299,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -292,7 +309,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -306,12 +323,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -329,15 +364,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -413,16 +461,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -449,7 +587,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -476,7 +617,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -486,5 +627,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/ts-type-guards/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/ts-type-guards/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/ts-type-guards/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-type-guards/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/ts-type-guards/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/ts-type-guards/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/ts-type-guards/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/ts-type-guards/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-complex-union/README.md.golden b/tests/golden/typescript/typescript-fetch/type-aliases-complex-union/README.md.golden index 52ef8245a..fa87f3f2b 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-complex-union/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-complex-union/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'complex-union-type-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'complex-union-type-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-complex-union/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-complex-union/apis/DefaultApi.ts.golden index a1bf6073e..1b662393a 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-complex-union/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-complex-union/apis/DefaultApi.ts.golden @@ -5,36 +5,57 @@ * Test fixture for complex union types */ import type { Foo } from '../models/Foo'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, +} from '../runtime/runtime'; export interface ApiTestComplexUnionRequest { body: Foo; } export type TestComplexUnionRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); - -export type TestComplexUnionErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestComplexUnionErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestComplexUnionError extends ResponseError { readonly detail: TestComplexUnionErrorDetail; - constructor(response: Response, detail: TestComplexUnionErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestComplexUnionErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - testComplexUnionRaw: (requestParameters: ApiTestComplexUnionRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - testComplexUnion: (requestParameters: ApiTestComplexUnionRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + testComplexUnionRaw: ( + requestParameters: ApiTestComplexUnionRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + testComplexUnion: ( + requestParameters: ApiTestComplexUnionRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class DefaultApi extends BaseAPI implements DefaultApiInterface { @@ -45,12 +66,14 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async testComplexUnionRaw(requestParameters: ApiTestComplexUnionRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async testComplexUnionRaw( + requestParameters: ApiTestComplexUnionRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling testComplexUnionRaw().' + 'Required parameter "body" was null or undefined when calling testComplexUnionRaw().', ); } // Build path with path parameters @@ -65,33 +88,45 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestComplexUnionError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestComplexUnionError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async testComplexUnion(requestParameters: ApiTestComplexUnionRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async testComplexUnion( + requestParameters: ApiTestComplexUnionRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.testComplexUnionRaw(requestParameters, initOverrides); - return await response.value() as Foo; + return (await response.value()) as Foo; } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-complex-union/package.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-complex-union/package.json.golden index 6cd8fd468..156fbef52 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-complex-union/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-complex-union/package.json.golden @@ -1,26 +1,26 @@ { + "name": "complex-union-type-test", + "version": "1.0.0", "description": "Test fixture for complex union types", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "complex-union-type-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-complex-union/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-complex-union/runtime/runtime.ts.golden index fb686b450..73ce56411 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-complex-union/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-complex-union/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Complex Union Type Test — 1.0.0 * Test fixture for complex union types */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-complex-union/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-complex-union/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-complex-union/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-complex-union/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-complex-union/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-complex-union/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-complex-union/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-complex-union/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-inline-discriminator-only/README.md.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-inline-discriminator-only/README.md.golden index e6bc2cc9d..da1e5f50b 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-inline-discriminator-only/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-inline-discriminator-only/README.md.golden @@ -11,7 +11,6 @@ discriminated unions. After the fix, these should generate properly prefixed names like "EventKindUnspecified" instead of generic "Kind". - **Version:** 1.0.0 ## Overview @@ -62,8 +61,8 @@ import { Configuration, DefaultApi } from 'discriminated-union-with-inline-discr const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -111,9 +110,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -136,12 +135,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -150,7 +149,11 @@ const config = new Configuration({ The client throws typed errors for different failure scenarios: ```typescript -import { ResponseError, FetchError, RequiredError } from 'discriminated-union-with-inline-discriminator-only-test'; +import { + ResponseError, + FetchError, + RequiredError, +} from 'discriminated-union-with-inline-discriminator-only-test'; try { const result = await api.someMethod(); @@ -219,12 +222,15 @@ This package works with standard TypeScript configurations. If you're using a bu ### Type Imports ```typescript -import type { User, CreateUserRequest } from 'discriminated-union-with-inline-discriminator-only-test'; +import type { + User, + CreateUserRequest, +} from 'discriminated-union-with-inline-discriminator-only-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-inline-discriminator-only/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-inline-discriminator-only/apis/DefaultApi.ts.golden index 00c9b7565..bdf570e0d 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-inline-discriminator-only/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-inline-discriminator-only/apis/DefaultApi.ts.golden @@ -14,36 +14,57 @@ * "EventKindUnspecified" instead of generic "Kind". */ import type { Event } from '../models/Event'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, +} from '../runtime/runtime'; export interface ApiCreateEventRequest { body: Event; } export type CreateEventRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); - -export type CreateEventErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type CreateEventErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class CreateEventError extends ResponseError { readonly detail: CreateEventErrorDetail; - constructor(response: Response, detail: CreateEventErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: CreateEventErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - createEventRaw: (requestParameters: ApiCreateEventRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - createEvent: (requestParameters: ApiCreateEventRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + createEventRaw: ( + requestParameters: ApiCreateEventRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + createEvent: ( + requestParameters: ApiCreateEventRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class DefaultApi extends BaseAPI implements DefaultApiInterface { @@ -54,12 +75,14 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async createEventRaw(requestParameters: ApiCreateEventRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createEventRaw( + requestParameters: ApiCreateEventRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling createEventRaw().' + 'Required parameter "body" was null or undefined when calling createEventRaw().', ); } // Build path with path parameters @@ -74,33 +97,45 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new CreateEventError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new CreateEventError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async createEvent(requestParameters: ApiCreateEventRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createEvent( + requestParameters: ApiCreateEventRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.createEventRaw(requestParameters, initOverrides); - return await response.value() as Event; + return (await response.value()) as Event; } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-inline-discriminator-only/models/Event.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-inline-discriminator-only/models/Event.ts.golden index bafe54de3..3e49a979c 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-inline-discriminator-only/models/Event.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-inline-discriminator-only/models/Event.ts.golden @@ -16,4 +16,7 @@ import type { EventEventCreated } from './EventEventCreated'; import type { EventEventUpdated } from './EventEventUpdated'; -export type Event = { kind: 'EVENT_UNSPECIFIED' } | ({ kind: 'EVENT_CREATED' } & EventEventCreated) | ({ kind: 'EVENT_UPDATED' } & EventEventUpdated); +export type Event = + | { kind: 'EVENT_UNSPECIFIED' } + | ({ kind: 'EVENT_CREATED' } & EventEventCreated) + | ({ kind: 'EVENT_UPDATED' } & EventEventUpdated); diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-inline-discriminator-only/package.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-inline-discriminator-only/package.json.golden index a7ba0d2f1..f628e9340 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-inline-discriminator-only/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-inline-discriminator-only/package.json.golden @@ -1,26 +1,26 @@ { + "name": "discriminated-union-with-inline-discriminator-only-test", + "version": "1.0.0", "description": "Test fixture for discriminated union where variants are inline objects\nwith ONLY a discriminator property (no additional fields).\n\nThis specifically tests the fix for the bug where inline objects with\nonly a discriminator property (like { kind: \"UNSPECIFIED\" }) were\ngenerating generic \"Kind.ts\" files that conflicted across different\ndiscriminated unions.\n\nAfter the fix, these should generate properly prefixed names like\n\"EventKindUnspecified\" instead of generic \"Kind\".\n", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "discriminated-union-with-inline-discriminator-only-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-inline-discriminator-only/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-inline-discriminator-only/runtime/runtime.ts.golden index 409381bea..60bdcfbe2 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-inline-discriminator-only/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-inline-discriminator-only/runtime/runtime.ts.golden @@ -13,7 +13,7 @@ * After the fix, these should generate properly prefixed names like * "EventKindUnspecified" instead of generic "Kind". */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -23,7 +23,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -102,8 +105,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -145,12 +150,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -160,7 +171,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -176,9 +187,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -193,13 +202,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -209,7 +220,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -219,10 +230,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -231,18 +243,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -250,16 +266,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -278,11 +295,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -292,7 +309,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -302,7 +319,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -316,12 +333,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -339,15 +374,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -423,16 +471,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -459,7 +597,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -486,7 +627,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -496,5 +637,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-inline-discriminator-only/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-inline-discriminator-only/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-inline-discriminator-only/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-inline-discriminator-only/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-inline-discriminator-only/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-inline-discriminator-only/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-inline-discriminator-only/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-inline-discriminator-only/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-internally-tagged/README.md.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-internally-tagged/README.md.golden index 476b8dd40..32e1844e9 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-internally-tagged/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-internally-tagged/README.md.golden @@ -4,7 +4,6 @@ Test fixture for internally tagged (adjacently tagged) discriminator unions. This tests that discriminator properties have literal types instead of union types. See: https://www.openapis.org/understanding-openapi/specification/models/ - **Version:** 1.0.0 ## Overview @@ -55,8 +54,8 @@ import { Configuration, DefaultApi } from 'discriminated-union-internally-tagged const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -104,9 +103,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -129,12 +128,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -143,7 +142,11 @@ const config = new Configuration({ The client throws typed errors for different failure scenarios: ```typescript -import { ResponseError, FetchError, RequiredError } from 'discriminated-union-internally-tagged-test'; +import { + ResponseError, + FetchError, + RequiredError, +} from 'discriminated-union-internally-tagged-test'; try { const result = await api.someMethod(); @@ -217,7 +220,7 @@ import type { User, CreateUserRequest } from 'discriminated-union-internally-tag const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-internally-tagged/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-internally-tagged/apis/DefaultApi.ts.golden index 58859fa1e..d85cefb57 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-internally-tagged/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-internally-tagged/apis/DefaultApi.ts.golden @@ -7,36 +7,57 @@ * See: https://www.openapis.org/understanding-openapi/specification/models/ */ import type { Resource } from '../models/Resource'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, +} from '../runtime/runtime'; export interface ApiCreateResourceRequest { body: Resource; } export type CreateResourceRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); - -export type CreateResourceErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type CreateResourceErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class CreateResourceError extends ResponseError { readonly detail: CreateResourceErrorDetail; - constructor(response: Response, detail: CreateResourceErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: CreateResourceErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - createResourceRaw: (requestParameters: ApiCreateResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - createResource: (requestParameters: ApiCreateResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + createResourceRaw: ( + requestParameters: ApiCreateResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + createResource: ( + requestParameters: ApiCreateResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class DefaultApi extends BaseAPI implements DefaultApiInterface { @@ -47,12 +68,14 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async createResourceRaw(requestParameters: ApiCreateResourceRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createResourceRaw( + requestParameters: ApiCreateResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling createResourceRaw().' + 'Required parameter "body" was null or undefined when calling createResourceRaw().', ); } // Build path with path parameters @@ -67,33 +90,45 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new CreateResourceError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new CreateResourceError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async createResource(requestParameters: ApiCreateResourceRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createResource( + requestParameters: ApiCreateResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.createResourceRaw(requestParameters, initOverrides); - return await response.value() as Resource; + return (await response.value()) as Resource; } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-internally-tagged/models/Resource.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-internally-tagged/models/Resource.ts.golden index 913b314f7..14f0fa36e 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-internally-tagged/models/Resource.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-internally-tagged/models/Resource.ts.golden @@ -10,4 +10,7 @@ import type { ResourceCustom } from './ResourceCustom'; import type { ResourceQuick } from './ResourceQuick'; import type { ResourceUnspecified } from './ResourceUnspecified'; -export type Resource = ({ kind: 'RESOURCE_UNSPECIFIED' } & ResourceUnspecified) | ({ kind: 'RESOURCE_QUICK' } & ResourceQuick) | ({ kind: 'RESOURCE_CUSTOM' } & ResourceCustom); +export type Resource = + | ({ kind: 'RESOURCE_UNSPECIFIED' } & ResourceUnspecified) + | ({ kind: 'RESOURCE_QUICK' } & ResourceQuick) + | ({ kind: 'RESOURCE_CUSTOM' } & ResourceCustom); diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-internally-tagged/package.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-internally-tagged/package.json.golden index 9f6bdf8e4..d112ccac4 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-internally-tagged/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-internally-tagged/package.json.golden @@ -1,26 +1,26 @@ { + "name": "discriminated-union-internally-tagged-test", + "version": "1.0.0", "description": "Test fixture for internally tagged (adjacently tagged) discriminator unions.\nThis tests that discriminator properties have literal types instead of union types.\nSee: https://www.openapis.org/understanding-openapi/specification/models/\n", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "discriminated-union-internally-tagged-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-internally-tagged/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-internally-tagged/runtime/runtime.ts.golden index a087cbc13..82afb2cff 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-internally-tagged/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-internally-tagged/runtime/runtime.ts.golden @@ -6,7 +6,7 @@ * This tests that discriminator properties have literal types instead of union types. * See: https://www.openapis.org/understanding-openapi/specification/models/ */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -16,7 +16,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -95,8 +98,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -138,12 +143,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -153,7 +164,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -169,9 +180,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -186,13 +195,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -202,7 +213,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -212,10 +223,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -224,18 +236,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -243,16 +259,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -271,11 +288,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -285,7 +302,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -295,7 +312,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -309,12 +326,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -332,15 +367,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -416,16 +464,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -452,7 +590,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -479,7 +620,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -489,5 +630,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-internally-tagged/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-internally-tagged/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-internally-tagged/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-internally-tagged/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-internally-tagged/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-internally-tagged/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-internally-tagged/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-internally-tagged/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-long-names/README.md.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-long-names/README.md.golden index eba065bcf..994c86d35 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-long-names/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-long-names/README.md.golden @@ -4,7 +4,6 @@ Test fixture for discriminated union where variant type names are intentionally long enough to force multi-line type alias output at the 100-char render width. Ensures PEP 695 parenthesization is correct. - **Version:** 1.0.0 ## Overview @@ -55,8 +54,8 @@ import { Configuration, DefaultApi } from 'discriminated-union-with-long-type-na const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -104,9 +103,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -129,12 +128,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -143,7 +142,11 @@ const config = new Configuration({ The client throws typed errors for different failure scenarios: ```typescript -import { ResponseError, FetchError, RequiredError } from 'discriminated-union-with-long-type-names-test'; +import { + ResponseError, + FetchError, + RequiredError, +} from 'discriminated-union-with-long-type-names-test'; try { const result = await api.someMethod(); @@ -217,7 +220,7 @@ import type { User, CreateUserRequest } from 'discriminated-union-with-long-type const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-long-names/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-long-names/apis/DefaultApi.ts.golden index e17c6cbf6..680be8add 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-long-names/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-long-names/apis/DefaultApi.ts.golden @@ -7,37 +7,57 @@ * 100-char render width. Ensures PEP 695 parenthesization is correct. */ import type { VeryLongDiscriminatedUnionTypeNameForTesting20260630 } from '../models/VeryLongDiscriminatedUnionTypeNameForTesting20260630'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, +} from '../runtime/runtime'; export interface ApiCreateResourceRequest { body: VeryLongDiscriminatedUnionTypeNameForTesting20260630; } export type CreateResourceRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); - -export type CreateResourceErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type CreateResourceErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class CreateResourceError extends ResponseError { readonly detail: CreateResourceErrorDetail; - constructor(response: Response, detail: CreateResourceErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: CreateResourceErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - createResourceRaw: (requestParameters: ApiCreateResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - createResource: (requestParameters: ApiCreateResourceRequest, - initOverrides?: RequestInit - | InitOverrideFunction) => Promise; + createResourceRaw: ( + requestParameters: ApiCreateResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + createResource: ( + requestParameters: ApiCreateResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class DefaultApi extends BaseAPI implements DefaultApiInterface { @@ -48,12 +68,14 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async createResourceRaw(requestParameters: ApiCreateResourceRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createResourceRaw( + requestParameters: ApiCreateResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling createResourceRaw().' + 'Required parameter "body" was null or undefined when calling createResourceRaw().', ); } // Build path with path parameters @@ -68,33 +90,47 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new CreateResourceError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new CreateResourceError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { - return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + return new JSONApiResponse(response) as JSONApiResponse & { + status: 200; + }; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async createResource(requestParameters: ApiCreateResourceRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createResource( + requestParameters: ApiCreateResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.createResourceRaw(requestParameters, initOverrides); - return await response.value() as VeryLongDiscriminatedUnionTypeNameForTesting20260630; + return (await response.value()) as VeryLongDiscriminatedUnionTypeNameForTesting20260630; } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-long-names/models/VeryLongDiscriminatedUnionTypeNameForTesting20260630.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-long-names/models/VeryLongDiscriminatedUnionTypeNameForTesting20260630.ts.golden index 9126447f7..ff7b5b51f 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-long-names/models/VeryLongDiscriminatedUnionTypeNameForTesting20260630.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-long-names/models/VeryLongDiscriminatedUnionTypeNameForTesting20260630.ts.golden @@ -10,4 +10,7 @@ import type { VeryLongDiscriminatedUnionTypeNameAlpha20260630 } from './VeryLong import type { VeryLongDiscriminatedUnionTypeNameBeta20260630 } from './VeryLongDiscriminatedUnionTypeNameBeta20260630'; import type { VeryLongDiscriminatedUnionTypeNameGamma20260630 } from './VeryLongDiscriminatedUnionTypeNameGamma20260630'; -export type VeryLongDiscriminatedUnionTypeNameForTesting20260630 = ({ kind: 'ALPHA' } & VeryLongDiscriminatedUnionTypeNameAlpha20260630) | ({ kind: 'BETA' } & VeryLongDiscriminatedUnionTypeNameBeta20260630) | ({ kind: 'GAMMA' } & VeryLongDiscriminatedUnionTypeNameGamma20260630); +export type VeryLongDiscriminatedUnionTypeNameForTesting20260630 = + | ({ kind: 'ALPHA' } & VeryLongDiscriminatedUnionTypeNameAlpha20260630) + | ({ kind: 'BETA' } & VeryLongDiscriminatedUnionTypeNameBeta20260630) + | ({ kind: 'GAMMA' } & VeryLongDiscriminatedUnionTypeNameGamma20260630); diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-long-names/package.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-long-names/package.json.golden index c3bed27c9..94a2f90f6 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-long-names/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-long-names/package.json.golden @@ -1,26 +1,26 @@ { + "name": "discriminated-union-with-long-type-names-test", + "version": "1.0.0", "description": "Test fixture for discriminated union where variant type names are\nintentionally long enough to force multi-line type alias output at the\n100-char render width. Ensures PEP 695 parenthesization is correct.\n", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "discriminated-union-with-long-type-names-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-long-names/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-long-names/runtime/runtime.ts.golden index f7d032043..c7edbb965 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-long-names/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-long-names/runtime/runtime.ts.golden @@ -6,7 +6,7 @@ * intentionally long enough to force multi-line type alias output at the * 100-char render width. Ensures PEP 695 parenthesization is correct. */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -16,7 +16,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -95,8 +98,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -138,12 +143,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -153,7 +164,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -169,9 +180,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -186,13 +195,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -202,7 +213,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -212,10 +223,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -224,18 +236,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -243,16 +259,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -271,11 +288,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -285,7 +302,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -295,7 +312,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -309,12 +326,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -332,15 +367,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -416,16 +464,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -452,7 +590,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -479,7 +620,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -489,5 +630,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-long-names/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-long-names/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-long-names/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-long-names/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-long-names/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-long-names/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-long-names/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-long-names/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-mixed-unit-and-allof/README.md.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-mixed-unit-and-allof/README.md.golden index 4a515a43e..2fb08e59c 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-mixed-unit-and-allof/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-mixed-unit-and-allof/README.md.golden @@ -7,7 +7,6 @@ use allOf to merge a $ref with a discriminator object. This pattern is generated by serde's `#[serde(tag = "kind")]` when one variant is a unit variant (no fields) and others carry data from referenced schemas. - **Version:** 1.0.0 ## Overview @@ -58,8 +57,8 @@ import { Configuration, DefaultApi } from 'discriminated-union-mixed-unit-and-al const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -107,9 +106,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -132,12 +131,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -146,7 +145,11 @@ const config = new Configuration({ The client throws typed errors for different failure scenarios: ```typescript -import { ResponseError, FetchError, RequiredError } from 'discriminated-union-mixed-unit-and-all-of-test'; +import { + ResponseError, + FetchError, + RequiredError, +} from 'discriminated-union-mixed-unit-and-all-of-test'; try { const result = await api.someMethod(); @@ -220,7 +223,7 @@ import type { User, CreateUserRequest } from 'discriminated-union-mixed-unit-and const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-mixed-unit-and-allof/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-mixed-unit-and-allof/apis/DefaultApi.ts.golden index ee6b8b711..8dc506699 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-mixed-unit-and-allof/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-mixed-unit-and-allof/apis/DefaultApi.ts.golden @@ -10,36 +10,57 @@ * is a unit variant (no fields) and others carry data from referenced schemas. */ import type { Setup } from '../models/Setup'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, +} from '../runtime/runtime'; export interface ApiCreateResourceRequest { body: Setup; } export type CreateResourceRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); - -export type CreateResourceErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type CreateResourceErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class CreateResourceError extends ResponseError { readonly detail: CreateResourceErrorDetail; - constructor(response: Response, detail: CreateResourceErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: CreateResourceErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - createResourceRaw: (requestParameters: ApiCreateResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - createResource: (requestParameters: ApiCreateResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + createResourceRaw: ( + requestParameters: ApiCreateResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + createResource: ( + requestParameters: ApiCreateResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class DefaultApi extends BaseAPI implements DefaultApiInterface { @@ -50,12 +71,14 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async createResourceRaw(requestParameters: ApiCreateResourceRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createResourceRaw( + requestParameters: ApiCreateResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling createResourceRaw().' + 'Required parameter "body" was null or undefined when calling createResourceRaw().', ); } // Build path with path parameters @@ -70,33 +93,45 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new CreateResourceError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new CreateResourceError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async createResource(requestParameters: ApiCreateResourceRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createResource( + requestParameters: ApiCreateResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.createResourceRaw(requestParameters, initOverrides); - return await response.value() as Setup; + return (await response.value()) as Setup; } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-mixed-unit-and-allof/models/Setup.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-mixed-unit-and-allof/models/Setup.ts.golden index 725f2c8fc..14cbae06c 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-mixed-unit-and-allof/models/Setup.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-mixed-unit-and-allof/models/Setup.ts.golden @@ -14,4 +14,7 @@ import type { SetupQuick } from './SetupQuick'; /** Setup: quick (managed), custom, or unspecified. */ -export type Setup = { kind: 'SETUP_UNSPECIFIED' } | ({ kind: 'SETUP_QUICK' } & SetupQuick) | ({ kind: 'SETUP_CUSTOM' } & SetupCustom); +export type Setup = + | { kind: 'SETUP_UNSPECIFIED' } + | ({ kind: 'SETUP_QUICK' } & SetupQuick) + | ({ kind: 'SETUP_CUSTOM' } & SetupCustom); diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-mixed-unit-and-allof/package.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-mixed-unit-and-allof/package.json.golden index 64297cd77..685932a69 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-mixed-unit-and-allof/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-mixed-unit-and-allof/package.json.golden @@ -1,26 +1,26 @@ { + "name": "discriminated-union-mixed-unit-and-all-of-test", + "version": "1.0.0", "description": "Test fixture for internally tagged discriminated union where the \"unspecified\"\nvariant is a plain object with only the discriminator field, while other variants\nuse allOf to merge a $ref with a discriminator object.\n\nThis pattern is generated by serde's `#[serde(tag = \"kind\")]` when one variant\nis a unit variant (no fields) and others carry data from referenced schemas.\n", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "discriminated-union-mixed-unit-and-all-of-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-mixed-unit-and-allof/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-mixed-unit-and-allof/runtime/runtime.ts.golden index 679331b00..4a1c10a71 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-mixed-unit-and-allof/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-mixed-unit-and-allof/runtime/runtime.ts.golden @@ -9,7 +9,7 @@ * This pattern is generated by serde's `#[serde(tag = "kind")]` when one variant * is a unit variant (no fields) and others carry data from referenced schemas. */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -19,7 +19,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -98,8 +101,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -141,12 +146,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -156,7 +167,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -172,9 +183,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -189,13 +198,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -205,7 +216,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -215,10 +226,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -227,18 +239,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -246,16 +262,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -274,11 +291,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -288,7 +305,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -298,7 +315,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -312,12 +329,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -335,15 +370,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -419,16 +467,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -455,7 +593,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -482,7 +623,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -492,5 +633,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-mixed-unit-and-allof/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-mixed-unit-and-allof/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-mixed-unit-and-allof/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-mixed-unit-and-allof/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-mixed-unit-and-allof/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-mixed-unit-and-allof/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-mixed-unit-and-allof/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-mixed-unit-and-allof/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/README.md.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/README.md.golden index 932806010..56ee6ca60 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/README.md.golden @@ -5,7 +5,6 @@ are properly namespaced and don't conflict. This reproduces the original bug where both unions would generate the same Kind.ts file causing conflicts. - **Version:** 1.0.0 ## Overview @@ -56,8 +55,8 @@ import { Configuration, DefaultApi } from 'multiple-discriminated-unions-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -105,9 +104,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -130,12 +129,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -218,7 +217,7 @@ import type { User, CreateUserRequest } from 'multiple-discriminated-unions-test const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/apis/DefaultApi.ts.golden index ac4255522..628e1bee6 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/apis/DefaultApi.ts.golden @@ -9,8 +9,19 @@ */ import type { ContainerKind } from '../models/ContainerKind'; import type { VolumeKind } from '../models/VolumeKind'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, +} from '../runtime/runtime'; export interface ApiCreateContainerRequest { body: ContainerKind; @@ -21,49 +32,69 @@ export interface ApiCreateVolumeRequest { } export type CreateContainerRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type CreateVolumeRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); -export type CreateContainerErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type CreateContainerErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class CreateContainerError extends ResponseError { readonly detail: CreateContainerErrorDetail; - constructor(response: Response, detail: CreateContainerErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: CreateContainerErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type CreateVolumeErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type CreateVolumeErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class CreateVolumeError extends ResponseError { readonly detail: CreateVolumeErrorDetail; - constructor(response: Response, detail: CreateVolumeErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: CreateVolumeErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - createContainerRaw: (requestParameters: ApiCreateContainerRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - createContainer: (requestParameters: ApiCreateContainerRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - createVolumeRaw: (requestParameters: ApiCreateVolumeRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - createVolume: (requestParameters: ApiCreateVolumeRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + createContainerRaw: ( + requestParameters: ApiCreateContainerRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + createContainer: ( + requestParameters: ApiCreateContainerRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + createVolumeRaw: ( + requestParameters: ApiCreateVolumeRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + createVolume: ( + requestParameters: ApiCreateVolumeRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class DefaultApi extends BaseAPI implements DefaultApiInterface { @@ -74,12 +105,14 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async createContainerRaw(requestParameters: ApiCreateContainerRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createContainerRaw( + requestParameters: ApiCreateContainerRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling createContainerRaw().' + 'Required parameter "body" was null or undefined when calling createContainerRaw().', ); } // Build path with path parameters @@ -94,42 +127,56 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new CreateContainerError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new CreateContainerError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async createContainer(requestParameters: ApiCreateContainerRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createContainer( + requestParameters: ApiCreateContainerRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.createContainerRaw(requestParameters, initOverrides); - return await response.value() as ContainerKind; + return (await response.value()) as ContainerKind; } - async createVolumeRaw(requestParameters: ApiCreateVolumeRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createVolumeRaw( + requestParameters: ApiCreateVolumeRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling createVolumeRaw().' + 'Required parameter "body" was null or undefined when calling createVolumeRaw().', ); } // Build path with path parameters @@ -144,33 +191,45 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new CreateVolumeError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new CreateVolumeError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async createVolume(requestParameters: ApiCreateVolumeRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createVolume( + requestParameters: ApiCreateVolumeRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.createVolumeRaw(requestParameters, initOverrides); - return await response.value() as VolumeKind; + return (await response.value()) as VolumeKind; } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/models/ContainerKind.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/models/ContainerKind.ts.golden index 874696bb0..8b6a2c6c2 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/models/ContainerKind.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/models/ContainerKind.ts.golden @@ -10,4 +10,6 @@ import type { ContainerKindCustom } from './ContainerKindCustom'; import type { ContainerKindManaged } from './ContainerKindManaged'; -export type ContainerKind = ({ kind: 'CONTAINER_KIND_MANAGED' } & ContainerKindManaged) | ({ kind: 'CONTAINER_KIND_CUSTOM' } & ContainerKindCustom); +export type ContainerKind = + | ({ kind: 'CONTAINER_KIND_MANAGED' } & ContainerKindManaged) + | ({ kind: 'CONTAINER_KIND_CUSTOM' } & ContainerKindCustom); diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/models/VolumeKind.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/models/VolumeKind.ts.golden index a78fd02ea..8c9cb06fe 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/models/VolumeKind.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/models/VolumeKind.ts.golden @@ -10,4 +10,6 @@ import type { VolumeKindLocal } from './VolumeKindLocal'; import type { VolumeKindRemote } from './VolumeKindRemote'; -export type VolumeKind = ({ kind: 'VOLUME_KIND_LOCAL' } & VolumeKindLocal) | ({ kind: 'VOLUME_KIND_REMOTE' } & VolumeKindRemote); +export type VolumeKind = + | ({ kind: 'VOLUME_KIND_LOCAL' } & VolumeKindLocal) + | ({ kind: 'VOLUME_KIND_REMOTE' } & VolumeKindRemote); diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/package.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/package.json.golden index 3fbff7e30..3ab461401 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/package.json.golden @@ -1,26 +1,26 @@ { + "name": "multiple-discriminated-unions-test", + "version": "1.0.0", "description": "Test fixture with multiple discriminated unions to verify Kind types\nare properly namespaced and don't conflict.\nThis reproduces the original bug where both unions would generate\nthe same Kind.ts file causing conflicts.\n", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "multiple-discriminated-unions-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/runtime/runtime.ts.golden index 7851df68e..93f0c5079 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/runtime/runtime.ts.golden @@ -7,7 +7,7 @@ * This reproduces the original bug where both unions would generate * the same Kind.ts file causing conflicts. */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -17,7 +17,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -96,8 +99,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -139,12 +144,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -154,7 +165,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -170,9 +181,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -187,13 +196,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -203,7 +214,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -213,10 +224,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -225,18 +237,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -244,16 +260,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -272,11 +289,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -286,7 +303,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -296,7 +313,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -310,12 +327,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -333,15 +368,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -417,16 +465,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -453,7 +591,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -480,7 +621,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -490,5 +631,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-multiple/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-with-refs/README.md.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-with-refs/README.md.golden index dafe063f0..cd36d2d79 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-with-refs/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-with-refs/README.md.golden @@ -3,7 +3,6 @@ Test fixture for discriminated union where variants are references to component schemas. This is similar to the ContainerImage pattern in the infiron API. - **Version:** 1.0.0 ## Overview @@ -54,8 +53,8 @@ import { Configuration, DefaultApi } from 'discriminated-union-with-references-t const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -103,9 +102,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -128,12 +127,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -216,7 +215,7 @@ import type { User, CreateUserRequest } from 'discriminated-union-with-reference const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-with-refs/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-with-refs/apis/DefaultApi.ts.golden index 9c6692eef..3a613f89d 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-with-refs/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-with-refs/apis/DefaultApi.ts.golden @@ -6,36 +6,57 @@ * This is similar to the ContainerImage pattern in the infiron API. */ import type { ContainerImage } from '../models/ContainerImage'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, +} from '../runtime/runtime'; export interface ApiCreateContainerRequest { body: ContainerImage; } export type CreateContainerRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); - -export type CreateContainerErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type CreateContainerErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class CreateContainerError extends ResponseError { readonly detail: CreateContainerErrorDetail; - constructor(response: Response, detail: CreateContainerErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: CreateContainerErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - createContainerRaw: (requestParameters: ApiCreateContainerRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - createContainer: (requestParameters: ApiCreateContainerRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + createContainerRaw: ( + requestParameters: ApiCreateContainerRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + createContainer: ( + requestParameters: ApiCreateContainerRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class DefaultApi extends BaseAPI implements DefaultApiInterface { @@ -46,12 +67,14 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async createContainerRaw(requestParameters: ApiCreateContainerRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createContainerRaw( + requestParameters: ApiCreateContainerRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling createContainerRaw().' + 'Required parameter "body" was null or undefined when calling createContainerRaw().', ); } // Build path with path parameters @@ -66,33 +89,45 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new CreateContainerError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new CreateContainerError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async createContainer(requestParameters: ApiCreateContainerRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createContainer( + requestParameters: ApiCreateContainerRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.createContainerRaw(requestParameters, initOverrides); - return await response.value() as ContainerImage; + return (await response.value()) as ContainerImage; } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-with-refs/models/ContainerImage.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-with-refs/models/ContainerImage.ts.golden index c85b22e02..13d686f13 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-with-refs/models/ContainerImage.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-with-refs/models/ContainerImage.ts.golden @@ -8,4 +8,6 @@ import type { ContainerImageCustom } from './ContainerImageCustom'; import type { ContainerImageManaged } from './ContainerImageManaged'; -export type ContainerImage = ({ kind: 'CONTAINER_IMAGE_MANAGED' } & ContainerImageManaged) | ({ kind: 'CONTAINER_IMAGE_CUSTOM' } & ContainerImageCustom); +export type ContainerImage = + | ({ kind: 'CONTAINER_IMAGE_MANAGED' } & ContainerImageManaged) + | ({ kind: 'CONTAINER_IMAGE_CUSTOM' } & ContainerImageCustom); diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-with-refs/package.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-with-refs/package.json.golden index 2192b29f9..26997847b 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-with-refs/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-with-refs/package.json.golden @@ -1,26 +1,26 @@ { + "name": "discriminated-union-with-references-test", + "version": "1.0.0", "description": "Test fixture for discriminated union where variants are references to component schemas.\nThis is similar to the ContainerImage pattern in the infiron API.\n", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "discriminated-union-with-references-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-with-refs/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-with-refs/runtime/runtime.ts.golden index 878305890..d10377f26 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-with-refs/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-with-refs/runtime/runtime.ts.golden @@ -5,7 +5,7 @@ * Test fixture for discriminated union where variants are references to component schemas. * This is similar to the ContainerImage pattern in the infiron API. */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -15,7 +15,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -94,8 +97,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -137,12 +142,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -152,7 +163,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -168,9 +179,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -185,13 +194,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -201,7 +212,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -211,10 +222,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -223,18 +235,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -242,16 +258,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -270,11 +287,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -284,7 +301,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -294,7 +311,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -308,12 +325,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -331,15 +366,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -415,16 +463,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -451,7 +589,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -478,7 +619,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -488,5 +629,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-with-refs/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-with-refs/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-with-refs/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-with-refs/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-with-refs/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-with-refs/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-with-refs/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-discriminated-union-with-refs/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-intersection-allof/README.md.golden b/tests/golden/typescript/typescript-fetch/type-aliases-intersection-allof/README.md.golden index 5e63e36ae..d8a69f807 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-intersection-allof/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-intersection-allof/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'intersection-type-all-of-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'intersection-type-all-of-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-intersection-allof/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-intersection-allof/apis/DefaultApi.ts.golden index 1e43dfa1f..2985e232c 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-intersection-allof/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-intersection-allof/apis/DefaultApi.ts.golden @@ -5,36 +5,57 @@ * Test fixture for allOf intersection types */ import type { Foo } from '../models/Foo'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, +} from '../runtime/runtime'; export interface ApiTestIntersectionRequest { body: Foo; } export type TestIntersectionRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); - -export type TestIntersectionErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestIntersectionErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestIntersectionError extends ResponseError { readonly detail: TestIntersectionErrorDetail; - constructor(response: Response, detail: TestIntersectionErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestIntersectionErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - testIntersectionRaw: (requestParameters: ApiTestIntersectionRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - testIntersection: (requestParameters: ApiTestIntersectionRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + testIntersectionRaw: ( + requestParameters: ApiTestIntersectionRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + testIntersection: ( + requestParameters: ApiTestIntersectionRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class DefaultApi extends BaseAPI implements DefaultApiInterface { @@ -45,12 +66,14 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async testIntersectionRaw(requestParameters: ApiTestIntersectionRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async testIntersectionRaw( + requestParameters: ApiTestIntersectionRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling testIntersectionRaw().' + 'Required parameter "body" was null or undefined when calling testIntersectionRaw().', ); } // Build path with path parameters @@ -65,33 +88,45 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestIntersectionError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestIntersectionError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async testIntersection(requestParameters: ApiTestIntersectionRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async testIntersection( + requestParameters: ApiTestIntersectionRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.testIntersectionRaw(requestParameters, initOverrides); - return await response.value() as Foo; + return (await response.value()) as Foo; } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-intersection-allof/package.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-intersection-allof/package.json.golden index b416967ec..68c4d847f 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-intersection-allof/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-intersection-allof/package.json.golden @@ -1,26 +1,26 @@ { + "name": "intersection-type-all-of-test", + "version": "1.0.0", "description": "Test fixture for allOf intersection types", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "intersection-type-all-of-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-intersection-allof/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-intersection-allof/runtime/runtime.ts.golden index 5ea10eca4..d661eff77 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-intersection-allof/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-intersection-allof/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Intersection Type (allOf) Test — 1.0.0 * Test fixture for allOf intersection types */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-intersection-allof/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-intersection-allof/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-intersection-allof/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-intersection-allof/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-intersection-allof/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-intersection-allof/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-intersection-allof/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-intersection-allof/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-intersection-with-nullable-reference/README.md.golden b/tests/golden/typescript/typescript-fetch/type-aliases-intersection-with-nullable-reference/README.md.golden index 7c3e4968c..952ebc564 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-intersection-with-nullable-reference/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-intersection-with-nullable-reference/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'intersection-type-with-nullable-refer const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -140,7 +140,11 @@ const config = new Configuration({ The client throws typed errors for different failure scenarios: ```typescript -import { ResponseError, FetchError, RequiredError } from 'intersection-type-with-nullable-reference-test'; +import { + ResponseError, + FetchError, + RequiredError, +} from 'intersection-type-with-nullable-reference-test'; try { const result = await api.someMethod(); @@ -214,7 +218,7 @@ import type { User, CreateUserRequest } from 'intersection-type-with-nullable-re const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-intersection-with-nullable-reference/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-intersection-with-nullable-reference/apis/DefaultApi.ts.golden index 42559a713..cfc4380ae 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-intersection-with-nullable-reference/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-intersection-with-nullable-reference/apis/DefaultApi.ts.golden @@ -5,8 +5,19 @@ * Test fixture for allOf intersection types with nullable reference properties */ import type { Baz } from '../models/Baz'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, +} from '../runtime/runtime'; export interface ApiCreateTestRequest { body: Baz; @@ -17,49 +28,69 @@ export interface ApiGetTestRequest { } export type CreateTestRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); export type GetTestRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); -export type CreateTestErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type CreateTestErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class CreateTestError extends ResponseError { readonly detail: CreateTestErrorDetail; - constructor(response: Response, detail: CreateTestErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: CreateTestErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } -export type GetTestErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type GetTestErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class GetTestError extends ResponseError { readonly detail: GetTestErrorDetail; - constructor(response: Response, detail: GetTestErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: GetTestErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - createTestRaw: (requestParameters: ApiCreateTestRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - createTest: (requestParameters: ApiCreateTestRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - getTestRaw: (requestParameters: ApiGetTestRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - getTest: (requestParameters: ApiGetTestRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + createTestRaw: ( + requestParameters: ApiCreateTestRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + createTest: ( + requestParameters: ApiCreateTestRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + getTestRaw: ( + requestParameters: ApiGetTestRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + getTest: ( + requestParameters: ApiGetTestRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class DefaultApi extends BaseAPI implements DefaultApiInterface { @@ -70,12 +101,14 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async createTestRaw(requestParameters: ApiCreateTestRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createTestRaw( + requestParameters: ApiCreateTestRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling createTestRaw().' + 'Required parameter "body" was null or undefined when calling createTestRaw().', ); } // Build path with path parameters @@ -90,42 +123,56 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new CreateTestError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new CreateTestError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async createTest(requestParameters: ApiCreateTestRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createTest( + requestParameters: ApiCreateTestRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.createTestRaw(requestParameters, initOverrides); - return await response.value() as Baz; + return (await response.value()) as Baz; } - async getTestRaw(requestParameters: ApiGetTestRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getTestRaw( + requestParameters: ApiGetTestRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.id === undefined || requestParameters.id === null) { throw new RequiredError( 'id', - 'Required parameter "id" was null or undefined when calling getTestRaw().' + 'Required parameter "id" was null or undefined when calling getTestRaw().', ); } // Build path with path parameters @@ -134,37 +181,48 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new GetTestError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new GetTestError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async getTest(requestParameters: ApiGetTestRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async getTest( + requestParameters: ApiGetTestRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.getTestRaw(requestParameters, initOverrides); - return await response.value() as Baz; + return (await response.value()) as Baz; } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-intersection-with-nullable-reference/package.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-intersection-with-nullable-reference/package.json.golden index e2201a11b..823d6a167 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-intersection-with-nullable-reference/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-intersection-with-nullable-reference/package.json.golden @@ -1,26 +1,26 @@ { + "name": "intersection-type-with-nullable-reference-test", + "version": "1.0.0", "description": "Test fixture for allOf intersection types with nullable reference properties", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "intersection-type-with-nullable-reference-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-intersection-with-nullable-reference/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-intersection-with-nullable-reference/runtime/runtime.ts.golden index 3da1cadac..8b3d9a1a7 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-intersection-with-nullable-reference/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-intersection-with-nullable-reference/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Intersection Type with Nullable Reference Test — 1.0.0 * Test fixture for allOf intersection types with nullable reference properties */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-intersection-with-nullable-reference/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-intersection-with-nullable-reference/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-intersection-with-nullable-reference/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-intersection-with-nullable-reference/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-intersection-with-nullable-reference/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-intersection-with-nullable-reference/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-intersection-with-nullable-reference/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-intersection-with-nullable-reference/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-nested-union/README.md.golden b/tests/golden/typescript/typescript-fetch/type-aliases-nested-union/README.md.golden index f91cacfe9..bd89ccdb8 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-nested-union/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-nested-union/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'nested-union-type-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'nested-union-type-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-nested-union/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-nested-union/apis/DefaultApi.ts.golden index 200c11b94..030f28f6a 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-nested-union/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-nested-union/apis/DefaultApi.ts.golden @@ -5,36 +5,57 @@ * Test fixture for union types that reference other union types */ import type { Foo } from '../models/Foo'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, +} from '../runtime/runtime'; export interface ApiTestNestedUnionRequest { body: Foo; } export type TestNestedUnionRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); - -export type TestNestedUnionErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestNestedUnionErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestNestedUnionError extends ResponseError { readonly detail: TestNestedUnionErrorDetail; - constructor(response: Response, detail: TestNestedUnionErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestNestedUnionErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - testNestedUnionRaw: (requestParameters: ApiTestNestedUnionRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - testNestedUnion: (requestParameters: ApiTestNestedUnionRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + testNestedUnionRaw: ( + requestParameters: ApiTestNestedUnionRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + testNestedUnion: ( + requestParameters: ApiTestNestedUnionRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class DefaultApi extends BaseAPI implements DefaultApiInterface { @@ -45,12 +66,14 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async testNestedUnionRaw(requestParameters: ApiTestNestedUnionRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async testNestedUnionRaw( + requestParameters: ApiTestNestedUnionRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling testNestedUnionRaw().' + 'Required parameter "body" was null or undefined when calling testNestedUnionRaw().', ); } // Build path with path parameters @@ -65,33 +88,45 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestNestedUnionError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestNestedUnionError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async testNestedUnion(requestParameters: ApiTestNestedUnionRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async testNestedUnion( + requestParameters: ApiTestNestedUnionRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.testNestedUnionRaw(requestParameters, initOverrides); - return await response.value() as Foo; + return (await response.value()) as Foo; } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-nested-union/package.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-nested-union/package.json.golden index dd9b1b651..dee724cdf 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-nested-union/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-nested-union/package.json.golden @@ -1,26 +1,26 @@ { + "name": "nested-union-type-test", + "version": "1.0.0", "description": "Test fixture for union types that reference other union types", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "nested-union-type-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-nested-union/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-nested-union/runtime/runtime.ts.golden index ab3b85509..f70e73663 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-nested-union/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-nested-union/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Nested Union Type Test — 1.0.0 * Test fixture for union types that reference other union types */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-nested-union/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-nested-union/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-nested-union/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-nested-union/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-nested-union/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-nested-union/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-nested-union/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-nested-union/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-simple-type-alias/README.md.golden b/tests/golden/typescript/typescript-fetch/type-aliases-simple-type-alias/README.md.golden index 50bc46fce..22d44745e 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-simple-type-alias/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-simple-type-alias/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'simple-type-alias-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'simple-type-alias-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-simple-type-alias/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-simple-type-alias/apis/DefaultApi.ts.golden index 68cab855f..b41980f80 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-simple-type-alias/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-simple-type-alias/apis/DefaultApi.ts.golden @@ -5,36 +5,57 @@ * Test fixture for simple type aliases (not unions or intersections) */ import type { Foo } from '../models/Foo'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, +} from '../runtime/runtime'; export interface ApiTestSimpleAliasRequest { body: Foo; } export type TestSimpleAliasRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); - -export type TestSimpleAliasErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestSimpleAliasErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestSimpleAliasError extends ResponseError { readonly detail: TestSimpleAliasErrorDetail; - constructor(response: Response, detail: TestSimpleAliasErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestSimpleAliasErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - testSimpleAliasRaw: (requestParameters: ApiTestSimpleAliasRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - testSimpleAlias: (requestParameters: ApiTestSimpleAliasRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + testSimpleAliasRaw: ( + requestParameters: ApiTestSimpleAliasRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + testSimpleAlias: ( + requestParameters: ApiTestSimpleAliasRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class DefaultApi extends BaseAPI implements DefaultApiInterface { @@ -45,12 +66,14 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async testSimpleAliasRaw(requestParameters: ApiTestSimpleAliasRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async testSimpleAliasRaw( + requestParameters: ApiTestSimpleAliasRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling testSimpleAliasRaw().' + 'Required parameter "body" was null or undefined when calling testSimpleAliasRaw().', ); } // Build path with path parameters @@ -65,33 +88,45 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestSimpleAliasError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestSimpleAliasError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async testSimpleAlias(requestParameters: ApiTestSimpleAliasRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async testSimpleAlias( + requestParameters: ApiTestSimpleAliasRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.testSimpleAliasRaw(requestParameters, initOverrides); - return await response.value() as Foo; + return (await response.value()) as Foo; } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-simple-type-alias/package.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-simple-type-alias/package.json.golden index c6afde19d..3dc218dbf 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-simple-type-alias/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-simple-type-alias/package.json.golden @@ -1,26 +1,26 @@ { + "name": "simple-type-alias-test", + "version": "1.0.0", "description": "Test fixture for simple type aliases (not unions or intersections)", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "simple-type-alias-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-simple-type-alias/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-simple-type-alias/runtime/runtime.ts.golden index 9a0628cf2..957ffa608 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-simple-type-alias/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-simple-type-alias/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Simple Type Alias Test — 1.0.0 * Test fixture for simple type aliases (not unions or intersections) */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-simple-type-alias/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-simple-type-alias/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-simple-type-alias/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-simple-type-alias/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-simple-type-alias/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-simple-type-alias/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-simple-type-alias/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-simple-type-alias/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-union-mixed/README.md.golden b/tests/golden/typescript/typescript-fetch/type-aliases-union-mixed/README.md.golden index f145d3e25..aa19a92fc 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-union-mixed/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-union-mixed/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'union-type-with-mixed-members-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'union-type-with-mixed-members-test const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-union-mixed/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-union-mixed/apis/DefaultApi.ts.golden index e58b39630..0bdeb8a1e 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-union-mixed/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-union-mixed/apis/DefaultApi.ts.golden @@ -5,36 +5,57 @@ * Test fixture for union types with both interfaces and primitives */ import type { Foo } from '../models/Foo'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, +} from '../runtime/runtime'; export interface ApiTestMixedUnionRequest { body: Foo; } export type TestMixedUnionRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); - -export type TestMixedUnionErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestMixedUnionErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestMixedUnionError extends ResponseError { readonly detail: TestMixedUnionErrorDetail; - constructor(response: Response, detail: TestMixedUnionErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestMixedUnionErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - testMixedUnionRaw: (requestParameters: ApiTestMixedUnionRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - testMixedUnion: (requestParameters: ApiTestMixedUnionRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + testMixedUnionRaw: ( + requestParameters: ApiTestMixedUnionRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + testMixedUnion: ( + requestParameters: ApiTestMixedUnionRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class DefaultApi extends BaseAPI implements DefaultApiInterface { @@ -45,12 +66,14 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async testMixedUnionRaw(requestParameters: ApiTestMixedUnionRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async testMixedUnionRaw( + requestParameters: ApiTestMixedUnionRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling testMixedUnionRaw().' + 'Required parameter "body" was null or undefined when calling testMixedUnionRaw().', ); } // Build path with path parameters @@ -65,33 +88,45 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestMixedUnionError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestMixedUnionError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async testMixedUnion(requestParameters: ApiTestMixedUnionRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async testMixedUnion( + requestParameters: ApiTestMixedUnionRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.testMixedUnionRaw(requestParameters, initOverrides); - return await response.value() as Foo; + return (await response.value()) as Foo; } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-union-mixed/package.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-union-mixed/package.json.golden index 68b0496de..3bc5aed35 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-union-mixed/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-union-mixed/package.json.golden @@ -1,26 +1,26 @@ { + "name": "union-type-with-mixed-members-test", + "version": "1.0.0", "description": "Test fixture for union types with both interfaces and primitives", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "union-type-with-mixed-members-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-union-mixed/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-union-mixed/runtime/runtime.ts.golden index 3db7eca4f..e75b010e8 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-union-mixed/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-union-mixed/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Union Type with Mixed Members Test — 1.0.0 * Test fixture for union types with both interfaces and primitives */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-union-mixed/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-union-mixed/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-union-mixed/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-union-mixed/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-union-mixed/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-union-mixed/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-union-mixed/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-union-mixed/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-any/README.md.golden b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-any/README.md.golden index fa657cd32..890db4b68 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-any/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-any/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'union-type-with-any-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'union-type-with-any-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-any/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-any/apis/DefaultApi.ts.golden index d1226cb59..3f9b65bbd 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-any/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-any/apis/DefaultApi.ts.golden @@ -5,36 +5,57 @@ * Test fixture for union types that include the any type */ import type { Config } from '../models/Config'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, +} from '../runtime/runtime'; export interface ApiTestUnionWithAnyRequest { body: Config; } export type TestUnionWithAnyRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); - -export type TestUnionWithAnyErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestUnionWithAnyErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestUnionWithAnyError extends ResponseError { readonly detail: TestUnionWithAnyErrorDetail; - constructor(response: Response, detail: TestUnionWithAnyErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestUnionWithAnyErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - testUnionWithAnyRaw: (requestParameters: ApiTestUnionWithAnyRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - testUnionWithAny: (requestParameters: ApiTestUnionWithAnyRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + testUnionWithAnyRaw: ( + requestParameters: ApiTestUnionWithAnyRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + testUnionWithAny: ( + requestParameters: ApiTestUnionWithAnyRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class DefaultApi extends BaseAPI implements DefaultApiInterface { @@ -45,12 +66,14 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async testUnionWithAnyRaw(requestParameters: ApiTestUnionWithAnyRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async testUnionWithAnyRaw( + requestParameters: ApiTestUnionWithAnyRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling testUnionWithAnyRaw().' + 'Required parameter "body" was null or undefined when calling testUnionWithAnyRaw().', ); } // Build path with path parameters @@ -65,33 +88,45 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestUnionWithAnyError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestUnionWithAnyError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async testUnionWithAny(requestParameters: ApiTestUnionWithAnyRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async testUnionWithAny( + requestParameters: ApiTestUnionWithAnyRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.testUnionWithAnyRaw(requestParameters, initOverrides); - return await response.value() as Config; + return (await response.value()) as Config; } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-any/package.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-any/package.json.golden index a67260c37..40024ea27 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-any/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-any/package.json.golden @@ -1,26 +1,26 @@ { + "name": "union-type-with-any-test", + "version": "1.0.0", "description": "Test fixture for union types that include the any type", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "union-type-with-any-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-any/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-any/runtime/runtime.ts.golden index ef8444fd6..d3b8fe48b 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-any/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-any/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Union Type with Any Test — 1.0.0 * Test fixture for union types that include the any type */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-any/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-any/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-any/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-any/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-any/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-any/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-any/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-any/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-inline-objects/README.md.golden b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-inline-objects/README.md.golden index 884d912ad..21233ea78 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-inline-objects/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-inline-objects/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'union-type-with-inline-objects-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'union-type-with-inline-objects-tes const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-inline-objects/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-inline-objects/apis/DefaultApi.ts.golden index 18c87fba8..5b509271d 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-inline-objects/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-inline-objects/apis/DefaultApi.ts.golden @@ -5,37 +5,57 @@ * Test fixture for union types (oneOf) with inline object schemas that should generate named interfaces */ import type { Foo } from '../models/Foo'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, +} from '../runtime/runtime'; export interface ApiTestUnionWithInlineObjectsRequest { body: Foo; } export type TestUnionWithInlineObjectsRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); - -export type TestUnionWithInlineObjectsErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestUnionWithInlineObjectsErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestUnionWithInlineObjectsError extends ResponseError { readonly detail: TestUnionWithInlineObjectsErrorDetail; - constructor(response: Response, detail: TestUnionWithInlineObjectsErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestUnionWithInlineObjectsErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - testUnionWithInlineObjectsRaw: (requestParameters: ApiTestUnionWithInlineObjectsRequest, - initOverrides?: RequestInit - | InitOverrideFunction) => Promise; - testUnionWithInlineObjects: (requestParameters: ApiTestUnionWithInlineObjectsRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + testUnionWithInlineObjectsRaw: ( + requestParameters: ApiTestUnionWithInlineObjectsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + testUnionWithInlineObjects: ( + requestParameters: ApiTestUnionWithInlineObjectsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class DefaultApi extends BaseAPI implements DefaultApiInterface { @@ -46,13 +66,14 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async testUnionWithInlineObjectsRaw(requestParameters: ApiTestUnionWithInlineObjectsRequest, - initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async testUnionWithInlineObjectsRaw( + requestParameters: ApiTestUnionWithInlineObjectsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling testUnionWithInlineObjectsRaw().' + 'Required parameter "body" was null or undefined when calling testUnionWithInlineObjectsRaw().', ); } // Build path with path parameters @@ -67,33 +88,45 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestUnionWithInlineObjectsError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestUnionWithInlineObjectsError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async testUnionWithInlineObjects(requestParameters: ApiTestUnionWithInlineObjectsRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async testUnionWithInlineObjects( + requestParameters: ApiTestUnionWithInlineObjectsRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.testUnionWithInlineObjectsRaw(requestParameters, initOverrides); - return await response.value() as Foo; + return (await response.value()) as Foo; } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-inline-objects/package.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-inline-objects/package.json.golden index 1adcba053..269e36bf3 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-inline-objects/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-inline-objects/package.json.golden @@ -1,26 +1,26 @@ { + "name": "union-type-with-inline-objects-test", + "version": "1.0.0", "description": "Test fixture for union types (oneOf) with inline object schemas that should generate named interfaces", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "union-type-with-inline-objects-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-inline-objects/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-inline-objects/runtime/runtime.ts.golden index 8328aa084..b69632269 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-inline-objects/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-inline-objects/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Union Type with Inline Objects Test — 1.0.0 * Test fixture for union types (oneOf) with inline object schemas that should generate named interfaces */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-inline-objects/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-inline-objects/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-inline-objects/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-inline-objects/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-inline-objects/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-inline-objects/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-inline-objects/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-inline-objects/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-interfaces/README.md.golden b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-interfaces/README.md.golden index dd13e00a8..33a68db9a 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-interfaces/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-interfaces/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'union-type-with-interfaces-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'union-type-with-interfaces-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-interfaces/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-interfaces/apis/DefaultApi.ts.golden index ce34b4811..b53e5250f 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-interfaces/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-interfaces/apis/DefaultApi.ts.golden @@ -5,36 +5,57 @@ * Test fixture for oneOf/anyOf union types with interface members */ import type { Foo } from '../models/Foo'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, +} from '../runtime/runtime'; export interface ApiTestUnionRequest { body: Foo; } export type TestUnionRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); - -export type TestUnionErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestUnionErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestUnionError extends ResponseError { readonly detail: TestUnionErrorDetail; - constructor(response: Response, detail: TestUnionErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestUnionErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - testUnionRaw: (requestParameters: ApiTestUnionRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - testUnion: (requestParameters: ApiTestUnionRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + testUnionRaw: ( + requestParameters: ApiTestUnionRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + testUnion: ( + requestParameters: ApiTestUnionRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class DefaultApi extends BaseAPI implements DefaultApiInterface { @@ -45,12 +66,14 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async testUnionRaw(requestParameters: ApiTestUnionRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async testUnionRaw( + requestParameters: ApiTestUnionRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling testUnionRaw().' + 'Required parameter "body" was null or undefined when calling testUnionRaw().', ); } // Build path with path parameters @@ -65,33 +88,45 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestUnionError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestUnionError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async testUnion(requestParameters: ApiTestUnionRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async testUnion( + requestParameters: ApiTestUnionRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.testUnionRaw(requestParameters, initOverrides); - return await response.value() as Foo; + return (await response.value()) as Foo; } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-interfaces/package.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-interfaces/package.json.golden index 537713784..b00330362 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-interfaces/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-interfaces/package.json.golden @@ -1,26 +1,26 @@ { + "name": "union-type-with-interfaces-test", + "version": "1.0.0", "description": "Test fixture for oneOf/anyOf union types with interface members", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "union-type-with-interfaces-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-interfaces/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-interfaces/runtime/runtime.ts.golden index dbca9c450..501a9c0a3 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-interfaces/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-interfaces/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Union Type with Interfaces Test — 1.0.0 * Test fixture for oneOf/anyOf union types with interface members */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-interfaces/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-interfaces/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-interfaces/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-interfaces/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-interfaces/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-interfaces/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-interfaces/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-interfaces/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-primitives/README.md.golden b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-primitives/README.md.golden index 34d7bc2c2..955467719 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-primitives/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-primitives/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'union-type-with-primitives-test'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'union-type-with-primitives-test'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-primitives/apis/DefaultApi.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-primitives/apis/DefaultApi.ts.golden index 62396c6ed..68650c858 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-primitives/apis/DefaultApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-primitives/apis/DefaultApi.ts.golden @@ -5,36 +5,57 @@ * Test fixture for union types with primitive members */ import type { Foo } from '../models/Foo'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, +} from '../runtime/runtime'; export interface ApiTestUnionPrimitivesRequest { body: Foo; } export type TestUnionPrimitivesRawResponse = - | JSONApiResponse & { status: 200 } - | JSONApiResponse & HttpSuccessResponse; + | (JSONApiResponse & { status: 200 }) + | (JSONApiResponse & HttpSuccessResponse); - -export type TestUnionPrimitivesErrorDetail = - { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; +export type TestUnionPrimitivesErrorDetail = { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; +}; export class TestUnionPrimitivesError extends ResponseError { readonly detail: TestUnionPrimitivesErrorDetail; - constructor(response: Response, detail: TestUnionPrimitivesErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: TestUnionPrimitivesErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface DefaultApiInterface { - testUnionPrimitivesRaw: (requestParameters: ApiTestUnionPrimitivesRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - testUnionPrimitives: (requestParameters: ApiTestUnionPrimitivesRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + testUnionPrimitivesRaw: ( + requestParameters: ApiTestUnionPrimitivesRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + testUnionPrimitives: ( + requestParameters: ApiTestUnionPrimitivesRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class DefaultApi extends BaseAPI implements DefaultApiInterface { @@ -45,12 +66,14 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { super(configuration ?? DefaultConfig); } - async testUnionPrimitivesRaw(requestParameters: ApiTestUnionPrimitivesRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async testUnionPrimitivesRaw( + requestParameters: ApiTestUnionPrimitivesRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling testUnionPrimitivesRaw().' + 'Required parameter "body" was null or undefined when calling testUnionPrimitivesRaw().', ); } // Build path with path parameters @@ -65,33 +88,45 @@ export class DefaultApi extends BaseAPI implements DefaultApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); - { + { let errorValue: Promise | undefined; - throw new TestUnionPrimitivesError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new TestUnionPrimitivesError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new JSONApiResponse(response) as JSONApiResponse & { status: 200 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async testUnionPrimitives(requestParameters: ApiTestUnionPrimitivesRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async testUnionPrimitives( + requestParameters: ApiTestUnionPrimitivesRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.testUnionPrimitivesRaw(requestParameters, initOverrides); - return await response.value() as Foo; + return (await response.value()) as Foo; } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-primitives/package.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-primitives/package.json.golden index 6b091d5ba..de55e2378 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-primitives/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-primitives/package.json.golden @@ -1,26 +1,26 @@ { + "name": "union-type-with-primitives-test", + "version": "1.0.0", "description": "Test fixture for union types with primitive members", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "union-type-with-primitives-test", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-primitives/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-primitives/runtime/runtime.ts.golden index 21b3d8090..40295c72c 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-primitives/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-primitives/runtime/runtime.ts.golden @@ -4,7 +4,7 @@ * Union Type with Primitives Test — 1.0.0 * Test fixture for union types with primitive members */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -14,7 +14,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -93,8 +96,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -136,12 +141,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -151,7 +162,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -167,9 +178,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -184,13 +193,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -200,7 +211,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -210,10 +221,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -222,18 +234,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -241,16 +257,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -269,11 +286,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -283,7 +300,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -293,7 +310,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -307,12 +324,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -330,15 +365,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -414,16 +462,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -450,7 +588,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -477,7 +618,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -487,5 +628,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-primitives/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-primitives/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-primitives/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-primitives/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-primitives/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-primitives/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/type-aliases-union-with-primitives/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/type-aliases-union-with-primitives/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/typed-error-responses/README.md.golden b/tests/golden/typescript/typescript-fetch/typed-error-responses/README.md.golden index e82e455b6..d6b684c5c 100644 --- a/tests/golden/typescript/typescript-fetch/typed-error-responses/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/typed-error-responses/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, ResourcesApi } from 'typed-error-responses-api'; const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -214,7 +214,7 @@ import type { User, CreateUserRequest } from 'typed-error-responses-api'; const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/typed-error-responses/apis/ResourcesApi.ts.golden b/tests/golden/typescript/typescript-fetch/typed-error-responses/apis/ResourcesApi.ts.golden index 975530102..55746058e 100644 --- a/tests/golden/typescript/typescript-fetch/typed-error-responses/apis/ResourcesApi.ts.golden +++ b/tests/golden/typescript/typescript-fetch/typed-error-responses/apis/ResourcesApi.ts.golden @@ -11,8 +11,20 @@ import type { DefaultError } from '../models/DefaultError'; import type { SameShapeValidationError } from '../models/SameShapeValidationError'; import type { ServerError } from '../models/ServerError'; import type { ValidationError } from '../models/ValidationError'; -import type { Configuration, HTTPQuery, HttpSuccessResponse, InitOverrideFunction } from '../runtime/runtime'; -import { BaseAPI, DefaultConfig, JSONApiResponse, RequiredError, ResponseError, VoidApiResponse } from '../runtime/runtime'; +import type { + Configuration, + HTTPQuery, + HttpSuccessResponse, + InitOverrideFunction, +} from '../runtime/runtime'; +import { + BaseAPI, + DefaultConfig, + JSONApiResponse, + RequiredError, + ResponseError, + VoidApiResponse, +} from '../runtime/runtime'; export interface ApiCreateResourceRequest { body: CreateResourceRequest; @@ -23,48 +35,62 @@ export interface ApiCreateResourceWithWildcardSuccessRequest { } export type CheckNoSuccessBodyRawResponse = - | VoidApiResponse & { status: 200 } - | VoidApiResponse & HttpSuccessResponse; - + | (VoidApiResponse & { status: 200 }) + | (VoidApiResponse & HttpSuccessResponse); export type CreateResourceRawResponse = - | JSONApiResponse & { status: 201 } - | JSONApiResponse & HttpSuccessResponse; - + | (JSONApiResponse & { status: 201 }) + | (JSONApiResponse & HttpSuccessResponse); export type CreateResourceWithWildcardSuccessRawResponse = - | JSONApiResponse & { status: 201 } - | JSONApiResponse & { status: number } - | JSONApiResponse & HttpSuccessResponse; + | (JSONApiResponse & { status: 201 }) + | (JSONApiResponse & { status: number }) + | (JSONApiResponse & HttpSuccessResponse); - -export function getCheckNoSuccessBodyXRequestIdHeader(response: CheckNoSuccessBodyRawResponse): string -| undefined { +export function getCheckNoSuccessBodyXRequestIdHeader( + response: CheckNoSuccessBodyRawResponse, +): string | undefined { return response.headers.get('X-Request-Id') ?? undefined; } -export function getCreateResource1RequestIdHeader(response: CreateResourceRawResponse): string -| undefined { +export function getCreateResource1RequestIdHeader( + response: CreateResourceRawResponse, +): string | undefined { return response.headers.get('1-Request-Id') ?? undefined; } -export function getCreateResourceXRequestIdHeader(response: CreateResourceRawResponse): string -| undefined { +export function getCreateResourceXRequestIdHeader( + response: CreateResourceRawResponse, +): string | undefined { return response.headers.get('X-Request-Id') ?? undefined; } -export function getCreateResourceXRequestIdHeader2(response: CreateResourceRawResponse): string -| undefined { +export function getCreateResourceXRequestIdHeader2( + response: CreateResourceRawResponse, +): string | undefined { return response.headers.get('X_Request_Id') ?? undefined; } export type CheckNoSuccessBodyErrorDetail = - { kind: 'serviceUnavailable'; status: 503; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'serviceUnavailable'; + status: 503; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class CheckNoSuccessBodyError extends ResponseError { readonly detail: CheckNoSuccessBodyErrorDetail; - constructor(response: Response, detail: CheckNoSuccessBodyErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: CheckNoSuccessBodyErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } @@ -75,21 +101,69 @@ export class CheckNoSuccessBodyError extends ResponseError { } export type CreateResourceErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'conflict'; status: 409; raw: Response; value(): Promise } - | { kind: 'validation'; status: 422; raw: Response; value(): Promise } - | { kind: 'status423'; status: 423; raw: Response; value(): Promise } - | { kind: 'status424'; status: 424; raw: Response; value(): Promise } - | { kind: 'tooManyRequests'; status: 429; raw: Response; value(): Promise } - | { kind: 'serverError'; status: number; raw: Response; value(): Promise } - | { kind: 'default'; status: number; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'conflict'; + status: 409; + raw: Response; + value(): Promise; + } + | { + kind: 'validation'; + status: 422; + raw: Response; + value(): Promise; + } + | { + kind: 'status423'; + status: 423; + raw: Response; + value(): Promise; + } + | { + kind: 'status424'; + status: 424; + raw: Response; + value(): Promise; + } + | { + kind: 'tooManyRequests'; + status: 429; + raw: Response; + value(): Promise; + } + | { + kind: 'serverError'; + status: number; + raw: Response; + value(): Promise; + } + | { + kind: 'default'; + status: number; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class CreateResourceError extends ResponseError { readonly detail: CreateResourceErrorDetail; - constructor(response: Response, detail: CreateResourceErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: CreateResourceErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } @@ -137,32 +211,53 @@ export class CreateResourceError extends ResponseError { } export type CreateResourceWithWildcardSuccessErrorDetail = - { kind: 'badRequest'; status: 400; raw: Response; value(): Promise } - | { kind: 'unexpected'; status: number; raw: Response; value(): Promise }; + | { + kind: 'badRequest'; + status: 400; + raw: Response; + value(): Promise; + } + | { + kind: 'unexpected'; + status: number; + raw: Response; + value(): Promise; + }; export class CreateResourceWithWildcardSuccessError extends ResponseError { readonly detail: CreateResourceWithWildcardSuccessErrorDetail; - constructor(response: Response, detail: CreateResourceWithWildcardSuccessErrorDetail, - msg = 'Response returned an error code') { + constructor( + response: Response, + detail: CreateResourceWithWildcardSuccessErrorDetail, + msg = 'Response returned an error code', + ) { super(response, msg); this.detail = detail; } } export interface ResourcesApiInterface { - checkNoSuccessBodyRaw: (initOverrides?: RequestInit - | InitOverrideFunction) => Promise; + checkNoSuccessBodyRaw: ( + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; checkNoSuccessBody: (initOverrides?: RequestInit | InitOverrideFunction) => Promise; - createResourceRaw: (requestParameters: ApiCreateResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - createResource: (requestParameters: ApiCreateResourceRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; - createResourceWithWildcardSuccessRaw: (requestParameters: ApiCreateResourceWithWildcardSuccessRequest, - initOverrides?: RequestInit - | InitOverrideFunction) => Promise; - createResourceWithWildcardSuccess: (requestParameters: ApiCreateResourceWithWildcardSuccessRequest, - initOverrides?: RequestInit | InitOverrideFunction) => Promise; + createResourceRaw: ( + requestParameters: ApiCreateResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + createResource: ( + requestParameters: ApiCreateResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + createResourceWithWildcardSuccessRaw: ( + requestParameters: ApiCreateResourceWithWildcardSuccessRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; + createResourceWithWildcardSuccess: ( + requestParameters: ApiCreateResourceWithWildcardSuccessRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ) => Promise; } export class ResourcesApi extends BaseAPI implements ResourcesApiInterface { @@ -173,41 +268,58 @@ export class ResourcesApi extends BaseAPI implements ResourcesApiInterface { super(configuration ?? DefaultConfig); } - async checkNoSuccessBodyRaw(initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async checkNoSuccessBodyRaw( + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { // Build path with path parameters const urlPath = `/no-success-body`; // Build query parameters const queryParameters: HTTPQuery = {}; // Build headers - const headerParameters: Record = { - }; + const headerParameters: Record = {}; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'GET', headers: headerParameters, query: queryParameters, body: undefined, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 503) { let errorValue: Promise | undefined; - throw new CheckNoSuccessBodyError(response, { kind: 'serviceUnavailable', status: response.status as 503, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone()).value() }); - } - else { + throw new CheckNoSuccessBodyError(response, { + kind: 'serviceUnavailable', + status: response.status as 503, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new CheckNoSuccessBodyError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new CheckNoSuccessBodyError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 200) { return new VoidApiResponse(response) as VoidApiResponse & { status: 200 }; - } - else { + } else { return new VoidApiResponse(response) as VoidApiResponse & HttpSuccessResponse; } } @@ -217,12 +329,14 @@ export class ResourcesApi extends BaseAPI implements ResourcesApiInterface { return await response.value(); } - async createResourceRaw(requestParameters: ApiCreateResourceRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createResourceRaw( + requestParameters: ApiCreateResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling createResourceRaw().' + 'Required parameter "body" was null or undefined when calling createResourceRaw().', ); } // Build path with path parameters @@ -237,71 +351,133 @@ export class ResourcesApi extends BaseAPI implements ResourcesApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new CreateResourceError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 409) { + throw new CreateResourceError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 409) { let errorValue: Promise | undefined; - throw new CreateResourceError(response, { kind: 'conflict', status: response.status as 409, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 422) { + throw new CreateResourceError(response, { + kind: 'conflict', + status: response.status as 409, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 422) { let errorValue: Promise | undefined; - throw new CreateResourceError(response, { kind: 'validation', status: response.status as 422, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 423) { + throw new CreateResourceError(response, { + kind: 'validation', + status: response.status as 422, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 423) { let errorValue: Promise | undefined; - throw new CreateResourceError(response, { kind: 'status423', status: response.status as 423, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 424) { + throw new CreateResourceError(response, { + kind: 'status423', + status: response.status as 423, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 424) { let errorValue: Promise | undefined; - throw new CreateResourceError(response, { kind: 'status424', status: response.status as 424, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone()).value() }); - } - else if (response.status === 429) { + throw new CreateResourceError(response, { + kind: 'status424', + status: response.status as 424, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status === 429) { let errorValue: Promise | undefined; - throw new CreateResourceError(response, { kind: 'tooManyRequests', status: response.status as 429, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone()).value() }); - } - else if (response.status >= 500 && response.status < 600) { + throw new CreateResourceError(response, { + kind: 'tooManyRequests', + status: response.status as 429, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else if (response.status >= 500 && response.status < 600) { let errorValue: Promise | undefined; - throw new CreateResourceError(response, { kind: 'serverError', status: response.status, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone()).value() }); - } - else { + throw new CreateResourceError(response, { + kind: 'serverError', + status: response.status, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new CreateResourceError(response, { kind: 'default', status: response.status, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone()).value() }); + throw new CreateResourceError(response, { + kind: 'default', + status: response.status, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); } } if (response.status === 201) { return new JSONApiResponse(response) as JSONApiResponse & { status: 201 }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async createResource(requestParameters: ApiCreateResourceRequest, initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createResource( + requestParameters: ApiCreateResourceRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.createResourceRaw(requestParameters, initOverrides); - return await response.value() as CreatedResource; + return (await response.value()) as CreatedResource; } - async createResourceWithWildcardSuccessRaw(requestParameters: ApiCreateResourceWithWildcardSuccessRequest, - initOverrides?: RequestInit - | InitOverrideFunction): Promise { + async createResourceWithWildcardSuccessRaw( + requestParameters: ApiCreateResourceWithWildcardSuccessRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { if (requestParameters.body === undefined || requestParameters.body === null) { throw new RequiredError( 'body', - 'Required parameter "body" was null or undefined when calling createResourceWithWildcardSuccessRaw().' + 'Required parameter "body" was null or undefined when calling createResourceWithWildcardSuccessRaw().', ); } // Build path with path parameters @@ -316,40 +492,58 @@ export class ResourcesApi extends BaseAPI implements ResourcesApiInterface { // Prepare request body const requestBody = requestParameters.body; // Make request - const response = await this.request({ + const response = await this.request( + { path: urlPath, method: 'POST', headers: headerParameters, query: queryParameters, body: requestBody, - }, initOverrides); + }, + initOverrides, + ); // Handle responses if (!(response.status >= 200 && response.status < 300)) { const errorRaw = response.clone(); if (response.status === 400) { let errorValue: Promise | undefined; - throw new CreateResourceWithWildcardSuccessError(response, { kind: 'badRequest', status: response.status as 400, raw: response, value: () => errorValue ??= new JSONApiResponse(errorRaw.clone()).value() }); - } - else { + throw new CreateResourceWithWildcardSuccessError(response, { + kind: 'badRequest', + status: response.status as 400, + raw: response, + value: () => { + errorValue ??= new JSONApiResponse(errorRaw.clone()).value(); + return errorValue; + }, + }); + } else { let errorValue: Promise | undefined; - throw new CreateResourceWithWildcardSuccessError(response, { kind: 'unexpected', status: response.status, raw: response, value: () => errorValue ??= errorRaw.clone().blob() }); + throw new CreateResourceWithWildcardSuccessError(response, { + kind: 'unexpected', + status: response.status, + raw: response, + value: () => { + errorValue ??= errorRaw.clone().blob(); + return errorValue; + }, + }); } } if (response.status === 201) { return new JSONApiResponse(response) as JSONApiResponse & { status: 201 }; - } - else if (response.status >= 200 && response.status < 300) { + } else if (response.status >= 200 && response.status < 300) { return new JSONApiResponse(response) as JSONApiResponse & { status: number }; - } - else { - return new JSONApiResponse(response) as JSONApiResponse &HttpSuccessResponse; + } else { + return new JSONApiResponse(response) as JSONApiResponse & HttpSuccessResponse; } } - async createResourceWithWildcardSuccess(requestParameters: ApiCreateResourceWithWildcardSuccessRequest, - initOverrides?: RequestInit | InitOverrideFunction): Promise { + async createResourceWithWildcardSuccess( + requestParameters: ApiCreateResourceWithWildcardSuccessRequest, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const response = await this.createResourceWithWildcardSuccessRaw(requestParameters, initOverrides); - return await response.value() as CreatedResource; + return (await response.value()) as CreatedResource; } } diff --git a/tests/golden/typescript/typescript-fetch/typed-error-responses/package.json.golden b/tests/golden/typescript/typescript-fetch/typed-error-responses/package.json.golden index 2061df3db..bf9d2511b 100644 --- a/tests/golden/typescript/typescript-fetch/typed-error-responses/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/typed-error-responses/package.json.golden @@ -1,26 +1,26 @@ { + "name": "typed-error-responses-api", + "version": "1.0.0", "description": "TypeScript client for Typed Error Responses API", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "typed-error-responses-api", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/typed-error-responses/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/typed-error-responses/runtime/runtime.ts.golden index 1554fcc2b..6a36d5c7a 100644 --- a/tests/golden/typescript/typescript-fetch/typed-error-responses/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/typed-error-responses/runtime/runtime.ts.golden @@ -3,7 +3,7 @@ * * Typed Error Responses API — 1.0.0 */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -13,7 +13,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -92,8 +95,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -135,12 +140,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -150,7 +161,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -166,9 +177,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -183,13 +192,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -199,7 +210,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -209,10 +220,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -221,18 +233,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -240,16 +256,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -268,11 +285,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -282,7 +299,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -292,7 +309,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -306,12 +323,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -329,15 +364,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -413,16 +461,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -449,7 +587,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -476,7 +617,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -486,5 +627,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/typed-error-responses/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/typed-error-responses/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/typed-error-responses/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/typed-error-responses/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/typed-error-responses/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/typed-error-responses/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/typed-error-responses/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/typed-error-responses/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +} diff --git a/tests/golden/typescript/typescript-fetch/typescript-additional-properties/README.md.golden b/tests/golden/typescript/typescript-fetch/typescript-additional-properties/README.md.golden index 893c067d5..06b726010 100644 --- a/tests/golden/typescript/typescript-fetch/typescript-additional-properties/README.md.golden +++ b/tests/golden/typescript/typescript-fetch/typescript-additional-properties/README.md.golden @@ -52,8 +52,8 @@ import { Configuration, DefaultApi } from 'type-script-additional-property-prese const config = new Configuration({ basePath: 'https://api.example.com', headers: { - 'Authorization': 'Bearer YOUR_TOKEN' - } + Authorization: 'Bearer YOUR_TOKEN', + }, }); // Initialize the API client @@ -101,9 +101,9 @@ const config = new Configuration({ basePath: 'https://api.example.com', headers: { 'X-API-Key': 'your-api-key', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', }, - credentials: 'include' + credentials: 'include', }); ``` @@ -126,12 +126,12 @@ const loggingMiddleware: Middleware = { onError: async (context) => { console.error('Error:', context.error); return undefined; - } + }, }; const config = new Configuration({ basePath: 'https://api.example.com', - middleware: [loggingMiddleware] + middleware: [loggingMiddleware], }); ``` @@ -140,7 +140,11 @@ const config = new Configuration({ The client throws typed errors for different failure scenarios: ```typescript -import { ResponseError, FetchError, RequiredError } from 'type-script-additional-property-preservation'; +import { + ResponseError, + FetchError, + RequiredError, +} from 'type-script-additional-property-preservation'; try { const result = await api.someMethod(); @@ -214,7 +218,7 @@ import type { User, CreateUserRequest } from 'type-script-additional-property-pr const user: User = { id: 1, name: 'John Doe', - email: 'john@example.com' + email: 'john@example.com', }; ``` diff --git a/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/AllOfJsonDictionary.ts.golden b/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/AllOfJsonDictionary.ts.golden index c990b28ac..a621c6a3f 100644 --- a/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/AllOfJsonDictionary.ts.golden +++ b/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/AllOfJsonDictionary.ts.golden @@ -6,5 +6,6 @@ import type { AllOfJsonDictionaryAllOf1 } from './AllOfJsonDictionaryAllOf1'; import type { AnyJsonValue } from './AnyJsonValue'; -export type AllOfJsonDictionary = Readonly>; +export type AllOfJsonDictionary = Readonly< + AllOfJsonDictionaryAllOf1 & Record +>; diff --git a/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/ClosedExternalEvent.ts.golden b/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/ClosedExternalEvent.ts.golden index f22181162..fd9897860 100644 --- a/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/ClosedExternalEvent.ts.golden +++ b/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/ClosedExternalEvent.ts.golden @@ -5,4 +5,4 @@ */ import type { Detail } from './Detail'; -export type ClosedExternalEvent = { 'started': Detail } | { 'finished': Detail }; +export type ClosedExternalEvent = { started: Detail } | { finished: Detail }; diff --git a/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/MixedExternalEvent.ts.golden b/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/MixedExternalEvent.ts.golden index 058bcd399..2d30f728c 100644 --- a/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/MixedExternalEvent.ts.golden +++ b/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/MixedExternalEvent.ts.golden @@ -5,6 +5,6 @@ */ import type { Detail } from './Detail'; -export type MixedExternalEvent = Readonly> -& Readonly> -| Readonly>; +export type MixedExternalEvent = + | (Readonly> & Readonly>) + | Readonly>; diff --git a/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/OpenExternalEvent.ts.golden b/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/OpenExternalEvent.ts.golden index 92758307d..024f26f4a 100644 --- a/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/OpenExternalEvent.ts.golden +++ b/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/OpenExternalEvent.ts.golden @@ -5,6 +5,6 @@ */ import type { Detail } from './Detail'; -export type OpenExternalEvent = Readonly> -& Readonly> -| Readonly> & Readonly>; +export type OpenExternalEvent = + | (Readonly> & Readonly>) + | (Readonly> & Readonly>); diff --git a/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/PlainJsonMap.ts.golden b/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/PlainJsonMap.ts.golden index f30825ada..de3beac00 100644 --- a/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/PlainJsonMap.ts.golden +++ b/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/PlainJsonMap.ts.golden @@ -3,5 +3,4 @@ * * TypeScript additional property preservation — 1.0.0 */ -export interface PlainJsonMap extends Readonly> { -} +export interface PlainJsonMap extends Readonly> {} diff --git a/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/PlainModelMap.ts.golden b/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/PlainModelMap.ts.golden index c0b2630b4..4f22dc646 100644 --- a/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/PlainModelMap.ts.golden +++ b/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/PlainModelMap.ts.golden @@ -5,5 +5,4 @@ */ import type { Detail } from './Detail'; -export interface PlainModelMap extends Readonly> { -} +export interface PlainModelMap extends Readonly> {} diff --git a/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/PlainStringMap.ts.golden b/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/PlainStringMap.ts.golden index 1f45d008e..37c1f8d64 100644 --- a/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/PlainStringMap.ts.golden +++ b/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/PlainStringMap.ts.golden @@ -3,5 +3,4 @@ * * TypeScript additional property preservation — 1.0.0 */ -export interface PlainStringMap extends Readonly> { -} +export interface PlainStringMap extends Readonly> {} diff --git a/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/SearchStreamEvent.ts.golden b/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/SearchStreamEvent.ts.golden index 8e830479d..ab5bf10f3 100644 --- a/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/SearchStreamEvent.ts.golden +++ b/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/SearchStreamEvent.ts.golden @@ -5,4 +5,8 @@ */ import type { SearchStreamEventResponseWebSearchCallSearching } from './SearchStreamEventResponseWebSearchCallSearching'; -export type SearchStreamEvent = ({ type: 'response.web_search_call.searching' } & SearchStreamEventResponseWebSearchCallSearching) | { type: 'response.completed' }; +export type SearchStreamEvent = + | ({ + type: 'response.web_search_call.searching'; + } & SearchStreamEventResponseWebSearchCallSearching) + | { type: 'response.completed' }; diff --git a/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/SearchStreamEventResponseWebSearchCallSearching.ts.golden b/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/SearchStreamEventResponseWebSearchCallSearching.ts.golden index 970000397..0b0f3f437 100644 --- a/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/SearchStreamEventResponseWebSearchCallSearching.ts.golden +++ b/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/SearchStreamEventResponseWebSearchCallSearching.ts.golden @@ -3,8 +3,9 @@ * * TypeScript additional property preservation — 1.0.0 */ -export interface SearchStreamEventResponseWebSearchCallSearching extends Readonly> { +export interface SearchStreamEventResponseWebSearchCallSearching extends Readonly< + Record +> { readonly sequence_number: number; readonly type: 'response.web_search_call.searching'; } diff --git a/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/TypedExternalEvent.ts.golden b/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/TypedExternalEvent.ts.golden index 130975dcf..5f6b7fd8d 100644 --- a/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/TypedExternalEvent.ts.golden +++ b/tests/golden/typescript/typescript-fetch/typescript-additional-properties/models/TypedExternalEvent.ts.golden @@ -5,6 +5,6 @@ */ import type { DetailAliasChain } from './DetailAliasChain'; -export type TypedExternalEvent = Readonly> -& Readonly> -| Readonly> & Readonly>; +export type TypedExternalEvent = + | (Readonly> & Readonly>) + | (Readonly> & Readonly>); diff --git a/tests/golden/typescript/typescript-fetch/typescript-additional-properties/package.json.golden b/tests/golden/typescript/typescript-fetch/typescript-additional-properties/package.json.golden index a6de9fffb..3046ade15 100644 --- a/tests/golden/typescript/typescript-fetch/typescript-additional-properties/package.json.golden +++ b/tests/golden/typescript/typescript-fetch/typescript-additional-properties/package.json.golden @@ -1,26 +1,26 @@ { + "name": "type-script-additional-property-preservation", + "version": "1.0.0", "description": "TypeScript client for TypeScript additional property preservation", + "keywords": [ + "api-client", + "generated", + "openapi", + "typescript" + ], + "files": [ + "dist" + ], + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { "default": "./dist/index.js", "types": "./dist/index.d.ts" } }, - "files": [ - "dist" - ], - "keywords": [ - "openapi", - "api-client", - "typescript", - "generated" - ], - "main": "./dist/index.js", - "name": "type-script-additional-property-preservation", "scripts": { "build": "tsc" - }, - "type": "module", - "types": "./dist/index.d.ts", - "version": "1.0.0" -} \ No newline at end of file + } +} diff --git a/tests/golden/typescript/typescript-fetch/typescript-additional-properties/runtime/runtime.ts.golden b/tests/golden/typescript/typescript-fetch/typescript-additional-properties/runtime/runtime.ts.golden index 800ffc9dd..d7c637a44 100644 --- a/tests/golden/typescript/typescript-fetch/typescript-additional-properties/runtime/runtime.ts.golden +++ b/tests/golden/typescript/typescript-fetch/typescript-additional-properties/runtime/runtime.ts.golden @@ -3,7 +3,7 @@ * * TypeScript additional property preservation — 1.0.0 */ -export const BASE_PATH = "http://localhost".replace(/\/+$/, ""); +export const BASE_PATH = 'http://localhost'.replace(/\/+$/, ''); export interface ConfigurationParameters { basePath?: string; // override base path @@ -13,7 +13,10 @@ export interface ConfigurationParameters { username?: string | (() => string | Promise); // parameter for basic security password?: string | (() => string | Promise); // parameter for basic security apiKey?: string | Promise | ((name: string) => string | Promise); // parameter for apiKey security - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security + accessToken?: + | string + | Promise + | ((name?: string, scopes?: string[]) => string | Promise); // parameter for oauth2 security headers?: HTTPHeaders; //header params we want to use on every request credentials?: RequestCredentials; //value for the credentials param we want to use on each request } @@ -92,8 +95,10 @@ export const DefaultConfig = new Configuration(); * This is the base class for all generated API classes. */ export class BaseAPI { - - private static readonly jsonRegex = new RegExp('^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i'); + private static readonly jsonRegex = new RegExp( + '^(:?application/json|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', + 'i', + ); protected configuration: Configuration; private middleware: Middleware[]; @@ -135,12 +140,18 @@ export class BaseAPI { return BaseAPI.jsonRegex.test(mime); } - protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise { + protected async request( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ): Promise { const { url, init } = await this.createFetchParams(context, initOverrides); return await this.fetchApi(url, init); } - private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) { + private async createFetchParams( + context: RequestOpts, + initOverrides?: RequestInit | InitOverrideFunction, + ) { let url = this.configuration.basePath + context.path; if (context.query !== undefined && Object.keys(context.query).length !== 0) { // only add the querystring to the URL if there are query parameters. @@ -150,7 +161,7 @@ export class BaseAPI { } const headers = Object.assign({}, this.configuration.headers, context.headers); - Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {}); + Object.keys(headers).forEach((key) => (headers[key] === undefined ? delete headers[key] : {})); const token = await this.configuration.accessToken?.(); if (token) { @@ -166,9 +177,7 @@ export class BaseAPI { } const initOverrideFn = - typeof initOverrides === "function" - ? initOverrides - : async () => initOverrides; + typeof initOverrides === 'function' ? initOverrides : async () => initOverrides; const initParams: HTTPRequestInit = { method: context.method, @@ -183,13 +192,15 @@ export class BaseAPI { ...(await initOverrideFn({ init: initParams, context, - })) + })), }; let body: BodyInit | null | undefined; - if (isFormData(overriddenInit.body) - || (overriddenInit.body instanceof URLSearchParams) - || isBlob(overriddenInit.body)) { + if ( + isFormData(overriddenInit.body) || + overriddenInit.body instanceof URLSearchParams || + isBlob(overriddenInit.body) + ) { body = overriddenInit.body; } else if (this.isJsonMime(headers['Content-Type'])) { body = JSON.stringify(overriddenInit.body); @@ -199,7 +210,7 @@ export class BaseAPI { const init: RequestInit = { ...overriddenInit, - body + body, }; return { url, init }; @@ -209,10 +220,11 @@ export class BaseAPI { let fetchParams = { url, init }; for (const middleware of this.middleware) { if (middleware.pre) { - fetchParams = await middleware.pre({ - fetch: this.fetchApi, - ...fetchParams, - }) || fetchParams; + fetchParams = + (await middleware.pre({ + fetch: this.fetchApi, + ...fetchParams, + })) || fetchParams; } } let response: Response | undefined = undefined; @@ -221,18 +233,22 @@ export class BaseAPI { } catch (e) { for (const middleware of this.middleware) { if (middleware.onError) { - response = await middleware.onError({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - error: e, - response: response ? response.clone() : undefined, - }) || response; + response = + (await middleware.onError({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + error: e, + response: response ? response.clone() : undefined, + })) || response; } } if (response === undefined) { if (e instanceof Error) { - throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response'); + throw new FetchError( + e, + 'The request failed and the interceptors did not return an alternative response', + ); } else { throw e; } @@ -240,16 +256,17 @@ export class BaseAPI { } for (const middleware of this.middleware) { if (middleware.post) { - response = await middleware.post({ - fetch: this.fetchApi, - url: fetchParams.url, - init: fetchParams.init, - response: response.clone(), - }) || response; + response = + (await middleware.post({ + fetch: this.fetchApi, + url: fetchParams.url, + init: fetchParams.init, + response: response.clone(), + })) || response; } } return response; - } + }; /** * Create a shallow clone of `this` by constructing a new instance @@ -268,11 +285,11 @@ function isBlob(value: unknown): value is Blob { } function isFormData(value: unknown): value is FormData { - return typeof FormData !== "undefined" && value instanceof FormData; + return typeof FormData !== 'undefined' && value instanceof FormData; } export class ResponseError extends Error { - override name = "ResponseError" as const; + override name = 'ResponseError' as const; public response: Response; constructor(response: Response, msg?: string) { @@ -282,7 +299,7 @@ export class ResponseError extends Error { } export class FetchError extends Error { - override name = "FetchError" as const; + override name = 'FetchError' as const; public cause: Error; constructor(cause: Error, msg?: string) { @@ -292,7 +309,7 @@ export class FetchError extends Error { } export class RequiredError extends Error { - override name = "RequiredError" as const; + override name = 'RequiredError' as const; public field: string; constructor(field: string, msg?: string) { @@ -306,12 +323,30 @@ export type FetchAPI = WindowOrWorkerGlobalScope['fetch']; export type Json = unknown; export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD'; export type HTTPHeaders = { [key: string]: string }; -export type HTTPQuery = { [key: string]: string | number | null | boolean | Array | Set | HTTPQuery }; +export type HTTPQuery = { + [key: string]: + | string + | number + | null + | boolean + | Array + | Set + | HTTPQuery; +}; export type HTTPBody = Json | Blob | FormData | URLSearchParams; // eslint-disable-line @typescript-eslint/no-redundant-type-constituents -export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody; signal?: AbortSignal }; +export type HTTPRequestInit = { + headers?: HTTPHeaders; + method: HTTPMethod; + credentials?: RequestCredentials; + body?: HTTPBody; + signal?: AbortSignal; +}; export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original'; -export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise +export type InitOverrideFunction = (requestContext: { + init: HTTPRequestInit; + context: RequestOpts; +}) => Promise; export interface FetchParams { url: string; @@ -329,15 +364,28 @@ export interface RequestOpts { export function querystring(params: HTTPQuery, prefix: string = ''): string { return Object.keys(params) - .map(key => querystringSingleKey(key, params[key], prefix)) - .filter(part => part.length > 0) + .map((key) => querystringSingleKey(key, params[key], prefix)) + .filter((part) => part.length > 0) .join('&'); } -function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array | Set | HTTPQuery, keyPrefix: string = ''): string { +function querystringSingleKey( + key: string, + value: + | string + | number + | null + | undefined + | boolean + | Array + | Set + | HTTPQuery, + keyPrefix: string = '', +): string { const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key); if (value instanceof Array) { - const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue))) + const multiValue = value + .map((singleValue) => encodeURIComponent(String(singleValue))) .join(`&${encodeURIComponent(fullKey)}=`); return `${encodeURIComponent(fullKey)}=${multiValue}`; } @@ -413,16 +461,106 @@ export interface ApiResponse { } export type HttpSuccessStatus = - | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 - | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 - | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 - | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 - | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 - | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 - | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 - | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 - | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 - | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299; + | 200 + | 201 + | 202 + | 203 + | 204 + | 205 + | 206 + | 207 + | 208 + | 209 + | 210 + | 211 + | 212 + | 213 + | 214 + | 215 + | 216 + | 217 + | 218 + | 219 + | 220 + | 221 + | 222 + | 223 + | 224 + | 225 + | 226 + | 227 + | 228 + | 229 + | 230 + | 231 + | 232 + | 233 + | 234 + | 235 + | 236 + | 237 + | 238 + | 239 + | 240 + | 241 + | 242 + | 243 + | 244 + | 245 + | 246 + | 247 + | 248 + | 249 + | 250 + | 251 + | 252 + | 253 + | 254 + | 255 + | 256 + | 257 + | 258 + | 259 + | 260 + | 261 + | 262 + | 263 + | 264 + | 265 + | 266 + | 267 + | 268 + | 269 + | 270 + | 271 + | 272 + | 273 + | 274 + | 275 + | 276 + | 277 + | 278 + | 279 + | 280 + | 281 + | 282 + | 283 + | 284 + | 285 + | 286 + | 287 + | 288 + | 289 + | 290 + | 291 + | 292 + | 293 + | 294 + | 295 + | 296 + | 297 + | 298 + | 299; export type HttpSuccessResponse = { status: HttpSuccessStatus }; @@ -449,7 +587,10 @@ class ApiResponseBase { export class JSONApiResponse extends ApiResponseBase { private transformer: ResponseTransformer; - constructor(raw: Response, transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T) { + constructor( + raw: Response, + transformer: ResponseTransformer = (jsonValue: unknown) => jsonValue as T, + ) { super(raw); this.transformer = transformer; } @@ -476,7 +617,7 @@ export class BlobApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.blob(); - }; + } } export class TextApiResponse extends ApiResponseBase { @@ -486,5 +627,5 @@ export class TextApiResponse extends ApiResponseBase { async value(): Promise { return await this.raw.text(); - }; + } } diff --git a/tests/golden/typescript/typescript-fetch/typescript-additional-properties/tsconfig.esm.json.golden b/tests/golden/typescript/typescript-fetch/typescript-additional-properties/tsconfig.esm.json.golden index bb8350cb6..769c716fd 100644 --- a/tests/golden/typescript/typescript-fetch/typescript-additional-properties/tsconfig.esm.json.golden +++ b/tests/golden/typescript/typescript-fetch/typescript-additional-properties/tsconfig.esm.json.golden @@ -4,4 +4,4 @@ "outDir": "dist/esm" }, "extends": "./tsconfig.json" -} \ No newline at end of file +} diff --git a/tests/golden/typescript/typescript-fetch/typescript-additional-properties/tsconfig.json.golden b/tests/golden/typescript/typescript-fetch/typescript-additional-properties/tsconfig.json.golden index 4b3a8cf7f..9f125842c 100644 --- a/tests/golden/typescript/typescript-fetch/typescript-additional-properties/tsconfig.json.golden +++ b/tests/golden/typescript/typescript-fetch/typescript-additional-properties/tsconfig.json.golden @@ -4,10 +4,7 @@ "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "lib": [ - "ES2020", - "DOM" - ], + "lib": ["ES2020", "DOM"], "module": "ES2020", "moduleResolution": "bundler", "outDir": "./dist", @@ -17,15 +14,8 @@ "sourceMap": true, "strict": true, "target": "ES2020", - "typeRoots": [ - "node_modules/@types" - ] + "typeRoots": ["node_modules/@types"] }, - "exclude": [ - "dist", - "node_modules" - ], - "include": [ - "**/*.ts" - ] -} \ No newline at end of file + "exclude": ["dist", "node_modules"], + "include": ["**/*.ts"] +}