diff --git a/eslint.config.js b/eslint.config.js index f4fb29e81..25548a8f0 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -78,6 +78,7 @@ export default tsPlugin.config( rules: { "no-restricted-syntax": [ "warn", + ...peformanceConcerns, { selector: "Identifier[name='createConditionalExpression']", message: "use makeTernary() helper", @@ -92,7 +93,7 @@ export default tsPlugin.config( }, { selector: "Identifier[name='createInterfaceDeclaration']", - message: "use makePublicInterface() helper", + message: "use makeInterface() helper", }, { selector: "Identifier[name='createClassDeclaration']", diff --git a/example/example.client.ts b/example/example.client.ts index fa0dbbbf9..0f18bd5ad 100644 --- a/example/example.client.ts +++ b/example/example.client.ts @@ -3,12 +3,14 @@ type Type1 = { features: Type1; }[]; +export type SomeOf = T[keyof T]; + type GetV1UserRetrieveInput = { /** a numeric string containing the id of the user */ id: string; }; -type GetV1UserRetrievePositiveResponse = { +type GetV1UserRetrievePositiveVariant1 = { status: "success"; data: { id: number; @@ -20,29 +22,37 @@ type GetV1UserRetrievePositiveResponse = { }; }; -type GetV1UserRetrieveNegativeResponse = { +interface GetV1UserRetrievePositiveResponseVariants { + 200: GetV1UserRetrievePositiveVariant1; +} + +type GetV1UserRetrieveNegativeVariant1 = { status: "error"; error: { message: string; }; }; -type GetV1UserRetrieveResponse = - | GetV1UserRetrievePositiveResponse - | GetV1UserRetrieveNegativeResponse; +interface GetV1UserRetrieveNegativeResponseVariants { + 400: GetV1UserRetrieveNegativeVariant1; +} type DeleteV1UserIdRemoveInput = { /** numeric string */ id: string; }; -type DeleteV1UserIdRemovePositiveResponse = undefined; +type DeleteV1UserIdRemovePositiveVariant1 = undefined; + +interface DeleteV1UserIdRemovePositiveResponseVariants { + 204: DeleteV1UserIdRemovePositiveVariant1; +} -type DeleteV1UserIdRemoveNegativeResponse = undefined; +type DeleteV1UserIdRemoveNegativeVariant1 = undefined; -type DeleteV1UserIdRemoveResponse = - | DeleteV1UserIdRemovePositiveResponse - | DeleteV1UserIdRemoveNegativeResponse; +interface DeleteV1UserIdRemoveNegativeResponseVariants { + 404: DeleteV1UserIdRemoveNegativeVariant1; +} type PatchV1UserIdInput = { key: string; @@ -51,7 +61,7 @@ type PatchV1UserIdInput = { birthday: string; }; -type PatchV1UserIdPositiveResponse = { +type PatchV1UserIdPositiveVariant1 = { status: "success"; data: { name: string; @@ -59,83 +69,106 @@ type PatchV1UserIdPositiveResponse = { }; }; -type PatchV1UserIdNegativeResponse = { +interface PatchV1UserIdPositiveResponseVariants { + 200: PatchV1UserIdPositiveVariant1; +} + +type PatchV1UserIdNegativeVariant1 = { status: "error"; error: { message: string; }; }; -type PatchV1UserIdResponse = - | PatchV1UserIdPositiveResponse - | PatchV1UserIdNegativeResponse; +interface PatchV1UserIdNegativeResponseVariants { + 400: PatchV1UserIdNegativeVariant1; +} type PostV1UserCreateInput = { name: string; }; -type PostV1UserCreatePositiveResponse = { +type PostV1UserCreatePositiveVariant1 = { status: "created"; data: { id: number; }; }; -type PostV1UserCreateNegativeResponse = - | { - status: "exists"; - id: number; - } - | { - status: "error"; - reason: string; - }; +interface PostV1UserCreatePositiveResponseVariants { + 201: PostV1UserCreatePositiveVariant1; + 202: PostV1UserCreatePositiveVariant1; +} + +type PostV1UserCreateNegativeVariant1 = { + status: "exists"; + id: number; +}; -type PostV1UserCreateResponse = - | PostV1UserCreatePositiveResponse - | PostV1UserCreateNegativeResponse; +type PostV1UserCreateNegativeVariant2 = { + status: "error"; + reason: string; +}; + +interface PostV1UserCreateNegativeResponseVariants { + 409: PostV1UserCreateNegativeVariant1; + 400: PostV1UserCreateNegativeVariant2; + 500: PostV1UserCreateNegativeVariant2; +} type GetV1UserListInput = {}; -type GetV1UserListPositiveResponse = { +type GetV1UserListPositiveVariant1 = { name: string; }[]; -type GetV1UserListNegativeResponse = string; +interface GetV1UserListPositiveResponseVariants { + 200: GetV1UserListPositiveVariant1; +} -type GetV1UserListResponse = - | GetV1UserListPositiveResponse - | GetV1UserListNegativeResponse; +type GetV1UserListNegativeVariant1 = string; + +interface GetV1UserListNegativeResponseVariants { + 400: GetV1UserListNegativeVariant1; +} type GetV1AvatarSendInput = { userId: string; }; -type GetV1AvatarSendPositiveResponse = string; +type GetV1AvatarSendPositiveVariant1 = string; -type GetV1AvatarSendNegativeResponse = string; +interface GetV1AvatarSendPositiveResponseVariants { + 200: GetV1AvatarSendPositiveVariant1; +} -type GetV1AvatarSendResponse = - | GetV1AvatarSendPositiveResponse - | GetV1AvatarSendNegativeResponse; +type GetV1AvatarSendNegativeVariant1 = string; + +interface GetV1AvatarSendNegativeResponseVariants { + 400: GetV1AvatarSendNegativeVariant1; +} type GetV1AvatarStreamInput = { userId: string; }; -type GetV1AvatarStreamPositiveResponse = Buffer; +type GetV1AvatarStreamPositiveVariant1 = Buffer; -type GetV1AvatarStreamNegativeResponse = string; +interface GetV1AvatarStreamPositiveResponseVariants { + 200: GetV1AvatarStreamPositiveVariant1; +} -type GetV1AvatarStreamResponse = - | GetV1AvatarStreamPositiveResponse - | GetV1AvatarStreamNegativeResponse; +type GetV1AvatarStreamNegativeVariant1 = string; + +interface GetV1AvatarStreamNegativeResponseVariants { + 400: GetV1AvatarStreamNegativeVariant1; +} type PostV1AvatarUploadInput = { avatar: any; }; -type PostV1AvatarUploadPositiveResponse = { +type PostV1AvatarUploadPositiveVariant1 = { status: "success"; data: { name: string; @@ -146,53 +179,65 @@ type PostV1AvatarUploadPositiveResponse = { }; }; -type PostV1AvatarUploadNegativeResponse = { +interface PostV1AvatarUploadPositiveResponseVariants { + 200: PostV1AvatarUploadPositiveVariant1; +} + +type PostV1AvatarUploadNegativeVariant1 = { status: "error"; error: { message: string; }; }; -type PostV1AvatarUploadResponse = - | PostV1AvatarUploadPositiveResponse - | PostV1AvatarUploadNegativeResponse; +interface PostV1AvatarUploadNegativeResponseVariants { + 400: PostV1AvatarUploadNegativeVariant1; +} type PostV1AvatarRawInput = Buffer; -type PostV1AvatarRawPositiveResponse = { +type PostV1AvatarRawPositiveVariant1 = { status: "success"; data: { length: number; }; }; -type PostV1AvatarRawNegativeResponse = { +interface PostV1AvatarRawPositiveResponseVariants { + 200: PostV1AvatarRawPositiveVariant1; +} + +type PostV1AvatarRawNegativeVariant1 = { status: "error"; error: { message: string; }; }; -type PostV1AvatarRawResponse = - | PostV1AvatarRawPositiveResponse - | PostV1AvatarRawNegativeResponse; +interface PostV1AvatarRawNegativeResponseVariants { + 400: PostV1AvatarRawNegativeVariant1; +} type GetV1EventsTimeInput = { trigger?: string | undefined; }; -type GetV1EventsTimePositiveResponse = { +type GetV1EventsTimePositiveVariant1 = { data: number; event: "time"; id?: string | undefined; retry?: number | undefined; }; -type GetV1EventsTimeNegativeResponse = string; +interface GetV1EventsTimePositiveResponseVariants { + 200: GetV1EventsTimePositiveVariant1; +} -type GetV1EventsTimeResponse = - | GetV1EventsTimePositiveResponse - | GetV1EventsTimeNegativeResponse; +type GetV1EventsTimeNegativeVariant1 = string; + +interface GetV1EventsTimeNegativeResponseVariants { + 400: GetV1EventsTimeNegativeVariant1; +} export type Path = | "/v1/user/retrieve" @@ -222,42 +267,85 @@ export interface Input { } export interface PositiveResponse { - "get /v1/user/retrieve": GetV1UserRetrievePositiveResponse; - "delete /v1/user/:id/remove": DeleteV1UserIdRemovePositiveResponse; - "patch /v1/user/:id": PatchV1UserIdPositiveResponse; - "post /v1/user/create": PostV1UserCreatePositiveResponse; - "get /v1/user/list": GetV1UserListPositiveResponse; - "get /v1/avatar/send": GetV1AvatarSendPositiveResponse; - "get /v1/avatar/stream": GetV1AvatarStreamPositiveResponse; - "post /v1/avatar/upload": PostV1AvatarUploadPositiveResponse; - "post /v1/avatar/raw": PostV1AvatarRawPositiveResponse; - "get /v1/events/time": GetV1EventsTimePositiveResponse; + "get /v1/user/retrieve": SomeOf; + "delete /v1/user/:id/remove": SomeOf; + "patch /v1/user/:id": SomeOf; + "post /v1/user/create": SomeOf; + "get /v1/user/list": SomeOf; + "get /v1/avatar/send": SomeOf; + "get /v1/avatar/stream": SomeOf; + "post /v1/avatar/upload": SomeOf; + "post /v1/avatar/raw": SomeOf; + "get /v1/events/time": SomeOf; } export interface NegativeResponse { - "get /v1/user/retrieve": GetV1UserRetrieveNegativeResponse; - "delete /v1/user/:id/remove": DeleteV1UserIdRemoveNegativeResponse; - "patch /v1/user/:id": PatchV1UserIdNegativeResponse; - "post /v1/user/create": PostV1UserCreateNegativeResponse; - "get /v1/user/list": GetV1UserListNegativeResponse; - "get /v1/avatar/send": GetV1AvatarSendNegativeResponse; - "get /v1/avatar/stream": GetV1AvatarStreamNegativeResponse; - "post /v1/avatar/upload": PostV1AvatarUploadNegativeResponse; - "post /v1/avatar/raw": PostV1AvatarRawNegativeResponse; - "get /v1/events/time": GetV1EventsTimeNegativeResponse; + "get /v1/user/retrieve": SomeOf; + "delete /v1/user/:id/remove": SomeOf; + "patch /v1/user/:id": SomeOf; + "post /v1/user/create": SomeOf; + "get /v1/user/list": SomeOf; + "get /v1/avatar/send": SomeOf; + "get /v1/avatar/stream": SomeOf; + "post /v1/avatar/upload": SomeOf; + "post /v1/avatar/raw": SomeOf; + "get /v1/events/time": SomeOf; +} + +export interface EncodedResponse { + "get /v1/user/retrieve": GetV1UserRetrievePositiveResponseVariants & + GetV1UserRetrieveNegativeResponseVariants; + "delete /v1/user/:id/remove": DeleteV1UserIdRemovePositiveResponseVariants & + DeleteV1UserIdRemoveNegativeResponseVariants; + "patch /v1/user/:id": PatchV1UserIdPositiveResponseVariants & + PatchV1UserIdNegativeResponseVariants; + "post /v1/user/create": PostV1UserCreatePositiveResponseVariants & + PostV1UserCreateNegativeResponseVariants; + "get /v1/user/list": GetV1UserListPositiveResponseVariants & + GetV1UserListNegativeResponseVariants; + "get /v1/avatar/send": GetV1AvatarSendPositiveResponseVariants & + GetV1AvatarSendNegativeResponseVariants; + "get /v1/avatar/stream": GetV1AvatarStreamPositiveResponseVariants & + GetV1AvatarStreamNegativeResponseVariants; + "post /v1/avatar/upload": PostV1AvatarUploadPositiveResponseVariants & + PostV1AvatarUploadNegativeResponseVariants; + "post /v1/avatar/raw": PostV1AvatarRawPositiveResponseVariants & + PostV1AvatarRawNegativeResponseVariants; + "get /v1/events/time": GetV1EventsTimePositiveResponseVariants & + GetV1EventsTimeNegativeResponseVariants; } export interface Response { - "get /v1/user/retrieve": GetV1UserRetrieveResponse; - "delete /v1/user/:id/remove": DeleteV1UserIdRemoveResponse; - "patch /v1/user/:id": PatchV1UserIdResponse; - "post /v1/user/create": PostV1UserCreateResponse; - "get /v1/user/list": GetV1UserListResponse; - "get /v1/avatar/send": GetV1AvatarSendResponse; - "get /v1/avatar/stream": GetV1AvatarStreamResponse; - "post /v1/avatar/upload": PostV1AvatarUploadResponse; - "post /v1/avatar/raw": PostV1AvatarRawResponse; - "get /v1/events/time": GetV1EventsTimeResponse; + "get /v1/user/retrieve": + | PositiveResponse["get /v1/user/retrieve"] + | NegativeResponse["get /v1/user/retrieve"]; + "delete /v1/user/:id/remove": + | PositiveResponse["delete /v1/user/:id/remove"] + | NegativeResponse["delete /v1/user/:id/remove"]; + "patch /v1/user/:id": + | PositiveResponse["patch /v1/user/:id"] + | NegativeResponse["patch /v1/user/:id"]; + "post /v1/user/create": + | PositiveResponse["post /v1/user/create"] + | NegativeResponse["post /v1/user/create"]; + "get /v1/user/list": + | PositiveResponse["get /v1/user/list"] + | NegativeResponse["get /v1/user/list"]; + "get /v1/avatar/send": + | PositiveResponse["get /v1/avatar/send"] + | NegativeResponse["get /v1/avatar/send"]; + "get /v1/avatar/stream": + | PositiveResponse["get /v1/avatar/stream"] + | NegativeResponse["get /v1/avatar/stream"]; + "post /v1/avatar/upload": + | PositiveResponse["post /v1/avatar/upload"] + | NegativeResponse["post /v1/avatar/upload"]; + "post /v1/avatar/raw": + | PositiveResponse["post /v1/avatar/raw"] + | NegativeResponse["post /v1/avatar/raw"]; + "get /v1/events/time": + | PositiveResponse["get /v1/events/time"] + | NegativeResponse["get /v1/events/time"]; } export type MethodPath = keyof Input; diff --git a/src/documentation.ts b/src/documentation.ts index 5f8d99fbc..6dd819233 100644 --- a/src/documentation.ts +++ b/src/documentation.ts @@ -71,7 +71,7 @@ interface DocumentationParams { export class Documentation extends OpenApiBuilder { protected lastSecuritySchemaIds = new Map(); protected lastOperationIdSuffixes = new Map(); - protected responseVariants = keys(defaultStatusCodes); // eslint-disable-line no-restricted-syntax -- literal + protected responseVariants = keys(defaultStatusCodes); // eslint-disable-line no-restricted-syntax -- need literal protected references = new Map(); protected makeRef( diff --git a/src/integration-helpers.ts b/src/integration-helpers.ts index ba2bdbf2a..8d08e13aa 100644 --- a/src/integration-helpers.ts +++ b/src/integration-helpers.ts @@ -69,12 +69,12 @@ export const makeEmptyInitializingConstructor = ( params: ts.ParameterDeclaration[], ) => f.createConstructorDeclaration(undefined, params, f.createBlock([])); -export const makeInterfaceProp = (name: string, ref: string) => +export const makeInterfaceProp = (name: string | number, value: ts.TypeNode) => f.createPropertySignature( undefined, - name, + typeof name === "number" ? f.createNumericLiteral(name) : name, undefined, - f.createTypeReferenceNode(ref), + value, ); export const makeDeconstruction = ( @@ -113,17 +113,36 @@ export const makePublicLiteralType = ( export const makeType = ( name: ts.Identifier | string, value: ts.TypeNode, - { isPublic, comment }: { isPublic?: boolean; comment?: string } = {}, + { + isPublic, + comment, + params, + }: { + isPublic?: boolean; + comment?: string; + params?: Parameters[0]; + } = {}, ) => { const node = f.createTypeAliasDeclaration( isPublic ? exportModifier : undefined, name, - undefined, + params && makeTypeParams(params), value, ); return comment ? addJsDocComment(node, comment) : node; }; +/** @example type SomeOf = T[keyof T]; */ +export const makeSomeOfHelper = () => + makeType( + "SomeOf", + f.createIndexedAccessTypeNode( + f.createTypeReferenceNode("T"), + makeKeyOf("T"), + ), + { isPublic: true, params: { T: undefined } }, + ); + export const makePublicMethod = ( name: ts.Identifier, params: ts.ParameterDeclaration[], @@ -152,7 +171,7 @@ export const makePublicClass = ( ...statements, ]); -export const makeKeyOf = (id: ts.Identifier) => +export const makeKeyOf = (id: ts.Identifier | string) => f.createTypeOperatorNode( ts.SyntaxKind.KeyOfKeyword, f.createTypeReferenceNode(id), @@ -177,21 +196,28 @@ export const makePromise = (subject: ts.TypeNode | "any") => : subject, ]); -export const makePublicInterface = ( - name: ts.Identifier, +export const makeInterface = ( + name: ts.Identifier | string, props: ts.PropertySignature[], + { isPublic }: { isPublic?: boolean } = {}, ) => f.createInterfaceDeclaration( - exportModifier, + isPublic ? exportModifier : undefined, name, undefined, undefined, props, ); -export const makeTypeParams = (params: Record) => +export const makeTypeParams = ( + params: Partial>, +) => Object.entries(params).map(([name, id]) => - f.createTypeParameterDeclaration([], name, f.createTypeReferenceNode(id)), + f.createTypeParameterDeclaration( + [], + name, + id && f.createTypeReferenceNode(id), + ), ); export const makeArrowFn = ( diff --git a/src/integration.ts b/src/integration.ts index 331f202e4..887bd8ed5 100644 --- a/src/integration.ts +++ b/src/integration.ts @@ -1,6 +1,7 @@ +import { chain, keys } from "ramda"; import ts from "typescript"; import { z } from "zod"; -import { ResponseVariant } from "./api-response"; +import { defaultStatusCodes, ResponseVariant } from "./api-response"; import { emptyTail, exportModifier, @@ -17,7 +18,7 @@ import { makeParams, makePropCall, makePublicClass, - makePublicInterface, + makeInterface, makePublicLiteralType, makePublicMethod, makeType, @@ -32,6 +33,7 @@ import { makeAnd, makeEqual, makeKeyOf, + makeSomeOfHelper, } from "./integration-helpers"; import { makeCleanId } from "./common-helpers"; import { Method, methods } from "./method"; @@ -44,7 +46,7 @@ import { zodToTs } from "./zts"; import { ZTSContext, printNode, addJsDocComment } from "./zts-helpers"; import type Prettier from "prettier"; -type IOKind = "input" | "response" | ResponseVariant; +type IOKind = "input" | "response" | ResponseVariant | "encoded"; interface IntegrationParams { routing: Routing; @@ -101,11 +103,16 @@ interface FormattedPrintingOptions { } export class Integration { - protected program: ts.Node[] = []; + protected responseVariants = keys(defaultStatusCodes); // eslint-disable-line no-restricted-syntax -- need literal + protected someOf = makeSomeOfHelper(); + protected program: ts.Node[] = [this.someOf]; protected usage: Array = []; protected registry = new Map< ReturnType, // method+path - Record & { isJson: boolean; tags: ReadonlyArray } + Record & { + isJson: boolean; + tags: ReadonlyArray; + } >(); protected paths = new Set(); protected aliases = new Map(); @@ -116,6 +123,7 @@ export class Integration { inputInterface: f.createIdentifier("Input"), posResponseInterface: f.createIdentifier("PositiveResponse"), negResponseInterface: f.createIdentifier("NegativeResponse"), + encResponseInterface: f.createIdentifier("EncodedResponse"), responseInterface: f.createIdentifier("Response"), jsonEndpointsConst: f.createIdentifier("jsonEndpoints"), endpointTagsConst: f.createIdentifier("endpointTags"), @@ -164,6 +172,12 @@ export class Integration { return f.createTypeReferenceNode(name); } + /** @example SomeOf<_>*/ + protected makeSomeOf = ({ name }: ts.TypeAliasDeclaration) => + f.createTypeReferenceNode(this.someOf.name, [ + f.createTypeReferenceNode(name), + ]); + public constructor({ routing, brandHandling, @@ -180,44 +194,55 @@ export class Integration { entitle("input"), zodToTs(endpoint.getSchema("input"), ctxIn), ); - const positiveSchema = endpoint - .getResponses("positive") - .map(({ schema, mimeTypes }) => (mimeTypes ? schema : noContent)) - .reduce((agg, schema) => agg.or(schema)); - const positiveResponse = makeType( - entitle("positive.response"), - zodToTs(positiveSchema, ctxOut), - ); - const negativeSchema = endpoint - .getResponses("negative") - .map(({ schema, mimeTypes }) => (mimeTypes ? schema : noContent)) - .reduce((agg, schema) => agg.or(schema)); - const negativeResponse = makeType( - entitle("negative.response"), - zodToTs(negativeSchema, ctxOut), - ); - const genericResponse = makeType( - entitle("response"), - f.createUnionTypeNode([ - f.createTypeReferenceNode(positiveResponse.name.text), - f.createTypeReferenceNode(negativeResponse.name.text), - ]), - ); - this.program.push( - input, - positiveResponse, - negativeResponse, - genericResponse, + this.program.push(input); + const dictionaries = this.responseVariants.reduce( + (agg, responseVariant) => { + const responses = endpoint.getResponses(responseVariant); + const props = chain(([idx, { schema, mimeTypes, statusCodes }]) => { + const variantType = makeType( + entitle(responseVariant, "variant", `${idx + 1}`), + zodToTs(mimeTypes ? schema : noContent, ctxOut), + ); + this.program.push(variantType); + return statusCodes.map((code) => + makeInterfaceProp( + code, + f.createTypeReferenceNode(variantType.name), + ), + ); + }, Array.from(responses.entries())); + const dict = makeInterface( + entitle(responseVariant, "response", "variants"), + props, + ); + this.program.push(dict); + return Object.assign(agg, { [responseVariant]: dict }); + }, + {} as Record, ); this.paths.add(path); const isJson = endpoint .getResponses("positive") .some(({ mimeTypes }) => mimeTypes?.includes(contentTypes.json)); - this.registry.set(quoteProp(method, path), { - input: input.name.text, - positive: positiveResponse.name.text, - negative: negativeResponse.name.text, - response: genericResponse.name.text, + const methodPath = quoteProp(method, path); + this.registry.set(methodPath, { + input: f.createTypeReferenceNode(input.name), + positive: this.makeSomeOf(dictionaries.positive), + negative: this.makeSomeOf(dictionaries.negative), + response: f.createUnionTypeNode([ + f.createIndexedAccessTypeNode( + f.createTypeReferenceNode(this.ids.posResponseInterface), + f.createTypeReferenceNode(methodPath), + ), + f.createIndexedAccessTypeNode( + f.createTypeReferenceNode(this.ids.negResponseInterface), + f.createTypeReferenceNode(methodPath), + ), + ]), + encoded: f.createIntersectionTypeNode([ + f.createTypeReferenceNode(dictionaries.positive.name), + f.createTypeReferenceNode(dictionaries.negative.name), + ]), tags: endpoint.getTags(), isJson, }); @@ -241,6 +266,7 @@ export class Integration { }, { id: this.ids.posResponseInterface, kind: "positive", props: [] }, { id: this.ids.negResponseInterface, kind: "negative", props: [] }, + { id: this.ids.encResponseInterface, kind: "encoded", props: [] }, { id: this.ids.responseInterface, kind: "response", @@ -276,7 +302,7 @@ export class Integration { // export interface Input { "get /v1/user/retrieve": GetV1UserRetrieveInput; } for (const { id, props } of this.interfaces) - this.program.push(makePublicInterface(id, props)); + this.program.push(makeInterface(id, props, { isPublic: true })); // export type MethodPath = keyof Input; this.program.push( diff --git a/tests/unit/__snapshots__/integration.spec.ts.snap b/tests/unit/__snapshots__/integration.spec.ts.snap index 8df3b9f5a..cc08add3c 100644 --- a/tests/unit/__snapshots__/integration.spec.ts.snap +++ b/tests/unit/__snapshots__/integration.spec.ts.snap @@ -1,27 +1,33 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`Integration > Feature #945: should have configurable treatment of optionals 0 1`] = ` -"type PostV1TestWithDashesInput = { +"export type SomeOf = T[keyof T]; + +type PostV1TestWithDashesInput = { opt?: string; }; -type PostV1TestWithDashesPositiveResponse = { +type PostV1TestWithDashesPositiveVariant1 = { status: "success"; data: { similar?: number; }; }; -type PostV1TestWithDashesNegativeResponse = { +interface PostV1TestWithDashesPositiveResponseVariants { + 200: PostV1TestWithDashesPositiveVariant1; +} + +type PostV1TestWithDashesNegativeVariant1 = { status: "error"; error: { message: string; }; }; -type PostV1TestWithDashesResponse = - | PostV1TestWithDashesPositiveResponse - | PostV1TestWithDashesNegativeResponse; +interface PostV1TestWithDashesNegativeResponseVariants { + 400: PostV1TestWithDashesNegativeVariant1; +} export type Path = "/v1/test-with-dashes"; @@ -32,15 +38,22 @@ export interface Input { } export interface PositiveResponse { - "post /v1/test-with-dashes": PostV1TestWithDashesPositiveResponse; + "post /v1/test-with-dashes": SomeOf; } export interface NegativeResponse { - "post /v1/test-with-dashes": PostV1TestWithDashesNegativeResponse; + "post /v1/test-with-dashes": SomeOf; +} + +export interface EncodedResponse { + "post /v1/test-with-dashes": PostV1TestWithDashesPositiveResponseVariants & + PostV1TestWithDashesNegativeResponseVariants; } export interface Response { - "post /v1/test-with-dashes": PostV1TestWithDashesResponse; + "post /v1/test-with-dashes": + | PositiveResponse["post /v1/test-with-dashes"] + | NegativeResponse["post /v1/test-with-dashes"]; } export type MethodPath = keyof Input; @@ -126,27 +139,33 @@ client.provide("get /v1/user/retrieve", { id: "10" }); `; exports[`Integration > Feature #945: should have configurable treatment of optionals 1 1`] = ` -"type PostV1TestWithDashesInput = { +"export type SomeOf = T[keyof T]; + +type PostV1TestWithDashesInput = { opt: string | undefined; }; -type PostV1TestWithDashesPositiveResponse = { +type PostV1TestWithDashesPositiveVariant1 = { status: "success"; data: { similar: number | undefined; }; }; -type PostV1TestWithDashesNegativeResponse = { +interface PostV1TestWithDashesPositiveResponseVariants { + 200: PostV1TestWithDashesPositiveVariant1; +} + +type PostV1TestWithDashesNegativeVariant1 = { status: "error"; error: { message: string; }; }; -type PostV1TestWithDashesResponse = - | PostV1TestWithDashesPositiveResponse - | PostV1TestWithDashesNegativeResponse; +interface PostV1TestWithDashesNegativeResponseVariants { + 400: PostV1TestWithDashesNegativeVariant1; +} export type Path = "/v1/test-with-dashes"; @@ -157,15 +176,22 @@ export interface Input { } export interface PositiveResponse { - "post /v1/test-with-dashes": PostV1TestWithDashesPositiveResponse; + "post /v1/test-with-dashes": SomeOf; } export interface NegativeResponse { - "post /v1/test-with-dashes": PostV1TestWithDashesNegativeResponse; + "post /v1/test-with-dashes": SomeOf; +} + +export interface EncodedResponse { + "post /v1/test-with-dashes": PostV1TestWithDashesPositiveResponseVariants & + PostV1TestWithDashesNegativeResponseVariants; } export interface Response { - "post /v1/test-with-dashes": PostV1TestWithDashesResponse; + "post /v1/test-with-dashes": + | PositiveResponse["post /v1/test-with-dashes"] + | NegativeResponse["post /v1/test-with-dashes"]; } export type MethodPath = keyof Input; @@ -251,27 +277,33 @@ client.provide("get /v1/user/retrieve", { id: "10" }); `; exports[`Integration > Feature #945: should have configurable treatment of optionals 2 1`] = ` -"type PostV1TestWithDashesInput = { +"export type SomeOf = T[keyof T]; + +type PostV1TestWithDashesInput = { opt: string; }; -type PostV1TestWithDashesPositiveResponse = { +type PostV1TestWithDashesPositiveVariant1 = { status: "success"; data: { similar: number; }; }; -type PostV1TestWithDashesNegativeResponse = { +interface PostV1TestWithDashesPositiveResponseVariants { + 200: PostV1TestWithDashesPositiveVariant1; +} + +type PostV1TestWithDashesNegativeVariant1 = { status: "error"; error: { message: string; }; }; -type PostV1TestWithDashesResponse = - | PostV1TestWithDashesPositiveResponse - | PostV1TestWithDashesNegativeResponse; +interface PostV1TestWithDashesNegativeResponseVariants { + 400: PostV1TestWithDashesNegativeVariant1; +} export type Path = "/v1/test-with-dashes"; @@ -282,15 +314,22 @@ export interface Input { } export interface PositiveResponse { - "post /v1/test-with-dashes": PostV1TestWithDashesPositiveResponse; + "post /v1/test-with-dashes": SomeOf; } export interface NegativeResponse { - "post /v1/test-with-dashes": PostV1TestWithDashesNegativeResponse; + "post /v1/test-with-dashes": SomeOf; +} + +export interface EncodedResponse { + "post /v1/test-with-dashes": PostV1TestWithDashesPositiveResponseVariants & + PostV1TestWithDashesNegativeResponseVariants; } export interface Response { - "post /v1/test-with-dashes": PostV1TestWithDashesResponse; + "post /v1/test-with-dashes": + | PositiveResponse["post /v1/test-with-dashes"] + | NegativeResponse["post /v1/test-with-dashes"]; } export type MethodPath = keyof Input; @@ -376,28 +415,34 @@ client.provide("get /v1/user/retrieve", { id: "10" }); `; exports[`Integration > Feature #1470: Custom brands > should by handled accordingly 1`] = ` -"type PostV1CustomInput = { +"export type SomeOf = T[keyof T]; + +type PostV1CustomInput = { string: boolean; regular: string; }; -type PostV1CustomPositiveResponse = { +type PostV1CustomPositiveVariant1 = { status: "success"; data: { number: boolean; }; }; -type PostV1CustomNegativeResponse = { +interface PostV1CustomPositiveResponseVariants { + 200: PostV1CustomPositiveVariant1; +} + +type PostV1CustomNegativeVariant1 = { status: "error"; error: { message: string; }; }; -type PostV1CustomResponse = - | PostV1CustomPositiveResponse - | PostV1CustomNegativeResponse; +interface PostV1CustomNegativeResponseVariants { + 400: PostV1CustomNegativeVariant1; +} export type Path = "/v1/custom"; @@ -408,15 +453,22 @@ export interface Input { } export interface PositiveResponse { - "post /v1/custom": PostV1CustomPositiveResponse; + "post /v1/custom": SomeOf; } export interface NegativeResponse { - "post /v1/custom": PostV1CustomNegativeResponse; + "post /v1/custom": SomeOf; +} + +export interface EncodedResponse { + "post /v1/custom": PostV1CustomPositiveResponseVariants & + PostV1CustomNegativeResponseVariants; } export interface Response { - "post /v1/custom": PostV1CustomResponse; + "post /v1/custom": + | PositiveResponse["post /v1/custom"] + | NegativeResponse["post /v1/custom"]; } export type MethodPath = keyof Input; @@ -429,12 +481,14 @@ exports[`Integration > Should generate a client for example API 1`] = ` features: Type1; }[]; +export type SomeOf = T[keyof T]; + type GetV1UserRetrieveInput = { /** a numeric string containing the id of the user */ id: string; }; -type GetV1UserRetrievePositiveResponse = { +type GetV1UserRetrievePositiveVariant1 = { status: "success"; data: { id: number; @@ -446,29 +500,37 @@ type GetV1UserRetrievePositiveResponse = { }; }; -type GetV1UserRetrieveNegativeResponse = { +interface GetV1UserRetrievePositiveResponseVariants { + 200: GetV1UserRetrievePositiveVariant1; +} + +type GetV1UserRetrieveNegativeVariant1 = { status: "error"; error: { message: string; }; }; -type GetV1UserRetrieveResponse = - | GetV1UserRetrievePositiveResponse - | GetV1UserRetrieveNegativeResponse; +interface GetV1UserRetrieveNegativeResponseVariants { + 400: GetV1UserRetrieveNegativeVariant1; +} type DeleteV1UserIdRemoveInput = { /** numeric string */ id: string; }; -type DeleteV1UserIdRemovePositiveResponse = undefined; +type DeleteV1UserIdRemovePositiveVariant1 = undefined; -type DeleteV1UserIdRemoveNegativeResponse = undefined; +interface DeleteV1UserIdRemovePositiveResponseVariants { + 204: DeleteV1UserIdRemovePositiveVariant1; +} -type DeleteV1UserIdRemoveResponse = - | DeleteV1UserIdRemovePositiveResponse - | DeleteV1UserIdRemoveNegativeResponse; +type DeleteV1UserIdRemoveNegativeVariant1 = undefined; + +interface DeleteV1UserIdRemoveNegativeResponseVariants { + 404: DeleteV1UserIdRemoveNegativeVariant1; +} type PatchV1UserIdInput = { key: string; @@ -477,7 +539,7 @@ type PatchV1UserIdInput = { birthday: string; }; -type PatchV1UserIdPositiveResponse = { +type PatchV1UserIdPositiveVariant1 = { status: "success"; data: { name: string; @@ -485,83 +547,106 @@ type PatchV1UserIdPositiveResponse = { }; }; -type PatchV1UserIdNegativeResponse = { +interface PatchV1UserIdPositiveResponseVariants { + 200: PatchV1UserIdPositiveVariant1; +} + +type PatchV1UserIdNegativeVariant1 = { status: "error"; error: { message: string; }; }; -type PatchV1UserIdResponse = - | PatchV1UserIdPositiveResponse - | PatchV1UserIdNegativeResponse; +interface PatchV1UserIdNegativeResponseVariants { + 400: PatchV1UserIdNegativeVariant1; +} type PostV1UserCreateInput = { name: string; }; -type PostV1UserCreatePositiveResponse = { +type PostV1UserCreatePositiveVariant1 = { status: "created"; data: { id: number; }; }; -type PostV1UserCreateNegativeResponse = - | { - status: "exists"; - id: number; - } - | { - status: "error"; - reason: string; - }; +interface PostV1UserCreatePositiveResponseVariants { + 201: PostV1UserCreatePositiveVariant1; + 202: PostV1UserCreatePositiveVariant1; +} -type PostV1UserCreateResponse = - | PostV1UserCreatePositiveResponse - | PostV1UserCreateNegativeResponse; +type PostV1UserCreateNegativeVariant1 = { + status: "exists"; + id: number; +}; + +type PostV1UserCreateNegativeVariant2 = { + status: "error"; + reason: string; +}; + +interface PostV1UserCreateNegativeResponseVariants { + 409: PostV1UserCreateNegativeVariant1; + 400: PostV1UserCreateNegativeVariant2; + 500: PostV1UserCreateNegativeVariant2; +} type GetV1UserListInput = {}; -type GetV1UserListPositiveResponse = { +type GetV1UserListPositiveVariant1 = { name: string; }[]; -type GetV1UserListNegativeResponse = string; +interface GetV1UserListPositiveResponseVariants { + 200: GetV1UserListPositiveVariant1; +} -type GetV1UserListResponse = - | GetV1UserListPositiveResponse - | GetV1UserListNegativeResponse; +type GetV1UserListNegativeVariant1 = string; + +interface GetV1UserListNegativeResponseVariants { + 400: GetV1UserListNegativeVariant1; +} type GetV1AvatarSendInput = { userId: string; }; -type GetV1AvatarSendPositiveResponse = string; +type GetV1AvatarSendPositiveVariant1 = string; -type GetV1AvatarSendNegativeResponse = string; +interface GetV1AvatarSendPositiveResponseVariants { + 200: GetV1AvatarSendPositiveVariant1; +} -type GetV1AvatarSendResponse = - | GetV1AvatarSendPositiveResponse - | GetV1AvatarSendNegativeResponse; +type GetV1AvatarSendNegativeVariant1 = string; + +interface GetV1AvatarSendNegativeResponseVariants { + 400: GetV1AvatarSendNegativeVariant1; +} type GetV1AvatarStreamInput = { userId: string; }; -type GetV1AvatarStreamPositiveResponse = Buffer; +type GetV1AvatarStreamPositiveVariant1 = Buffer; -type GetV1AvatarStreamNegativeResponse = string; +interface GetV1AvatarStreamPositiveResponseVariants { + 200: GetV1AvatarStreamPositiveVariant1; +} -type GetV1AvatarStreamResponse = - | GetV1AvatarStreamPositiveResponse - | GetV1AvatarStreamNegativeResponse; +type GetV1AvatarStreamNegativeVariant1 = string; + +interface GetV1AvatarStreamNegativeResponseVariants { + 400: GetV1AvatarStreamNegativeVariant1; +} type PostV1AvatarUploadInput = { avatar: any; }; -type PostV1AvatarUploadPositiveResponse = { +type PostV1AvatarUploadPositiveVariant1 = { status: "success"; data: { name: string; @@ -572,53 +657,65 @@ type PostV1AvatarUploadPositiveResponse = { }; }; -type PostV1AvatarUploadNegativeResponse = { +interface PostV1AvatarUploadPositiveResponseVariants { + 200: PostV1AvatarUploadPositiveVariant1; +} + +type PostV1AvatarUploadNegativeVariant1 = { status: "error"; error: { message: string; }; }; -type PostV1AvatarUploadResponse = - | PostV1AvatarUploadPositiveResponse - | PostV1AvatarUploadNegativeResponse; +interface PostV1AvatarUploadNegativeResponseVariants { + 400: PostV1AvatarUploadNegativeVariant1; +} type PostV1AvatarRawInput = Buffer; -type PostV1AvatarRawPositiveResponse = { +type PostV1AvatarRawPositiveVariant1 = { status: "success"; data: { length: number; }; }; -type PostV1AvatarRawNegativeResponse = { +interface PostV1AvatarRawPositiveResponseVariants { + 200: PostV1AvatarRawPositiveVariant1; +} + +type PostV1AvatarRawNegativeVariant1 = { status: "error"; error: { message: string; }; }; -type PostV1AvatarRawResponse = - | PostV1AvatarRawPositiveResponse - | PostV1AvatarRawNegativeResponse; +interface PostV1AvatarRawNegativeResponseVariants { + 400: PostV1AvatarRawNegativeVariant1; +} type GetV1EventsTimeInput = { trigger?: string | undefined; }; -type GetV1EventsTimePositiveResponse = { +type GetV1EventsTimePositiveVariant1 = { data: number; event: "time"; id?: string | undefined; retry?: number | undefined; }; -type GetV1EventsTimeNegativeResponse = string; +interface GetV1EventsTimePositiveResponseVariants { + 200: GetV1EventsTimePositiveVariant1; +} + +type GetV1EventsTimeNegativeVariant1 = string; -type GetV1EventsTimeResponse = - | GetV1EventsTimePositiveResponse - | GetV1EventsTimeNegativeResponse; +interface GetV1EventsTimeNegativeResponseVariants { + 400: GetV1EventsTimeNegativeVariant1; +} export type Path = | "/v1/user/retrieve" @@ -648,42 +745,85 @@ export interface Input { } export interface PositiveResponse { - "get /v1/user/retrieve": GetV1UserRetrievePositiveResponse; - "delete /v1/user/:id/remove": DeleteV1UserIdRemovePositiveResponse; - "patch /v1/user/:id": PatchV1UserIdPositiveResponse; - "post /v1/user/create": PostV1UserCreatePositiveResponse; - "get /v1/user/list": GetV1UserListPositiveResponse; - "get /v1/avatar/send": GetV1AvatarSendPositiveResponse; - "get /v1/avatar/stream": GetV1AvatarStreamPositiveResponse; - "post /v1/avatar/upload": PostV1AvatarUploadPositiveResponse; - "post /v1/avatar/raw": PostV1AvatarRawPositiveResponse; - "get /v1/events/time": GetV1EventsTimePositiveResponse; + "get /v1/user/retrieve": SomeOf; + "delete /v1/user/:id/remove": SomeOf; + "patch /v1/user/:id": SomeOf; + "post /v1/user/create": SomeOf; + "get /v1/user/list": SomeOf; + "get /v1/avatar/send": SomeOf; + "get /v1/avatar/stream": SomeOf; + "post /v1/avatar/upload": SomeOf; + "post /v1/avatar/raw": SomeOf; + "get /v1/events/time": SomeOf; } export interface NegativeResponse { - "get /v1/user/retrieve": GetV1UserRetrieveNegativeResponse; - "delete /v1/user/:id/remove": DeleteV1UserIdRemoveNegativeResponse; - "patch /v1/user/:id": PatchV1UserIdNegativeResponse; - "post /v1/user/create": PostV1UserCreateNegativeResponse; - "get /v1/user/list": GetV1UserListNegativeResponse; - "get /v1/avatar/send": GetV1AvatarSendNegativeResponse; - "get /v1/avatar/stream": GetV1AvatarStreamNegativeResponse; - "post /v1/avatar/upload": PostV1AvatarUploadNegativeResponse; - "post /v1/avatar/raw": PostV1AvatarRawNegativeResponse; - "get /v1/events/time": GetV1EventsTimeNegativeResponse; + "get /v1/user/retrieve": SomeOf; + "delete /v1/user/:id/remove": SomeOf; + "patch /v1/user/:id": SomeOf; + "post /v1/user/create": SomeOf; + "get /v1/user/list": SomeOf; + "get /v1/avatar/send": SomeOf; + "get /v1/avatar/stream": SomeOf; + "post /v1/avatar/upload": SomeOf; + "post /v1/avatar/raw": SomeOf; + "get /v1/events/time": SomeOf; +} + +export interface EncodedResponse { + "get /v1/user/retrieve": GetV1UserRetrievePositiveResponseVariants & + GetV1UserRetrieveNegativeResponseVariants; + "delete /v1/user/:id/remove": DeleteV1UserIdRemovePositiveResponseVariants & + DeleteV1UserIdRemoveNegativeResponseVariants; + "patch /v1/user/:id": PatchV1UserIdPositiveResponseVariants & + PatchV1UserIdNegativeResponseVariants; + "post /v1/user/create": PostV1UserCreatePositiveResponseVariants & + PostV1UserCreateNegativeResponseVariants; + "get /v1/user/list": GetV1UserListPositiveResponseVariants & + GetV1UserListNegativeResponseVariants; + "get /v1/avatar/send": GetV1AvatarSendPositiveResponseVariants & + GetV1AvatarSendNegativeResponseVariants; + "get /v1/avatar/stream": GetV1AvatarStreamPositiveResponseVariants & + GetV1AvatarStreamNegativeResponseVariants; + "post /v1/avatar/upload": PostV1AvatarUploadPositiveResponseVariants & + PostV1AvatarUploadNegativeResponseVariants; + "post /v1/avatar/raw": PostV1AvatarRawPositiveResponseVariants & + PostV1AvatarRawNegativeResponseVariants; + "get /v1/events/time": GetV1EventsTimePositiveResponseVariants & + GetV1EventsTimeNegativeResponseVariants; } export interface Response { - "get /v1/user/retrieve": GetV1UserRetrieveResponse; - "delete /v1/user/:id/remove": DeleteV1UserIdRemoveResponse; - "patch /v1/user/:id": PatchV1UserIdResponse; - "post /v1/user/create": PostV1UserCreateResponse; - "get /v1/user/list": GetV1UserListResponse; - "get /v1/avatar/send": GetV1AvatarSendResponse; - "get /v1/avatar/stream": GetV1AvatarStreamResponse; - "post /v1/avatar/upload": PostV1AvatarUploadResponse; - "post /v1/avatar/raw": PostV1AvatarRawResponse; - "get /v1/events/time": GetV1EventsTimeResponse; + "get /v1/user/retrieve": + | PositiveResponse["get /v1/user/retrieve"] + | NegativeResponse["get /v1/user/retrieve"]; + "delete /v1/user/:id/remove": + | PositiveResponse["delete /v1/user/:id/remove"] + | NegativeResponse["delete /v1/user/:id/remove"]; + "patch /v1/user/:id": + | PositiveResponse["patch /v1/user/:id"] + | NegativeResponse["patch /v1/user/:id"]; + "post /v1/user/create": + | PositiveResponse["post /v1/user/create"] + | NegativeResponse["post /v1/user/create"]; + "get /v1/user/list": + | PositiveResponse["get /v1/user/list"] + | NegativeResponse["get /v1/user/list"]; + "get /v1/avatar/send": + | PositiveResponse["get /v1/avatar/send"] + | NegativeResponse["get /v1/avatar/send"]; + "get /v1/avatar/stream": + | PositiveResponse["get /v1/avatar/stream"] + | NegativeResponse["get /v1/avatar/stream"]; + "post /v1/avatar/upload": + | PositiveResponse["post /v1/avatar/upload"] + | NegativeResponse["post /v1/avatar/upload"]; + "post /v1/avatar/raw": + | PositiveResponse["post /v1/avatar/raw"] + | NegativeResponse["post /v1/avatar/raw"]; + "get /v1/events/time": + | PositiveResponse["get /v1/events/time"] + | NegativeResponse["get /v1/events/time"]; } export type MethodPath = keyof Input; @@ -792,12 +932,14 @@ exports[`Integration > Should generate a types for example API 1`] = ` features: Type1; }[]; +export type SomeOf = T[keyof T]; + type GetV1UserRetrieveInput = { /** a numeric string containing the id of the user */ id: string; }; -type GetV1UserRetrievePositiveResponse = { +type GetV1UserRetrievePositiveVariant1 = { status: "success"; data: { id: number; @@ -809,29 +951,37 @@ type GetV1UserRetrievePositiveResponse = { }; }; -type GetV1UserRetrieveNegativeResponse = { +interface GetV1UserRetrievePositiveResponseVariants { + 200: GetV1UserRetrievePositiveVariant1; +} + +type GetV1UserRetrieveNegativeVariant1 = { status: "error"; error: { message: string; }; }; -type GetV1UserRetrieveResponse = - | GetV1UserRetrievePositiveResponse - | GetV1UserRetrieveNegativeResponse; +interface GetV1UserRetrieveNegativeResponseVariants { + 400: GetV1UserRetrieveNegativeVariant1; +} type DeleteV1UserIdRemoveInput = { /** numeric string */ id: string; }; -type DeleteV1UserIdRemovePositiveResponse = undefined; +type DeleteV1UserIdRemovePositiveVariant1 = undefined; -type DeleteV1UserIdRemoveNegativeResponse = undefined; +interface DeleteV1UserIdRemovePositiveResponseVariants { + 204: DeleteV1UserIdRemovePositiveVariant1; +} -type DeleteV1UserIdRemoveResponse = - | DeleteV1UserIdRemovePositiveResponse - | DeleteV1UserIdRemoveNegativeResponse; +type DeleteV1UserIdRemoveNegativeVariant1 = undefined; + +interface DeleteV1UserIdRemoveNegativeResponseVariants { + 404: DeleteV1UserIdRemoveNegativeVariant1; +} type PatchV1UserIdInput = { key: string; @@ -840,7 +990,7 @@ type PatchV1UserIdInput = { birthday: string; }; -type PatchV1UserIdPositiveResponse = { +type PatchV1UserIdPositiveVariant1 = { status: "success"; data: { name: string; @@ -848,83 +998,106 @@ type PatchV1UserIdPositiveResponse = { }; }; -type PatchV1UserIdNegativeResponse = { +interface PatchV1UserIdPositiveResponseVariants { + 200: PatchV1UserIdPositiveVariant1; +} + +type PatchV1UserIdNegativeVariant1 = { status: "error"; error: { message: string; }; }; -type PatchV1UserIdResponse = - | PatchV1UserIdPositiveResponse - | PatchV1UserIdNegativeResponse; +interface PatchV1UserIdNegativeResponseVariants { + 400: PatchV1UserIdNegativeVariant1; +} type PostV1UserCreateInput = { name: string; }; -type PostV1UserCreatePositiveResponse = { +type PostV1UserCreatePositiveVariant1 = { status: "created"; data: { id: number; }; }; -type PostV1UserCreateNegativeResponse = - | { - status: "exists"; - id: number; - } - | { - status: "error"; - reason: string; - }; +interface PostV1UserCreatePositiveResponseVariants { + 201: PostV1UserCreatePositiveVariant1; + 202: PostV1UserCreatePositiveVariant1; +} + +type PostV1UserCreateNegativeVariant1 = { + status: "exists"; + id: number; +}; + +type PostV1UserCreateNegativeVariant2 = { + status: "error"; + reason: string; +}; -type PostV1UserCreateResponse = - | PostV1UserCreatePositiveResponse - | PostV1UserCreateNegativeResponse; +interface PostV1UserCreateNegativeResponseVariants { + 409: PostV1UserCreateNegativeVariant1; + 400: PostV1UserCreateNegativeVariant2; + 500: PostV1UserCreateNegativeVariant2; +} type GetV1UserListInput = {}; -type GetV1UserListPositiveResponse = { +type GetV1UserListPositiveVariant1 = { name: string; }[]; -type GetV1UserListNegativeResponse = string; +interface GetV1UserListPositiveResponseVariants { + 200: GetV1UserListPositiveVariant1; +} + +type GetV1UserListNegativeVariant1 = string; -type GetV1UserListResponse = - | GetV1UserListPositiveResponse - | GetV1UserListNegativeResponse; +interface GetV1UserListNegativeResponseVariants { + 400: GetV1UserListNegativeVariant1; +} type GetV1AvatarSendInput = { userId: string; }; -type GetV1AvatarSendPositiveResponse = string; +type GetV1AvatarSendPositiveVariant1 = string; -type GetV1AvatarSendNegativeResponse = string; +interface GetV1AvatarSendPositiveResponseVariants { + 200: GetV1AvatarSendPositiveVariant1; +} -type GetV1AvatarSendResponse = - | GetV1AvatarSendPositiveResponse - | GetV1AvatarSendNegativeResponse; +type GetV1AvatarSendNegativeVariant1 = string; + +interface GetV1AvatarSendNegativeResponseVariants { + 400: GetV1AvatarSendNegativeVariant1; +} type GetV1AvatarStreamInput = { userId: string; }; -type GetV1AvatarStreamPositiveResponse = Buffer; +type GetV1AvatarStreamPositiveVariant1 = Buffer; -type GetV1AvatarStreamNegativeResponse = string; +interface GetV1AvatarStreamPositiveResponseVariants { + 200: GetV1AvatarStreamPositiveVariant1; +} -type GetV1AvatarStreamResponse = - | GetV1AvatarStreamPositiveResponse - | GetV1AvatarStreamNegativeResponse; +type GetV1AvatarStreamNegativeVariant1 = string; + +interface GetV1AvatarStreamNegativeResponseVariants { + 400: GetV1AvatarStreamNegativeVariant1; +} type PostV1AvatarUploadInput = { avatar: any; }; -type PostV1AvatarUploadPositiveResponse = { +type PostV1AvatarUploadPositiveVariant1 = { status: "success"; data: { name: string; @@ -935,53 +1108,65 @@ type PostV1AvatarUploadPositiveResponse = { }; }; -type PostV1AvatarUploadNegativeResponse = { +interface PostV1AvatarUploadPositiveResponseVariants { + 200: PostV1AvatarUploadPositiveVariant1; +} + +type PostV1AvatarUploadNegativeVariant1 = { status: "error"; error: { message: string; }; }; -type PostV1AvatarUploadResponse = - | PostV1AvatarUploadPositiveResponse - | PostV1AvatarUploadNegativeResponse; +interface PostV1AvatarUploadNegativeResponseVariants { + 400: PostV1AvatarUploadNegativeVariant1; +} type PostV1AvatarRawInput = Buffer; -type PostV1AvatarRawPositiveResponse = { +type PostV1AvatarRawPositiveVariant1 = { status: "success"; data: { length: number; }; }; -type PostV1AvatarRawNegativeResponse = { +interface PostV1AvatarRawPositiveResponseVariants { + 200: PostV1AvatarRawPositiveVariant1; +} + +type PostV1AvatarRawNegativeVariant1 = { status: "error"; error: { message: string; }; }; -type PostV1AvatarRawResponse = - | PostV1AvatarRawPositiveResponse - | PostV1AvatarRawNegativeResponse; +interface PostV1AvatarRawNegativeResponseVariants { + 400: PostV1AvatarRawNegativeVariant1; +} type GetV1EventsTimeInput = { trigger?: string | undefined; }; -type GetV1EventsTimePositiveResponse = { +type GetV1EventsTimePositiveVariant1 = { data: number; event: "time"; id?: string | undefined; retry?: number | undefined; }; -type GetV1EventsTimeNegativeResponse = string; +interface GetV1EventsTimePositiveResponseVariants { + 200: GetV1EventsTimePositiveVariant1; +} + +type GetV1EventsTimeNegativeVariant1 = string; -type GetV1EventsTimeResponse = - | GetV1EventsTimePositiveResponse - | GetV1EventsTimeNegativeResponse; +interface GetV1EventsTimeNegativeResponseVariants { + 400: GetV1EventsTimeNegativeVariant1; +} export type Path = | "/v1/user/retrieve" @@ -1011,42 +1196,85 @@ export interface Input { } export interface PositiveResponse { - "get /v1/user/retrieve": GetV1UserRetrievePositiveResponse; - "delete /v1/user/:id/remove": DeleteV1UserIdRemovePositiveResponse; - "patch /v1/user/:id": PatchV1UserIdPositiveResponse; - "post /v1/user/create": PostV1UserCreatePositiveResponse; - "get /v1/user/list": GetV1UserListPositiveResponse; - "get /v1/avatar/send": GetV1AvatarSendPositiveResponse; - "get /v1/avatar/stream": GetV1AvatarStreamPositiveResponse; - "post /v1/avatar/upload": PostV1AvatarUploadPositiveResponse; - "post /v1/avatar/raw": PostV1AvatarRawPositiveResponse; - "get /v1/events/time": GetV1EventsTimePositiveResponse; + "get /v1/user/retrieve": SomeOf; + "delete /v1/user/:id/remove": SomeOf; + "patch /v1/user/:id": SomeOf; + "post /v1/user/create": SomeOf; + "get /v1/user/list": SomeOf; + "get /v1/avatar/send": SomeOf; + "get /v1/avatar/stream": SomeOf; + "post /v1/avatar/upload": SomeOf; + "post /v1/avatar/raw": SomeOf; + "get /v1/events/time": SomeOf; } export interface NegativeResponse { - "get /v1/user/retrieve": GetV1UserRetrieveNegativeResponse; - "delete /v1/user/:id/remove": DeleteV1UserIdRemoveNegativeResponse; - "patch /v1/user/:id": PatchV1UserIdNegativeResponse; - "post /v1/user/create": PostV1UserCreateNegativeResponse; - "get /v1/user/list": GetV1UserListNegativeResponse; - "get /v1/avatar/send": GetV1AvatarSendNegativeResponse; - "get /v1/avatar/stream": GetV1AvatarStreamNegativeResponse; - "post /v1/avatar/upload": PostV1AvatarUploadNegativeResponse; - "post /v1/avatar/raw": PostV1AvatarRawNegativeResponse; - "get /v1/events/time": GetV1EventsTimeNegativeResponse; + "get /v1/user/retrieve": SomeOf; + "delete /v1/user/:id/remove": SomeOf; + "patch /v1/user/:id": SomeOf; + "post /v1/user/create": SomeOf; + "get /v1/user/list": SomeOf; + "get /v1/avatar/send": SomeOf; + "get /v1/avatar/stream": SomeOf; + "post /v1/avatar/upload": SomeOf; + "post /v1/avatar/raw": SomeOf; + "get /v1/events/time": SomeOf; +} + +export interface EncodedResponse { + "get /v1/user/retrieve": GetV1UserRetrievePositiveResponseVariants & + GetV1UserRetrieveNegativeResponseVariants; + "delete /v1/user/:id/remove": DeleteV1UserIdRemovePositiveResponseVariants & + DeleteV1UserIdRemoveNegativeResponseVariants; + "patch /v1/user/:id": PatchV1UserIdPositiveResponseVariants & + PatchV1UserIdNegativeResponseVariants; + "post /v1/user/create": PostV1UserCreatePositiveResponseVariants & + PostV1UserCreateNegativeResponseVariants; + "get /v1/user/list": GetV1UserListPositiveResponseVariants & + GetV1UserListNegativeResponseVariants; + "get /v1/avatar/send": GetV1AvatarSendPositiveResponseVariants & + GetV1AvatarSendNegativeResponseVariants; + "get /v1/avatar/stream": GetV1AvatarStreamPositiveResponseVariants & + GetV1AvatarStreamNegativeResponseVariants; + "post /v1/avatar/upload": PostV1AvatarUploadPositiveResponseVariants & + PostV1AvatarUploadNegativeResponseVariants; + "post /v1/avatar/raw": PostV1AvatarRawPositiveResponseVariants & + PostV1AvatarRawNegativeResponseVariants; + "get /v1/events/time": GetV1EventsTimePositiveResponseVariants & + GetV1EventsTimeNegativeResponseVariants; } export interface Response { - "get /v1/user/retrieve": GetV1UserRetrieveResponse; - "delete /v1/user/:id/remove": DeleteV1UserIdRemoveResponse; - "patch /v1/user/:id": PatchV1UserIdResponse; - "post /v1/user/create": PostV1UserCreateResponse; - "get /v1/user/list": GetV1UserListResponse; - "get /v1/avatar/send": GetV1AvatarSendResponse; - "get /v1/avatar/stream": GetV1AvatarStreamResponse; - "post /v1/avatar/upload": PostV1AvatarUploadResponse; - "post /v1/avatar/raw": PostV1AvatarRawResponse; - "get /v1/events/time": GetV1EventsTimeResponse; + "get /v1/user/retrieve": + | PositiveResponse["get /v1/user/retrieve"] + | NegativeResponse["get /v1/user/retrieve"]; + "delete /v1/user/:id/remove": + | PositiveResponse["delete /v1/user/:id/remove"] + | NegativeResponse["delete /v1/user/:id/remove"]; + "patch /v1/user/:id": + | PositiveResponse["patch /v1/user/:id"] + | NegativeResponse["patch /v1/user/:id"]; + "post /v1/user/create": + | PositiveResponse["post /v1/user/create"] + | NegativeResponse["post /v1/user/create"]; + "get /v1/user/list": + | PositiveResponse["get /v1/user/list"] + | NegativeResponse["get /v1/user/list"]; + "get /v1/avatar/send": + | PositiveResponse["get /v1/avatar/send"] + | NegativeResponse["get /v1/avatar/send"]; + "get /v1/avatar/stream": + | PositiveResponse["get /v1/avatar/stream"] + | NegativeResponse["get /v1/avatar/stream"]; + "post /v1/avatar/upload": + | PositiveResponse["post /v1/avatar/upload"] + | NegativeResponse["post /v1/avatar/upload"]; + "post /v1/avatar/raw": + | PositiveResponse["post /v1/avatar/raw"] + | NegativeResponse["post /v1/avatar/raw"]; + "get /v1/events/time": + | PositiveResponse["get /v1/events/time"] + | NegativeResponse["get /v1/events/time"]; } export type MethodPath = keyof Input; @@ -1054,29 +1282,39 @@ export type MethodPath = keyof Input; `; exports[`Integration > Should support multiple response schemas depending on status code 1`] = ` -"type PostV1MtplInput = { +"export type SomeOf = T[keyof T]; + +type PostV1MtplInput = { test: number; }; -type PostV1MtplPositiveResponse = - | { - status: "ok"; - data: { - payload: string; - }; - } - | { - status: "kinda"; - data: { - payload: string; - }; - }; +type PostV1MtplPositiveVariant1 = { + status: "ok"; + data: { + payload: string; + }; +}; -type PostV1MtplNegativeResponse = "error" | "failure"; +type PostV1MtplPositiveVariant2 = { + status: "kinda"; + data: { + payload: string; + }; +}; + +interface PostV1MtplPositiveResponseVariants { + 200: PostV1MtplPositiveVariant1; + 201: PostV1MtplPositiveVariant2; +} + +type PostV1MtplNegativeVariant1 = "error"; -type PostV1MtplResponse = - | PostV1MtplPositiveResponse - | PostV1MtplNegativeResponse; +type PostV1MtplNegativeVariant2 = "failure"; + +interface PostV1MtplNegativeResponseVariants { + 400: PostV1MtplNegativeVariant1; + 500: PostV1MtplNegativeVariant2; +} export type Path = "/v1/mtpl"; @@ -1087,15 +1325,22 @@ export interface Input { } export interface PositiveResponse { - "post /v1/mtpl": PostV1MtplPositiveResponse; + "post /v1/mtpl": SomeOf; } export interface NegativeResponse { - "post /v1/mtpl": PostV1MtplNegativeResponse; + "post /v1/mtpl": SomeOf; +} + +export interface EncodedResponse { + "post /v1/mtpl": PostV1MtplPositiveResponseVariants & + PostV1MtplNegativeResponseVariants; } export interface Response { - "post /v1/mtpl": PostV1MtplResponse; + "post /v1/mtpl": + | PositiveResponse["post /v1/mtpl"] + | NegativeResponse["post /v1/mtpl"]; } export type MethodPath = keyof Input; @@ -1103,27 +1348,33 @@ export type MethodPath = keyof Input; `; exports[`Integration > Should treat optionals the same way as z.infer() by default 1`] = ` -"type PostV1TestWithDashesInput = { +"export type SomeOf = T[keyof T]; + +type PostV1TestWithDashesInput = { opt?: string | undefined; }; -type PostV1TestWithDashesPositiveResponse = { +type PostV1TestWithDashesPositiveVariant1 = { status: "success"; data: { similar?: number | undefined; }; }; -type PostV1TestWithDashesNegativeResponse = { +interface PostV1TestWithDashesPositiveResponseVariants { + 200: PostV1TestWithDashesPositiveVariant1; +} + +type PostV1TestWithDashesNegativeVariant1 = { status: "error"; error: { message: string; }; }; -type PostV1TestWithDashesResponse = - | PostV1TestWithDashesPositiveResponse - | PostV1TestWithDashesNegativeResponse; +interface PostV1TestWithDashesNegativeResponseVariants { + 400: PostV1TestWithDashesNegativeVariant1; +} export type Path = "/v1/test-with-dashes"; @@ -1134,15 +1385,22 @@ export interface Input { } export interface PositiveResponse { - "post /v1/test-with-dashes": PostV1TestWithDashesPositiveResponse; + "post /v1/test-with-dashes": SomeOf; } export interface NegativeResponse { - "post /v1/test-with-dashes": PostV1TestWithDashesNegativeResponse; + "post /v1/test-with-dashes": SomeOf; +} + +export interface EncodedResponse { + "post /v1/test-with-dashes": PostV1TestWithDashesPositiveResponseVariants & + PostV1TestWithDashesNegativeResponseVariants; } export interface Response { - "post /v1/test-with-dashes": PostV1TestWithDashesResponse; + "post /v1/test-with-dashes": + | PositiveResponse["post /v1/test-with-dashes"] + | NegativeResponse["post /v1/test-with-dashes"]; } export type MethodPath = keyof Input;