From 50a17cd1084e2c5cedab432008d2769e6517cb4a Mon Sep 17 00:00:00 2001 From: Malcolm Kee Date: Thu, 19 Mar 2026 23:27:18 +1100 Subject: [PATCH 01/16] feat: add msw plugin --- dev/package.json | 1 + dev/typescript/presets.ts | 1 + docs/openapi-ts/plugins/msw.md | 226 +- .../openapi-ts-fetch/openapi-ts.config.ts | 1 + examples/openapi-ts-fetch/package.json | 5 +- .../openapi-ts-fetch/src/client/msw.gen.ts | 551 +++++ .../openapi-ts-fetch/test/msw-types.test-d.ts | 165 ++ examples/openapi-ts-fetch/test/msw.test.ts | 303 +++ examples/openapi-ts-fetch/vitest.config.ts | 10 + packages/openapi-ts-tests/main/package.json | 1 + .../2.0.x/plugins/msw/default/index.ts | 3 + .../2.0.x/plugins/msw/default/msw.gen.ts | 277 +++ .../2.0.x/plugins/msw/default/types.gen.ts | 1190 ++++++++++ .../msw/response-example-disabled/index.ts | 3 + .../msw/response-example-disabled/msw.gen.ts | 75 + .../response-example-disabled/types.gen.ts | 50 + .../plugins/msw/response-example/index.ts | 3 + .../plugins/msw/response-example/msw.gen.ts | 68 + .../plugins/msw/response-example/types.gen.ts | 50 + .../2.0.x/plugins/msw/servers/index.ts | 3 + .../2.0.x/plugins/msw/servers/msw.gen.ts | 67 + .../2.0.x/plugins/msw/servers/types.gen.ts | 21 + .../3.0.x/plugins/msw/default/index.ts | 3 + .../3.0.x/plugins/msw/default/msw.gen.ts | 382 +++ .../3.0.x/plugins/msw/default/types.gen.ts | 2081 ++++++++++++++++ .../msw/response-example-disabled/index.ts | 3 + .../msw/response-example-disabled/msw.gen.ts | 75 + .../response-example-disabled/types.gen.ts | 50 + .../plugins/msw/response-example/index.ts | 3 + .../plugins/msw/response-example/msw.gen.ts | 81 + .../plugins/msw/response-example/types.gen.ts | 50 + .../3.0.x/plugins/msw/response-types/index.ts | 3 + .../plugins/msw/response-types/msw.gen.ts | 67 + .../plugins/msw/response-types/types.gen.ts | 23 + .../3.0.x/plugins/msw/servers/index.ts | 3 + .../3.0.x/plugins/msw/servers/msw.gen.ts | 67 + .../3.0.x/plugins/msw/servers/types.gen.ts | 21 + .../3.1.x/plugins/msw/default/index.ts | 3 + .../3.1.x/plugins/msw/default/msw.gen.ts | 382 +++ .../3.1.x/plugins/msw/default/types.gen.ts | 2100 +++++++++++++++++ .../msw/response-example-disabled/index.ts | 3 + .../msw/response-example-disabled/msw.gen.ts | 75 + .../response-example-disabled/types.gen.ts | 50 + .../plugins/msw/response-example/index.ts | 3 + .../plugins/msw/response-example/msw.gen.ts | 68 + .../plugins/msw/response-example/types.gen.ts | 50 + .../3.1.x/plugins/msw/response-types/index.ts | 3 + .../plugins/msw/response-types/msw.gen.ts | 56 + .../plugins/msw/response-types/types.gen.ts | 23 + .../3.1.x/plugins/msw/servers/index.ts | 3 + .../3.1.x/plugins/msw/servers/msw.gen.ts | 67 + .../3.1.x/plugins/msw/servers/types.gen.ts | 21 + .../main/test/plugins.test.ts | 45 +- packages/openapi-ts/package.json | 1 + packages/openapi-ts/src/index.ts | 7 + packages/openapi-ts/src/plugins/config.ts | 2 + .../plugins/msw/computeDominantResponse.ts | 145 ++ packages/openapi-ts/src/plugins/msw/config.ts | 20 + .../src/plugins/msw/handlerCreator.ts | 406 ++++ packages/openapi-ts/src/plugins/msw/index.ts | 2 + packages/openapi-ts/src/plugins/msw/plugin.ts | 316 +++ packages/openapi-ts/src/plugins/msw/types.ts | 19 + pnpm-lock.yaml | 326 ++- specs/2.0.x/response-example.yaml | 54 + specs/3.0.x/response-example.yaml | 53 + specs/3.0.x/response-types.yaml | 26 + specs/3.1.x/response-example.yaml | 53 + specs/3.1.x/response-types.yaml | 26 + 68 files changed, 10322 insertions(+), 72 deletions(-) create mode 100644 examples/openapi-ts-fetch/src/client/msw.gen.ts create mode 100644 examples/openapi-ts-fetch/test/msw-types.test-d.ts create mode 100644 examples/openapi-ts-fetch/test/msw.test.ts create mode 100644 examples/openapi-ts-fetch/vitest.config.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/index.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/msw.gen.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/types.gen.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example-disabled/index.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example-disabled/msw.gen.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example-disabled/types.gen.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example/index.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example/msw.gen.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example/types.gen.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/servers/index.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/servers/msw.gen.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/servers/types.gen.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/default/index.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/default/msw.gen.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/default/types.gen.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example-disabled/index.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example-disabled/msw.gen.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example-disabled/types.gen.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example/index.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example/msw.gen.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example/types.gen.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-types/index.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-types/msw.gen.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-types/types.gen.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/servers/index.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/servers/msw.gen.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/servers/types.gen.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/default/index.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/default/msw.gen.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/default/types.gen.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example-disabled/index.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example-disabled/msw.gen.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example-disabled/types.gen.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example/index.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example/msw.gen.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example/types.gen.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-types/index.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-types/msw.gen.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-types/types.gen.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/servers/index.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/servers/msw.gen.ts create mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/servers/types.gen.ts create mode 100644 packages/openapi-ts/src/plugins/msw/computeDominantResponse.ts create mode 100644 packages/openapi-ts/src/plugins/msw/config.ts create mode 100644 packages/openapi-ts/src/plugins/msw/handlerCreator.ts create mode 100644 packages/openapi-ts/src/plugins/msw/index.ts create mode 100644 packages/openapi-ts/src/plugins/msw/plugin.ts create mode 100644 packages/openapi-ts/src/plugins/msw/types.ts create mode 100644 specs/2.0.x/response-example.yaml create mode 100644 specs/3.0.x/response-example.yaml create mode 100644 specs/3.0.x/response-types.yaml create mode 100644 specs/3.1.x/response-example.yaml create mode 100644 specs/3.1.x/response-types.yaml diff --git a/dev/package.json b/dev/package.json index 0d965770b4..a7012d3580 100644 --- a/dev/package.json +++ b/dev/package.json @@ -22,6 +22,7 @@ "@tanstack/svelte-query": "5.90.2", "@tanstack/vue-query": "5.92.9", "arktype": "2.2.0", + "msw": "2.10.2", "nuxt": "3.21.0", "swr": "2.4.1", "tsx": "4.21.0", diff --git a/dev/typescript/presets.ts b/dev/typescript/presets.ts index 4a38c5cc1e..69205d7710 100644 --- a/dev/typescript/presets.ts +++ b/dev/typescript/presets.ts @@ -30,6 +30,7 @@ export const presets = { }, }, ], + msw: () => ['@hey-api/typescript', 'msw'], rpc: () => [ /** RPC-style SDK with Zod validation */ 'orpc', diff --git a/docs/openapi-ts/plugins/msw.md b/docs/openapi-ts/plugins/msw.md index 56decd8c05..4719b1d7bc 100644 --- a/docs/openapi-ts/plugins/msw.md +++ b/docs/openapi-ts/plugins/msw.md @@ -4,15 +4,233 @@ description: MSW plugin for Hey API. Compatible with all our features. --- -# MSW soon - - +# MSW ### About [MSW](https://mswjs.io) is an API mocking library that allows you to write client-agnostic mocks and reuse them across any frameworks, tools, and environments. +The MSW plugin for Hey API generates type-safe mock handler factories from your OpenAPI spec, removing the tedious work of defining mock endpoints and ensuring your mocks stay in sync with your API. + +## Features + +- type-safe mock handlers generated from your OpenAPI spec +- seamless integration with `@hey-api/openapi-ts` ecosystem +- support for static response values or custom MSW resolver functions +- Helper to generate handlers for every operation at once +- typed path parameters and request bodies +- minimal learning curve thanks to extending the underlying technology + +## Installation + +::: warning +MSW plugin requires `msw@^2` as a peer dependency. Make sure to install it in your project. +::: + +In your [configuration](/openapi-ts/get-started), add `msw` to your plugins and you'll be ready to generate MSW artifacts. :tada: + +```js +export default { + // ...other options + plugins: [ + // ...other plugins + 'msw', // [!code ++] + ], +}; +``` + +## Output + +The MSW plugin will generate a `msw.gen.ts` file containing the following artifacts. + +### Handler Exports + +Each operation is exported as a handler creator named `Mock`. These use a wildcard (`*`) base URL so they match requests regardless of origin. A `getAllMocks` function is also exported. + +```ts +import { getPetByIdMock, getAllMocks } from './client/msw.gen'; +``` + +## Usage + +### Static Response + +The simplest way to mock an endpoint is to provide a static response object with a `result` property. The `status` property is optional — when omitted, it defaults to the operation's dominant success status code (e.g. `200`). + +```ts +import { setupServer } from 'msw/node'; +import { getPetByIdMock } from './client/msw.gen'; + +const mockServer = setupServer( + // result only — status defaults to the dominant success code (200) + getPetByIdMock({ result: { id: 1, name: 'Fido' } }), + + // explicit status code + getPetByIdMock({ status: 200, result: { id: 1, name: 'Fido' } }), + + // type error if result type is incorrect + // @ts-expect-error + getPetByIdMock({ result: 'wrong type' }), +); +``` + +### Custom Resolver + +For more control, pass an MSW `HttpResponseResolver` function. The resolver receives typed path parameters and request body when available. + +```ts +import { delay, HttpResponse } from 'msw'; +import { setupServer } from 'msw/node'; +import { getPetByIdMock, updatePetMock } from './client/msw.gen'; + +const mockServer = setupServer( + // custom resolver with typed params and body + updatePetMock(async ({ request, params }) => { + const body = await request.json(); + return HttpResponse.json({ id: Number(params.petId), ...body }, { status: 200 }); + }), + + // async resolver with delay + getPetByIdMock(async () => { + await delay(100); + return HttpResponse.json({ id: 1, name: 'Fido' }); + }), +); +``` + +::: tip +Path parameters are typed as `string` because MSW normalizes all path parameters to strings. Use `Number()` or similar conversions if you need numeric values. +::: + +### Operations Without Responses + +For operations that don't define a response type, the handler creator can be invoked without arguments or with a custom resolver function. + +```ts +import { deletePetMock } from './client/msw.gen'; + +const mockServer = setupServer( + deletePetMock(), + + deletePetMock(() => new HttpResponse(null, { status: 204 })), +); +``` + +### Response Examples + +When your OpenAPI spec includes response examples, the generated handlers will use them as default values. This means you can call the handler without arguments and it will return the example response automatically. + +```ts +import { getFooMock } from './client/msw.gen'; + +const mockServer = setupServer( + // uses the example response from the OpenAPI spec as default + getFooMock(), + + // you can still override with a custom response + getFooMock({ result: { name: 'Custom' } }), +); +``` + +By default, `valueSources` is set to `['example']`, which embeds OpenAPI examples in the generated output. To disable this, set `valueSources` to an empty array. + +::: code-group + +```js [config] +export default { + // ...other options + plugins: [ + // ...other plugins + { + name: 'msw', + valueSources: [], // [!code ++] + }, + ], +}; +``` + +::: + +### All Handlers (`getAllMocks`) + +The `getAllMocks` function generates handlers for all operations at once. This is useful for quickly setting up a mock server without manually listing each operation. + +```ts +import { setupServer } from 'msw/node'; +import { getAllMocks } from './client/msw.gen'; + +const server = setupServer(...getAllMocks()); +``` + +#### `onMissingMock` + +Some operations require a response argument (because they have no default example value). The `onMissingMock` option controls what happens for these operations: + +- `'skip'` (default) — skips handlers that require an argument, only including operations that have default values or no response type +- `'error'` — includes all handlers, but operations without a provided response return a `501` error with the message `'[heyapi-msw] The mock of this request is not implemented.'` + +```ts +// strict mode: all endpoints are mocked, missing ones return 501 +const server = setupServer(...getAllMocks({ onMissingMock: 'error' })); +``` + +#### `overrides` + +Use `overrides` to provide static responses for specific operations. The keys are handler names (operation ID suffixed with `Mock`) and the values are the same as what you'd pass to the individual handler creator. + +```ts +import { setupServer } from 'msw/node'; +import { getAllMocks } from './client/msw.gen'; + +const server = setupServer( + ...getAllMocks({ + onMissingMock: 'skip', + overrides: { + getPetByIdMock: { + result: { id: 1, name: 'Fido', photoUrls: [] }, + }, + }, + }), +); +``` + +When an override is provided for a required handler, it will always be included regardless of the `onMissingMock` setting. + +### Custom Base URL + +The individually exported handlers use a wildcard (`*`) base URL that matches requests regardless of origin. If you need handlers bound to a specific base URL, use the `createMswHandlerFactory` function: + +```ts +import { setupServer } from 'msw/node'; +import { createMswHandlerFactory } from './client/msw.gen'; + +const createMock = createMswHandlerFactory({ + baseUrl: 'http://localhost:8000', +}); + +const server = setupServer(createMock.getPetByIdMock({ result: { id: 1, name: 'Fido' } })); +``` + +When called without arguments, the factory infers the base URL from the OpenAPI spec's `servers` field. + +### Handler Options + +[Handler options](https://mswjs.io/docs/api/http#handler-options) can be provided. The object will be passed on to MSW helpers. + +```ts +const mockServer = setupServer(getPetByIdMock({ result: { id: 1, name: 'Fido' } }, { once: true })); +``` + +## Known Limitations + +- Query parameters are not typed in the resolver. MSW doesn't provide typed query params natively — use `new URL(request.url).searchParams` instead. +- The response type generic is omitted from `HttpResponseResolver` to avoid MSW's `DefaultBodyType` constraint issues with union and void response types. + +## API + +You can view the complete list of options in the [UserConfig](https://github.com/hey-api/openapi-ts/blob/main/packages/openapi-ts/src/plugins/msw/types.ts) interface. + + diff --git a/examples/openapi-ts-fetch/openapi-ts.config.ts b/examples/openapi-ts-fetch/openapi-ts.config.ts index acb2c6549c..535ba57340 100644 --- a/examples/openapi-ts-fetch/openapi-ts.config.ts +++ b/examples/openapi-ts-fetch/openapi-ts.config.ts @@ -18,5 +18,6 @@ export default defineConfig({ enums: 'javascript', name: '@hey-api/typescript', }, + 'msw', ], }); diff --git a/examples/openapi-ts-fetch/package.json b/examples/openapi-ts-fetch/package.json index 165a1e265a..b95dacc250 100644 --- a/examples/openapi-ts-fetch/package.json +++ b/examples/openapi-ts-fetch/package.json @@ -9,6 +9,7 @@ "lint": "eslint . --report-unused-disable-directives --max-warnings 0", "openapi-ts": "openapi-ts", "preview": "vite preview", + "test": "vitest run", "typecheck": "tsgo --noEmit" }, "dependencies": { @@ -29,10 +30,12 @@ "eslint": "9.17.0", "eslint-plugin-react-hooks": "5.2.0", "eslint-plugin-react-refresh": "0.4.7", + "msw": "2.10.2", "oxfmt": "0.27.0", "postcss": "8.4.41", "tailwindcss": "3.4.9", "typescript": "5.9.3", - "vite": "7.3.1" + "vite": "7.3.1", + "vitest": "4.0.18" } } diff --git a/examples/openapi-ts-fetch/src/client/msw.gen.ts b/examples/openapi-ts-fetch/src/client/msw.gen.ts new file mode 100644 index 0000000000..3730745d52 --- /dev/null +++ b/examples/openapi-ts-fetch/src/client/msw.gen.ts @@ -0,0 +1,551 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { + http, + type HttpHandler, + HttpResponse, + type HttpResponseResolver, + type RequestHandlerOptions, +} from 'msw'; + +import type { + AddPetData, + AddPetResponses, + CreateUserData, + CreateUserResponses, + CreateUsersWithListInputData, + CreateUsersWithListInputResponses, + DeleteOrderResponses, + DeletePetResponses, + DeleteUserResponses, + FindPetsByStatusResponses, + FindPetsByTagsResponses, + GetInventoryResponses, + GetOrderByIdResponses, + GetPetByIdResponses, + GetUserByNameResponses, + LoginUserResponses, + LogoutUserResponses, + PlaceOrderData, + PlaceOrderResponses, + UpdatePetData, + UpdatePetResponses, + UpdatePetWithFormResponses, + UpdateUserData, + UpdateUserResponses, + UploadFileData, + UploadFileResponses, +} from './types.gen'; + +const resolveToNull = () => new HttpResponse(null); + +type ToResponseUnion = { + [K in Extract]: { + result: T[K]; + status: K; + }; +}[Extract]; + +type HttpHandlerFactory = ( + responseOrResolver: ResponseOrResolver, + options?: RequestHandlerOptions, +) => HttpHandler; + +type OptionalHttpHandlerFactory = ( + responseOrResolver?: ResponseOrResolver, + options?: RequestHandlerOptions, +) => HttpHandler; + +export type SingleHandlerFactories = { + addPetMock: HttpHandlerFactory< + | { + result: AddPetResponses[200]; + status?: 200; + } + | ToResponseUnion + | HttpResponseResolver + >; + createUserMock: HttpHandlerFactory< + | { + result: CreateUserResponses[200]; + status?: 200; + } + | ToResponseUnion + | HttpResponseResolver + >; + createUsersWithListInputMock: HttpHandlerFactory< + | { + result: CreateUsersWithListInputResponses[200]; + status?: 200; + } + | ToResponseUnion + | HttpResponseResolver + >; + deleteOrderMock: OptionalHttpHandlerFactory< + | { + result: DeleteOrderResponses[200]; + status?: 200; + } + | ToResponseUnion + | HttpResponseResolver< + { + orderId: string; + }, + never + > + >; + deletePetMock: OptionalHttpHandlerFactory< + | { + result: DeletePetResponses[200]; + status?: 200; + } + | ToResponseUnion + | HttpResponseResolver< + { + petId: string; + }, + never + > + >; + deleteUserMock: OptionalHttpHandlerFactory< + | { + result: DeleteUserResponses[200]; + status?: 200; + } + | ToResponseUnion + | HttpResponseResolver< + { + username: string; + }, + never + > + >; + findPetsByStatusMock: HttpHandlerFactory< + | { + result: FindPetsByStatusResponses[200]; + status?: 200; + } + | ToResponseUnion + | HttpResponseResolver + >; + findPetsByTagsMock: HttpHandlerFactory< + | { + result: FindPetsByTagsResponses[200]; + status?: 200; + } + | ToResponseUnion + | HttpResponseResolver + >; + getInventoryMock: HttpHandlerFactory< + | { + result: GetInventoryResponses[200]; + status?: 200; + } + | ToResponseUnion + | HttpResponseResolver + >; + getOrderByIdMock: HttpHandlerFactory< + | { + result: GetOrderByIdResponses[200]; + status?: 200; + } + | ToResponseUnion + | HttpResponseResolver< + { + orderId: string; + }, + never + > + >; + getPetByIdMock: HttpHandlerFactory< + | { + result: GetPetByIdResponses[200]; + status?: 200; + } + | ToResponseUnion + | HttpResponseResolver< + { + petId: string; + }, + never + > + >; + getUserByNameMock: HttpHandlerFactory< + | { + result: GetUserByNameResponses[200]; + status?: 200; + } + | ToResponseUnion + | HttpResponseResolver< + { + username: string; + }, + never + > + >; + loginUserMock: HttpHandlerFactory< + | { + result: LoginUserResponses[200]; + status?: 200; + } + | ToResponseUnion + | HttpResponseResolver + >; + logoutUserMock: OptionalHttpHandlerFactory< + | { + result: LogoutUserResponses[200]; + status?: 200; + } + | ToResponseUnion + | HttpResponseResolver + >; + placeOrderMock: HttpHandlerFactory< + | { + result: PlaceOrderResponses[200]; + status?: 200; + } + | ToResponseUnion + | HttpResponseResolver + >; + updatePetMock: HttpHandlerFactory< + | { + result: UpdatePetResponses[200]; + status?: 200; + } + | ToResponseUnion + | HttpResponseResolver + >; + updatePetWithFormMock: HttpHandlerFactory< + | { + result: UpdatePetWithFormResponses[200]; + status?: 200; + } + | ToResponseUnion + | HttpResponseResolver< + { + petId: string; + }, + never + > + >; + updateUserMock: OptionalHttpHandlerFactory< + | { + result: UpdateUserResponses[200]; + status?: 200; + } + | ToResponseUnion + | HttpResponseResolver< + { + username: string; + }, + UpdateUserData['body'] + > + >; + uploadFileMock: HttpHandlerFactory< + | { + result: UploadFileResponses[200]; + status?: 200; + } + | ToResponseUnion + | HttpResponseResolver< + { + petId: string; + }, + UploadFileData['body'] + > + >; +}; + +export type GetAllMocksOptions = { + onMissingMock?: 'error' | 'skip'; + overrides?: { + [K in keyof SingleHandlerFactories]?: Parameters[0]; + }; +}; + +export type MswHandlerFactory = SingleHandlerFactories & { + getAllMocks: (options?: GetAllMocksOptions) => Array; +}; + +export const createMswHandlerFactory = (config?: { baseUrl?: string }): MswHandlerFactory => { + const baseUrl = config?.baseUrl ?? 'https://petstore3.swagger.io/api/v3'; + const mocks: SingleHandlerFactories = { + addPetMock: (res, options) => + http.post( + `${baseUrl}${'/pet'}`, + typeof res === 'object' && res.result + ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) + : typeof res === 'function' + ? res + : resolveToNull, + options, + ), + createUserMock: (res, options) => + http.post( + `${baseUrl}${'/user'}`, + typeof res === 'object' && res.result + ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) + : typeof res === 'function' + ? res + : resolveToNull, + options, + ), + createUsersWithListInputMock: (res, options) => + http.post( + `${baseUrl}${'/user/createWithList'}`, + typeof res === 'object' && res.result + ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) + : typeof res === 'function' + ? res + : resolveToNull, + options, + ), + deleteOrderMock: (res, options) => + http.delete( + `${baseUrl}${'/store/order/:orderId'}`, + typeof res === 'object' && res.result + ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 200 }) + : typeof res === 'function' + ? res + : resolveToNull, + options, + ), + deletePetMock: (res, options) => + http.delete( + `${baseUrl}${'/pet/:petId'}`, + typeof res === 'object' && res.result + ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 200 }) + : typeof res === 'function' + ? res + : resolveToNull, + options, + ), + deleteUserMock: (res, options) => + http.delete( + `${baseUrl}${'/user/:username'}`, + typeof res === 'object' && res.result + ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 200 }) + : typeof res === 'function' + ? res + : resolveToNull, + options, + ), + findPetsByStatusMock: (res, options) => + http.get( + `${baseUrl}${'/pet/findByStatus'}`, + typeof res === 'object' && res.result + ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) + : typeof res === 'function' + ? res + : resolveToNull, + options, + ), + findPetsByTagsMock: (res, options) => + http.get( + `${baseUrl}${'/pet/findByTags'}`, + typeof res === 'object' && res.result + ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) + : typeof res === 'function' + ? res + : resolveToNull, + options, + ), + getInventoryMock: (res, options) => + http.get( + `${baseUrl}${'/store/inventory'}`, + typeof res === 'object' && res.result + ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) + : typeof res === 'function' + ? res + : resolveToNull, + options, + ), + getOrderByIdMock: (res, options) => + http.get( + `${baseUrl}${'/store/order/:orderId'}`, + typeof res === 'object' && res.result + ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) + : typeof res === 'function' + ? res + : resolveToNull, + options, + ), + getPetByIdMock: (res, options) => + http.get( + `${baseUrl}${'/pet/:petId'}`, + typeof res === 'object' && res.result + ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) + : typeof res === 'function' + ? res + : resolveToNull, + options, + ), + getUserByNameMock: (res, options) => + http.get( + `${baseUrl}${'/user/:username'}`, + typeof res === 'object' && res.result + ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) + : typeof res === 'function' + ? res + : resolveToNull, + options, + ), + loginUserMock: (res, options) => + http.get( + `${baseUrl}${'/user/login'}`, + typeof res === 'object' && res.result + ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) + : typeof res === 'function' + ? res + : resolveToNull, + options, + ), + logoutUserMock: (res, options) => + http.get( + `${baseUrl}${'/user/logout'}`, + typeof res === 'object' && res.result + ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 200 }) + : typeof res === 'function' + ? res + : resolveToNull, + options, + ), + placeOrderMock: (res, options) => + http.post( + `${baseUrl}${'/store/order'}`, + typeof res === 'object' && res.result + ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) + : typeof res === 'function' + ? res + : resolveToNull, + options, + ), + updatePetMock: (res, options) => + http.put( + `${baseUrl}${'/pet'}`, + typeof res === 'object' && res.result + ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) + : typeof res === 'function' + ? res + : resolveToNull, + options, + ), + updatePetWithFormMock: (res, options) => + http.post( + `${baseUrl}${'/pet/:petId'}`, + typeof res === 'object' && res.result + ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) + : typeof res === 'function' + ? res + : resolveToNull, + options, + ), + updateUserMock: (res, options) => + http.put( + `${baseUrl}${'/user/:username'}`, + typeof res === 'object' && res.result + ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 200 }) + : typeof res === 'function' + ? res + : resolveToNull, + options, + ), + uploadFileMock: (res, options) => + http.post( + `${baseUrl}${'/pet/:petId/uploadImage'}`, + typeof res === 'object' && res.result + ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) + : typeof res === 'function' + ? res + : resolveToNull, + options, + ), + }; + const getAllMocks = (options?: GetAllMocksOptions): Array => { + const onMissingMock = options?.onMissingMock ?? 'skip'; + const overrides = options?.overrides; + const handlers: Array = []; + const addRequiredHandler = ( + handler: (value: Value | (() => HttpResponse)) => HttpHandler, + override: Value | undefined, + ) => { + if (override != null) { + handlers.push(handler(override)); + } else { + if (onMissingMock === 'error') { + handlers.push( + handler( + () => + new HttpResponse('[heyapi-msw] The mock of this request is not implemented.', { + status: 501, + }), + ), + ); + } + } + }; + addRequiredHandler(mocks.addPetMock, overrides?.addPetMock); + addRequiredHandler(mocks.updatePetMock, overrides?.updatePetMock); + addRequiredHandler(mocks.findPetsByStatusMock, overrides?.findPetsByStatusMock); + addRequiredHandler(mocks.findPetsByTagsMock, overrides?.findPetsByTagsMock); + handlers.push(mocks.deletePetMock(overrides?.deletePetMock)); + addRequiredHandler(mocks.getPetByIdMock, overrides?.getPetByIdMock); + addRequiredHandler(mocks.updatePetWithFormMock, overrides?.updatePetWithFormMock); + addRequiredHandler(mocks.uploadFileMock, overrides?.uploadFileMock); + addRequiredHandler(mocks.getInventoryMock, overrides?.getInventoryMock); + addRequiredHandler(mocks.placeOrderMock, overrides?.placeOrderMock); + handlers.push(mocks.deleteOrderMock(overrides?.deleteOrderMock)); + addRequiredHandler(mocks.getOrderByIdMock, overrides?.getOrderByIdMock); + addRequiredHandler(mocks.createUserMock, overrides?.createUserMock); + addRequiredHandler(mocks.createUsersWithListInputMock, overrides?.createUsersWithListInputMock); + addRequiredHandler(mocks.loginUserMock, overrides?.loginUserMock); + handlers.push(mocks.logoutUserMock(overrides?.logoutUserMock)); + handlers.push(mocks.deleteUserMock(overrides?.deleteUserMock)); + addRequiredHandler(mocks.getUserByNameMock, overrides?.getUserByNameMock); + handlers.push(mocks.updateUserMock(overrides?.updateUserMock)); + return handlers; + }; + return { ...mocks, getAllMocks }; +}; + +const _defaults = createMswHandlerFactory({ baseUrl: '*' }); + +export const addPetMock = _defaults.addPetMock; + +export const updatePetMock = _defaults.updatePetMock; + +export const findPetsByStatusMock = _defaults.findPetsByStatusMock; + +export const findPetsByTagsMock = _defaults.findPetsByTagsMock; + +export const deletePetMock = _defaults.deletePetMock; + +export const getPetByIdMock = _defaults.getPetByIdMock; + +export const updatePetWithFormMock = _defaults.updatePetWithFormMock; + +export const uploadFileMock = _defaults.uploadFileMock; + +export const getInventoryMock = _defaults.getInventoryMock; + +export const placeOrderMock = _defaults.placeOrderMock; + +export const deleteOrderMock = _defaults.deleteOrderMock; + +export const getOrderByIdMock = _defaults.getOrderByIdMock; + +export const createUserMock = _defaults.createUserMock; + +export const createUsersWithListInputMock = _defaults.createUsersWithListInputMock; + +export const loginUserMock = _defaults.loginUserMock; + +export const logoutUserMock = _defaults.logoutUserMock; + +export const deleteUserMock = _defaults.deleteUserMock; + +export const getUserByNameMock = _defaults.getUserByNameMock; + +export const updateUserMock = _defaults.updateUserMock; + +export const getAllMocks = _defaults.getAllMocks; diff --git a/examples/openapi-ts-fetch/test/msw-types.test-d.ts b/examples/openapi-ts-fetch/test/msw-types.test-d.ts new file mode 100644 index 0000000000..574e767dfc --- /dev/null +++ b/examples/openapi-ts-fetch/test/msw-types.test-d.ts @@ -0,0 +1,165 @@ +import { type HttpHandler, HttpResponse } from 'msw'; +import { describe, expectTypeOf, it } from 'vitest'; + +import { createMswHandlerFactory } from '../src/client/msw.gen'; +import type { Order, Pet } from '../src/client/types.gen'; + +const createMock = createMswHandlerFactory(); + +describe('MSW plugin type-level tests', () => { + describe('static response values', () => { + it('accepts correct response type (Pet) with status', () => { + const pet: Pet = { name: 'Fido', photoUrls: [] }; + createMock.getPetByIdMock({ result: pet, status: 200 }); + createMock.addPetMock({ result: pet, status: 200 }); + createMock.updatePetMock({ result: pet, status: 200 }); + createMock.findPetsByStatusMock({ result: [pet], status: 200 }); + }); + + it('accepts correct response type (Order) with status', () => { + const order: Order = { id: 1, petId: 1, quantity: 1 }; + createMock.placeOrderMock({ result: order, status: 200 }); + createMock.getOrderByIdMock({ result: order, status: 200 }); + }); + + it('accepts correct response type (string) with status', () => { + createMock.loginUserMock({ result: 'session-token', status: 200 }); + }); + + it('accepts correct response type (record) with status', () => { + createMock.getInventoryMock({ result: { available: 10, pending: 5 }, status: 200 }); + }); + + it('rejects wrong response type for getPetById', () => { + // @ts-expect-error - string is not a valid Pet response + createMock.getPetByIdMock({ result: 'wrong type', status: 200 }); + }); + + it('rejects wrong response type for addPet', () => { + // @ts-expect-error - number is not a valid Pet response + createMock.addPetMock({ result: 42, status: 200 }); + }); + + it('rejects wrong response type for findPetsByStatus', () => { + // @ts-expect-error - a single Pet is not Array + createMock.findPetsByStatusMock({ result: { name: 'Fido', photoUrls: [] }, status: 200 }); + }); + + it('rejects wrong response type for placeOrder', () => { + // @ts-expect-error - Pet is not a valid Order response + createMock.placeOrderMock({ result: { name: 'Fido', photoUrls: [] }, status: 200 }); + }); + + it('rejects wrong response type for loginUser', () => { + // @ts-expect-error - number is not a valid string response + createMock.loginUserMock({ result: 123, status: 200 }); + }); + + it('rejects wrong status code', () => { + const pet: Pet = { name: 'Fido', photoUrls: [] }; + // @ts-expect-error - 999 is not a valid status code + createMock.getPetByIdMock({ result: pet, status: 999 }); + }); + + it('accepts result without status (uses dominant response default)', () => { + const pet: Pet = { name: 'Fido', photoUrls: [] }; + createMock.getPetByIdMock({ result: pet }); + createMock.addPetMock({ result: pet }); + createMock.updatePetMock({ result: pet }); + createMock.findPetsByStatusMock({ result: [pet] }); + }); + + it('accepts result without status for Order operations', () => { + const order: Order = { id: 1, petId: 1, quantity: 1 }; + createMock.placeOrderMock({ result: order }); + createMock.getOrderByIdMock({ result: order }); + }); + + it('accepts result without status for string response', () => { + createMock.loginUserMock({ result: 'session-token' }); + }); + + it('accepts result without status for record response', () => { + createMock.getInventoryMock({ result: { available: 10, pending: 5 } }); + }); + + it('rejects wrong response type even without status', () => { + // @ts-expect-error - string is not a valid Pet response + createMock.getPetByIdMock({ result: 'wrong type' }); + }); + }); + + describe('void operations accept no arguments', () => { + it('logoutUser accepts no arguments', () => { + createMock.logoutUserMock(); + }); + + it('deletePet accepts no arguments', () => { + createMock.deletePetMock(); + }); + + it('deleteOrder accepts no arguments', () => { + createMock.deleteOrderMock(); + }); + + it('deleteUser accepts no arguments', () => { + createMock.deleteUserMock(); + }); + }); + + describe('resolver function typing', () => { + it('accepts HttpResponseResolver', () => { + createMock.getInventoryMock(() => HttpResponse.json({ available: 1 })); + }); + + it('accepts async HttpResponseResolver', () => { + createMock.getInventoryMock(async () => HttpResponse.json({ available: 1 })); + }); + + it('resolver for path-param operation receives typed params', () => { + createMock.getPetByIdMock(({ params }) => { + // params.petId should be string (StringifyPathParams) + expectTypeOf(params.petId).toEqualTypeOf(); + return HttpResponse.json({ name: 'Test', photoUrls: [] }); + }); + }); + + it('resolver for body operation receives typed body via request', () => { + createMock.addPetMock(async ({ request }) => { + const body = await request.json(); + // body should be typed as Pet (AddPetData['body']) + expectTypeOf(body).toEqualTypeOf(); + return HttpResponse.json({ name: body.name, photoUrls: body.photoUrls }); + }); + }); + + it('resolver for void operation is typed correctly', () => { + createMock.logoutUserMock(() => HttpResponse.json(null)); + }); + + it('resolver for void operation with path params', () => { + createMock.deletePetMock(({ params }) => { + expectTypeOf(params.petId).toEqualTypeOf(); + return new HttpResponse(null); + }); + }); + }); + + describe('return type', () => { + it('all handler creators return HttpHandler', () => { + const handler = createMock.getPetByIdMock({ + result: { name: 'Test', photoUrls: [] }, + status: 200, + }); + expectTypeOf(handler).toExtend(); + }); + }); + + describe('factory configuration', () => { + it('accepts optional config', () => { + createMswHandlerFactory(); + createMswHandlerFactory({}); + createMswHandlerFactory({ baseUrl: 'http://localhost:3000' }); + }); + }); +}); diff --git a/examples/openapi-ts-fetch/test/msw.test.ts b/examples/openapi-ts-fetch/test/msw.test.ts new file mode 100644 index 0000000000..ce47f08fdf --- /dev/null +++ b/examples/openapi-ts-fetch/test/msw.test.ts @@ -0,0 +1,303 @@ +import { HttpResponse } from 'msw'; +import { setupServer } from 'msw/node'; +import { afterAll, afterEach, beforeAll, describe, expect, it } from 'vitest'; + +import { client } from '../src/client/client.gen'; +import { createMswHandlerFactory } from '../src/client/msw.gen'; +import { + addPet, + findPetsByStatus, + getInventory, + getOrderById, + getPetById, + getUserByName, + uploadFile, +} from '../src/client/sdk.gen'; +import type { Pet } from '../src/client/types.gen'; + +const BASE_URL = 'http://localhost:3000/api/v3'; + +const createMock = createMswHandlerFactory({ baseUrl: BASE_URL }); + +const server = setupServer(); + +beforeAll(() => { + client.setConfig({ baseUrl: BASE_URL }); + server.listen({ onUnhandledRequest: 'error' }); +}); + +afterEach(() => { + server.resetHandlers(); +}); + +afterAll(() => { + server.close(); +}); + +describe('MSW plugin runtime tests', () => { + describe('static response value', () => { + it('returns static response for GET without path params', async () => { + const mockInventory = { available: 10, pending: 5 }; + server.use(createMock.getInventoryMock({ result: mockInventory, status: 200 })); + + const result = await getInventory({ client }); + + expect(result.data).toEqual(mockInventory); + }); + + it('returns static response for GET with path params', async () => { + const mockPet: Pet = { + id: 1, + name: 'Fido', + photoUrls: ['https://example.com/fido.jpg'], + status: 'available', + }; + server.use(createMock.getPetByIdMock({ result: mockPet, status: 200 })); + + const result = await getPetById({ + client, + path: { petId: 1 }, + }); + + expect(result.data).toEqual(mockPet); + }); + + it('returns static response for GET with query params', async () => { + const mockPets: Pet[] = [ + { id: 1, name: 'Fido', photoUrls: [], status: 'available' }, + { id: 2, name: 'Rex', photoUrls: [], status: 'available' }, + ]; + server.use(createMock.findPetsByStatusMock({ result: mockPets, status: 200 })); + + const result = await findPetsByStatus({ + client, + query: { status: 'available' }, + }); + + expect(result.data).toEqual(mockPets); + }); + + it('returns static response for POST with body', async () => { + const mockPet: Pet = { + id: 10, + name: 'NewPet', + photoUrls: ['https://example.com/new.jpg'], + status: 'pending', + }; + server.use(createMock.addPetMock({ result: mockPet, status: 200 })); + + const result = await addPet({ + body: { + name: 'NewPet', + photoUrls: ['https://example.com/new.jpg'], + }, + client, + }); + + expect(result.data).toEqual(mockPet); + }); + }); + + describe('static response without status (dominant response default)', () => { + it('returns correct data when status is omitted', async () => { + const mockPet: Pet = { + id: 1, + name: 'Fido', + photoUrls: ['https://example.com/fido.jpg'], + status: 'available', + }; + server.use(createMock.getPetByIdMock({ result: mockPet })); + + const result = await getPetById({ + client, + path: { petId: 1 }, + }); + + expect(result.data).toEqual(mockPet); + }); + + it('returns correct data for POST when status is omitted', async () => { + const mockPet: Pet = { + id: 10, + name: 'NewPet', + photoUrls: ['https://example.com/new.jpg'], + status: 'pending', + }; + server.use(createMock.addPetMock({ result: mockPet })); + + const result = await addPet({ + body: { + name: 'NewPet', + photoUrls: ['https://example.com/new.jpg'], + }, + client, + }); + + expect(result.data).toEqual(mockPet); + }); + }); + + describe('custom resolver function', () => { + it('supports custom resolver for GET', async () => { + server.use( + createMock.getPetByIdMock(({ params }) => + HttpResponse.json({ + id: Number(params.petId), + name: `Pet-${params.petId}`, + photoUrls: [], + status: 'available', + }), + ), + ); + + const result = await getPetById({ + client, + path: { petId: 42 }, + }); + + expect(result.data).toEqual({ + id: 42, + name: 'Pet-42', + photoUrls: [], + status: 'available', + }); + }); + + it('supports custom resolver with request body', async () => { + server.use( + createMock.addPetMock(async ({ request }) => { + const body = await request.json(); + return HttpResponse.json({ + id: 99, + ...body, + }); + }), + ); + + const result = await addPet({ + body: { + name: 'EchoedPet', + photoUrls: ['https://example.com/echo.jpg'], + }, + client, + }); + + expect(result.data).toMatchObject({ + id: 99, + name: 'EchoedPet', + }); + }); + + it('supports custom status codes', async () => { + server.use( + createMock.getPetByIdMock(() => + HttpResponse.json({ message: 'not found' }, { status: 404 }), + ), + ); + + const result = await getPetById({ + client, + path: { petId: 999 }, + }); + + expect(result.response.status).toBe(404); + expect(result.error).toEqual({ message: 'not found' }); + }); + }); + + describe('toMswPath conversion', () => { + it('handles numeric path param (e.g. /pet/{petId})', async () => { + const mockPet: Pet = { + id: 5, + name: 'PathTest', + photoUrls: [], + }; + server.use(createMock.getPetByIdMock({ result: mockPet, status: 200 })); + + const result = await getPetById({ + client, + path: { petId: 5 }, + }); + + expect(result.response.ok).toBe(true); + expect(result.data).toEqual(mockPet); + }); + + it('handles string path param (e.g. /user/{username})', async () => { + const mockUser = { + email: 'john@example.com', + firstName: 'John', + id: 1, + lastName: 'Doe', + username: 'john_doe', + }; + server.use(createMock.getUserByNameMock({ result: mockUser, status: 200 })); + + const result = await getUserByName({ + client, + path: { username: 'john_doe' }, + }); + + expect(result.response.ok).toBe(true); + expect(result.data).toEqual(mockUser); + }); + + it('handles path param mid-path (e.g. /pet/{petId}/uploadImage)', async () => { + const mockResponse = { code: 200, message: 'uploaded', type: 'ok' }; + server.use(createMock.uploadFileMock({ result: mockResponse, status: 200 })); + + const result = await uploadFile({ + body: new Blob(['fake-image']), + client, + path: { petId: 7 }, + }); + + expect(result.response.ok).toBe(true); + expect(result.data).toEqual(mockResponse); + }); + + it('resolver receives correct path param values', async () => { + server.use( + createMock.getOrderByIdMock(({ params }) => { + // MSW normalizes path params to strings + expect(typeof params.orderId).toBe('string'); + return HttpResponse.json({ + complete: false, + id: Number(params.orderId), + petId: 1, + quantity: 1, + status: 'placed', + }); + }), + ); + + const result = await getOrderById({ + client, + path: { orderId: 123 }, + }); + + expect(result.data).toMatchObject({ id: 123 }); + }); + }); + + describe('handler override', () => { + it('later handlers override earlier ones', async () => { + server.use(createMock.getInventoryMock({ result: { available: 1 }, status: 200 })); + server.use(createMock.getInventoryMock({ result: { available: 999 }, status: 200 })); + + const result = await getInventory({ client }); + + expect(result.data).toEqual({ available: 999 }); + }); + }); + + describe('void operations', () => { + it('handles operations with no response body', async () => { + server.use(createMock.logoutUserMock()); + + const result = await (await import('../src/client/sdk.gen')).logoutUser({ client }); + + expect(result.response.ok).toBe(true); + }); + }); +}); diff --git a/examples/openapi-ts-fetch/vitest.config.ts b/examples/openapi-ts-fetch/vitest.config.ts new file mode 100644 index 0000000000..052a593edc --- /dev/null +++ b/examples/openapi-ts-fetch/vitest.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + environment: 'node', + typecheck: { + enabled: true, + }, + }, +}); diff --git a/packages/openapi-ts-tests/main/package.json b/packages/openapi-ts-tests/main/package.json index 42841f4be3..824f42d5bb 100644 --- a/packages/openapi-ts-tests/main/package.json +++ b/packages/openapi-ts-tests/main/package.json @@ -36,6 +36,7 @@ "eslint": "9.39.1", "fastify": "5.7.4", "ky": "1.14.3", + "msw": "2.10.2", "node-fetch": "3.3.2", "nuxt": "3.14.1592", "ofetch": "1.5.1", diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/index.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/index.ts new file mode 100644 index 0000000000..c42215da06 --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/index.ts @@ -0,0 +1,3 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type { ArrayWithArray, ArrayWithBooleans, ArrayWithNumbers, ArrayWithProperties, ArrayWithReferences, ArrayWithStrings, CallToTestOrderOfParamsData, CallWithDefaultOptionalParametersData, CallWithDefaultParametersData, CallWithDescriptionsData, CallWithDuplicateResponsesData, CallWithDuplicateResponsesError, CallWithDuplicateResponsesErrors, CallWithDuplicateResponsesResponse, CallWithDuplicateResponsesResponses, CallWithNoContentResponseData, CallWithNoContentResponseResponses, CallWithParametersData, CallWithResponseAndNoContentResponseData, CallWithResponseAndNoContentResponseResponse, CallWithResponseAndNoContentResponseResponses, CallWithResponseData, CallWithResponseResponse, CallWithResponseResponses, CallWithResponsesData, CallWithResponsesError, CallWithResponsesErrors, CallWithResponsesResponse, CallWithResponsesResponses, CallWithResultFromHeaderData, CallWithResultFromHeaderErrors, CallWithResultFromHeaderResponses, CallWithWeirdParameterNamesData, ClientOptions, CollectionFormatData, CommentWithBackticks, CommentWithBackticksAndQuotes, CommentWithBreaks, CommentWithExpressionPlaceholders, CommentWithQuotes, CommentWithReservedCharacters, CommentWithSlashes, ComplexTypesData, ComplexTypesErrors, ComplexTypesResponse, ComplexTypesResponses, Date, Default, DeleteCallWithoutParametersAndResponseData, DictionaryWithArray, DictionaryWithDictionary, DictionaryWithProperties, DictionaryWithReference, DictionaryWithString, DummyAData, DummyAResponses, DummyBData, DummyBResponses, DuplicateName2Data, DuplicateName3Data, DuplicateName4Data, DuplicateNameData, EnumFromDescription, EnumWithExtensions, EnumWithNumbers, EnumWithStrings, ExternalRefA, ExternalRefB, ExternalSharedModel, FailureFailure, FooWowData, FooWowResponses, GetCallWithoutParametersAndResponseData, HeadCallWithoutParametersAndResponseData, ModelThatExtends, ModelThatExtendsExtends, ModelWithArray, ModelWithBoolean, ModelWithCircularReference, ModelWithDictionary, ModelWithDuplicateImports, ModelWithDuplicateProperties, ModelWithEnum, ModelWithEnumFromDescription, ModelWithInteger, ModelWithNestedEnums, ModelWithNestedProperties, ModelWithNullableString, ModelWithOrderedProperties, ModelWithPattern, ModelWithPatternWritable, ModelWithProperties, ModelWithPropertiesWritable, ModelWithReference, ModelWithReferenceWritable, ModelWithString, ModelWithStringError, NonAsciiæøåÆøÅöôêÊ字符串Data, NonAsciiæøåÆøÅöôêÊ字符串Response, NonAsciiæøåÆøÅöôêÊ字符串Responses, NonAsciiStringæøåÆøÅöôêÊ字符串, OptionsCallWithoutParametersAndResponseData, ParameterActivityParams, PatchApiVbyApiVersionNoTagData, PatchApiVbyApiVersionNoTagResponses, PatchCallWithoutParametersAndResponseData, PostApiVbyApiVersionBodyData, PostApiVbyApiVersionBodyError, PostApiVbyApiVersionBodyErrors, PostApiVbyApiVersionBodyResponse, PostApiVbyApiVersionBodyResponses, PostCallWithoutParametersAndResponseData, PutCallWithoutParametersAndResponseData, ResponsePostActivityResponse, ServiceWithEmptyTagData, SimpleBoolean, SimpleFile, SimpleInteger, SimpleReference, SimpleString, SimpleStringWithPattern, TestErrorCodeData, TestErrorCodeErrors, TestErrorCodeResponses, TypesData, TypesResponse, TypesResponses } from './types.gen'; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/msw.gen.ts new file mode 100644 index 0000000000..1057a046f8 --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/msw.gen.ts @@ -0,0 +1,277 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions } from 'msw'; + +import type { CallWithDuplicateResponsesResponses, CallWithNoContentResponseResponses, CallWithResponseAndNoContentResponseResponses, CallWithResponsesResponses, CallWithResultFromHeaderResponses, CallWithWeirdParameterNamesData, ComplexTypesResponses, DummyAResponses, DummyBResponses, NonAsciiæøåÆøÅöôêÊ字符串Responses, PostApiVbyApiVersionBodyData, PostApiVbyApiVersionBodyResponses, TestErrorCodeResponses, TypesResponses } from './types.gen'; + +const resolveToNull = () => new HttpResponse(null); + +type OptionalHttpHandlerFactory = (responseOrResolver?: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; + +type ToResponseUnion = { + [K in Extract]: { + status: K; + result: T[K]; + }; +}[Extract]; + +type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; + +export type SingleHandlerFactories = { + serviceWithEmptyTagMock: OptionalHttpHandlerFactory; + patchApiVbyApiVersionNoTagMock: OptionalHttpHandlerFactory; + fooWowMock: OptionalHttpHandlerFactory; + deleteCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; + getCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; + headCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; + optionsCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; + patchCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; + postCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; + putCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; + callWithDescriptionsMock: OptionalHttpHandlerFactory; + callWithParametersMock: OptionalHttpHandlerFactory>; + callWithWeirdParameterNamesMock: OptionalHttpHandlerFactory>; + callWithDefaultParametersMock: OptionalHttpHandlerFactory; + callWithDefaultOptionalParametersMock: OptionalHttpHandlerFactory; + callToTestOrderOfParamsMock: OptionalHttpHandlerFactory; + duplicateNameMock: OptionalHttpHandlerFactory; + duplicateName2Mock: OptionalHttpHandlerFactory; + duplicateName3Mock: OptionalHttpHandlerFactory; + duplicateName4Mock: OptionalHttpHandlerFactory; + callWithNoContentResponseMock: OptionalHttpHandlerFactory<{ + result: CallWithNoContentResponseResponses[204]; + status?: 204; + } | ToResponseUnion | HttpResponseResolver>; + callWithResponseAndNoContentResponseMock: HttpHandlerFactory<{ + result: CallWithResponseAndNoContentResponseResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + dummyAMock: OptionalHttpHandlerFactory<{ + result: DummyAResponses[204]; + status?: 204; + } | ToResponseUnion | HttpResponseResolver>; + dummyBMock: OptionalHttpHandlerFactory<{ + result: DummyBResponses[204]; + status?: 204; + } | ToResponseUnion | HttpResponseResolver>; + callWithResponseMock: OptionalHttpHandlerFactory; + callWithDuplicateResponsesMock: HttpHandlerFactory<{ + result: CallWithDuplicateResponsesResponses[201]; + status?: 201; + } | ToResponseUnion | HttpResponseResolver>; + callWithResponsesMock: HttpHandlerFactory<{ + result: CallWithResponsesResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + collectionFormatMock: OptionalHttpHandlerFactory; + typesMock: HttpHandlerFactory<{ + result: TypesResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver<{ + apiVersion: string; + }, never>>; + complexTypesMock: HttpHandlerFactory<{ + result: ComplexTypesResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + callWithResultFromHeaderMock: OptionalHttpHandlerFactory<{ + result: CallWithResultFromHeaderResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + testErrorCodeMock: OptionalHttpHandlerFactory<{ + result: TestErrorCodeResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + nonAsciiæøåÆøÅöôêÊ字符串Mock: HttpHandlerFactory<{ + result: NonAsciiæøåÆøÅöôêÊ字符串Responses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + postApiVbyApiVersionBodyMock: HttpHandlerFactory<{ + result: PostApiVbyApiVersionBodyResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; +}; + +export type GetAllMocksOptions = { + onMissingMock?: 'error' | 'skip'; + overrides?: { + [K in keyof SingleHandlerFactories]?: Parameters[0]; + }; +}; + +export type MswHandlerFactory = SingleHandlerFactories & { + getAllMocks: (options?: GetAllMocksOptions) => Array; +}; + +export const createMswHandlerFactory = (config?: { + baseUrl?: string; +}): MswHandlerFactory => { + const baseUrl = config?.baseUrl ?? 'http://localhost:3000/base'; + const mocks: SingleHandlerFactories = { + serviceWithEmptyTagMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/no+tag'}`, typeof res === 'function' ? res : resolveToNull, options), + patchApiVbyApiVersionNoTagMock: (res, options) => http.patch(`${baseUrl}${'/api/v:apiVersion/no+tag'}`, typeof res === 'function' ? res : resolveToNull, options), + fooWowMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/no+tag'}`, typeof res === 'function' ? res : resolveToNull, options), + deleteCallWithoutParametersAndResponseMock: (res, options) => http.delete(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), + getCallWithoutParametersAndResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), + headCallWithoutParametersAndResponseMock: (res, options) => http.head(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), + optionsCallWithoutParametersAndResponseMock: (res, options) => http.options(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), + patchCallWithoutParametersAndResponseMock: (res, options) => http.patch(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), + postCallWithoutParametersAndResponseMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), + putCallWithoutParametersAndResponseMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), + callWithDescriptionsMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/descriptions/'}`, typeof res === 'function' ? res : resolveToNull, options), + callWithParametersMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/parameters/:parameterPath'}`, typeof res === 'function' ? res : resolveToNull, options), + callWithWeirdParameterNamesMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/parameters/:parameterPath1/:parameterPath2/:PARAMETERPATH3'}`, typeof res === 'function' ? res : resolveToNull, options), + callWithDefaultParametersMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/defaults'}`, typeof res === 'function' ? res : resolveToNull, options), + callWithDefaultOptionalParametersMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/defaults'}`, typeof res === 'function' ? res : resolveToNull, options), + callToTestOrderOfParamsMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/defaults'}`, typeof res === 'function' ? res : resolveToNull, options), + duplicateNameMock: (res, options) => http.delete(`${baseUrl}${'/api/v:apiVersion/duplicate'}`, typeof res === 'function' ? res : resolveToNull, options), + duplicateName2Mock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/duplicate'}`, typeof res === 'function' ? res : resolveToNull, options), + duplicateName3Mock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/duplicate'}`, typeof res === 'function' ? res : resolveToNull, options), + duplicateName4Mock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/duplicate'}`, typeof res === 'function' ? res : resolveToNull, options), + callWithNoContentResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/no-content'}`, typeof res === 'object' && res.result ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 204 }) : typeof res === 'function' ? res : resolveToNull, options), + callWithResponseAndNoContentResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/multiple-tags/response-and-no-content'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + dummyAMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/multiple-tags/a'}`, typeof res === 'object' && res.result ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 204 }) : typeof res === 'function' ? res : resolveToNull, options), + dummyBMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/multiple-tags/b'}`, typeof res === 'object' && res.result ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 204 }) : typeof res === 'function' ? res : resolveToNull, options), + callWithResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/response'}`, typeof res === 'function' ? res : resolveToNull, options), + callWithDuplicateResponsesMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/response'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 201 }) : typeof res === 'function' ? res : resolveToNull, options), + callWithResponsesMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/response'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + collectionFormatMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/collectionFormat'}`, typeof res === 'function' ? res : resolveToNull, options), + typesMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/types'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + complexTypesMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/complex'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + callWithResultFromHeaderMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/header'}`, typeof res === 'object' && res.result ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + testErrorCodeMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/error'}`, typeof res === 'object' && res.result ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + nonAsciiæøåÆøÅöôêÊ字符串Mock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/non-ascii-æøåÆØÅöôêÊ字符串'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + postApiVbyApiVersionBodyMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/body'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options) + }; + const getAllMocks = (options?: GetAllMocksOptions): Array => { + const onMissingMock = options?.onMissingMock ?? 'skip'; + const overrides = options?.overrides; + const handlers: Array = []; + const addRequiredHandler = (handler: (value: Value | (() => HttpResponse)) => HttpHandler, override: Value | undefined) => { + if (override != null) { + handlers.push(handler(override)); + } + else { + if (onMissingMock === 'error') { + handlers.push(handler(() => new HttpResponse('[heyapi-msw] The mock of this request is not implemented.', { status: 501 }))); + } + } + }; + handlers.push(mocks.serviceWithEmptyTagMock(overrides?.serviceWithEmptyTagMock)); + handlers.push(mocks.patchApiVbyApiVersionNoTagMock(overrides?.patchApiVbyApiVersionNoTagMock)); + handlers.push(mocks.fooWowMock(overrides?.fooWowMock)); + handlers.push(mocks.deleteCallWithoutParametersAndResponseMock(overrides?.deleteCallWithoutParametersAndResponseMock)); + handlers.push(mocks.getCallWithoutParametersAndResponseMock(overrides?.getCallWithoutParametersAndResponseMock)); + handlers.push(mocks.headCallWithoutParametersAndResponseMock(overrides?.headCallWithoutParametersAndResponseMock)); + handlers.push(mocks.optionsCallWithoutParametersAndResponseMock(overrides?.optionsCallWithoutParametersAndResponseMock)); + handlers.push(mocks.patchCallWithoutParametersAndResponseMock(overrides?.patchCallWithoutParametersAndResponseMock)); + handlers.push(mocks.postCallWithoutParametersAndResponseMock(overrides?.postCallWithoutParametersAndResponseMock)); + handlers.push(mocks.putCallWithoutParametersAndResponseMock(overrides?.putCallWithoutParametersAndResponseMock)); + handlers.push(mocks.callWithDescriptionsMock(overrides?.callWithDescriptionsMock)); + handlers.push(mocks.callWithParametersMock(overrides?.callWithParametersMock)); + handlers.push(mocks.callWithWeirdParameterNamesMock(overrides?.callWithWeirdParameterNamesMock)); + handlers.push(mocks.callWithDefaultParametersMock(overrides?.callWithDefaultParametersMock)); + handlers.push(mocks.callWithDefaultOptionalParametersMock(overrides?.callWithDefaultOptionalParametersMock)); + handlers.push(mocks.callToTestOrderOfParamsMock(overrides?.callToTestOrderOfParamsMock)); + handlers.push(mocks.duplicateNameMock(overrides?.duplicateNameMock)); + handlers.push(mocks.duplicateName2Mock(overrides?.duplicateName2Mock)); + handlers.push(mocks.duplicateName3Mock(overrides?.duplicateName3Mock)); + handlers.push(mocks.duplicateName4Mock(overrides?.duplicateName4Mock)); + handlers.push(mocks.callWithNoContentResponseMock(overrides?.callWithNoContentResponseMock)); + addRequiredHandler(mocks.callWithResponseAndNoContentResponseMock, overrides?.callWithResponseAndNoContentResponseMock); + handlers.push(mocks.dummyAMock(overrides?.dummyAMock)); + handlers.push(mocks.dummyBMock(overrides?.dummyBMock)); + handlers.push(mocks.callWithResponseMock(overrides?.callWithResponseMock)); + addRequiredHandler(mocks.callWithDuplicateResponsesMock, overrides?.callWithDuplicateResponsesMock); + addRequiredHandler(mocks.callWithResponsesMock, overrides?.callWithResponsesMock); + handlers.push(mocks.collectionFormatMock(overrides?.collectionFormatMock)); + addRequiredHandler(mocks.typesMock, overrides?.typesMock); + addRequiredHandler(mocks.complexTypesMock, overrides?.complexTypesMock); + handlers.push(mocks.callWithResultFromHeaderMock(overrides?.callWithResultFromHeaderMock)); + handlers.push(mocks.testErrorCodeMock(overrides?.testErrorCodeMock)); + addRequiredHandler(mocks.nonAsciiæøåÆøÅöôêÊ字符串Mock, overrides?.nonAsciiæøåÆøÅöôêÊ字符串Mock); + addRequiredHandler(mocks.postApiVbyApiVersionBodyMock, overrides?.postApiVbyApiVersionBodyMock); + return handlers; + }; + return { ...mocks, getAllMocks }; +}; + +const _defaults = createMswHandlerFactory({ baseUrl: '*' }); + +export const serviceWithEmptyTagMock = _defaults.serviceWithEmptyTagMock; + +export const patchApiVbyApiVersionNoTagMock = _defaults.patchApiVbyApiVersionNoTagMock; + +export const fooWowMock = _defaults.fooWowMock; + +export const deleteCallWithoutParametersAndResponseMock = _defaults.deleteCallWithoutParametersAndResponseMock; + +export const getCallWithoutParametersAndResponseMock = _defaults.getCallWithoutParametersAndResponseMock; + +export const headCallWithoutParametersAndResponseMock = _defaults.headCallWithoutParametersAndResponseMock; + +export const optionsCallWithoutParametersAndResponseMock = _defaults.optionsCallWithoutParametersAndResponseMock; + +export const patchCallWithoutParametersAndResponseMock = _defaults.patchCallWithoutParametersAndResponseMock; + +export const postCallWithoutParametersAndResponseMock = _defaults.postCallWithoutParametersAndResponseMock; + +export const putCallWithoutParametersAndResponseMock = _defaults.putCallWithoutParametersAndResponseMock; + +export const callWithDescriptionsMock = _defaults.callWithDescriptionsMock; + +export const callWithParametersMock = _defaults.callWithParametersMock; + +export const callWithWeirdParameterNamesMock = _defaults.callWithWeirdParameterNamesMock; + +export const callWithDefaultParametersMock = _defaults.callWithDefaultParametersMock; + +export const callWithDefaultOptionalParametersMock = _defaults.callWithDefaultOptionalParametersMock; + +export const callToTestOrderOfParamsMock = _defaults.callToTestOrderOfParamsMock; + +export const duplicateNameMock = _defaults.duplicateNameMock; + +export const duplicateName2Mock = _defaults.duplicateName2Mock; + +export const duplicateName3Mock = _defaults.duplicateName3Mock; + +export const duplicateName4Mock = _defaults.duplicateName4Mock; + +export const callWithNoContentResponseMock = _defaults.callWithNoContentResponseMock; + +export const callWithResponseAndNoContentResponseMock = _defaults.callWithResponseAndNoContentResponseMock; + +export const dummyAMock = _defaults.dummyAMock; + +export const dummyBMock = _defaults.dummyBMock; + +export const callWithResponseMock = _defaults.callWithResponseMock; + +export const callWithDuplicateResponsesMock = _defaults.callWithDuplicateResponsesMock; + +export const callWithResponsesMock = _defaults.callWithResponsesMock; + +export const collectionFormatMock = _defaults.collectionFormatMock; + +export const typesMock = _defaults.typesMock; + +export const complexTypesMock = _defaults.complexTypesMock; + +export const callWithResultFromHeaderMock = _defaults.callWithResultFromHeaderMock; + +export const testErrorCodeMock = _defaults.testErrorCodeMock; + +export const nonAsciiæøåÆøÅöôêÊ字符串Mock = _defaults.nonAsciiæøåÆøÅöôêÊ字符串Mock; + +export const postApiVbyApiVersionBodyMock = _defaults.postApiVbyApiVersionBodyMock; + +export const getAllMocks = _defaults.getAllMocks; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/types.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/types.gen.ts new file mode 100644 index 0000000000..d69b074040 --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/types.gen.ts @@ -0,0 +1,1190 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type ClientOptions = { + baseUrl: 'http://localhost:3000/base' | (string & {}); +}; + +export type ExternalRefA = ExternalSharedModel; + +export type ExternalRefB = ExternalSharedModel; + +/** + * Testing multiline comments in string: First line + * Second line + * + * Fourth line + */ +export type CommentWithBreaks = number; + +/** + * Testing backticks in string: `backticks` and ```multiple backticks``` should work + */ +export type CommentWithBackticks = number; + +/** + * Testing backticks and quotes in string: `backticks`, 'quotes', "double quotes" and ```multiple backticks``` should work + */ +export type CommentWithBackticksAndQuotes = number; + +/** + * Testing slashes in string: \backwards\\\ and /forwards/// should work + */ +export type CommentWithSlashes = number; + +/** + * Testing expression placeholders in string: ${expression} should work + */ +export type CommentWithExpressionPlaceholders = number; + +/** + * Testing quotes in string: 'single quote''' and "double quotes""" should work + */ +export type CommentWithQuotes = number; + +/** + * Testing reserved characters in string: * inline * and ** inline ** should work + */ +export type CommentWithReservedCharacters = number; + +/** + * This is a simple number + */ +export type SimpleInteger = number; + +/** + * This is a simple boolean + */ +export type SimpleBoolean = boolean; + +/** + * This is a simple string + */ +export type SimpleString = string; + +/** + * A string with non-ascii (unicode) characters valid in typescript identifiers (æøåÆØÅöÔèÈ字符串) + */ +export type NonAsciiStringæøåÆøÅöôêÊ字符串 = string; + +/** + * This is a simple file + */ +export type SimpleFile = Blob | File; + +export type SimpleReference = ModelWithString; + +/** + * This is a simple string + */ +export type SimpleStringWithPattern = string; + +/** + * This is a simple enum with strings + */ +export type EnumWithStrings = 'Success' | 'Warning' | 'Error' | '\'Single Quote\'' | '"Double Quotes"' | 'Non-ascii: øæåôöØÆÅÔÖ字符串'; + +/** + * This is a simple enum with numbers + */ +export type EnumWithNumbers = 1 | 2 | 3 | 1.1 | 1.2 | 1.3 | 100 | 200 | 300 | -100 | -200 | -300 | -1.1 | -1.2 | -1.3; + +/** + * Success=1,Warning=2,Error=3 + */ +export type EnumFromDescription = number; + +/** + * This is a simple enum with numbers + */ +export type EnumWithExtensions = 200 | 400 | 500; + +/** + * This is a simple array with numbers + */ +export type ArrayWithNumbers = Array; + +/** + * This is a simple array with booleans + */ +export type ArrayWithBooleans = Array; + +/** + * This is a simple array with strings + */ +export type ArrayWithStrings = Array; + +/** + * This is a simple array with references + */ +export type ArrayWithReferences = Array; + +/** + * This is a simple array containing an array + */ +export type ArrayWithArray = Array>; + +/** + * This is a simple array with properties + */ +export type ArrayWithProperties = Array<{ + foo?: string; + bar?: string; +}>; + +/** + * This is a string dictionary + */ +export type DictionaryWithString = { + [key: string]: string; +}; + +/** + * This is a string reference + */ +export type DictionaryWithReference = { + [key: string]: ModelWithString; +}; + +/** + * This is a complex dictionary + */ +export type DictionaryWithArray = { + [key: string]: Array; +}; + +/** + * This is a string dictionary + */ +export type DictionaryWithDictionary = { + [key: string]: { + [key: string]: string; + }; +}; + +/** + * This is a complex dictionary + */ +export type DictionaryWithProperties = { + [key: string]: { + foo?: string; + bar?: string; + }; +}; + +/** + * This is a type-only model that defines Date as a string + */ +export type Date = string; + +/** + * This is a model with one number property + */ +export type ModelWithInteger = { + /** + * This is a simple number property + */ + prop?: number; +}; + +/** + * This is a model with one boolean property + */ +export type ModelWithBoolean = { + /** + * This is a simple boolean property + */ + prop?: boolean; +}; + +/** + * This is a model with one string property + */ +export type ModelWithString = { + /** + * This is a simple string property + */ + prop?: string; +}; + +/** + * This is a model with one string property + */ +export type ModelWithStringError = { + /** + * This is a simple string property + */ + prop?: string; +}; + +/** + * This is a model with one string property + */ +export type ModelWithNullableString = { + /** + * This is a simple string property + */ + nullableProp?: string | null; + /** + * This is a simple string property + */ + nullableRequiredProp: string | null; +}; + +/** + * This is a model with one enum + */ +export type ModelWithEnum = { + /** + * This is a simple enum with strings + */ + test?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; + /** + * These are the HTTP error code enums + */ + statusCode?: '100' | '200 FOO' | '300 FOO_BAR' | '400 foo-bar' | '500 foo.bar' | '600 foo&bar'; + /** + * Simple boolean enum + */ + bool?: true; +}; + +/** + * This is a model with one enum + */ +export type ModelWithEnumFromDescription = { + /** + * Success=1,Warning=2,Error=3 + */ + test?: number; +}; + +/** + * This is a model with nested enums + */ +export type ModelWithNestedEnums = { + dictionaryWithEnum?: { + [key: string]: 'Success' | 'Warning' | 'Error'; + }; + dictionaryWithEnumFromDescription?: { + [key: string]: number; + }; + arrayWithEnum?: Array<'Success' | 'Warning' | 'Error'>; + arrayWithDescription?: Array; +}; + +/** + * This is a model with one property containing a reference + */ +export type ModelWithReference = { + prop?: ModelWithProperties; +}; + +/** + * This is a model with one property containing an array + */ +export type ModelWithArray = { + prop?: Array; + propWithFile?: Array; + propWithNumber?: Array; +}; + +/** + * This is a model with one property containing a dictionary + */ +export type ModelWithDictionary = { + prop?: { + [key: string]: string; + }; +}; + +/** + * This is a model with one property containing a circular reference + */ +export type ModelWithCircularReference = { + prop?: ModelWithCircularReference; +}; + +/** + * This is a model with one nested property + */ +export type ModelWithProperties = { + required: string; + readonly requiredAndReadOnly: string; + string?: string; + number?: number; + boolean?: boolean; + reference?: ModelWithString; + 'property with space'?: string; + default?: string; + try?: string; + readonly '@namespace.string'?: string; + readonly '@namespace.integer'?: number; +}; + +/** + * This is a model with one nested property + */ +export type ModelWithNestedProperties = { + readonly first: { + readonly second: { + readonly third: string; + }; + }; +}; + +/** + * This is a model with duplicated properties + */ +export type ModelWithDuplicateProperties = { + prop?: ModelWithString; +}; + +/** + * This is a model with ordered properties + */ +export type ModelWithOrderedProperties = { + zebra?: string; + apple?: string; + hawaii?: string; +}; + +/** + * This is a model with duplicated imports + */ +export type ModelWithDuplicateImports = { + propA?: ModelWithString; + propB?: ModelWithString; + propC?: ModelWithString; +}; + +/** + * This is a model that extends another model + */ +export type ModelThatExtends = ModelWithString & { + propExtendsA?: string; + propExtendsB?: ModelWithString; +}; + +/** + * This is a model that extends another model + */ +export type ModelThatExtendsExtends = ModelWithString & ModelThatExtends & { + propExtendsC?: string; + propExtendsD?: ModelWithString; +}; + +export type Default = { + name?: string; +}; + +/** + * This is a model that contains a some patterns + */ +export type ModelWithPattern = { + key: string; + name: string; + readonly enabled?: boolean; + readonly modified?: string; + id?: string; + text?: string; + patternWithSingleQuotes?: string; + patternWithNewline?: string; + patternWithBacktick?: string; + patternWithUnicode?: string; +}; + +export type ParameterActivityParams = { + description?: string; + graduate_id?: number; + organization_id?: number; + parent_activity?: number; + post_id?: number; +}; + +export type ResponsePostActivityResponse = { + description?: string; + graduate_id?: number; + organization_id?: number; + parent_activity_id?: number; + post_id?: number; +}; + +export type FailureFailure = { + error?: string; + message?: string; + reference_code?: string; +}; + +export type ExternalSharedModel = { + id: string; + name?: string; +}; + +/** + * This is a model with one property containing a reference + */ +export type ModelWithReferenceWritable = { + prop?: ModelWithPropertiesWritable; +}; + +/** + * This is a model with one nested property + */ +export type ModelWithPropertiesWritable = { + required: string; + string?: string; + number?: number; + boolean?: boolean; + reference?: ModelWithString; + 'property with space'?: string; + default?: string; + try?: string; +}; + +/** + * This is a model that contains a some patterns + */ +export type ModelWithPatternWritable = { + key: string; + name: string; + id?: string; + text?: string; + patternWithSingleQuotes?: string; + patternWithNewline?: string; + patternWithBacktick?: string; + patternWithUnicode?: string; +}; + +export type ServiceWithEmptyTagData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/no+tag'; +}; + +export type PatchApiVbyApiVersionNoTagData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/no+tag'; +}; + +export type PatchApiVbyApiVersionNoTagResponses = { + /** + * OK + */ + default: unknown; +}; + +export type FooWowData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/no+tag'; +}; + +export type FooWowResponses = { + /** + * OK + */ + default: unknown; +}; + +export type DeleteCallWithoutParametersAndResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/simple'; +}; + +export type GetCallWithoutParametersAndResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/simple'; +}; + +export type HeadCallWithoutParametersAndResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/simple'; +}; + +export type OptionsCallWithoutParametersAndResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/simple'; +}; + +export type PatchCallWithoutParametersAndResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/simple'; +}; + +export type PostCallWithoutParametersAndResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/simple'; +}; + +export type PutCallWithoutParametersAndResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/simple'; +}; + +export type CallWithDescriptionsData = { + body?: never; + path?: never; + query?: { + /** + * Testing multiline comments in string: First line + * Second line + * + * Fourth line + */ + parameterWithBreaks?: string; + /** + * Testing backticks in string: `backticks` and ```multiple backticks``` should work + */ + parameterWithBackticks?: string; + /** + * Testing slashes in string: \backwards\\\ and /forwards/// should work + */ + parameterWithSlashes?: string; + /** + * Testing expression placeholders in string: ${expression} should work + */ + parameterWithExpressionPlaceholders?: string; + /** + * Testing quotes in string: 'single quote''' and "double quotes""" should work + */ + parameterWithQuotes?: string; + /** + * Testing reserved characters in string: * inline * and ** inline ** should work + */ + parameterWithReservedCharacters?: string; + }; + url: '/api/v{api-version}/descriptions/'; +}; + +export type CallWithParametersData = { + body?: never; + headers: { + /** + * This is the parameter that goes into the header + */ + parameterHeader: string; + }; + path: { + /** + * This is the parameter that goes into the path + */ + parameterPath: string; + /** + * api-version should be required in standalone clients + */ + 'api-version': string; + }; + query: { + /** + * This is the parameter that goes into the query params + */ + parameterQuery: string; + }; + url: '/api/v{api-version}/parameters/{parameterPath}'; +}; + +export type CallWithWeirdParameterNamesData = { + /** + * This is the parameter that is sent as request body + */ + body: string; + headers: { + /** + * This is the parameter that goes into the request header + */ + 'parameter.header': string; + }; + path: { + /** + * This is the parameter that goes into the path + */ + 'parameter.path.1'?: string; + /** + * This is the parameter that goes into the path + */ + 'parameter-path-2'?: string; + /** + * This is the parameter that goes into the path + */ + 'PARAMETER-PATH-3'?: string; + /** + * api-version should be required in standalone clients + */ + 'api-version': string; + }; + query: { + /** + * This is the parameter with a reserved keyword + */ + default?: string; + /** + * This is the parameter that goes into the request query params + */ + 'parameter-query': string; + }; + url: '/api/v{api-version}/parameters/{parameter.path.1}/{parameter-path-2}/{PARAMETER-PATH-3}'; +}; + +export type CallWithDefaultParametersData = { + body?: never; + path?: never; + query: { + /** + * This is a simple string with default value + */ + parameterString: string; + /** + * This is a simple number with default value + */ + parameterNumber: number; + /** + * This is a simple boolean with default value + */ + parameterBoolean: boolean; + /** + * This is a simple enum with default value + */ + parameterEnum: 'Success' | 'Warning' | 'Error'; + /** + * This is a model with one string property + */ + parameterModel: { + /** + * This is a simple string property + */ + prop?: string; + }; + }; + url: '/api/v{api-version}/defaults'; +}; + +export type CallWithDefaultOptionalParametersData = { + body?: never; + path?: never; + query?: { + /** + * This is a simple string that is optional with default value + */ + parameterString?: string; + /** + * This is a simple number that is optional with default value + */ + parameterNumber?: number; + /** + * This is a simple boolean that is optional with default value + */ + parameterBoolean?: boolean; + /** + * This is a simple enum that is optional with default value + */ + parameterEnum?: 'Success' | 'Warning' | 'Error'; + }; + url: '/api/v{api-version}/defaults'; +}; + +export type CallToTestOrderOfParamsData = { + body?: never; + path?: never; + query: { + /** + * This is a optional string with default + */ + parameterOptionalStringWithDefault?: string; + /** + * This is a optional string with empty default + */ + parameterOptionalStringWithEmptyDefault?: string; + /** + * This is a optional string with no default + */ + parameterOptionalStringWithNoDefault?: string; + /** + * This is a string with default + */ + parameterStringWithDefault: string; + /** + * This is a string with empty default + */ + parameterStringWithEmptyDefault: string; + /** + * This is a string with no default + */ + parameterStringWithNoDefault: string; + /** + * This is a string that can be null with no default + */ + parameterStringNullableWithNoDefault?: string | null; + /** + * This is a string that can be null with default + */ + parameterStringNullableWithDefault?: string | null; + }; + url: '/api/v{api-version}/defaults'; +}; + +export type DuplicateNameData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/duplicate'; +}; + +export type DuplicateName2Data = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/duplicate'; +}; + +export type DuplicateName3Data = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/duplicate'; +}; + +export type DuplicateName4Data = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/duplicate'; +}; + +export type CallWithNoContentResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/no-content'; +}; + +export type CallWithNoContentResponseResponses = { + /** + * Success + */ + 204: unknown; +}; + +export type CallWithResponseAndNoContentResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/multiple-tags/response-and-no-content'; +}; + +export type CallWithResponseAndNoContentResponseResponses = { + /** + * Response is a simple number + */ + 200: number; + /** + * Success + */ + 204: unknown; +}; + +export type CallWithResponseAndNoContentResponseResponse = CallWithResponseAndNoContentResponseResponses[keyof CallWithResponseAndNoContentResponseResponses]; + +export type DummyAData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/multiple-tags/a'; +}; + +export type DummyAResponses = { + /** + * Success + */ + 204: unknown; +}; + +export type DummyBData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/multiple-tags/b'; +}; + +export type DummyBResponses = { + /** + * Success + */ + 204: unknown; +}; + +export type CallWithResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/response'; +}; + +export type CallWithResponseResponses = { + /** + * Message for default response + */ + default: ModelWithString; +}; + +export type CallWithResponseResponse = CallWithResponseResponses[keyof CallWithResponseResponses]; + +export type CallWithDuplicateResponsesData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/response'; +}; + +export type CallWithDuplicateResponsesErrors = { + /** + * Message for 500 error + */ + 500: ModelWithStringError; + /** + * Message for 501 error + */ + 501: ModelWithStringError; + /** + * Message for 502 error + */ + 502: ModelWithStringError; + /** + * Message for default response + */ + default: ModelWithString; +}; + +export type CallWithDuplicateResponsesError = CallWithDuplicateResponsesErrors[keyof CallWithDuplicateResponsesErrors]; + +export type CallWithDuplicateResponsesResponses = { + /** + * Message for 201 response + */ + 201: ModelWithString; + /** + * Message for 202 response + */ + 202: ModelWithString; +}; + +export type CallWithDuplicateResponsesResponse = CallWithDuplicateResponsesResponses[keyof CallWithDuplicateResponsesResponses]; + +export type CallWithResponsesData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/response'; +}; + +export type CallWithResponsesErrors = { + /** + * Message for 500 error + */ + 500: ModelWithStringError; + /** + * Message for 501 error + */ + 501: ModelWithStringError; + /** + * Message for 502 error + */ + 502: ModelWithStringError; + /** + * Message for default response + */ + default: ModelWithString; +}; + +export type CallWithResponsesError = CallWithResponsesErrors[keyof CallWithResponsesErrors]; + +export type CallWithResponsesResponses = { + /** + * Message for 200 response + */ + 200: { + readonly '@namespace.string'?: string; + readonly '@namespace.integer'?: number; + readonly value?: Array; + }; + /** + * Message for 201 response + */ + 201: ModelThatExtends; + /** + * Message for 202 response + */ + 202: ModelThatExtendsExtends; +}; + +export type CallWithResponsesResponse = CallWithResponsesResponses[keyof CallWithResponsesResponses]; + +export type CollectionFormatData = { + body?: never; + path?: never; + query: { + /** + * This is an array parameter that is sent as csv format (comma-separated values) + */ + parameterArrayCSV: Array; + /** + * This is an array parameter that is sent as ssv format (space-separated values) + */ + parameterArraySSV: Array; + /** + * This is an array parameter that is sent as tsv format (tab-separated values) + */ + parameterArrayTSV: Array; + /** + * This is an array parameter that is sent as pipes format (pipe-separated values) + */ + parameterArrayPipes: Array; + /** + * This is an array parameter that is sent as multi format (multiple parameter instances) + */ + parameterArrayMulti: Array; + }; + url: '/api/v{api-version}/collectionFormat'; +}; + +export type TypesData = { + body?: never; + path?: { + /** + * This is a number parameter + */ + id?: number; + }; + query: { + /** + * This is a number parameter + */ + parameterNumber: number; + /** + * This is a string parameter + */ + parameterString: string; + /** + * This is a boolean parameter + */ + parameterBoolean: boolean; + /** + * This is an array parameter + */ + parameterArray: Array; + /** + * This is a dictionary parameter + */ + parameterDictionary: { + [key: string]: unknown; + }; + /** + * This is an enum parameter + */ + parameterEnum: 'Success' | 'Warning' | 'Error'; + }; + url: '/api/v{api-version}/types'; +}; + +export type TypesResponses = { + /** + * Response is a simple number + */ + 200: number; + /** + * Response is a simple string + */ + 201: string; + /** + * Response is a simple boolean + */ + 202: boolean; + /** + * Response is a simple object + */ + 203: { + [key: string]: unknown; + }; +}; + +export type TypesResponse = TypesResponses[keyof TypesResponses]; + +export type ComplexTypesData = { + body?: never; + path?: never; + query: { + /** + * Parameter containing object + */ + parameterObject: { + first?: { + second?: { + third?: string; + }; + }; + }; + /** + * This is a model with one string property + */ + parameterReference: { + /** + * This is a simple string property + */ + prop?: string; + }; + }; + url: '/api/v{api-version}/complex'; +}; + +export type ComplexTypesErrors = { + /** + * 400 server error + */ + 400: unknown; + /** + * 500 server error + */ + 500: unknown; +}; + +export type ComplexTypesResponses = { + /** + * Successful response + */ + 200: Array; +}; + +export type ComplexTypesResponse = ComplexTypesResponses[keyof ComplexTypesResponses]; + +export type CallWithResultFromHeaderData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/header'; +}; + +export type CallWithResultFromHeaderErrors = { + /** + * 400 server error + */ + 400: unknown; + /** + * 500 server error + */ + 500: unknown; +}; + +export type CallWithResultFromHeaderResponses = { + /** + * Successful response + */ + 200: unknown; +}; + +export type TestErrorCodeData = { + body?: never; + path?: never; + query: { + /** + * Status code to return + */ + status: string; + }; + url: '/api/v{api-version}/error'; +}; + +export type TestErrorCodeErrors = { + /** + * Custom message: Internal Server Error + */ + 500: unknown; + /** + * Custom message: Not Implemented + */ + 501: unknown; + /** + * Custom message: Bad Gateway + */ + 502: unknown; + /** + * Custom message: Service Unavailable + */ + 503: unknown; +}; + +export type TestErrorCodeResponses = { + /** + * Custom message: Successful response + */ + 200: unknown; +}; + +export type NonAsciiæøåÆøÅöôêÊ字符串Data = { + body?: never; + path?: never; + query: { + /** + * Dummy input param + */ + nonAsciiParamæøåÆØÅöôêÊ: number; + }; + url: '/api/v{api-version}/non-ascii-æøåÆØÅöôêÊ字符串'; +}; + +export type NonAsciiæøåÆøÅöôêÊ字符串Responses = { + /** + * Successful response + */ + 200: NonAsciiStringæøåÆøÅöôêÊ字符串; +}; + +export type NonAsciiæøåÆøÅöôêÊ字符串Response = NonAsciiæøåÆøÅöôêÊ字符串Responses[keyof NonAsciiæøåÆøÅöôêÊ字符串Responses]; + +export type PostApiVbyApiVersionBodyData = { + /** + * Body should not be unknown + */ + body: ParameterActivityParams; + path?: never; + query?: never; + url: '/api/v{api-version}/body'; +}; + +export type PostApiVbyApiVersionBodyErrors = { + /** + * Bad Request + */ + 400: FailureFailure; + /** + * Internal Server Error + */ + 500: FailureFailure; +}; + +export type PostApiVbyApiVersionBodyError = PostApiVbyApiVersionBodyErrors[keyof PostApiVbyApiVersionBodyErrors]; + +export type PostApiVbyApiVersionBodyResponses = { + /** + * OK + */ + 200: ResponsePostActivityResponse; +}; + +export type PostApiVbyApiVersionBodyResponse = PostApiVbyApiVersionBodyResponses[keyof PostApiVbyApiVersionBodyResponses]; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example-disabled/index.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example-disabled/index.ts new file mode 100644 index 0000000000..b545604fba --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example-disabled/index.ts @@ -0,0 +1,3 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type { ClientOptions, GetFooData, GetFooResponse, GetFooResponses, Person, PostFooData, PostFooResponse, PostFooResponses } from './types.gen'; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example-disabled/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example-disabled/msw.gen.ts new file mode 100644 index 0000000000..6bc96de46f --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example-disabled/msw.gen.ts @@ -0,0 +1,75 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions } from 'msw'; + +import type { GetFooResponses, PostFooData, PostFooResponses } from './types.gen'; + +const resolveToNull = () => new HttpResponse(null); + +type ToResponseUnion = { + [K in Extract]: { + status: K; + result: T[K]; + }; +}[Extract]; + +type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; + +export type SingleHandlerFactories = { + getFooMock: HttpHandlerFactory<{ + result: GetFooResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + postFooMock: HttpHandlerFactory<{ + result: PostFooResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; +}; + +export type GetAllMocksOptions = { + onMissingMock?: 'error' | 'skip'; + overrides?: { + [K in keyof SingleHandlerFactories]?: Parameters[0]; + }; +}; + +export type MswHandlerFactory = SingleHandlerFactories & { + getAllMocks: (options?: GetAllMocksOptions) => Array; +}; + +export const createMswHandlerFactory = (config?: { + baseUrl?: string; +}): MswHandlerFactory => { + const baseUrl = config?.baseUrl ?? ''; + const mocks: SingleHandlerFactories = { + getFooMock: (res, options) => http.get(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + postFooMock: (res, options) => http.post(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options) + }; + const getAllMocks = (options?: GetAllMocksOptions): Array => { + const onMissingMock = options?.onMissingMock ?? 'skip'; + const overrides = options?.overrides; + const handlers: Array = []; + const addRequiredHandler = (handler: (value: Value | (() => HttpResponse)) => HttpHandler, override: Value | undefined) => { + if (override != null) { + handlers.push(handler(override)); + } + else { + if (onMissingMock === 'error') { + handlers.push(handler(() => new HttpResponse('[heyapi-msw] The mock of this request is not implemented.', { status: 501 }))); + } + } + }; + addRequiredHandler(mocks.getFooMock, overrides?.getFooMock); + addRequiredHandler(mocks.postFooMock, overrides?.postFooMock); + return handlers; + }; + return { ...mocks, getAllMocks }; +}; + +const _defaults = createMswHandlerFactory({ baseUrl: '*' }); + +export const getFooMock = _defaults.getFooMock; + +export const postFooMock = _defaults.postFooMock; + +export const getAllMocks = _defaults.getAllMocks; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example-disabled/types.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example-disabled/types.gen.ts new file mode 100644 index 0000000000..bf9849161c --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example-disabled/types.gen.ts @@ -0,0 +1,50 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type ClientOptions = { + baseUrl: string; +}; + +export type Person = { + firstName?: string; + lastName?: string; + age?: number; +}; + +export type GetFooData = { + body?: never; + path?: never; + query?: never; + url: '/foo'; +}; + +export type GetFooResponses = { + /** + * OK + */ + 200: Person; +}; + +export type GetFooResponse = GetFooResponses[keyof GetFooResponses]; + +export type PostFooData = { + body: string; + path?: never; + query?: never; + url: '/foo'; +}; + +export type PostFooResponses = { + /** + * OK + */ + 200: { + fullName?: string; + age?: number; + }; + /** + * SUCCESSFUL + */ + 204: unknown; +}; + +export type PostFooResponse = PostFooResponses[keyof PostFooResponses]; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example/index.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example/index.ts new file mode 100644 index 0000000000..b545604fba --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example/index.ts @@ -0,0 +1,3 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type { ClientOptions, GetFooData, GetFooResponse, GetFooResponses, Person, PostFooData, PostFooResponse, PostFooResponses } from './types.gen'; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example/msw.gen.ts new file mode 100644 index 0000000000..c5bc51f48e --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example/msw.gen.ts @@ -0,0 +1,68 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions } from 'msw'; + +import type { GetFooResponses, PostFooData, PostFooResponses } from './types.gen'; + +const resolveToNull = () => new HttpResponse(null); + +type ToResponseUnion = { + [K in Extract]: { + status: K; + result: T[K]; + }; +}[Extract]; + +type OptionalHttpHandlerFactory = (responseOrResolver?: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; + +export type SingleHandlerFactories = { + getFooMock: OptionalHttpHandlerFactory<{ + result: GetFooResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + postFooMock: OptionalHttpHandlerFactory<{ + result: PostFooResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; +}; + +export type GetAllMocksOptions = { + onMissingMock?: 'error' | 'skip'; + overrides?: { + [K in keyof SingleHandlerFactories]?: Parameters[0]; + }; +}; + +export type MswHandlerFactory = SingleHandlerFactories & { + getAllMocks: (options?: GetAllMocksOptions) => Array; +}; + +export const createMswHandlerFactory = (config?: { + baseUrl?: string; +}): MswHandlerFactory => { + const baseUrl = config?.baseUrl ?? ''; + const mocks: SingleHandlerFactories = { + getFooMock: (res = { result: { + firstName: 'Marry', + lastName: 'Jane', + age: 30 + }, status: 200 }, options) => http.get(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + postFooMock: (res = { result: { fullName: 'John Doe', age: 34 }, status: 200 }, options) => http.post(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options) + }; + const getAllMocks = (options?: GetAllMocksOptions): Array => { + const overrides = options?.overrides; + const handlers: Array = []; + handlers.push(mocks.getFooMock(overrides?.getFooMock)); + handlers.push(mocks.postFooMock(overrides?.postFooMock)); + return handlers; + }; + return { ...mocks, getAllMocks }; +}; + +const _defaults = createMswHandlerFactory({ baseUrl: '*' }); + +export const getFooMock = _defaults.getFooMock; + +export const postFooMock = _defaults.postFooMock; + +export const getAllMocks = _defaults.getAllMocks; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example/types.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example/types.gen.ts new file mode 100644 index 0000000000..bf9849161c --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example/types.gen.ts @@ -0,0 +1,50 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type ClientOptions = { + baseUrl: string; +}; + +export type Person = { + firstName?: string; + lastName?: string; + age?: number; +}; + +export type GetFooData = { + body?: never; + path?: never; + query?: never; + url: '/foo'; +}; + +export type GetFooResponses = { + /** + * OK + */ + 200: Person; +}; + +export type GetFooResponse = GetFooResponses[keyof GetFooResponses]; + +export type PostFooData = { + body: string; + path?: never; + query?: never; + url: '/foo'; +}; + +export type PostFooResponses = { + /** + * OK + */ + 200: { + fullName?: string; + age?: number; + }; + /** + * SUCCESSFUL + */ + 204: unknown; +}; + +export type PostFooResponse = PostFooResponses[keyof PostFooResponses]; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/servers/index.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/servers/index.ts new file mode 100644 index 0000000000..f389f85547 --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/servers/index.ts @@ -0,0 +1,3 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type { ClientOptions, GetFooData, GetFooResponse, GetFooResponses } from './types.gen'; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/servers/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/servers/msw.gen.ts new file mode 100644 index 0000000000..e9a5d27215 --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/servers/msw.gen.ts @@ -0,0 +1,67 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions } from 'msw'; + +import type { GetFooResponses } from './types.gen'; + +const resolveToNull = () => new HttpResponse(null); + +type ToResponseUnion = { + [K in Extract]: { + status: K; + result: T[K]; + }; +}[Extract]; + +type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; + +export type SingleHandlerFactories = { + getFooMock: HttpHandlerFactory<{ + result: GetFooResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; +}; + +export type GetAllMocksOptions = { + onMissingMock?: 'error' | 'skip'; + overrides?: { + [K in keyof SingleHandlerFactories]?: Parameters[0]; + }; +}; + +export type MswHandlerFactory = SingleHandlerFactories & { + getAllMocks: (options?: GetAllMocksOptions) => Array; +}; + +export const createMswHandlerFactory = (config?: { + baseUrl?: string; +}): MswHandlerFactory => { + const baseUrl = config?.baseUrl ?? 'https://foo.com/v1'; + const mocks: SingleHandlerFactories = { + getFooMock: (res, options) => http.get(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options) + }; + const getAllMocks = (options?: GetAllMocksOptions): Array => { + const onMissingMock = options?.onMissingMock ?? 'skip'; + const overrides = options?.overrides; + const handlers: Array = []; + const addRequiredHandler = (handler: (value: Value | (() => HttpResponse)) => HttpHandler, override: Value | undefined) => { + if (override != null) { + handlers.push(handler(override)); + } + else { + if (onMissingMock === 'error') { + handlers.push(handler(() => new HttpResponse('[heyapi-msw] The mock of this request is not implemented.', { status: 501 }))); + } + } + }; + addRequiredHandler(mocks.getFooMock, overrides?.getFooMock); + return handlers; + }; + return { ...mocks, getAllMocks }; +}; + +const _defaults = createMswHandlerFactory({ baseUrl: '*' }); + +export const getFooMock = _defaults.getFooMock; + +export const getAllMocks = _defaults.getAllMocks; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/servers/types.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/servers/types.gen.ts new file mode 100644 index 0000000000..b54728320a --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/servers/types.gen.ts @@ -0,0 +1,21 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type ClientOptions = { + baseUrl: 'https://foo.com/v1' | (string & {}); +}; + +export type GetFooData = { + body?: never; + path?: never; + query?: never; + url: '/foo'; +}; + +export type GetFooResponses = { + /** + * OK + */ + 200: string; +}; + +export type GetFooResponse = GetFooResponses[keyof GetFooResponses]; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/default/index.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/default/index.ts new file mode 100644 index 0000000000..2ef59c1f0c --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/default/index.ts @@ -0,0 +1,3 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type { _3eNum1Период, _400, AdditionalPropertiesIntegerIssue, AdditionalPropertiesUnknownIssue, AdditionalPropertiesUnknownIssue2, AdditionalPropertiesUnknownIssue3, AdditionalPropertiesUnknownIssueWritable, AnyOfAnyAndNull, AnyOfArrays, ApiVVersionODataControllerCountData, ApiVVersionODataControllerCountResponse, ApiVVersionODataControllerCountResponses, ArrayWithAnyOfProperties, ArrayWithArray, ArrayWithBooleans, ArrayWithNumbers, ArrayWithProperties, ArrayWithReferences, ArrayWithStrings, CallToTestOrderOfParamsData, CallWithDefaultOptionalParametersData, CallWithDefaultParametersData, CallWithDescriptionsData, CallWithDuplicateResponsesData, CallWithDuplicateResponsesError, CallWithDuplicateResponsesErrors, CallWithDuplicateResponsesResponse, CallWithDuplicateResponsesResponses, CallWithNoContentResponseData, CallWithNoContentResponseResponse, CallWithNoContentResponseResponses, CallWithParametersData, CallWithResponseAndNoContentResponseData, CallWithResponseAndNoContentResponseResponse, CallWithResponseAndNoContentResponseResponses, CallWithResponseData, CallWithResponseResponse, CallWithResponseResponses, CallWithResponsesData, CallWithResponsesError, CallWithResponsesErrors, CallWithResponsesResponse, CallWithResponsesResponses, CallWithResultFromHeaderData, CallWithResultFromHeaderErrors, CallWithResultFromHeaderResponses, CallWithWeirdParameterNamesData, CamelCaseCommentWithBreaks, CharactersInDescription, ClientOptions, CollectionFormatData, CommentWithBackticks, CommentWithBackticksAndQuotes, CommentWithBreaks, CommentWithExpressionPlaceholders, CommentWithQuotes, CommentWithReservedCharacters, CommentWithSlashes, ComplexParamsData, ComplexParamsResponse, ComplexParamsResponses, ComplexTypesData, ComplexTypesErrors, ComplexTypesResponse, ComplexTypesResponses, CompositionBaseModel, CompositionExtendedModel, CompositionWithAllOfAndNullable, CompositionWithAnyOf, CompositionWithAnyOfAndNullable, CompositionWithAnyOfAnonymous, CompositionWithNestedAnyAndTypeNull, CompositionWithNestedAnyOfAndNull, CompositionWithOneOf, CompositionWithOneOfAndComplexArrayDictionary, CompositionWithOneOfAndNullable, CompositionWithOneOfAndProperties, CompositionWithOneOfAndSimpleArrayDictionary, CompositionWithOneOfAndSimpleDictionary, CompositionWithOneOfAnonymous, CompositionWithOneOfDiscriminator, ConstValue, Default, DeleteCallWithoutParametersAndResponseData, DeleteFooData, DeleteFooData2, DeleteFooData3, DeprecatedCallData, DeprecatedModel, DictionaryWithArray, DictionaryWithDictionary, DictionaryWithProperties, DictionaryWithPropertiesAndAdditionalProperties, DictionaryWithReference, DictionaryWithString, DummyAData, DummyAResponse, DummyAResponses, DummyBData, DummyBResponse, DummyBResponses, DuplicateName2Data, DuplicateName3Data, DuplicateName4Data, DuplicateNameData, EnumFromDescription, EnumWithExtensions, EnumWithNumbers, EnumWithReplacedCharacters, EnumWithStrings, EnumWithXEnumNames, ExportData, ExternalRefA, ExternalRefB, ExternalSharedModel, File, FileResponseData, FileResponseResponse, FileResponseResponses, FileWritable, FooWowData, FooWowResponses, FreeFormObjectWithAdditionalPropertiesEqEmptyObject, FreeFormObjectWithAdditionalPropertiesEqTrue, FreeFormObjectWithoutAdditionalProperties, GenericSchemaDuplicateIssue1SystemBoolean, GenericSchemaDuplicateIssue1SystemBooleanWritable, GenericSchemaDuplicateIssue1SystemString, GenericSchemaDuplicateIssue1SystemStringWritable, GetApiVbyApiVersionSimpleOperationData, GetApiVbyApiVersionSimpleOperationError, GetApiVbyApiVersionSimpleOperationErrors, GetApiVbyApiVersionSimpleOperationResponse, GetApiVbyApiVersionSimpleOperationResponses, GetCallWithOptionalParamData, GetCallWithoutParametersAndResponseData, HeadCallWithoutParametersAndResponseData, Import, ImportData, ImportResponse, ImportResponses, IoK8sApimachineryPkgApisMetaV1DeleteOptions, IoK8sApimachineryPkgApisMetaV1Preconditions, ModelCircle, ModelFromZendesk, ModelSquare, ModelThatExtends, ModelThatExtendsExtends, ModelWithAdditionalPropertiesEqTrue, ModelWithAdditionalPropertiesRef, ModelWithAnyOfConstantSizeArray, ModelWithAnyOfConstantSizeArrayAndIntersect, ModelWithAnyOfConstantSizeArrayNullable, ModelWithAnyOfConstantSizeArrayWithNSizeAndOptions, ModelWithAnyOfConstantSizeArrayWithNSizeAndOptionsWritable, ModelWithArray, ModelWithArrayReadOnlyAndWriteOnly, ModelWithArrayReadOnlyAndWriteOnlyWritable, ModelWithBackticksInDescription, ModelWithBoolean, ModelWithCircularReference, ModelWithConst, ModelWithConstantSizeArray, ModelWithDictionary, ModelWithDuplicateImports, ModelWithDuplicateProperties, ModelWithEnum, ModelWithEnumFromDescription, ModelWithEnumWithHyphen, ModelWithInteger, ModelWithNestedArrayEnums, ModelWithNestedArrayEnumsData, ModelWithNestedArrayEnumsDataBar, ModelWithNestedArrayEnumsDataFoo, ModelWithNestedCompositionEnums, ModelWithNestedEnums, ModelWithNestedProperties, ModelWithNullableObject, ModelWithNullableString, ModelWithNumericEnumUnion, ModelWithOneOfAndProperties, ModelWithOneOfEnum, ModelWithOrderedProperties, ModelWithPattern, ModelWithPatternWritable, ModelWithPrefixItemsConstantSizeArray, ModelWithProperties, ModelWithPropertiesWritable, ModelWithReadOnlyAndWriteOnly, ModelWithReadOnlyAndWriteOnlyWritable, ModelWithReference, ModelWithReferenceWritable, ModelWithString, ModelWithStringError, MultipartRequestData, MultipartResponseData, MultipartResponseResponse, MultipartResponseResponses, NestedAnyOfArraysNullable, NonAsciiæøåÆøÅöôêÊ字符串Data, NonAsciiæøåÆøÅöôêÊ字符串Response, NonAsciiæøåÆøÅöôêÊ字符串Responses, NonAsciiStringæøåÆøÅöôêÊ字符串, NullableObject, OneOfAllOfIssue, OneOfAllOfIssueWritable, OptionsCallWithoutParametersAndResponseData, Pageable, ParameterSimpleParameterUnused, PatchApiVbyApiVersionNoTagData, PatchApiVbyApiVersionNoTagResponses, PatchCallWithoutParametersAndResponseData, PostApiVbyApiVersionFormDataData, PostApiVbyApiVersionRequestBodyData, PostCallWithOptionalParamData, PostCallWithOptionalParamResponse, PostCallWithOptionalParamResponses, PostCallWithoutParametersAndResponseData, PostServiceWithEmptyTagResponse, PostServiceWithEmptyTagResponse2, PutCallWithoutParametersAndResponseData, PutWithFormUrlEncodedData, SchemaWithFormRestrictedKeys, SimpleBoolean, SimpleFile, SimpleFormData, SimpleInteger, SimpleParameter, SimpleReference, SimpleRequestBody, SimpleString, SimpleStringWithPattern, TestErrorCodeData, TestErrorCodeErrors, TestErrorCodeResponses, TypesData, TypesResponse, TypesResponses, UploadFileData, UploadFileResponse, UploadFileResponses, XFooBar } from './types.gen'; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/default/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/default/msw.gen.ts new file mode 100644 index 0000000000..f1e386dcf4 --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/default/msw.gen.ts @@ -0,0 +1,382 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions } from 'msw'; + +import type { ApiVVersionODataControllerCountResponses, CallWithDuplicateResponsesResponses, CallWithNoContentResponseResponses, CallWithParametersData, CallWithResponseAndNoContentResponseResponses, CallWithResponsesResponses, CallWithResultFromHeaderResponses, CallWithWeirdParameterNamesData, ComplexParamsData, ComplexParamsResponses, ComplexTypesResponses, DummyAResponses, DummyBResponses, FileResponseResponses, GetApiVbyApiVersionSimpleOperationResponses, GetCallWithOptionalParamData, ImportData, ImportResponses, MultipartRequestData, MultipartResponseResponses, NonAsciiæøåÆøÅöôêÊ字符串Responses, PostApiVbyApiVersionFormDataData, PostApiVbyApiVersionRequestBodyData, PostCallWithOptionalParamData, PostCallWithOptionalParamResponses, PutWithFormUrlEncodedData, TestErrorCodeResponses, TypesResponses, UploadFileData, UploadFileResponses } from './types.gen'; + +const resolveToNull = () => new HttpResponse(null); + +type OptionalHttpHandlerFactory = (responseOrResolver?: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; + +type ToResponseUnion = { + [K in Extract]: { + status: K; + result: T[K]; + }; +}[Extract]; + +type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; + +export type SingleHandlerFactories = { + exportMock: OptionalHttpHandlerFactory; + patchApiVbyApiVersionNoTagMock: OptionalHttpHandlerFactory; + importMock: HttpHandlerFactory<{ + result: ImportResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + fooWowMock: OptionalHttpHandlerFactory; + apiVVersionODataControllerCountMock: HttpHandlerFactory<{ + result: ApiVVersionODataControllerCountResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + getApiVbyApiVersionSimpleOperationMock: HttpHandlerFactory<{ + result: GetApiVbyApiVersionSimpleOperationResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver<{ + apiVersion: string; + }, never>>; + deleteCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; + getCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; + headCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; + optionsCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; + patchCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; + postCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; + putCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; + deleteFooMock: OptionalHttpHandlerFactory>; + callWithDescriptionsMock: OptionalHttpHandlerFactory; + deprecatedCallMock: OptionalHttpHandlerFactory; + callWithParametersMock: OptionalHttpHandlerFactory>; + callWithWeirdParameterNamesMock: OptionalHttpHandlerFactory>; + getCallWithOptionalParamMock: OptionalHttpHandlerFactory>; + postCallWithOptionalParamMock: HttpHandlerFactory<{ + result: PostCallWithOptionalParamResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + postApiVbyApiVersionRequestBodyMock: OptionalHttpHandlerFactory>; + postApiVbyApiVersionFormDataMock: OptionalHttpHandlerFactory>; + callWithDefaultParametersMock: OptionalHttpHandlerFactory; + callWithDefaultOptionalParametersMock: OptionalHttpHandlerFactory; + callToTestOrderOfParamsMock: OptionalHttpHandlerFactory; + duplicateNameMock: OptionalHttpHandlerFactory; + duplicateName2Mock: OptionalHttpHandlerFactory; + duplicateName3Mock: OptionalHttpHandlerFactory; + duplicateName4Mock: OptionalHttpHandlerFactory; + callWithNoContentResponseMock: OptionalHttpHandlerFactory<{ + result: CallWithNoContentResponseResponses[204]; + status?: 204; + } | ToResponseUnion | HttpResponseResolver>; + callWithResponseAndNoContentResponseMock: HttpHandlerFactory<{ + result: CallWithResponseAndNoContentResponseResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + dummyAMock: HttpHandlerFactory<{ + result: DummyAResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + dummyBMock: OptionalHttpHandlerFactory<{ + result: DummyBResponses[204]; + status?: 204; + } | ToResponseUnion | HttpResponseResolver>; + callWithResponseMock: OptionalHttpHandlerFactory; + callWithDuplicateResponsesMock: HttpHandlerFactory<{ + result: CallWithDuplicateResponsesResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + callWithResponsesMock: HttpHandlerFactory<{ + result: CallWithResponsesResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + collectionFormatMock: OptionalHttpHandlerFactory; + typesMock: HttpHandlerFactory<{ + result: TypesResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver<{ + apiVersion: string; + }, never>>; + uploadFileMock: HttpHandlerFactory<{ + result: UploadFileResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver<{ + apiVersion: string; + }, UploadFileData['body']>>; + fileResponseMock: HttpHandlerFactory<{ + result: FileResponseResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver<{ + apiVersion: string; + id: string; + }, never>>; + complexTypesMock: HttpHandlerFactory<{ + result: ComplexTypesResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + multipartResponseMock: HttpHandlerFactory<{ + result: MultipartResponseResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + multipartRequestMock: OptionalHttpHandlerFactory>; + complexParamsMock: HttpHandlerFactory<{ + result: ComplexParamsResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver<{ + apiVersion: string; + id: string; + }, ComplexParamsData['body']>>; + callWithResultFromHeaderMock: OptionalHttpHandlerFactory<{ + result: CallWithResultFromHeaderResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + testErrorCodeMock: OptionalHttpHandlerFactory<{ + result: TestErrorCodeResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + nonAsciiæøåÆøÅöôêÊ字符串Mock: HttpHandlerFactory<{ + result: NonAsciiæøåÆøÅöôêÊ字符串Responses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + putWithFormUrlEncodedMock: OptionalHttpHandlerFactory>; +}; + +export type GetAllMocksOptions = { + onMissingMock?: 'error' | 'skip'; + overrides?: { + [K in keyof SingleHandlerFactories]?: Parameters[0]; + }; +}; + +export type MswHandlerFactory = SingleHandlerFactories & { + getAllMocks: (options?: GetAllMocksOptions) => Array; +}; + +export const createMswHandlerFactory = (config?: { + baseUrl?: string; +}): MswHandlerFactory => { + const baseUrl = config?.baseUrl ?? 'http://localhost:3000/base'; + const mocks: SingleHandlerFactories = { + exportMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/no+tag'}`, typeof res === 'function' ? res : resolveToNull, options), + patchApiVbyApiVersionNoTagMock: (res, options) => http.patch(`${baseUrl}${'/api/v:apiVersion/no+tag'}`, typeof res === 'function' ? res : resolveToNull, options), + importMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/no+tag'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + fooWowMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/no+tag'}`, typeof res === 'function' ? res : resolveToNull, options), + apiVVersionODataControllerCountMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/simple/$count'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + getApiVbyApiVersionSimpleOperationMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/simple\\:operation'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + deleteCallWithoutParametersAndResponseMock: (res, options) => http.delete(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), + getCallWithoutParametersAndResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), + headCallWithoutParametersAndResponseMock: (res, options) => http.head(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), + optionsCallWithoutParametersAndResponseMock: (res, options) => http.options(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), + patchCallWithoutParametersAndResponseMock: (res, options) => http.patch(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), + postCallWithoutParametersAndResponseMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), + putCallWithoutParametersAndResponseMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), + deleteFooMock: (res, options) => http.delete(`${baseUrl}${'/api/v:apiVersion/foo/:foo_param/bar/:BarParam'}`, typeof res === 'function' ? res : resolveToNull, options), + callWithDescriptionsMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/descriptions'}`, typeof res === 'function' ? res : resolveToNull, options), + deprecatedCallMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/parameters/deprecated'}`, typeof res === 'function' ? res : resolveToNull, options), + callWithParametersMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/parameters/:parameterPath'}`, typeof res === 'function' ? res : resolveToNull, options), + callWithWeirdParameterNamesMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/parameters/:parameterPath1/:parameterPath2/:PARAMETERPATH3'}`, typeof res === 'function' ? res : resolveToNull, options), + getCallWithOptionalParamMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/parameters'}`, typeof res === 'function' ? res : resolveToNull, options), + postCallWithOptionalParamMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/parameters'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + postApiVbyApiVersionRequestBodyMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/requestBody'}`, typeof res === 'function' ? res : resolveToNull, options), + postApiVbyApiVersionFormDataMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/formData'}`, typeof res === 'function' ? res : resolveToNull, options), + callWithDefaultParametersMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/defaults'}`, typeof res === 'function' ? res : resolveToNull, options), + callWithDefaultOptionalParametersMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/defaults'}`, typeof res === 'function' ? res : resolveToNull, options), + callToTestOrderOfParamsMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/defaults'}`, typeof res === 'function' ? res : resolveToNull, options), + duplicateNameMock: (res, options) => http.delete(`${baseUrl}${'/api/v:apiVersion/duplicate'}`, typeof res === 'function' ? res : resolveToNull, options), + duplicateName2Mock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/duplicate'}`, typeof res === 'function' ? res : resolveToNull, options), + duplicateName3Mock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/duplicate'}`, typeof res === 'function' ? res : resolveToNull, options), + duplicateName4Mock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/duplicate'}`, typeof res === 'function' ? res : resolveToNull, options), + callWithNoContentResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/no-content'}`, typeof res === 'object' && res.result ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 204 }) : typeof res === 'function' ? res : resolveToNull, options), + callWithResponseAndNoContentResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/multiple-tags/response-and-no-content'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + dummyAMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/multiple-tags/a'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + dummyBMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/multiple-tags/b'}`, typeof res === 'object' && res.result ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 204 }) : typeof res === 'function' ? res : resolveToNull, options), + callWithResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/response'}`, typeof res === 'function' ? res : resolveToNull, options), + callWithDuplicateResponsesMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/response'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + callWithResponsesMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/response'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + collectionFormatMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/collectionFormat'}`, typeof res === 'function' ? res : resolveToNull, options), + typesMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/types'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + uploadFileMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/upload'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + fileResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/file/:id'}`, typeof res === 'object' && res.result ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + complexTypesMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/complex'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + multipartResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/multipart'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + multipartRequestMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/multipart'}`, typeof res === 'function' ? res : resolveToNull, options), + complexParamsMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/complex/:id'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + callWithResultFromHeaderMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/header'}`, typeof res === 'object' && res.result ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + testErrorCodeMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/error'}`, typeof res === 'object' && res.result ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + nonAsciiæøåÆøÅöôêÊ字符串Mock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/non-ascii-æøåÆØÅöôêÊ字符串'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + putWithFormUrlEncodedMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/non-ascii-æøåÆØÅöôêÊ字符串'}`, typeof res === 'function' ? res : resolveToNull, options) + }; + const getAllMocks = (options?: GetAllMocksOptions): Array => { + const onMissingMock = options?.onMissingMock ?? 'skip'; + const overrides = options?.overrides; + const handlers: Array = []; + const addRequiredHandler = (handler: (value: Value | (() => HttpResponse)) => HttpHandler, override: Value | undefined) => { + if (override != null) { + handlers.push(handler(override)); + } + else { + if (onMissingMock === 'error') { + handlers.push(handler(() => new HttpResponse('[heyapi-msw] The mock of this request is not implemented.', { status: 501 }))); + } + } + }; + handlers.push(mocks.exportMock(overrides?.exportMock)); + handlers.push(mocks.patchApiVbyApiVersionNoTagMock(overrides?.patchApiVbyApiVersionNoTagMock)); + addRequiredHandler(mocks.importMock, overrides?.importMock); + handlers.push(mocks.fooWowMock(overrides?.fooWowMock)); + addRequiredHandler(mocks.apiVVersionODataControllerCountMock, overrides?.apiVVersionODataControllerCountMock); + addRequiredHandler(mocks.getApiVbyApiVersionSimpleOperationMock, overrides?.getApiVbyApiVersionSimpleOperationMock); + handlers.push(mocks.deleteCallWithoutParametersAndResponseMock(overrides?.deleteCallWithoutParametersAndResponseMock)); + handlers.push(mocks.getCallWithoutParametersAndResponseMock(overrides?.getCallWithoutParametersAndResponseMock)); + handlers.push(mocks.headCallWithoutParametersAndResponseMock(overrides?.headCallWithoutParametersAndResponseMock)); + handlers.push(mocks.optionsCallWithoutParametersAndResponseMock(overrides?.optionsCallWithoutParametersAndResponseMock)); + handlers.push(mocks.patchCallWithoutParametersAndResponseMock(overrides?.patchCallWithoutParametersAndResponseMock)); + handlers.push(mocks.postCallWithoutParametersAndResponseMock(overrides?.postCallWithoutParametersAndResponseMock)); + handlers.push(mocks.putCallWithoutParametersAndResponseMock(overrides?.putCallWithoutParametersAndResponseMock)); + handlers.push(mocks.deleteFooMock(overrides?.deleteFooMock)); + handlers.push(mocks.callWithDescriptionsMock(overrides?.callWithDescriptionsMock)); + handlers.push(mocks.deprecatedCallMock(overrides?.deprecatedCallMock)); + handlers.push(mocks.callWithParametersMock(overrides?.callWithParametersMock)); + handlers.push(mocks.callWithWeirdParameterNamesMock(overrides?.callWithWeirdParameterNamesMock)); + handlers.push(mocks.getCallWithOptionalParamMock(overrides?.getCallWithOptionalParamMock)); + addRequiredHandler(mocks.postCallWithOptionalParamMock, overrides?.postCallWithOptionalParamMock); + handlers.push(mocks.postApiVbyApiVersionRequestBodyMock(overrides?.postApiVbyApiVersionRequestBodyMock)); + handlers.push(mocks.postApiVbyApiVersionFormDataMock(overrides?.postApiVbyApiVersionFormDataMock)); + handlers.push(mocks.callWithDefaultParametersMock(overrides?.callWithDefaultParametersMock)); + handlers.push(mocks.callWithDefaultOptionalParametersMock(overrides?.callWithDefaultOptionalParametersMock)); + handlers.push(mocks.callToTestOrderOfParamsMock(overrides?.callToTestOrderOfParamsMock)); + handlers.push(mocks.duplicateNameMock(overrides?.duplicateNameMock)); + handlers.push(mocks.duplicateName2Mock(overrides?.duplicateName2Mock)); + handlers.push(mocks.duplicateName3Mock(overrides?.duplicateName3Mock)); + handlers.push(mocks.duplicateName4Mock(overrides?.duplicateName4Mock)); + handlers.push(mocks.callWithNoContentResponseMock(overrides?.callWithNoContentResponseMock)); + addRequiredHandler(mocks.callWithResponseAndNoContentResponseMock, overrides?.callWithResponseAndNoContentResponseMock); + addRequiredHandler(mocks.dummyAMock, overrides?.dummyAMock); + handlers.push(mocks.dummyBMock(overrides?.dummyBMock)); + handlers.push(mocks.callWithResponseMock(overrides?.callWithResponseMock)); + addRequiredHandler(mocks.callWithDuplicateResponsesMock, overrides?.callWithDuplicateResponsesMock); + addRequiredHandler(mocks.callWithResponsesMock, overrides?.callWithResponsesMock); + handlers.push(mocks.collectionFormatMock(overrides?.collectionFormatMock)); + addRequiredHandler(mocks.typesMock, overrides?.typesMock); + addRequiredHandler(mocks.uploadFileMock, overrides?.uploadFileMock); + addRequiredHandler(mocks.fileResponseMock, overrides?.fileResponseMock); + addRequiredHandler(mocks.complexTypesMock, overrides?.complexTypesMock); + addRequiredHandler(mocks.multipartResponseMock, overrides?.multipartResponseMock); + handlers.push(mocks.multipartRequestMock(overrides?.multipartRequestMock)); + addRequiredHandler(mocks.complexParamsMock, overrides?.complexParamsMock); + handlers.push(mocks.callWithResultFromHeaderMock(overrides?.callWithResultFromHeaderMock)); + handlers.push(mocks.testErrorCodeMock(overrides?.testErrorCodeMock)); + addRequiredHandler(mocks.nonAsciiæøåÆøÅöôêÊ字符串Mock, overrides?.nonAsciiæøåÆøÅöôêÊ字符串Mock); + handlers.push(mocks.putWithFormUrlEncodedMock(overrides?.putWithFormUrlEncodedMock)); + return handlers; + }; + return { ...mocks, getAllMocks }; +}; + +const _defaults = createMswHandlerFactory({ baseUrl: '*' }); + +export const exportMock = _defaults.exportMock; + +export const patchApiVbyApiVersionNoTagMock = _defaults.patchApiVbyApiVersionNoTagMock; + +export const importMock = _defaults.importMock; + +export const fooWowMock = _defaults.fooWowMock; + +export const apiVVersionODataControllerCountMock = _defaults.apiVVersionODataControllerCountMock; + +export const getApiVbyApiVersionSimpleOperationMock = _defaults.getApiVbyApiVersionSimpleOperationMock; + +export const deleteCallWithoutParametersAndResponseMock = _defaults.deleteCallWithoutParametersAndResponseMock; + +export const getCallWithoutParametersAndResponseMock = _defaults.getCallWithoutParametersAndResponseMock; + +export const headCallWithoutParametersAndResponseMock = _defaults.headCallWithoutParametersAndResponseMock; + +export const optionsCallWithoutParametersAndResponseMock = _defaults.optionsCallWithoutParametersAndResponseMock; + +export const patchCallWithoutParametersAndResponseMock = _defaults.patchCallWithoutParametersAndResponseMock; + +export const postCallWithoutParametersAndResponseMock = _defaults.postCallWithoutParametersAndResponseMock; + +export const putCallWithoutParametersAndResponseMock = _defaults.putCallWithoutParametersAndResponseMock; + +export const deleteFooMock = _defaults.deleteFooMock; + +export const callWithDescriptionsMock = _defaults.callWithDescriptionsMock; + +export const deprecatedCallMock = _defaults.deprecatedCallMock; + +export const callWithParametersMock = _defaults.callWithParametersMock; + +export const callWithWeirdParameterNamesMock = _defaults.callWithWeirdParameterNamesMock; + +export const getCallWithOptionalParamMock = _defaults.getCallWithOptionalParamMock; + +export const postCallWithOptionalParamMock = _defaults.postCallWithOptionalParamMock; + +export const postApiVbyApiVersionRequestBodyMock = _defaults.postApiVbyApiVersionRequestBodyMock; + +export const postApiVbyApiVersionFormDataMock = _defaults.postApiVbyApiVersionFormDataMock; + +export const callWithDefaultParametersMock = _defaults.callWithDefaultParametersMock; + +export const callWithDefaultOptionalParametersMock = _defaults.callWithDefaultOptionalParametersMock; + +export const callToTestOrderOfParamsMock = _defaults.callToTestOrderOfParamsMock; + +export const duplicateNameMock = _defaults.duplicateNameMock; + +export const duplicateName2Mock = _defaults.duplicateName2Mock; + +export const duplicateName3Mock = _defaults.duplicateName3Mock; + +export const duplicateName4Mock = _defaults.duplicateName4Mock; + +export const callWithNoContentResponseMock = _defaults.callWithNoContentResponseMock; + +export const callWithResponseAndNoContentResponseMock = _defaults.callWithResponseAndNoContentResponseMock; + +export const dummyAMock = _defaults.dummyAMock; + +export const dummyBMock = _defaults.dummyBMock; + +export const callWithResponseMock = _defaults.callWithResponseMock; + +export const callWithDuplicateResponsesMock = _defaults.callWithDuplicateResponsesMock; + +export const callWithResponsesMock = _defaults.callWithResponsesMock; + +export const collectionFormatMock = _defaults.collectionFormatMock; + +export const typesMock = _defaults.typesMock; + +export const uploadFileMock = _defaults.uploadFileMock; + +export const fileResponseMock = _defaults.fileResponseMock; + +export const complexTypesMock = _defaults.complexTypesMock; + +export const multipartResponseMock = _defaults.multipartResponseMock; + +export const multipartRequestMock = _defaults.multipartRequestMock; + +export const complexParamsMock = _defaults.complexParamsMock; + +export const callWithResultFromHeaderMock = _defaults.callWithResultFromHeaderMock; + +export const testErrorCodeMock = _defaults.testErrorCodeMock; + +export const nonAsciiæøåÆøÅöôêÊ字符串Mock = _defaults.nonAsciiæøåÆøÅöôêÊ字符串Mock; + +export const putWithFormUrlEncodedMock = _defaults.putWithFormUrlEncodedMock; + +export const getAllMocks = _defaults.getAllMocks; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/default/types.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/default/types.gen.ts new file mode 100644 index 0000000000..3287ee8737 --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/default/types.gen.ts @@ -0,0 +1,2081 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type ClientOptions = { + baseUrl: 'http://localhost:3000/base' | (string & {}); +}; + +/** + * Model with number-only name + */ +export type _400 = string; + +export type ExternalRefA = ExternalSharedModel; + +export type ExternalRefB = ExternalSharedModel; + +/** + * Testing multiline comments in string: First line + * Second line + * + * Fourth line + */ +export type CamelCaseCommentWithBreaks = number; + +/** + * Testing multiline comments in string: First line + * Second line + * + * Fourth line + */ +export type CommentWithBreaks = number; + +/** + * Testing backticks in string: `backticks` and ```multiple backticks``` should work + */ +export type CommentWithBackticks = number; + +/** + * Testing backticks and quotes in string: `backticks`, 'quotes', "double quotes" and ```multiple backticks``` should work + */ +export type CommentWithBackticksAndQuotes = number; + +/** + * Testing slashes in string: \backwards\\\ and /forwards/// should work + */ +export type CommentWithSlashes = number; + +/** + * Testing expression placeholders in string: ${expression} should work + */ +export type CommentWithExpressionPlaceholders = number; + +/** + * Testing quotes in string: 'single quote''' and "double quotes""" should work + */ +export type CommentWithQuotes = number; + +/** + * Testing reserved characters in string: * inline * and ** inline ** should work + */ +export type CommentWithReservedCharacters = number; + +/** + * This is a simple number + */ +export type SimpleInteger = number; + +/** + * This is a simple boolean + */ +export type SimpleBoolean = boolean; + +/** + * This is a simple string + */ +export type SimpleString = string; + +/** + * A string with non-ascii (unicode) characters valid in typescript identifiers (æøåÆØÅöÔèÈ字符串) + */ +export type NonAsciiStringæøåÆøÅöôêÊ字符串 = string; + +/** + * This is a simple file + */ +export type SimpleFile = Blob | File; + +/** + * This is a simple reference + */ +export type SimpleReference = ModelWithString; + +/** + * This is a simple string + */ +export type SimpleStringWithPattern = string | null; + +/** + * This is a simple enum with strings + */ +export type EnumWithStrings = 'Success' | 'Warning' | 'Error' | '\'Single Quote\'' | '"Double Quotes"' | 'Non-ascii: øæåôöØÆÅÔÖ字符串'; + +export type EnumWithReplacedCharacters = '\'Single Quote\'' | '"Double Quotes"' | 'øæåôöØÆÅÔÖ字符串' | 3.1 | ''; + +/** + * This is a simple enum with numbers + */ +export type EnumWithNumbers = 1 | 2 | 3 | 1.1 | 1.2 | 1.3 | 100 | 200 | 300 | -100 | -200 | -300 | -1.1 | -1.2 | -1.3; + +/** + * Success=1,Warning=2,Error=3 + */ +export type EnumFromDescription = number; + +/** + * This is a simple enum with numbers + */ +export type EnumWithExtensions = 200 | 400 | 500; + +export type EnumWithXEnumNames = 0 | 1 | 2; + +/** + * This is a simple array with numbers + */ +export type ArrayWithNumbers = Array; + +/** + * This is a simple array with booleans + */ +export type ArrayWithBooleans = Array; + +/** + * This is a simple array with strings + */ +export type ArrayWithStrings = Array; + +/** + * This is a simple array with references + */ +export type ArrayWithReferences = Array; + +/** + * This is a simple array containing an array + */ +export type ArrayWithArray = Array>; + +/** + * This is a simple array with properties + */ +export type ArrayWithProperties = Array<{ + '16x16'?: CamelCaseCommentWithBreaks; + bar?: string; +}>; + +/** + * This is a simple array with any of properties + */ +export type ArrayWithAnyOfProperties = Array<{ + foo?: string; +} | { + bar?: string; +}>; + +export type AnyOfAnyAndNull = { + data?: unknown; +}; + +/** + * This is a simple array with any of properties + */ +export type AnyOfArrays = { + results?: Array<{ + foo?: string; + } | { + bar?: string; + }>; +}; + +/** + * This is a string dictionary + */ +export type DictionaryWithString = { + [key: string]: string; +}; + +export type DictionaryWithPropertiesAndAdditionalProperties = { + foo?: number; + bar?: boolean; + [key: string]: string | number | boolean | undefined; +}; + +/** + * This is a string reference + */ +export type DictionaryWithReference = { + [key: string]: ModelWithString; +}; + +/** + * This is a complex dictionary + */ +export type DictionaryWithArray = { + [key: string]: Array; +}; + +/** + * This is a string dictionary + */ +export type DictionaryWithDictionary = { + [key: string]: { + [key: string]: string; + }; +}; + +/** + * This is a complex dictionary + */ +export type DictionaryWithProperties = { + [key: string]: { + foo?: string; + bar?: string; + }; +}; + +/** + * This is a model with one number property + */ +export type ModelWithInteger = { + /** + * This is a simple number property + */ + prop?: number; +}; + +/** + * This is a model with one boolean property + */ +export type ModelWithBoolean = { + /** + * This is a simple boolean property + */ + prop?: boolean; +}; + +/** + * This is a model with one string property + */ +export type ModelWithString = { + /** + * This is a simple string property + */ + prop?: string; +}; + +/** + * This is a model with one string property + */ +export type ModelWithStringError = { + /** + * This is a simple string property + */ + prop?: string; +}; + +/** + * `Comment` or `VoiceComment`. The JSON object for adding voice comments to tickets is different. See [Adding voice comments to tickets](/documentation/ticketing/managing-tickets/adding-voice-comments-to-tickets) + */ +export type ModelFromZendesk = string; + +/** + * This is a model with one string property + */ +export type ModelWithNullableString = { + /** + * This is a simple string property + */ + nullableProp1?: string | null; + /** + * This is a simple string property + */ + nullableRequiredProp1: string | null; + /** + * This is a simple string property + */ + nullableProp2?: string | null; + /** + * This is a simple string property + */ + nullableRequiredProp2: string | null; + /** + * This is a simple enum with strings + */ + 'foo_bar-enum'?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; +}; + +/** + * This is a model with one enum + */ +export type ModelWithEnum = { + /** + * This is a simple enum with strings + */ + 'foo_bar-enum'?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; + /** + * These are the HTTP error code enums + */ + statusCode?: '100' | '200 FOO' | '300 FOO_BAR' | '400 foo-bar' | '500 foo.bar' | '600 foo&bar'; + /** + * Simple boolean enum + */ + bool?: true; +}; + +/** + * This is a model with one enum with escaped name + */ +export type ModelWithEnumWithHyphen = { + /** + * Foo-Bar-Baz-Qux + */ + 'foo-bar-baz-qux'?: '3.0'; +}; + +/** + * This is a model with one enum + */ +export type ModelWithEnumFromDescription = { + /** + * Success=1,Warning=2,Error=3 + */ + test?: number; +}; + +/** + * This is a model with nested enums + */ +export type ModelWithNestedEnums = { + dictionaryWithEnum?: { + [key: string]: 'Success' | 'Warning' | 'Error'; + }; + dictionaryWithEnumFromDescription?: { + [key: string]: number; + }; + arrayWithEnum?: Array<'Success' | 'Warning' | 'Error'>; + arrayWithDescription?: Array; + /** + * This is a simple enum with strings + */ + 'foo_bar-enum'?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; +}; + +/** + * This is a model with one property containing a reference + */ +export type ModelWithReference = { + prop?: ModelWithProperties; +}; + +/** + * This is a model with one property containing an array + */ +export type ModelWithArrayReadOnlyAndWriteOnly = { + prop?: Array; + propWithFile?: Array; + propWithNumber?: Array; +}; + +/** + * This is a model with one property containing an array + */ +export type ModelWithArray = { + prop?: Array; + propWithFile?: Array; + propWithNumber?: Array; +}; + +/** + * This is a model with one property containing a dictionary + */ +export type ModelWithDictionary = { + prop?: { + [key: string]: string; + }; +}; + +/** + * This is a deprecated model with a deprecated property + * + * @deprecated + */ +export type DeprecatedModel = { + /** + * This is a deprecated property + * + * @deprecated + */ + prop?: string; +}; + +/** + * This is a model with one property containing a circular reference + */ +export type ModelWithCircularReference = { + prop?: ModelWithCircularReference; +}; + +/** + * This is a model with one property with a 'one of' relationship + */ +export type CompositionWithOneOf = { + propA?: ModelWithString | ModelWithEnum | ModelWithArray | ModelWithDictionary; +}; + +/** + * This is a model with one property with a 'one of' relationship where the options are not $ref + */ +export type CompositionWithOneOfAnonymous = { + propA?: { + propA?: string; + } | string | number; +}; + +/** + * Circle + */ +export type ModelCircle = { + kind: string; + radius?: number; +}; + +/** + * Square + */ +export type ModelSquare = { + kind: string; + sideLength?: number; +}; + +/** + * This is a model with one property with a 'one of' relationship where the options are not $ref + */ +export type CompositionWithOneOfDiscriminator = ({ + kind: 'circle'; +} & ModelCircle) | ({ + kind: 'square'; +} & ModelSquare); + +/** + * This is a model with one property with a 'any of' relationship + */ +export type CompositionWithAnyOf = { + propA?: ModelWithString | ModelWithEnum | ModelWithArray | ModelWithDictionary; +}; + +/** + * This is a model with one property with a 'any of' relationship where the options are not $ref + */ +export type CompositionWithAnyOfAnonymous = { + propA?: { + propA?: string; + } | string | number; +}; + +/** + * This is a model with nested 'any of' property with a type null + */ +export type CompositionWithNestedAnyAndTypeNull = { + propA?: Array | Array; +}; + +export type _3eNum1Период = 'Bird' | 'Dog'; + +export type ConstValue = 'ConstValue'; + +/** + * This is a model with one property with a 'any of' relationship where the options are not $ref + */ +export type CompositionWithNestedAnyOfAndNull = { + propA?: Array<_3eNum1Период | ConstValue> | null; +}; + +/** + * This is a model with one property with a 'one of' relationship + */ +export type CompositionWithOneOfAndNullable = { + propA?: { + boolean?: boolean; + } | ModelWithEnum | ModelWithArray | ModelWithDictionary | null; +}; + +/** + * This is a model that contains a simple dictionary within composition + */ +export type CompositionWithOneOfAndSimpleDictionary = { + propA?: boolean | { + [key: string]: number; + }; +}; + +/** + * This is a model that contains a dictionary of simple arrays within composition + */ +export type CompositionWithOneOfAndSimpleArrayDictionary = { + propA?: boolean | { + [key: string]: Array; + }; +}; + +/** + * This is a model that contains a dictionary of complex arrays (composited) within composition + */ +export type CompositionWithOneOfAndComplexArrayDictionary = { + propA?: boolean | { + [key: string]: Array; + }; +}; + +/** + * This is a model with one property with a 'all of' relationship + */ +export type CompositionWithAllOfAndNullable = { + propA?: ({ + boolean?: boolean; + } & ModelWithEnum & ModelWithArray & ModelWithDictionary) | null; +}; + +/** + * This is a model with one property with a 'any of' relationship + */ +export type CompositionWithAnyOfAndNullable = { + propA?: { + boolean?: boolean; + } | ModelWithEnum | ModelWithArray | ModelWithDictionary | null; +}; + +/** + * This is a base model with two simple optional properties + */ +export type CompositionBaseModel = { + firstName?: string; + lastname?: string; +}; + +/** + * This is a model that extends the base model + */ +export type CompositionExtendedModel = CompositionBaseModel & { + age: number; + firstName: string; + lastname: string; +}; + +/** + * This is a model with one nested property + */ +export type ModelWithProperties = { + required: string; + readonly requiredAndReadOnly: string; + requiredAndNullable: string | null; + string?: string; + number?: number; + boolean?: boolean; + reference?: ModelWithString; + 'property with space'?: string; + default?: string; + try?: string; + readonly '@namespace.string'?: string; + readonly '@namespace.integer'?: number; +}; + +/** + * This is a model with one nested property + */ +export type ModelWithNestedProperties = { + readonly first: { + readonly second: { + readonly third: string | null; + } | null; + } | null; +}; + +/** + * This is a model with duplicated properties + */ +export type ModelWithDuplicateProperties = { + prop?: ModelWithString; +}; + +/** + * This is a model with ordered properties + */ +export type ModelWithOrderedProperties = { + zebra?: string; + apple?: string; + hawaii?: string; +}; + +/** + * This is a model with duplicated imports + */ +export type ModelWithDuplicateImports = { + propA?: ModelWithString; + propB?: ModelWithString; + propC?: ModelWithString; +}; + +/** + * This is a model that extends another model + */ +export type ModelThatExtends = ModelWithString & { + propExtendsA?: string; + propExtendsB?: ModelWithString; +}; + +/** + * This is a model that extends another model + */ +export type ModelThatExtendsExtends = ModelWithString & ModelThatExtends & { + propExtendsC?: string; + propExtendsD?: ModelWithString; +}; + +/** + * This is a model that contains a some patterns + */ +export type ModelWithPattern = { + key: string; + name: string; + readonly enabled?: boolean; + readonly modified?: string; + id?: string; + text?: string; + patternWithSingleQuotes?: string; + patternWithNewline?: string; + patternWithBacktick?: string; + patternWithUnicode?: string; +}; + +export type File = { + /** + * Id + */ + readonly id?: string; + /** + * Updated at + */ + readonly updated_at?: string; + /** + * Created at + */ + readonly created_at?: string; + /** + * Mime + */ + mime: string; + /** + * File + */ + readonly file?: string; +}; + +export type Default = { + name?: string; +}; + +export type Pageable = { + page?: number; + size?: number; + sort?: Array; +}; + +/** + * This is a free-form object without additionalProperties. + */ +export type FreeFormObjectWithoutAdditionalProperties = { + [key: string]: unknown; +}; + +/** + * This is a free-form object with additionalProperties: true. + */ +export type FreeFormObjectWithAdditionalPropertiesEqTrue = { + [key: string]: unknown; +}; + +/** + * This is a free-form object with additionalProperties: {}. + */ +export type FreeFormObjectWithAdditionalPropertiesEqEmptyObject = { + [key: string]: unknown; +}; + +export type ModelWithConst = { + String?: 'String'; + number?: 0; + null?: unknown; + withType?: 'Some string'; +}; + +/** + * This is a model with one property and additionalProperties: true + */ +export type ModelWithAdditionalPropertiesEqTrue = { + /** + * This is a simple string property + */ + prop?: string; + [key: string]: unknown; +}; + +export type NestedAnyOfArraysNullable = { + nullableArray?: Array | null; +}; + +export type CompositionWithOneOfAndProperties = ({ + foo: SimpleParameter; +} | { + bar: NonAsciiStringæøåÆøÅöôêÊ字符串; +}) & { + baz: number | null; + qux: number; +}; + +/** + * An object that can be null + */ +export type NullableObject = { + foo?: string; +} | null; + +/** + * Some % character + */ +export type CharactersInDescription = string; + +export type ModelWithNullableObject = { + data?: NullableObject; +}; + +/** + * An object with additional properties that can be null + */ +export type ModelWithAdditionalPropertiesRef = { + [key: string]: NullableObject | null; +}; + +export type ModelWithOneOfEnum = { + foo: 'Bar'; +} | { + foo: 'Baz'; +} | { + foo: 'Qux'; +} | { + content: string; + foo: 'Quux'; +} | { + content: [ + string, + string + ]; + foo: 'Corge'; +}; + +export type ModelWithNestedArrayEnumsDataFoo = 'foo' | 'bar'; + +export type ModelWithNestedArrayEnumsDataBar = 'baz' | 'qux'; + +export type ModelWithNestedArrayEnumsData = { + foo?: Array; + bar?: Array; +}; + +export type ModelWithNestedArrayEnums = { + array_strings?: Array; + data?: ModelWithNestedArrayEnumsData; +}; + +export type ModelWithNestedCompositionEnums = { + foo?: ModelWithNestedArrayEnumsDataFoo; +}; + +export type ModelWithReadOnlyAndWriteOnly = { + foo: string; + readonly bar: string; +}; + +export type ModelWithConstantSizeArray = [ + number, + number +]; + +export type ModelWithAnyOfConstantSizeArray = [ + number | string, + number | string, + number | string +]; + +export type ModelWithPrefixItemsConstantSizeArray = Array; + +export type ModelWithAnyOfConstantSizeArrayNullable = [ + number | null | string, + number | null | string, + number | null | string +]; + +export type ModelWithAnyOfConstantSizeArrayWithNSizeAndOptions = [ + number | Import, + number | Import +]; + +export type ModelWithAnyOfConstantSizeArrayAndIntersect = [ + number & string, + number & string +]; + +export type ModelWithNumericEnumUnion = { + /** + * Период + */ + value?: -10 | -1 | 0 | 1 | 3 | 6 | 12; +}; + +/** + * Some description with `back ticks` + */ +export type ModelWithBackticksInDescription = { + /** + * The template `that` should be used for parsing and importing the contents of the CSV file. + * + *

There is one placeholder currently supported:

  • ${x} - refers to the n-th column in the CSV file, e.g. ${1}, ${2}, ...)

Example of a correct JSON template:

+ *
+     * [
+     * {
+     * "resourceType": "Asset",
+     * "identifier": {
+     * "name": "${1}",
+     * "domain": {
+     * "name": "${2}",
+     * "community": {
+     * "name": "Some Community"
+     * }
+     * }
+     * },
+     * "attributes" : {
+     * "00000000-0000-0000-0000-000000003115" : [ {
+     * "value" : "${3}"
+     * } ],
+     * "00000000-0000-0000-0000-000000000222" : [ {
+     * "value" : "${4}"
+     * } ]
+     * }
+     * }
+     * ]
+     * 
+ */ + template?: string; +}; + +export type ModelWithOneOfAndProperties = (SimpleParameter | NonAsciiStringæøåÆøÅöôêÊ字符串) & { + baz: number | null; + qux: number; +}; + +/** + * Model used to test deduplication strategy (unused) + */ +export type ParameterSimpleParameterUnused = string; + +/** + * Model used to test deduplication strategy + */ +export type PostServiceWithEmptyTagResponse = string; + +/** + * Model used to test deduplication strategy + */ +export type PostServiceWithEmptyTagResponse2 = string; + +/** + * Model used to test deduplication strategy + */ +export type DeleteFooData = string; + +/** + * Model used to test deduplication strategy + */ +export type DeleteFooData2 = string; + +/** + * Model with restricted keyword name + */ +export type Import = string; + +export type SchemaWithFormRestrictedKeys = { + description?: string; + 'x-enum-descriptions'?: string; + 'x-enum-varnames'?: string; + 'x-enumNames'?: string; + title?: string; + object?: { + description?: string; + 'x-enum-descriptions'?: string; + 'x-enum-varnames'?: string; + 'x-enumNames'?: string; + title?: string; + }; + array?: Array<{ + description?: string; + 'x-enum-descriptions'?: string; + 'x-enum-varnames'?: string; + 'x-enumNames'?: string; + title?: string; + }>; +}; + +/** + * This schema was giving PascalCase transformations a hard time + */ +export type IoK8sApimachineryPkgApisMetaV1DeleteOptions = { + /** + * Must be fulfilled before a deletion is carried out. If not possible, a 409 Conflict status will be returned. + */ + preconditions?: IoK8sApimachineryPkgApisMetaV1Preconditions; +}; + +/** + * This schema was giving PascalCase transformations a hard time + */ +export type IoK8sApimachineryPkgApisMetaV1Preconditions = { + /** + * Specifies the target ResourceVersion + */ + resourceVersion?: string; + /** + * Specifies the target UID. + */ + uid?: string; +}; + +export type AdditionalPropertiesUnknownIssue = { + [key: string]: string | number; +}; + +export type AdditionalPropertiesUnknownIssue2 = { + [key: string]: string | number; +}; + +export type AdditionalPropertiesUnknownIssue3 = string & { + entries: { + [key: string]: AdditionalPropertiesUnknownIssue; + }; +}; + +export type AdditionalPropertiesIntegerIssue = { + value: number; + [key: string]: number; +}; + +export type OneOfAllOfIssue = ((ConstValue | GenericSchemaDuplicateIssue1SystemBoolean) & _3eNum1Период) | GenericSchemaDuplicateIssue1SystemString; + +export type GenericSchemaDuplicateIssue1SystemBoolean = { + item?: boolean; + error?: string | null; + readonly hasError?: boolean; + data?: { + [key: string]: never; + }; +}; + +export type GenericSchemaDuplicateIssue1SystemString = { + item?: string | null; + error?: string | null; + readonly hasError?: boolean; +}; + +export type ExternalSharedModel = { + id: string; + name?: string; +}; + +/** + * This is a model with one property containing a reference + */ +export type ModelWithReferenceWritable = { + prop?: ModelWithPropertiesWritable; +}; + +/** + * This is a model with one property containing an array + */ +export type ModelWithArrayReadOnlyAndWriteOnlyWritable = { + prop?: Array; + propWithFile?: Array; + propWithNumber?: Array; +}; + +/** + * This is a model with one nested property + */ +export type ModelWithPropertiesWritable = { + required: string; + requiredAndNullable: string | null; + string?: string; + number?: number; + boolean?: boolean; + reference?: ModelWithString; + 'property with space'?: string; + default?: string; + try?: string; +}; + +/** + * This is a model that contains a some patterns + */ +export type ModelWithPatternWritable = { + key: string; + name: string; + id?: string; + text?: string; + patternWithSingleQuotes?: string; + patternWithNewline?: string; + patternWithBacktick?: string; + patternWithUnicode?: string; +}; + +export type FileWritable = { + /** + * Mime + */ + mime: string; +}; + +export type ModelWithReadOnlyAndWriteOnlyWritable = { + foo: string; + baz: string; +}; + +export type ModelWithAnyOfConstantSizeArrayWithNSizeAndOptionsWritable = [ + number | Import, + number | Import +]; + +export type AdditionalPropertiesUnknownIssueWritable = { + [key: string]: string | number; +}; + +export type OneOfAllOfIssueWritable = ((ConstValue | GenericSchemaDuplicateIssue1SystemBoolean) & _3eNum1Период) | GenericSchemaDuplicateIssue1SystemString; + +export type GenericSchemaDuplicateIssue1SystemBooleanWritable = { + item?: boolean; + error?: string | null; + data?: { + [key: string]: never; + }; +}; + +export type GenericSchemaDuplicateIssue1SystemStringWritable = { + item?: string | null; + error?: string | null; +}; + +/** + * This is a reusable parameter + */ +export type SimpleParameter = string; + +/** + * Parameter with illegal characters + */ +export type XFooBar = ModelWithString; + +export type SimpleRequestBody = ModelWithString; + +export type SimpleFormData = ModelWithString; + +export type ExportData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/no+tag'; +}; + +export type PatchApiVbyApiVersionNoTagData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/no+tag'; +}; + +export type PatchApiVbyApiVersionNoTagResponses = { + /** + * OK + */ + default: unknown; +}; + +export type ImportData = { + body: ModelWithReadOnlyAndWriteOnlyWritable | ModelWithArrayReadOnlyAndWriteOnlyWritable; + path?: never; + query?: never; + url: '/api/v{api-version}/no+tag'; +}; + +export type ImportResponses = { + /** + * Success + */ + 200: ModelFromZendesk; + /** + * Default success response + */ + default: ModelWithReadOnlyAndWriteOnly; +}; + +export type ImportResponse = ImportResponses[keyof ImportResponses]; + +export type FooWowData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/no+tag'; +}; + +export type FooWowResponses = { + /** + * OK + */ + default: unknown; +}; + +export type ApiVVersionODataControllerCountData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/simple/$count'; +}; + +export type ApiVVersionODataControllerCountResponses = { + /** + * Success + */ + 200: ModelFromZendesk; +}; + +export type ApiVVersionODataControllerCountResponse = ApiVVersionODataControllerCountResponses[keyof ApiVVersionODataControllerCountResponses]; + +export type GetApiVbyApiVersionSimpleOperationData = { + body?: never; + path: { + /** + * foo in method + */ + foo_param: string; + }; + query?: never; + url: '/api/v{api-version}/simple:operation'; +}; + +export type GetApiVbyApiVersionSimpleOperationErrors = { + /** + * Default error response + */ + default: ModelWithBoolean; +}; + +export type GetApiVbyApiVersionSimpleOperationError = GetApiVbyApiVersionSimpleOperationErrors[keyof GetApiVbyApiVersionSimpleOperationErrors]; + +export type GetApiVbyApiVersionSimpleOperationResponses = { + /** + * Response is a simple number + */ + 200: number; +}; + +export type GetApiVbyApiVersionSimpleOperationResponse = GetApiVbyApiVersionSimpleOperationResponses[keyof GetApiVbyApiVersionSimpleOperationResponses]; + +export type DeleteCallWithoutParametersAndResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/simple'; +}; + +export type GetCallWithoutParametersAndResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/simple'; +}; + +export type HeadCallWithoutParametersAndResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/simple'; +}; + +export type OptionsCallWithoutParametersAndResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/simple'; +}; + +export type PatchCallWithoutParametersAndResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/simple'; +}; + +export type PostCallWithoutParametersAndResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/simple'; +}; + +export type PutCallWithoutParametersAndResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/simple'; +}; + +export type DeleteFooData3 = { + body?: never; + headers: { + /** + * Parameter with illegal characters + */ + 'x-Foo-Bar': ModelWithString; + }; + path: { + /** + * foo in method + */ + foo_param: string; + /** + * bar in method + */ + BarParam: string; + }; + query?: never; + url: '/api/v{api-version}/foo/{foo_param}/bar/{BarParam}'; +}; + +export type CallWithDescriptionsData = { + body?: never; + path?: never; + query?: { + /** + * Testing multiline comments in string: First line + * Second line + * + * Fourth line + */ + parameterWithBreaks?: string; + /** + * Testing backticks in string: `backticks` and ```multiple backticks``` should work + */ + parameterWithBackticks?: string; + /** + * Testing slashes in string: \backwards\\\ and /forwards/// should work + */ + parameterWithSlashes?: string; + /** + * Testing expression placeholders in string: ${expression} should work + */ + parameterWithExpressionPlaceholders?: string; + /** + * Testing quotes in string: 'single quote''' and "double quotes""" should work + */ + parameterWithQuotes?: string; + /** + * Testing reserved characters in string: * inline * and ** inline ** should work + */ + parameterWithReservedCharacters?: string; + }; + url: '/api/v{api-version}/descriptions'; +}; + +export type DeprecatedCallData = { + body?: never; + headers: { + /** + * This parameter is deprecated + * + * @deprecated + */ + parameter: DeprecatedModel | null; + }; + path?: never; + query?: never; + url: '/api/v{api-version}/parameters/deprecated'; +}; + +export type CallWithParametersData = { + /** + * This is the parameter that goes into the body + */ + body: { + [key: string]: unknown; + } | null; + headers: { + /** + * This is the parameter that goes into the header + */ + parameterHeader: string | null; + }; + path: { + /** + * This is the parameter that goes into the path + */ + parameterPath: string | null; + /** + * api-version should be required in standalone clients + */ + 'api-version': string | null; + }; + query: { + foo_ref_enum?: ModelWithNestedArrayEnumsDataFoo; + foo_all_of_enum: ModelWithNestedArrayEnumsDataFoo; + /** + * This is the parameter that goes into the query params + */ + cursor: string | null; + }; + url: '/api/v{api-version}/parameters/{parameterPath}'; +}; + +export type CallWithWeirdParameterNamesData = { + /** + * This is the parameter that goes into the body + */ + body: ModelWithString | null; + headers: { + /** + * This is the parameter that goes into the request header + */ + 'parameter.header': string | null; + }; + path: { + /** + * This is the parameter that goes into the path + */ + 'parameter.path.1'?: string; + /** + * This is the parameter that goes into the path + */ + 'parameter-path-2'?: string; + /** + * This is the parameter that goes into the path + */ + 'PARAMETER-PATH-3'?: string; + /** + * api-version should be required in standalone clients + */ + 'api-version': string | null; + }; + query: { + /** + * This is the parameter with a reserved keyword + */ + default?: string; + /** + * This is the parameter that goes into the request query params + */ + 'parameter-query': string | null; + }; + url: '/api/v{api-version}/parameters/{parameter.path.1}/{parameter-path-2}/{PARAMETER-PATH-3}'; +}; + +export type GetCallWithOptionalParamData = { + /** + * This is a required parameter + */ + body: ModelWithOneOfEnum; + path?: never; + query?: { + /** + * This is an optional parameter + */ + page?: number; + }; + url: '/api/v{api-version}/parameters'; +}; + +export type PostCallWithOptionalParamData = { + /** + * This is an optional parameter + */ + body?: { + offset?: number | null; + }; + path?: never; + query: { + /** + * This is a required parameter + */ + parameter: Pageable; + }; + url: '/api/v{api-version}/parameters'; +}; + +export type PostCallWithOptionalParamResponses = { + /** + * Response is a simple number + */ + 200: number; + /** + * Success + */ + 204: void; +}; + +export type PostCallWithOptionalParamResponse = PostCallWithOptionalParamResponses[keyof PostCallWithOptionalParamResponses]; + +export type PostApiVbyApiVersionRequestBodyData = { + /** + * A reusable request body + */ + body?: SimpleRequestBody; + path?: never; + query?: { + /** + * This is a reusable parameter + */ + parameter?: string; + }; + url: '/api/v{api-version}/requestBody'; +}; + +export type PostApiVbyApiVersionFormDataData = { + /** + * A reusable request body + */ + body?: SimpleFormData; + path?: never; + query?: { + /** + * This is a reusable parameter + */ + parameter?: string; + }; + url: '/api/v{api-version}/formData'; +}; + +export type CallWithDefaultParametersData = { + body?: never; + path?: never; + query?: { + /** + * This is a simple string with default value + */ + parameterString?: string | null; + /** + * This is a simple number with default value + */ + parameterNumber?: number | null; + /** + * This is a simple boolean with default value + */ + parameterBoolean?: boolean | null; + /** + * This is a simple enum with default value + */ + parameterEnum?: 'Success' | 'Warning' | 'Error'; + /** + * This is a simple model with default value + */ + parameterModel?: ModelWithString | null; + }; + url: '/api/v{api-version}/defaults'; +}; + +export type CallWithDefaultOptionalParametersData = { + body?: never; + path?: never; + query?: { + /** + * This is a simple string that is optional with default value + */ + parameterString?: string; + /** + * This is a simple number that is optional with default value + */ + parameterNumber?: number; + /** + * This is a simple boolean that is optional with default value + */ + parameterBoolean?: boolean; + /** + * This is a simple enum that is optional with default value + */ + parameterEnum?: 'Success' | 'Warning' | 'Error'; + /** + * This is a simple model that is optional with default value + */ + parameterModel?: ModelWithString; + }; + url: '/api/v{api-version}/defaults'; +}; + +export type CallToTestOrderOfParamsData = { + body?: never; + path?: never; + query: { + /** + * This is a optional string with default + */ + parameterOptionalStringWithDefault?: string; + /** + * This is a optional string with empty default + */ + parameterOptionalStringWithEmptyDefault?: string; + /** + * This is a optional string with no default + */ + parameterOptionalStringWithNoDefault?: string; + /** + * This is a string with default + */ + parameterStringWithDefault: string; + /** + * This is a string with empty default + */ + parameterStringWithEmptyDefault: string; + /** + * This is a string with no default + */ + parameterStringWithNoDefault: string; + /** + * This is a string that can be null with no default + */ + parameterStringNullableWithNoDefault?: string | null; + /** + * This is a string that can be null with default + */ + parameterStringNullableWithDefault?: string | null; + }; + url: '/api/v{api-version}/defaults'; +}; + +export type DuplicateNameData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/duplicate'; +}; + +export type DuplicateName2Data = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/duplicate'; +}; + +export type DuplicateName3Data = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/duplicate'; +}; + +export type DuplicateName4Data = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/duplicate'; +}; + +export type CallWithNoContentResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/no-content'; +}; + +export type CallWithNoContentResponseResponses = { + /** + * Success + */ + 204: void; +}; + +export type CallWithNoContentResponseResponse = CallWithNoContentResponseResponses[keyof CallWithNoContentResponseResponses]; + +export type CallWithResponseAndNoContentResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/multiple-tags/response-and-no-content'; +}; + +export type CallWithResponseAndNoContentResponseResponses = { + /** + * Response is a simple number + */ + 200: number; + /** + * Success + */ + 204: void; +}; + +export type CallWithResponseAndNoContentResponseResponse = CallWithResponseAndNoContentResponseResponses[keyof CallWithResponseAndNoContentResponseResponses]; + +export type DummyAData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/multiple-tags/a'; +}; + +export type DummyAResponses = { + 200: _400; +}; + +export type DummyAResponse = DummyAResponses[keyof DummyAResponses]; + +export type DummyBData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/multiple-tags/b'; +}; + +export type DummyBResponses = { + /** + * Success + */ + 204: void; +}; + +export type DummyBResponse = DummyBResponses[keyof DummyBResponses]; + +export type CallWithResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/response'; +}; + +export type CallWithResponseResponses = { + default: Import; +}; + +export type CallWithResponseResponse = CallWithResponseResponses[keyof CallWithResponseResponses]; + +export type CallWithDuplicateResponsesData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/response'; +}; + +export type CallWithDuplicateResponsesErrors = { + /** + * Message for 500 error + */ + 500: ModelWithStringError; + /** + * Message for 501 error + */ + 501: ModelWithStringError; + /** + * Message for 502 error + */ + 502: ModelWithStringError; + /** + * Message for 4XX errors + */ + '4XX': DictionaryWithArray; + /** + * Default error response + */ + default: ModelWithBoolean; +}; + +export type CallWithDuplicateResponsesError = CallWithDuplicateResponsesErrors[keyof CallWithDuplicateResponsesErrors]; + +export type CallWithDuplicateResponsesResponses = { + /** + * Message for 200 response + */ + 200: ModelWithBoolean & ModelWithInteger; + /** + * Message for 201 response + */ + 201: ModelWithString; + /** + * Message for 202 response + */ + 202: ModelWithString; +}; + +export type CallWithDuplicateResponsesResponse = CallWithDuplicateResponsesResponses[keyof CallWithDuplicateResponsesResponses]; + +export type CallWithResponsesData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/response'; +}; + +export type CallWithResponsesErrors = { + /** + * Message for 500 error + */ + 500: ModelWithStringError; + /** + * Message for 501 error + */ + 501: ModelWithStringError; + /** + * Message for 502 error + */ + 502: ModelWithStringError; + /** + * Message for default response + */ + default: ModelWithStringError; +}; + +export type CallWithResponsesError = CallWithResponsesErrors[keyof CallWithResponsesErrors]; + +export type CallWithResponsesResponses = { + /** + * Message for 200 response + */ + 200: { + readonly '@namespace.string'?: string; + readonly '@namespace.integer'?: number; + readonly value?: Array; + }; + /** + * Message for 201 response + */ + 201: ModelThatExtends; + /** + * Message for 202 response + */ + 202: ModelThatExtendsExtends; +}; + +export type CallWithResponsesResponse = CallWithResponsesResponses[keyof CallWithResponsesResponses]; + +export type CollectionFormatData = { + body?: never; + path?: never; + query: { + /** + * This is an array parameter that is sent as csv format (comma-separated values) + */ + parameterArrayCSV: Array | null; + /** + * This is an array parameter that is sent as ssv format (space-separated values) + */ + parameterArraySSV: Array | null; + /** + * This is an array parameter that is sent as tsv format (tab-separated values) + */ + parameterArrayTSV: Array | null; + /** + * This is an array parameter that is sent as pipes format (pipe-separated values) + */ + parameterArrayPipes: Array | null; + /** + * This is an array parameter that is sent as multi format (multiple parameter instances) + */ + parameterArrayMulti: Array | null; + }; + url: '/api/v{api-version}/collectionFormat'; +}; + +export type TypesData = { + body?: never; + path?: { + /** + * This is a number parameter + */ + id?: number; + }; + query: { + /** + * This is a number parameter + */ + parameterNumber: number; + /** + * This is a string parameter + */ + parameterString: string | null; + /** + * This is a boolean parameter + */ + parameterBoolean: boolean | null; + /** + * This is an object parameter + */ + parameterObject: { + [key: string]: unknown; + } | null; + /** + * This is an array parameter + */ + parameterArray: Array | null; + /** + * This is a dictionary parameter + */ + parameterDictionary: { + [key: string]: unknown; + } | null; + /** + * This is an enum parameter + */ + parameterEnum: 'Success' | 'Warning' | 'Error'; + }; + url: '/api/v{api-version}/types'; +}; + +export type TypesResponses = { + /** + * Response is a simple number + */ + 200: number; + /** + * Response is a simple string + */ + 201: string; + /** + * Response is a simple boolean + */ + 202: boolean; + /** + * Response is a simple object + */ + 203: { + [key: string]: unknown; + }; +}; + +export type TypesResponse = TypesResponses[keyof TypesResponses]; + +export type UploadFileData = { + body: Blob | File; + path: { + /** + * api-version should be required in standalone clients + */ + 'api-version': string | null; + }; + query?: never; + url: '/api/v{api-version}/upload'; +}; + +export type UploadFileResponses = { + 200: boolean; +}; + +export type UploadFileResponse = UploadFileResponses[keyof UploadFileResponses]; + +export type FileResponseData = { + body?: never; + path: { + id: string; + /** + * api-version should be required in standalone clients + */ + 'api-version': string; + }; + query?: never; + url: '/api/v{api-version}/file/{id}'; +}; + +export type FileResponseResponses = { + /** + * Success + */ + 200: Blob | File; +}; + +export type FileResponseResponse = FileResponseResponses[keyof FileResponseResponses]; + +export type ComplexTypesData = { + body?: never; + path?: never; + query: { + /** + * Parameter containing object + */ + parameterObject: { + first?: { + second?: { + third?: string; + }; + }; + }; + /** + * Parameter containing reference + */ + parameterReference: ModelWithString; + }; + url: '/api/v{api-version}/complex'; +}; + +export type ComplexTypesErrors = { + /** + * 400 `server` error + */ + 400: unknown; + /** + * 500 server error + */ + 500: unknown; +}; + +export type ComplexTypesResponses = { + /** + * Successful response + */ + 200: Array; +}; + +export type ComplexTypesResponse = ComplexTypesResponses[keyof ComplexTypesResponses]; + +export type MultipartResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/multipart'; +}; + +export type MultipartResponseResponses = { + /** + * OK + */ + 200: { + file?: Blob | File; + metadata?: { + foo?: string; + bar?: string; + }; + }; +}; + +export type MultipartResponseResponse = MultipartResponseResponses[keyof MultipartResponseResponses]; + +export type MultipartRequestData = { + body?: { + content?: Blob | File; + data?: ModelWithString | null; + }; + path?: never; + query?: never; + url: '/api/v{api-version}/multipart'; +}; + +export type ComplexParamsData = { + body?: { + readonly key: string | null; + name: string | null; + enabled?: boolean; + type: 'Monkey' | 'Horse' | 'Bird'; + listOfModels?: Array | null; + listOfStrings?: Array | null; + parameters: ModelWithString | ModelWithEnum | ModelWithArray | ModelWithDictionary; + readonly user?: { + readonly id?: number; + readonly name?: string | null; + }; + }; + path: { + id: number; + /** + * api-version should be required in standalone clients + */ + 'api-version': string; + }; + query?: never; + url: '/api/v{api-version}/complex/{id}'; +}; + +export type ComplexParamsResponses = { + /** + * Success + */ + 200: ModelWithString; +}; + +export type ComplexParamsResponse = ComplexParamsResponses[keyof ComplexParamsResponses]; + +export type CallWithResultFromHeaderData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/header'; +}; + +export type CallWithResultFromHeaderErrors = { + /** + * 400 server error + */ + 400: unknown; + /** + * 500 server error + */ + 500: unknown; +}; + +export type CallWithResultFromHeaderResponses = { + /** + * Successful response + */ + 200: unknown; +}; + +export type TestErrorCodeData = { + body?: never; + path?: never; + query: { + /** + * Status code to return + */ + status: number; + }; + url: '/api/v{api-version}/error'; +}; + +export type TestErrorCodeErrors = { + /** + * Custom message: Internal Server Error + */ + 500: unknown; + /** + * Custom message: Not Implemented + */ + 501: unknown; + /** + * Custom message: Bad Gateway + */ + 502: unknown; + /** + * Custom message: Service Unavailable + */ + 503: unknown; +}; + +export type TestErrorCodeResponses = { + /** + * Custom message: Successful response + */ + 200: unknown; +}; + +export type NonAsciiæøåÆøÅöôêÊ字符串Data = { + body?: never; + path?: never; + query: { + /** + * Dummy input param + */ + nonAsciiParamæøåÆØÅöôêÊ: number; + }; + url: '/api/v{api-version}/non-ascii-æøåÆØÅöôêÊ字符串'; +}; + +export type NonAsciiæøåÆøÅöôêÊ字符串Responses = { + /** + * Successful response + */ + 200: Array; +}; + +export type NonAsciiæøåÆøÅöôêÊ字符串Response = NonAsciiæøåÆøÅöôêÊ字符串Responses[keyof NonAsciiæøåÆøÅöôêÊ字符串Responses]; + +export type PutWithFormUrlEncodedData = { + body: ArrayWithStrings; + path?: never; + query?: never; + url: '/api/v{api-version}/non-ascii-æøåÆØÅöôêÊ字符串'; +}; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example-disabled/index.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example-disabled/index.ts new file mode 100644 index 0000000000..b545604fba --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example-disabled/index.ts @@ -0,0 +1,3 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type { ClientOptions, GetFooData, GetFooResponse, GetFooResponses, Person, PostFooData, PostFooResponse, PostFooResponses } from './types.gen'; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example-disabled/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example-disabled/msw.gen.ts new file mode 100644 index 0000000000..6bc96de46f --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example-disabled/msw.gen.ts @@ -0,0 +1,75 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions } from 'msw'; + +import type { GetFooResponses, PostFooData, PostFooResponses } from './types.gen'; + +const resolveToNull = () => new HttpResponse(null); + +type ToResponseUnion = { + [K in Extract]: { + status: K; + result: T[K]; + }; +}[Extract]; + +type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; + +export type SingleHandlerFactories = { + getFooMock: HttpHandlerFactory<{ + result: GetFooResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + postFooMock: HttpHandlerFactory<{ + result: PostFooResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; +}; + +export type GetAllMocksOptions = { + onMissingMock?: 'error' | 'skip'; + overrides?: { + [K in keyof SingleHandlerFactories]?: Parameters[0]; + }; +}; + +export type MswHandlerFactory = SingleHandlerFactories & { + getAllMocks: (options?: GetAllMocksOptions) => Array; +}; + +export const createMswHandlerFactory = (config?: { + baseUrl?: string; +}): MswHandlerFactory => { + const baseUrl = config?.baseUrl ?? ''; + const mocks: SingleHandlerFactories = { + getFooMock: (res, options) => http.get(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + postFooMock: (res, options) => http.post(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options) + }; + const getAllMocks = (options?: GetAllMocksOptions): Array => { + const onMissingMock = options?.onMissingMock ?? 'skip'; + const overrides = options?.overrides; + const handlers: Array = []; + const addRequiredHandler = (handler: (value: Value | (() => HttpResponse)) => HttpHandler, override: Value | undefined) => { + if (override != null) { + handlers.push(handler(override)); + } + else { + if (onMissingMock === 'error') { + handlers.push(handler(() => new HttpResponse('[heyapi-msw] The mock of this request is not implemented.', { status: 501 }))); + } + } + }; + addRequiredHandler(mocks.getFooMock, overrides?.getFooMock); + addRequiredHandler(mocks.postFooMock, overrides?.postFooMock); + return handlers; + }; + return { ...mocks, getAllMocks }; +}; + +const _defaults = createMswHandlerFactory({ baseUrl: '*' }); + +export const getFooMock = _defaults.getFooMock; + +export const postFooMock = _defaults.postFooMock; + +export const getAllMocks = _defaults.getAllMocks; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example-disabled/types.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example-disabled/types.gen.ts new file mode 100644 index 0000000000..9d0535a2e7 --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example-disabled/types.gen.ts @@ -0,0 +1,50 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type ClientOptions = { + baseUrl: `${string}://${string}` | (string & {}); +}; + +export type Person = { + firstName?: string; + lastName?: string; + age?: number; +}; + +export type GetFooData = { + body?: never; + path?: never; + query?: never; + url: '/foo'; +}; + +export type GetFooResponses = { + /** + * OK + */ + 200: Person; +}; + +export type GetFooResponse = GetFooResponses[keyof GetFooResponses]; + +export type PostFooData = { + body: string; + path?: never; + query?: never; + url: '/foo'; +}; + +export type PostFooResponses = { + /** + * OK + */ + 200: { + fullName?: string; + age?: number; + }; + /** + * SUCCESSFUL + */ + 204: void; +}; + +export type PostFooResponse = PostFooResponses[keyof PostFooResponses]; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example/index.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example/index.ts new file mode 100644 index 0000000000..b545604fba --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example/index.ts @@ -0,0 +1,3 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type { ClientOptions, GetFooData, GetFooResponse, GetFooResponses, Person, PostFooData, PostFooResponse, PostFooResponses } from './types.gen'; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example/msw.gen.ts new file mode 100644 index 0000000000..c0552c7c42 --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example/msw.gen.ts @@ -0,0 +1,81 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions } from 'msw'; + +import type { GetFooResponses, PostFooData, PostFooResponses } from './types.gen'; + +const resolveToNull = () => new HttpResponse(null); + +type ToResponseUnion = { + [K in Extract]: { + status: K; + result: T[K]; + }; +}[Extract]; + +type OptionalHttpHandlerFactory = (responseOrResolver?: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; + +type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; + +export type SingleHandlerFactories = { + getFooMock: OptionalHttpHandlerFactory<{ + result: GetFooResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + postFooMock: HttpHandlerFactory<{ + result: PostFooResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; +}; + +export type GetAllMocksOptions = { + onMissingMock?: 'error' | 'skip'; + overrides?: { + [K in keyof SingleHandlerFactories]?: Parameters[0]; + }; +}; + +export type MswHandlerFactory = SingleHandlerFactories & { + getAllMocks: (options?: GetAllMocksOptions) => Array; +}; + +export const createMswHandlerFactory = (config?: { + baseUrl?: string; +}): MswHandlerFactory => { + const baseUrl = config?.baseUrl ?? ''; + const mocks: SingleHandlerFactories = { + getFooMock: (res = { result: { + firstName: 'Marry', + lastName: 'Jane', + age: 30 + }, status: 200 }, options) => http.get(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + postFooMock: (res, options) => http.post(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options) + }; + const getAllMocks = (options?: GetAllMocksOptions): Array => { + const onMissingMock = options?.onMissingMock ?? 'skip'; + const overrides = options?.overrides; + const handlers: Array = []; + const addRequiredHandler = (handler: (value: Value | (() => HttpResponse)) => HttpHandler, override: Value | undefined) => { + if (override != null) { + handlers.push(handler(override)); + } + else { + if (onMissingMock === 'error') { + handlers.push(handler(() => new HttpResponse('[heyapi-msw] The mock of this request is not implemented.', { status: 501 }))); + } + } + }; + handlers.push(mocks.getFooMock(overrides?.getFooMock)); + addRequiredHandler(mocks.postFooMock, overrides?.postFooMock); + return handlers; + }; + return { ...mocks, getAllMocks }; +}; + +const _defaults = createMswHandlerFactory({ baseUrl: '*' }); + +export const getFooMock = _defaults.getFooMock; + +export const postFooMock = _defaults.postFooMock; + +export const getAllMocks = _defaults.getAllMocks; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example/types.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example/types.gen.ts new file mode 100644 index 0000000000..9d0535a2e7 --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example/types.gen.ts @@ -0,0 +1,50 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type ClientOptions = { + baseUrl: `${string}://${string}` | (string & {}); +}; + +export type Person = { + firstName?: string; + lastName?: string; + age?: number; +}; + +export type GetFooData = { + body?: never; + path?: never; + query?: never; + url: '/foo'; +}; + +export type GetFooResponses = { + /** + * OK + */ + 200: Person; +}; + +export type GetFooResponse = GetFooResponses[keyof GetFooResponses]; + +export type PostFooData = { + body: string; + path?: never; + query?: never; + url: '/foo'; +}; + +export type PostFooResponses = { + /** + * OK + */ + 200: { + fullName?: string; + age?: number; + }; + /** + * SUCCESSFUL + */ + 204: void; +}; + +export type PostFooResponse = PostFooResponses[keyof PostFooResponses]; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-types/index.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-types/index.ts new file mode 100644 index 0000000000..f389f85547 --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-types/index.ts @@ -0,0 +1,3 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type { ClientOptions, GetFooData, GetFooResponse, GetFooResponses } from './types.gen'; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-types/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-types/msw.gen.ts new file mode 100644 index 0000000000..f27d2f0cd8 --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-types/msw.gen.ts @@ -0,0 +1,67 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions } from 'msw'; + +import type { GetFooResponses } from './types.gen'; + +const resolveToNull = () => new HttpResponse(null); + +type ToResponseUnion = { + [K in Extract]: { + status: K; + result: T[K]; + }; +}[Extract]; + +type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; + +export type SingleHandlerFactories = { + getFooMock: HttpHandlerFactory<{ + result: GetFooResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; +}; + +export type GetAllMocksOptions = { + onMissingMock?: 'error' | 'skip'; + overrides?: { + [K in keyof SingleHandlerFactories]?: Parameters[0]; + }; +}; + +export type MswHandlerFactory = SingleHandlerFactories & { + getAllMocks: (options?: GetAllMocksOptions) => Array; +}; + +export const createMswHandlerFactory = (config?: { + baseUrl?: string; +}): MswHandlerFactory => { + const baseUrl = config?.baseUrl ?? ''; + const mocks: SingleHandlerFactories = { + getFooMock: (res, options) => http.get(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options) + }; + const getAllMocks = (options?: GetAllMocksOptions): Array => { + const onMissingMock = options?.onMissingMock ?? 'skip'; + const overrides = options?.overrides; + const handlers: Array = []; + const addRequiredHandler = (handler: (value: Value | (() => HttpResponse)) => HttpHandler, override: Value | undefined) => { + if (override != null) { + handlers.push(handler(override)); + } + else { + if (onMissingMock === 'error') { + handlers.push(handler(() => new HttpResponse('[heyapi-msw] The mock of this request is not implemented.', { status: 501 }))); + } + } + }; + addRequiredHandler(mocks.getFooMock, overrides?.getFooMock); + return handlers; + }; + return { ...mocks, getAllMocks }; +}; + +const _defaults = createMswHandlerFactory({ baseUrl: '*' }); + +export const getFooMock = _defaults.getFooMock; + +export const getAllMocks = _defaults.getAllMocks; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-types/types.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-types/types.gen.ts new file mode 100644 index 0000000000..a0b37c70a4 --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-types/types.gen.ts @@ -0,0 +1,23 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type ClientOptions = { + baseUrl: `${string}://${string}` | (string & {}); +}; + +export type GetFooData = { + body?: never; + path?: never; + query?: never; + url: '/foo'; +}; + +export type GetFooResponses = { + /** + * OK + */ + 200: { + name?: string; + }; +}; + +export type GetFooResponse = GetFooResponses[keyof GetFooResponses]; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/servers/index.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/servers/index.ts new file mode 100644 index 0000000000..f389f85547 --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/servers/index.ts @@ -0,0 +1,3 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type { ClientOptions, GetFooData, GetFooResponse, GetFooResponses } from './types.gen'; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/servers/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/servers/msw.gen.ts new file mode 100644 index 0000000000..e9a5d27215 --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/servers/msw.gen.ts @@ -0,0 +1,67 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions } from 'msw'; + +import type { GetFooResponses } from './types.gen'; + +const resolveToNull = () => new HttpResponse(null); + +type ToResponseUnion = { + [K in Extract]: { + status: K; + result: T[K]; + }; +}[Extract]; + +type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; + +export type SingleHandlerFactories = { + getFooMock: HttpHandlerFactory<{ + result: GetFooResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; +}; + +export type GetAllMocksOptions = { + onMissingMock?: 'error' | 'skip'; + overrides?: { + [K in keyof SingleHandlerFactories]?: Parameters[0]; + }; +}; + +export type MswHandlerFactory = SingleHandlerFactories & { + getAllMocks: (options?: GetAllMocksOptions) => Array; +}; + +export const createMswHandlerFactory = (config?: { + baseUrl?: string; +}): MswHandlerFactory => { + const baseUrl = config?.baseUrl ?? 'https://foo.com/v1'; + const mocks: SingleHandlerFactories = { + getFooMock: (res, options) => http.get(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options) + }; + const getAllMocks = (options?: GetAllMocksOptions): Array => { + const onMissingMock = options?.onMissingMock ?? 'skip'; + const overrides = options?.overrides; + const handlers: Array = []; + const addRequiredHandler = (handler: (value: Value | (() => HttpResponse)) => HttpHandler, override: Value | undefined) => { + if (override != null) { + handlers.push(handler(override)); + } + else { + if (onMissingMock === 'error') { + handlers.push(handler(() => new HttpResponse('[heyapi-msw] The mock of this request is not implemented.', { status: 501 }))); + } + } + }; + addRequiredHandler(mocks.getFooMock, overrides?.getFooMock); + return handlers; + }; + return { ...mocks, getAllMocks }; +}; + +const _defaults = createMswHandlerFactory({ baseUrl: '*' }); + +export const getFooMock = _defaults.getFooMock; + +export const getAllMocks = _defaults.getAllMocks; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/servers/types.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/servers/types.gen.ts new file mode 100644 index 0000000000..d7a0ac4610 --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/servers/types.gen.ts @@ -0,0 +1,21 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type ClientOptions = { + baseUrl: 'https://foo.com/v1' | `${string}://${string}/v1` | (string & {}); +}; + +export type GetFooData = { + body?: never; + path?: never; + query?: never; + url: '/foo'; +}; + +export type GetFooResponses = { + /** + * OK + */ + 200: string; +}; + +export type GetFooResponse = GetFooResponses[keyof GetFooResponses]; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/default/index.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/default/index.ts new file mode 100644 index 0000000000..2ef59c1f0c --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/default/index.ts @@ -0,0 +1,3 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type { _3eNum1Период, _400, AdditionalPropertiesIntegerIssue, AdditionalPropertiesUnknownIssue, AdditionalPropertiesUnknownIssue2, AdditionalPropertiesUnknownIssue3, AdditionalPropertiesUnknownIssueWritable, AnyOfAnyAndNull, AnyOfArrays, ApiVVersionODataControllerCountData, ApiVVersionODataControllerCountResponse, ApiVVersionODataControllerCountResponses, ArrayWithAnyOfProperties, ArrayWithArray, ArrayWithBooleans, ArrayWithNumbers, ArrayWithProperties, ArrayWithReferences, ArrayWithStrings, CallToTestOrderOfParamsData, CallWithDefaultOptionalParametersData, CallWithDefaultParametersData, CallWithDescriptionsData, CallWithDuplicateResponsesData, CallWithDuplicateResponsesError, CallWithDuplicateResponsesErrors, CallWithDuplicateResponsesResponse, CallWithDuplicateResponsesResponses, CallWithNoContentResponseData, CallWithNoContentResponseResponse, CallWithNoContentResponseResponses, CallWithParametersData, CallWithResponseAndNoContentResponseData, CallWithResponseAndNoContentResponseResponse, CallWithResponseAndNoContentResponseResponses, CallWithResponseData, CallWithResponseResponse, CallWithResponseResponses, CallWithResponsesData, CallWithResponsesError, CallWithResponsesErrors, CallWithResponsesResponse, CallWithResponsesResponses, CallWithResultFromHeaderData, CallWithResultFromHeaderErrors, CallWithResultFromHeaderResponses, CallWithWeirdParameterNamesData, CamelCaseCommentWithBreaks, CharactersInDescription, ClientOptions, CollectionFormatData, CommentWithBackticks, CommentWithBackticksAndQuotes, CommentWithBreaks, CommentWithExpressionPlaceholders, CommentWithQuotes, CommentWithReservedCharacters, CommentWithSlashes, ComplexParamsData, ComplexParamsResponse, ComplexParamsResponses, ComplexTypesData, ComplexTypesErrors, ComplexTypesResponse, ComplexTypesResponses, CompositionBaseModel, CompositionExtendedModel, CompositionWithAllOfAndNullable, CompositionWithAnyOf, CompositionWithAnyOfAndNullable, CompositionWithAnyOfAnonymous, CompositionWithNestedAnyAndTypeNull, CompositionWithNestedAnyOfAndNull, CompositionWithOneOf, CompositionWithOneOfAndComplexArrayDictionary, CompositionWithOneOfAndNullable, CompositionWithOneOfAndProperties, CompositionWithOneOfAndSimpleArrayDictionary, CompositionWithOneOfAndSimpleDictionary, CompositionWithOneOfAnonymous, CompositionWithOneOfDiscriminator, ConstValue, Default, DeleteCallWithoutParametersAndResponseData, DeleteFooData, DeleteFooData2, DeleteFooData3, DeprecatedCallData, DeprecatedModel, DictionaryWithArray, DictionaryWithDictionary, DictionaryWithProperties, DictionaryWithPropertiesAndAdditionalProperties, DictionaryWithReference, DictionaryWithString, DummyAData, DummyAResponse, DummyAResponses, DummyBData, DummyBResponse, DummyBResponses, DuplicateName2Data, DuplicateName3Data, DuplicateName4Data, DuplicateNameData, EnumFromDescription, EnumWithExtensions, EnumWithNumbers, EnumWithReplacedCharacters, EnumWithStrings, EnumWithXEnumNames, ExportData, ExternalRefA, ExternalRefB, ExternalSharedModel, File, FileResponseData, FileResponseResponse, FileResponseResponses, FileWritable, FooWowData, FooWowResponses, FreeFormObjectWithAdditionalPropertiesEqEmptyObject, FreeFormObjectWithAdditionalPropertiesEqTrue, FreeFormObjectWithoutAdditionalProperties, GenericSchemaDuplicateIssue1SystemBoolean, GenericSchemaDuplicateIssue1SystemBooleanWritable, GenericSchemaDuplicateIssue1SystemString, GenericSchemaDuplicateIssue1SystemStringWritable, GetApiVbyApiVersionSimpleOperationData, GetApiVbyApiVersionSimpleOperationError, GetApiVbyApiVersionSimpleOperationErrors, GetApiVbyApiVersionSimpleOperationResponse, GetApiVbyApiVersionSimpleOperationResponses, GetCallWithOptionalParamData, GetCallWithoutParametersAndResponseData, HeadCallWithoutParametersAndResponseData, Import, ImportData, ImportResponse, ImportResponses, IoK8sApimachineryPkgApisMetaV1DeleteOptions, IoK8sApimachineryPkgApisMetaV1Preconditions, ModelCircle, ModelFromZendesk, ModelSquare, ModelThatExtends, ModelThatExtendsExtends, ModelWithAdditionalPropertiesEqTrue, ModelWithAdditionalPropertiesRef, ModelWithAnyOfConstantSizeArray, ModelWithAnyOfConstantSizeArrayAndIntersect, ModelWithAnyOfConstantSizeArrayNullable, ModelWithAnyOfConstantSizeArrayWithNSizeAndOptions, ModelWithAnyOfConstantSizeArrayWithNSizeAndOptionsWritable, ModelWithArray, ModelWithArrayReadOnlyAndWriteOnly, ModelWithArrayReadOnlyAndWriteOnlyWritable, ModelWithBackticksInDescription, ModelWithBoolean, ModelWithCircularReference, ModelWithConst, ModelWithConstantSizeArray, ModelWithDictionary, ModelWithDuplicateImports, ModelWithDuplicateProperties, ModelWithEnum, ModelWithEnumFromDescription, ModelWithEnumWithHyphen, ModelWithInteger, ModelWithNestedArrayEnums, ModelWithNestedArrayEnumsData, ModelWithNestedArrayEnumsDataBar, ModelWithNestedArrayEnumsDataFoo, ModelWithNestedCompositionEnums, ModelWithNestedEnums, ModelWithNestedProperties, ModelWithNullableObject, ModelWithNullableString, ModelWithNumericEnumUnion, ModelWithOneOfAndProperties, ModelWithOneOfEnum, ModelWithOrderedProperties, ModelWithPattern, ModelWithPatternWritable, ModelWithPrefixItemsConstantSizeArray, ModelWithProperties, ModelWithPropertiesWritable, ModelWithReadOnlyAndWriteOnly, ModelWithReadOnlyAndWriteOnlyWritable, ModelWithReference, ModelWithReferenceWritable, ModelWithString, ModelWithStringError, MultipartRequestData, MultipartResponseData, MultipartResponseResponse, MultipartResponseResponses, NestedAnyOfArraysNullable, NonAsciiæøåÆøÅöôêÊ字符串Data, NonAsciiæøåÆøÅöôêÊ字符串Response, NonAsciiæøåÆøÅöôêÊ字符串Responses, NonAsciiStringæøåÆøÅöôêÊ字符串, NullableObject, OneOfAllOfIssue, OneOfAllOfIssueWritable, OptionsCallWithoutParametersAndResponseData, Pageable, ParameterSimpleParameterUnused, PatchApiVbyApiVersionNoTagData, PatchApiVbyApiVersionNoTagResponses, PatchCallWithoutParametersAndResponseData, PostApiVbyApiVersionFormDataData, PostApiVbyApiVersionRequestBodyData, PostCallWithOptionalParamData, PostCallWithOptionalParamResponse, PostCallWithOptionalParamResponses, PostCallWithoutParametersAndResponseData, PostServiceWithEmptyTagResponse, PostServiceWithEmptyTagResponse2, PutCallWithoutParametersAndResponseData, PutWithFormUrlEncodedData, SchemaWithFormRestrictedKeys, SimpleBoolean, SimpleFile, SimpleFormData, SimpleInteger, SimpleParameter, SimpleReference, SimpleRequestBody, SimpleString, SimpleStringWithPattern, TestErrorCodeData, TestErrorCodeErrors, TestErrorCodeResponses, TypesData, TypesResponse, TypesResponses, UploadFileData, UploadFileResponse, UploadFileResponses, XFooBar } from './types.gen'; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/default/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/default/msw.gen.ts new file mode 100644 index 0000000000..f1e386dcf4 --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/default/msw.gen.ts @@ -0,0 +1,382 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions } from 'msw'; + +import type { ApiVVersionODataControllerCountResponses, CallWithDuplicateResponsesResponses, CallWithNoContentResponseResponses, CallWithParametersData, CallWithResponseAndNoContentResponseResponses, CallWithResponsesResponses, CallWithResultFromHeaderResponses, CallWithWeirdParameterNamesData, ComplexParamsData, ComplexParamsResponses, ComplexTypesResponses, DummyAResponses, DummyBResponses, FileResponseResponses, GetApiVbyApiVersionSimpleOperationResponses, GetCallWithOptionalParamData, ImportData, ImportResponses, MultipartRequestData, MultipartResponseResponses, NonAsciiæøåÆøÅöôêÊ字符串Responses, PostApiVbyApiVersionFormDataData, PostApiVbyApiVersionRequestBodyData, PostCallWithOptionalParamData, PostCallWithOptionalParamResponses, PutWithFormUrlEncodedData, TestErrorCodeResponses, TypesResponses, UploadFileData, UploadFileResponses } from './types.gen'; + +const resolveToNull = () => new HttpResponse(null); + +type OptionalHttpHandlerFactory = (responseOrResolver?: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; + +type ToResponseUnion = { + [K in Extract]: { + status: K; + result: T[K]; + }; +}[Extract]; + +type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; + +export type SingleHandlerFactories = { + exportMock: OptionalHttpHandlerFactory; + patchApiVbyApiVersionNoTagMock: OptionalHttpHandlerFactory; + importMock: HttpHandlerFactory<{ + result: ImportResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + fooWowMock: OptionalHttpHandlerFactory; + apiVVersionODataControllerCountMock: HttpHandlerFactory<{ + result: ApiVVersionODataControllerCountResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + getApiVbyApiVersionSimpleOperationMock: HttpHandlerFactory<{ + result: GetApiVbyApiVersionSimpleOperationResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver<{ + apiVersion: string; + }, never>>; + deleteCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; + getCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; + headCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; + optionsCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; + patchCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; + postCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; + putCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; + deleteFooMock: OptionalHttpHandlerFactory>; + callWithDescriptionsMock: OptionalHttpHandlerFactory; + deprecatedCallMock: OptionalHttpHandlerFactory; + callWithParametersMock: OptionalHttpHandlerFactory>; + callWithWeirdParameterNamesMock: OptionalHttpHandlerFactory>; + getCallWithOptionalParamMock: OptionalHttpHandlerFactory>; + postCallWithOptionalParamMock: HttpHandlerFactory<{ + result: PostCallWithOptionalParamResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + postApiVbyApiVersionRequestBodyMock: OptionalHttpHandlerFactory>; + postApiVbyApiVersionFormDataMock: OptionalHttpHandlerFactory>; + callWithDefaultParametersMock: OptionalHttpHandlerFactory; + callWithDefaultOptionalParametersMock: OptionalHttpHandlerFactory; + callToTestOrderOfParamsMock: OptionalHttpHandlerFactory; + duplicateNameMock: OptionalHttpHandlerFactory; + duplicateName2Mock: OptionalHttpHandlerFactory; + duplicateName3Mock: OptionalHttpHandlerFactory; + duplicateName4Mock: OptionalHttpHandlerFactory; + callWithNoContentResponseMock: OptionalHttpHandlerFactory<{ + result: CallWithNoContentResponseResponses[204]; + status?: 204; + } | ToResponseUnion | HttpResponseResolver>; + callWithResponseAndNoContentResponseMock: HttpHandlerFactory<{ + result: CallWithResponseAndNoContentResponseResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + dummyAMock: HttpHandlerFactory<{ + result: DummyAResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + dummyBMock: OptionalHttpHandlerFactory<{ + result: DummyBResponses[204]; + status?: 204; + } | ToResponseUnion | HttpResponseResolver>; + callWithResponseMock: OptionalHttpHandlerFactory; + callWithDuplicateResponsesMock: HttpHandlerFactory<{ + result: CallWithDuplicateResponsesResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + callWithResponsesMock: HttpHandlerFactory<{ + result: CallWithResponsesResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + collectionFormatMock: OptionalHttpHandlerFactory; + typesMock: HttpHandlerFactory<{ + result: TypesResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver<{ + apiVersion: string; + }, never>>; + uploadFileMock: HttpHandlerFactory<{ + result: UploadFileResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver<{ + apiVersion: string; + }, UploadFileData['body']>>; + fileResponseMock: HttpHandlerFactory<{ + result: FileResponseResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver<{ + apiVersion: string; + id: string; + }, never>>; + complexTypesMock: HttpHandlerFactory<{ + result: ComplexTypesResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + multipartResponseMock: HttpHandlerFactory<{ + result: MultipartResponseResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + multipartRequestMock: OptionalHttpHandlerFactory>; + complexParamsMock: HttpHandlerFactory<{ + result: ComplexParamsResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver<{ + apiVersion: string; + id: string; + }, ComplexParamsData['body']>>; + callWithResultFromHeaderMock: OptionalHttpHandlerFactory<{ + result: CallWithResultFromHeaderResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + testErrorCodeMock: OptionalHttpHandlerFactory<{ + result: TestErrorCodeResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + nonAsciiæøåÆøÅöôêÊ字符串Mock: HttpHandlerFactory<{ + result: NonAsciiæøåÆøÅöôêÊ字符串Responses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + putWithFormUrlEncodedMock: OptionalHttpHandlerFactory>; +}; + +export type GetAllMocksOptions = { + onMissingMock?: 'error' | 'skip'; + overrides?: { + [K in keyof SingleHandlerFactories]?: Parameters[0]; + }; +}; + +export type MswHandlerFactory = SingleHandlerFactories & { + getAllMocks: (options?: GetAllMocksOptions) => Array; +}; + +export const createMswHandlerFactory = (config?: { + baseUrl?: string; +}): MswHandlerFactory => { + const baseUrl = config?.baseUrl ?? 'http://localhost:3000/base'; + const mocks: SingleHandlerFactories = { + exportMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/no+tag'}`, typeof res === 'function' ? res : resolveToNull, options), + patchApiVbyApiVersionNoTagMock: (res, options) => http.patch(`${baseUrl}${'/api/v:apiVersion/no+tag'}`, typeof res === 'function' ? res : resolveToNull, options), + importMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/no+tag'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + fooWowMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/no+tag'}`, typeof res === 'function' ? res : resolveToNull, options), + apiVVersionODataControllerCountMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/simple/$count'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + getApiVbyApiVersionSimpleOperationMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/simple\\:operation'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + deleteCallWithoutParametersAndResponseMock: (res, options) => http.delete(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), + getCallWithoutParametersAndResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), + headCallWithoutParametersAndResponseMock: (res, options) => http.head(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), + optionsCallWithoutParametersAndResponseMock: (res, options) => http.options(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), + patchCallWithoutParametersAndResponseMock: (res, options) => http.patch(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), + postCallWithoutParametersAndResponseMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), + putCallWithoutParametersAndResponseMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), + deleteFooMock: (res, options) => http.delete(`${baseUrl}${'/api/v:apiVersion/foo/:foo_param/bar/:BarParam'}`, typeof res === 'function' ? res : resolveToNull, options), + callWithDescriptionsMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/descriptions'}`, typeof res === 'function' ? res : resolveToNull, options), + deprecatedCallMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/parameters/deprecated'}`, typeof res === 'function' ? res : resolveToNull, options), + callWithParametersMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/parameters/:parameterPath'}`, typeof res === 'function' ? res : resolveToNull, options), + callWithWeirdParameterNamesMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/parameters/:parameterPath1/:parameterPath2/:PARAMETERPATH3'}`, typeof res === 'function' ? res : resolveToNull, options), + getCallWithOptionalParamMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/parameters'}`, typeof res === 'function' ? res : resolveToNull, options), + postCallWithOptionalParamMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/parameters'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + postApiVbyApiVersionRequestBodyMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/requestBody'}`, typeof res === 'function' ? res : resolveToNull, options), + postApiVbyApiVersionFormDataMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/formData'}`, typeof res === 'function' ? res : resolveToNull, options), + callWithDefaultParametersMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/defaults'}`, typeof res === 'function' ? res : resolveToNull, options), + callWithDefaultOptionalParametersMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/defaults'}`, typeof res === 'function' ? res : resolveToNull, options), + callToTestOrderOfParamsMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/defaults'}`, typeof res === 'function' ? res : resolveToNull, options), + duplicateNameMock: (res, options) => http.delete(`${baseUrl}${'/api/v:apiVersion/duplicate'}`, typeof res === 'function' ? res : resolveToNull, options), + duplicateName2Mock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/duplicate'}`, typeof res === 'function' ? res : resolveToNull, options), + duplicateName3Mock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/duplicate'}`, typeof res === 'function' ? res : resolveToNull, options), + duplicateName4Mock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/duplicate'}`, typeof res === 'function' ? res : resolveToNull, options), + callWithNoContentResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/no-content'}`, typeof res === 'object' && res.result ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 204 }) : typeof res === 'function' ? res : resolveToNull, options), + callWithResponseAndNoContentResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/multiple-tags/response-and-no-content'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + dummyAMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/multiple-tags/a'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + dummyBMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/multiple-tags/b'}`, typeof res === 'object' && res.result ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 204 }) : typeof res === 'function' ? res : resolveToNull, options), + callWithResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/response'}`, typeof res === 'function' ? res : resolveToNull, options), + callWithDuplicateResponsesMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/response'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + callWithResponsesMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/response'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + collectionFormatMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/collectionFormat'}`, typeof res === 'function' ? res : resolveToNull, options), + typesMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/types'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + uploadFileMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/upload'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + fileResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/file/:id'}`, typeof res === 'object' && res.result ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + complexTypesMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/complex'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + multipartResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/multipart'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + multipartRequestMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/multipart'}`, typeof res === 'function' ? res : resolveToNull, options), + complexParamsMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/complex/:id'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + callWithResultFromHeaderMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/header'}`, typeof res === 'object' && res.result ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + testErrorCodeMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/error'}`, typeof res === 'object' && res.result ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + nonAsciiæøåÆøÅöôêÊ字符串Mock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/non-ascii-æøåÆØÅöôêÊ字符串'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + putWithFormUrlEncodedMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/non-ascii-æøåÆØÅöôêÊ字符串'}`, typeof res === 'function' ? res : resolveToNull, options) + }; + const getAllMocks = (options?: GetAllMocksOptions): Array => { + const onMissingMock = options?.onMissingMock ?? 'skip'; + const overrides = options?.overrides; + const handlers: Array = []; + const addRequiredHandler = (handler: (value: Value | (() => HttpResponse)) => HttpHandler, override: Value | undefined) => { + if (override != null) { + handlers.push(handler(override)); + } + else { + if (onMissingMock === 'error') { + handlers.push(handler(() => new HttpResponse('[heyapi-msw] The mock of this request is not implemented.', { status: 501 }))); + } + } + }; + handlers.push(mocks.exportMock(overrides?.exportMock)); + handlers.push(mocks.patchApiVbyApiVersionNoTagMock(overrides?.patchApiVbyApiVersionNoTagMock)); + addRequiredHandler(mocks.importMock, overrides?.importMock); + handlers.push(mocks.fooWowMock(overrides?.fooWowMock)); + addRequiredHandler(mocks.apiVVersionODataControllerCountMock, overrides?.apiVVersionODataControllerCountMock); + addRequiredHandler(mocks.getApiVbyApiVersionSimpleOperationMock, overrides?.getApiVbyApiVersionSimpleOperationMock); + handlers.push(mocks.deleteCallWithoutParametersAndResponseMock(overrides?.deleteCallWithoutParametersAndResponseMock)); + handlers.push(mocks.getCallWithoutParametersAndResponseMock(overrides?.getCallWithoutParametersAndResponseMock)); + handlers.push(mocks.headCallWithoutParametersAndResponseMock(overrides?.headCallWithoutParametersAndResponseMock)); + handlers.push(mocks.optionsCallWithoutParametersAndResponseMock(overrides?.optionsCallWithoutParametersAndResponseMock)); + handlers.push(mocks.patchCallWithoutParametersAndResponseMock(overrides?.patchCallWithoutParametersAndResponseMock)); + handlers.push(mocks.postCallWithoutParametersAndResponseMock(overrides?.postCallWithoutParametersAndResponseMock)); + handlers.push(mocks.putCallWithoutParametersAndResponseMock(overrides?.putCallWithoutParametersAndResponseMock)); + handlers.push(mocks.deleteFooMock(overrides?.deleteFooMock)); + handlers.push(mocks.callWithDescriptionsMock(overrides?.callWithDescriptionsMock)); + handlers.push(mocks.deprecatedCallMock(overrides?.deprecatedCallMock)); + handlers.push(mocks.callWithParametersMock(overrides?.callWithParametersMock)); + handlers.push(mocks.callWithWeirdParameterNamesMock(overrides?.callWithWeirdParameterNamesMock)); + handlers.push(mocks.getCallWithOptionalParamMock(overrides?.getCallWithOptionalParamMock)); + addRequiredHandler(mocks.postCallWithOptionalParamMock, overrides?.postCallWithOptionalParamMock); + handlers.push(mocks.postApiVbyApiVersionRequestBodyMock(overrides?.postApiVbyApiVersionRequestBodyMock)); + handlers.push(mocks.postApiVbyApiVersionFormDataMock(overrides?.postApiVbyApiVersionFormDataMock)); + handlers.push(mocks.callWithDefaultParametersMock(overrides?.callWithDefaultParametersMock)); + handlers.push(mocks.callWithDefaultOptionalParametersMock(overrides?.callWithDefaultOptionalParametersMock)); + handlers.push(mocks.callToTestOrderOfParamsMock(overrides?.callToTestOrderOfParamsMock)); + handlers.push(mocks.duplicateNameMock(overrides?.duplicateNameMock)); + handlers.push(mocks.duplicateName2Mock(overrides?.duplicateName2Mock)); + handlers.push(mocks.duplicateName3Mock(overrides?.duplicateName3Mock)); + handlers.push(mocks.duplicateName4Mock(overrides?.duplicateName4Mock)); + handlers.push(mocks.callWithNoContentResponseMock(overrides?.callWithNoContentResponseMock)); + addRequiredHandler(mocks.callWithResponseAndNoContentResponseMock, overrides?.callWithResponseAndNoContentResponseMock); + addRequiredHandler(mocks.dummyAMock, overrides?.dummyAMock); + handlers.push(mocks.dummyBMock(overrides?.dummyBMock)); + handlers.push(mocks.callWithResponseMock(overrides?.callWithResponseMock)); + addRequiredHandler(mocks.callWithDuplicateResponsesMock, overrides?.callWithDuplicateResponsesMock); + addRequiredHandler(mocks.callWithResponsesMock, overrides?.callWithResponsesMock); + handlers.push(mocks.collectionFormatMock(overrides?.collectionFormatMock)); + addRequiredHandler(mocks.typesMock, overrides?.typesMock); + addRequiredHandler(mocks.uploadFileMock, overrides?.uploadFileMock); + addRequiredHandler(mocks.fileResponseMock, overrides?.fileResponseMock); + addRequiredHandler(mocks.complexTypesMock, overrides?.complexTypesMock); + addRequiredHandler(mocks.multipartResponseMock, overrides?.multipartResponseMock); + handlers.push(mocks.multipartRequestMock(overrides?.multipartRequestMock)); + addRequiredHandler(mocks.complexParamsMock, overrides?.complexParamsMock); + handlers.push(mocks.callWithResultFromHeaderMock(overrides?.callWithResultFromHeaderMock)); + handlers.push(mocks.testErrorCodeMock(overrides?.testErrorCodeMock)); + addRequiredHandler(mocks.nonAsciiæøåÆøÅöôêÊ字符串Mock, overrides?.nonAsciiæøåÆøÅöôêÊ字符串Mock); + handlers.push(mocks.putWithFormUrlEncodedMock(overrides?.putWithFormUrlEncodedMock)); + return handlers; + }; + return { ...mocks, getAllMocks }; +}; + +const _defaults = createMswHandlerFactory({ baseUrl: '*' }); + +export const exportMock = _defaults.exportMock; + +export const patchApiVbyApiVersionNoTagMock = _defaults.patchApiVbyApiVersionNoTagMock; + +export const importMock = _defaults.importMock; + +export const fooWowMock = _defaults.fooWowMock; + +export const apiVVersionODataControllerCountMock = _defaults.apiVVersionODataControllerCountMock; + +export const getApiVbyApiVersionSimpleOperationMock = _defaults.getApiVbyApiVersionSimpleOperationMock; + +export const deleteCallWithoutParametersAndResponseMock = _defaults.deleteCallWithoutParametersAndResponseMock; + +export const getCallWithoutParametersAndResponseMock = _defaults.getCallWithoutParametersAndResponseMock; + +export const headCallWithoutParametersAndResponseMock = _defaults.headCallWithoutParametersAndResponseMock; + +export const optionsCallWithoutParametersAndResponseMock = _defaults.optionsCallWithoutParametersAndResponseMock; + +export const patchCallWithoutParametersAndResponseMock = _defaults.patchCallWithoutParametersAndResponseMock; + +export const postCallWithoutParametersAndResponseMock = _defaults.postCallWithoutParametersAndResponseMock; + +export const putCallWithoutParametersAndResponseMock = _defaults.putCallWithoutParametersAndResponseMock; + +export const deleteFooMock = _defaults.deleteFooMock; + +export const callWithDescriptionsMock = _defaults.callWithDescriptionsMock; + +export const deprecatedCallMock = _defaults.deprecatedCallMock; + +export const callWithParametersMock = _defaults.callWithParametersMock; + +export const callWithWeirdParameterNamesMock = _defaults.callWithWeirdParameterNamesMock; + +export const getCallWithOptionalParamMock = _defaults.getCallWithOptionalParamMock; + +export const postCallWithOptionalParamMock = _defaults.postCallWithOptionalParamMock; + +export const postApiVbyApiVersionRequestBodyMock = _defaults.postApiVbyApiVersionRequestBodyMock; + +export const postApiVbyApiVersionFormDataMock = _defaults.postApiVbyApiVersionFormDataMock; + +export const callWithDefaultParametersMock = _defaults.callWithDefaultParametersMock; + +export const callWithDefaultOptionalParametersMock = _defaults.callWithDefaultOptionalParametersMock; + +export const callToTestOrderOfParamsMock = _defaults.callToTestOrderOfParamsMock; + +export const duplicateNameMock = _defaults.duplicateNameMock; + +export const duplicateName2Mock = _defaults.duplicateName2Mock; + +export const duplicateName3Mock = _defaults.duplicateName3Mock; + +export const duplicateName4Mock = _defaults.duplicateName4Mock; + +export const callWithNoContentResponseMock = _defaults.callWithNoContentResponseMock; + +export const callWithResponseAndNoContentResponseMock = _defaults.callWithResponseAndNoContentResponseMock; + +export const dummyAMock = _defaults.dummyAMock; + +export const dummyBMock = _defaults.dummyBMock; + +export const callWithResponseMock = _defaults.callWithResponseMock; + +export const callWithDuplicateResponsesMock = _defaults.callWithDuplicateResponsesMock; + +export const callWithResponsesMock = _defaults.callWithResponsesMock; + +export const collectionFormatMock = _defaults.collectionFormatMock; + +export const typesMock = _defaults.typesMock; + +export const uploadFileMock = _defaults.uploadFileMock; + +export const fileResponseMock = _defaults.fileResponseMock; + +export const complexTypesMock = _defaults.complexTypesMock; + +export const multipartResponseMock = _defaults.multipartResponseMock; + +export const multipartRequestMock = _defaults.multipartRequestMock; + +export const complexParamsMock = _defaults.complexParamsMock; + +export const callWithResultFromHeaderMock = _defaults.callWithResultFromHeaderMock; + +export const testErrorCodeMock = _defaults.testErrorCodeMock; + +export const nonAsciiæøåÆøÅöôêÊ字符串Mock = _defaults.nonAsciiæøåÆøÅöôêÊ字符串Mock; + +export const putWithFormUrlEncodedMock = _defaults.putWithFormUrlEncodedMock; + +export const getAllMocks = _defaults.getAllMocks; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/default/types.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/default/types.gen.ts new file mode 100644 index 0000000000..d819316644 --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/default/types.gen.ts @@ -0,0 +1,2100 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type ClientOptions = { + baseUrl: 'http://localhost:3000/base' | (string & {}); +}; + +/** + * Model with number-only name + */ +export type _400 = string; + +/** + * External ref to shared model (A) + */ +export type ExternalRefA = ExternalSharedModel; + +/** + * External ref to shared model (B) + */ +export type ExternalRefB = ExternalSharedModel; + +/** + * Testing multiline comments in string: First line + * Second line + * + * Fourth line + */ +export type CamelCaseCommentWithBreaks = number; + +/** + * Testing multiline comments in string: First line + * Second line + * + * Fourth line + */ +export type CommentWithBreaks = number; + +/** + * Testing backticks in string: `backticks` and ```multiple backticks``` should work + */ +export type CommentWithBackticks = number; + +/** + * Testing backticks and quotes in string: `backticks`, 'quotes', "double quotes" and ```multiple backticks``` should work + */ +export type CommentWithBackticksAndQuotes = number; + +/** + * Testing slashes in string: \backwards\\\ and /forwards/// should work + */ +export type CommentWithSlashes = number; + +/** + * Testing expression placeholders in string: ${expression} should work + */ +export type CommentWithExpressionPlaceholders = number; + +/** + * Testing quotes in string: 'single quote''' and "double quotes""" should work + */ +export type CommentWithQuotes = number; + +/** + * Testing reserved characters in string: * inline * and ** inline ** should work + */ +export type CommentWithReservedCharacters = number; + +/** + * This is a simple number + */ +export type SimpleInteger = number; + +/** + * This is a simple boolean + */ +export type SimpleBoolean = boolean; + +/** + * This is a simple string + */ +export type SimpleString = string; + +/** + * A string with non-ascii (unicode) characters valid in typescript identifiers (æøåÆØÅöÔèÈ字符串) + */ +export type NonAsciiStringæøåÆøÅöôêÊ字符串 = string; + +/** + * This is a simple file + */ +export type SimpleFile = Blob | File; + +/** + * This is a simple reference + */ +export type SimpleReference = ModelWithString; + +/** + * This is a simple string + */ +export type SimpleStringWithPattern = string | null; + +/** + * This is a simple enum with strings + */ +export type EnumWithStrings = 'Success' | 'Warning' | 'Error' | '\'Single Quote\'' | '"Double Quotes"' | 'Non-ascii: øæåôöØÆÅÔÖ字符串'; + +export type EnumWithReplacedCharacters = '\'Single Quote\'' | '"Double Quotes"' | 'øæåôöØÆÅÔÖ字符串' | 3.1 | ''; + +/** + * This is a simple enum with numbers + */ +export type EnumWithNumbers = 1 | 2 | 3 | 1.1 | 1.2 | 1.3 | 100 | 200 | 300 | -100 | -200 | -300 | -1.1 | -1.2 | -1.3; + +/** + * Success=1,Warning=2,Error=3 + */ +export type EnumFromDescription = number; + +/** + * This is a simple enum with numbers + */ +export type EnumWithExtensions = 200 | 400 | 500; + +export type EnumWithXEnumNames = 0 | 1 | 2; + +/** + * This is a simple array with numbers + */ +export type ArrayWithNumbers = Array; + +/** + * This is a simple array with booleans + */ +export type ArrayWithBooleans = Array; + +/** + * This is a simple array with strings + */ +export type ArrayWithStrings = Array; + +/** + * This is a simple array with references + */ +export type ArrayWithReferences = Array; + +/** + * This is a simple array containing an array + */ +export type ArrayWithArray = Array>; + +/** + * This is a simple array with properties + */ +export type ArrayWithProperties = Array<{ + '16x16'?: CamelCaseCommentWithBreaks; + bar?: string; +}>; + +/** + * This is a simple array with any of properties + */ +export type ArrayWithAnyOfProperties = Array<{ + foo?: string; +} | { + bar?: string; +}>; + +export type AnyOfAnyAndNull = { + data?: unknown | null; +}; + +/** + * This is a simple array with any of properties + */ +export type AnyOfArrays = { + results?: Array<{ + foo?: string; + } | { + bar?: string; + }>; +}; + +/** + * This is a string dictionary + */ +export type DictionaryWithString = { + [key: string]: string; +}; + +export type DictionaryWithPropertiesAndAdditionalProperties = { + foo?: number; + bar?: boolean; + [key: string]: string | number | boolean | undefined; +}; + +/** + * This is a string reference + */ +export type DictionaryWithReference = { + [key: string]: ModelWithString; +}; + +/** + * This is a complex dictionary + */ +export type DictionaryWithArray = { + [key: string]: Array; +}; + +/** + * This is a string dictionary + */ +export type DictionaryWithDictionary = { + [key: string]: { + [key: string]: string; + }; +}; + +/** + * This is a complex dictionary + */ +export type DictionaryWithProperties = { + [key: string]: { + foo?: string; + bar?: string; + }; +}; + +/** + * This is a model with one number property + */ +export type ModelWithInteger = { + /** + * This is a simple number property + */ + prop?: number; +}; + +/** + * This is a model with one boolean property + */ +export type ModelWithBoolean = { + /** + * This is a simple boolean property + */ + prop?: boolean; +}; + +/** + * This is a model with one string property + */ +export type ModelWithString = { + /** + * This is a simple string property + */ + prop?: string; +}; + +/** + * This is a model with one string property + */ +export type ModelWithStringError = { + /** + * This is a simple string property + */ + prop?: string; +}; + +/** + * `Comment` or `VoiceComment`. The JSON object for adding voice comments to tickets is different. See [Adding voice comments to tickets](/documentation/ticketing/managing-tickets/adding-voice-comments-to-tickets) + */ +export type ModelFromZendesk = string; + +/** + * This is a model with one string property + */ +export type ModelWithNullableString = { + /** + * This is a simple string property + */ + nullableProp1?: string | null; + /** + * This is a simple string property + */ + nullableRequiredProp1: string | null; + /** + * This is a simple string property + */ + nullableProp2?: string | null; + /** + * This is a simple string property + */ + nullableRequiredProp2: string | null; + /** + * This is a simple enum with strings + */ + 'foo_bar-enum'?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; +}; + +/** + * This is a model with one enum + */ +export type ModelWithEnum = { + /** + * This is a simple enum with strings + */ + 'foo_bar-enum'?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; + /** + * These are the HTTP error code enums + */ + statusCode?: '100' | '200 FOO' | '300 FOO_BAR' | '400 foo-bar' | '500 foo.bar' | '600 foo&bar'; + /** + * Simple boolean enum + */ + bool?: true; +}; + +/** + * This is a model with one enum with escaped name + */ +export type ModelWithEnumWithHyphen = { + /** + * Foo-Bar-Baz-Qux + */ + 'foo-bar-baz-qux'?: '3.0'; +}; + +/** + * This is a model with one enum + */ +export type ModelWithEnumFromDescription = { + /** + * Success=1,Warning=2,Error=3 + */ + test?: number; +}; + +/** + * This is a model with nested enums + */ +export type ModelWithNestedEnums = { + dictionaryWithEnum?: { + [key: string]: 'Success' | 'Warning' | 'Error'; + }; + dictionaryWithEnumFromDescription?: { + [key: string]: number; + }; + arrayWithEnum?: Array<'Success' | 'Warning' | 'Error'>; + arrayWithDescription?: Array; + /** + * This is a simple enum with strings + */ + 'foo_bar-enum'?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; +}; + +/** + * This is a model with one property containing a reference + */ +export type ModelWithReference = { + prop?: ModelWithProperties; +}; + +/** + * This is a model with one property containing an array + */ +export type ModelWithArrayReadOnlyAndWriteOnly = { + prop?: Array; + propWithFile?: Array; + propWithNumber?: Array; +}; + +/** + * This is a model with one property containing an array + */ +export type ModelWithArray = { + prop?: Array; + propWithFile?: Array; + propWithNumber?: Array; +}; + +/** + * This is a model with one property containing a dictionary + */ +export type ModelWithDictionary = { + prop?: { + [key: string]: string; + }; +}; + +/** + * This is a deprecated model with a deprecated property + * + * @deprecated + */ +export type DeprecatedModel = { + /** + * This is a deprecated property + * + * @deprecated + */ + prop?: string; +}; + +/** + * This is a model with one property containing a circular reference + */ +export type ModelWithCircularReference = { + prop?: ModelWithCircularReference; +}; + +/** + * This is a model with one property with a 'one of' relationship + */ +export type CompositionWithOneOf = { + propA?: ModelWithString | ModelWithEnum | ModelWithArray | ModelWithDictionary; +}; + +/** + * This is a model with one property with a 'one of' relationship where the options are not $ref + */ +export type CompositionWithOneOfAnonymous = { + propA?: { + propA?: string; + } | string | number; +}; + +/** + * Circle + */ +export type ModelCircle = { + kind: string; + radius?: number; +}; + +/** + * Square + */ +export type ModelSquare = { + kind: string; + sideLength?: number; +}; + +/** + * This is a model with one property with a 'one of' relationship where the options are not $ref + */ +export type CompositionWithOneOfDiscriminator = ({ + kind: 'circle'; +} & ModelCircle) | ({ + kind: 'square'; +} & ModelSquare); + +/** + * This is a model with one property with a 'any of' relationship + */ +export type CompositionWithAnyOf = { + propA?: ModelWithString | ModelWithEnum | ModelWithArray | ModelWithDictionary; +}; + +/** + * This is a model with one property with a 'any of' relationship where the options are not $ref + */ +export type CompositionWithAnyOfAnonymous = { + propA?: { + propA?: string; + } | string | number; +}; + +/** + * This is a model with nested 'any of' property with a type null + */ +export type CompositionWithNestedAnyAndTypeNull = { + propA?: Array | Array; +}; + +export type _3eNum1Период = 'Bird' | 'Dog'; + +export type ConstValue = 'ConstValue'; + +/** + * This is a model with one property with a 'any of' relationship where the options are not $ref + */ +export type CompositionWithNestedAnyOfAndNull = { + /** + * Scopes + */ + propA?: Array<_3eNum1Период | ConstValue> | null; +}; + +/** + * This is a model with one property with a 'one of' relationship + */ +export type CompositionWithOneOfAndNullable = { + propA?: { + boolean?: boolean; + } | ModelWithEnum | ModelWithArray | ModelWithDictionary | null; +}; + +/** + * This is a model that contains a simple dictionary within composition + */ +export type CompositionWithOneOfAndSimpleDictionary = { + propA?: boolean | { + [key: string]: number; + }; +}; + +/** + * This is a model that contains a dictionary of simple arrays within composition + */ +export type CompositionWithOneOfAndSimpleArrayDictionary = { + propA?: boolean | { + [key: string]: Array; + }; +}; + +/** + * This is a model that contains a dictionary of complex arrays (composited) within composition + */ +export type CompositionWithOneOfAndComplexArrayDictionary = { + propA?: boolean | { + [key: string]: Array; + }; +}; + +/** + * This is a model with one property with a 'all of' relationship + */ +export type CompositionWithAllOfAndNullable = { + propA?: ({ + boolean?: boolean; + } & ModelWithEnum & ModelWithArray & ModelWithDictionary) | null; +}; + +/** + * This is a model with one property with a 'any of' relationship + */ +export type CompositionWithAnyOfAndNullable = { + propA?: { + boolean?: boolean; + } | ModelWithEnum | ModelWithArray | ModelWithDictionary | null; +}; + +/** + * This is a base model with two simple optional properties + */ +export type CompositionBaseModel = { + firstName?: string; + lastname?: string; +}; + +/** + * This is a model that extends the base model + */ +export type CompositionExtendedModel = CompositionBaseModel & { + age: number; + firstName: string; + lastname: string; +}; + +/** + * This is a model with one nested property + */ +export type ModelWithProperties = { + required: string; + readonly requiredAndReadOnly: string; + requiredAndNullable: string | null; + string?: string; + number?: number; + boolean?: boolean; + reference?: ModelWithString; + 'property with space'?: string; + default?: string; + try?: string; + readonly '@namespace.string'?: string; + readonly '@namespace.integer'?: number; +}; + +/** + * This is a model with one nested property + */ +export type ModelWithNestedProperties = { + readonly first: { + readonly second: { + readonly third: string | null; + } | null; + } | null; +}; + +/** + * This is a model with duplicated properties + */ +export type ModelWithDuplicateProperties = { + prop?: ModelWithString; +}; + +/** + * This is a model with ordered properties + */ +export type ModelWithOrderedProperties = { + zebra?: string; + apple?: string; + hawaii?: string; +}; + +/** + * This is a model with duplicated imports + */ +export type ModelWithDuplicateImports = { + propA?: ModelWithString; + propB?: ModelWithString; + propC?: ModelWithString; +}; + +/** + * This is a model that extends another model + */ +export type ModelThatExtends = ModelWithString & { + propExtendsA?: string; + propExtendsB?: ModelWithString; +}; + +/** + * This is a model that extends another model + */ +export type ModelThatExtendsExtends = ModelWithString & ModelThatExtends & { + propExtendsC?: string; + propExtendsD?: ModelWithString; +}; + +/** + * This is a model that contains a some patterns + */ +export type ModelWithPattern = { + key: string; + name: string; + readonly enabled?: boolean; + readonly modified?: string; + id?: string; + text?: string; + patternWithSingleQuotes?: string; + patternWithNewline?: string; + patternWithBacktick?: string; + patternWithUnicode?: string; +}; + +export type File = { + /** + * Id + */ + readonly id?: string; + /** + * Updated at + */ + readonly updated_at?: string; + /** + * Created at + */ + readonly created_at?: string; + /** + * Mime + */ + mime: string; + /** + * File + */ + readonly file?: string; +}; + +export type Default = { + name?: string; +}; + +export type Pageable = { + page?: number; + size?: number; + sort?: Array; +}; + +/** + * This is a free-form object without additionalProperties. + */ +export type FreeFormObjectWithoutAdditionalProperties = { + [key: string]: unknown; +}; + +/** + * This is a free-form object with additionalProperties: true. + */ +export type FreeFormObjectWithAdditionalPropertiesEqTrue = { + [key: string]: unknown; +}; + +/** + * This is a free-form object with additionalProperties: {}. + */ +export type FreeFormObjectWithAdditionalPropertiesEqEmptyObject = { + [key: string]: unknown; +}; + +export type ModelWithConst = { + String?: 'String'; + number?: 0; + null?: null; + withType?: 'Some string'; +}; + +/** + * This is a model with one property and additionalProperties: true + */ +export type ModelWithAdditionalPropertiesEqTrue = { + /** + * This is a simple string property + */ + prop?: string; + [key: string]: unknown; +}; + +export type NestedAnyOfArraysNullable = { + nullableArray?: Array | null; +}; + +export type CompositionWithOneOfAndProperties = ({ + foo: SimpleParameter; +} | { + bar: NonAsciiStringæøåÆøÅöôêÊ字符串; +}) & { + baz: number | null; + qux: number; +}; + +/** + * An object that can be null + */ +export type NullableObject = { + foo?: string; +} | null; + +/** + * Some % character + */ +export type CharactersInDescription = string; + +export type ModelWithNullableObject = { + data?: NullableObject; +}; + +/** + * An object with additional properties that can be null (anyOf ref + null) + */ +export type ModelWithAdditionalPropertiesRef = { + [key: string]: NullableObject | null; +}; + +export type ModelWithOneOfEnum = { + foo: 'Bar'; +} | { + foo: 'Baz'; +} | { + foo: 'Qux'; +} | { + content: string; + foo: 'Quux'; +} | { + content: [ + string, + string + ]; + foo: 'Corge'; +}; + +export type ModelWithNestedArrayEnumsDataFoo = 'foo' | 'bar'; + +export type ModelWithNestedArrayEnumsDataBar = 'baz' | 'qux'; + +export type ModelWithNestedArrayEnumsData = { + foo?: Array; + bar?: Array; +}; + +export type ModelWithNestedArrayEnums = { + array_strings?: Array; + data?: ModelWithNestedArrayEnumsData; +}; + +export type ModelWithNestedCompositionEnums = { + foo?: ModelWithNestedArrayEnumsDataFoo; +}; + +export type ModelWithReadOnlyAndWriteOnly = { + foo: string; + readonly bar: string; +}; + +export type ModelWithConstantSizeArray = [ + number, + number +]; + +export type ModelWithAnyOfConstantSizeArray = [ + number | string, + number | string, + number | string +]; + +export type ModelWithPrefixItemsConstantSizeArray = [ + ModelWithInteger, + number | string, + string +]; + +export type ModelWithAnyOfConstantSizeArrayNullable = [ + number | null | string, + number | null | string, + number | null | string +]; + +export type ModelWithAnyOfConstantSizeArrayWithNSizeAndOptions = [ + number | Import, + number | Import +]; + +export type ModelWithAnyOfConstantSizeArrayAndIntersect = [ + number & string, + number & string +]; + +export type ModelWithNumericEnumUnion = { + /** + * Период + */ + value?: -10 | -1 | 0 | 1 | 3 | 6 | 12; +}; + +/** + * Some description with `back ticks` + */ +export type ModelWithBackticksInDescription = { + /** + * The template `that` should be used for parsing and importing the contents of the CSV file. + * + *

There is one placeholder currently supported:

  • ${x} - refers to the n-th column in the CSV file, e.g. ${1}, ${2}, ...)

Example of a correct JSON template:

+ *
+     * [
+     * {
+     * "resourceType": "Asset",
+     * "identifier": {
+     * "name": "${1}",
+     * "domain": {
+     * "name": "${2}",
+     * "community": {
+     * "name": "Some Community"
+     * }
+     * }
+     * },
+     * "attributes" : {
+     * "00000000-0000-0000-0000-000000003115" : [ {
+     * "value" : "${3}"
+     * } ],
+     * "00000000-0000-0000-0000-000000000222" : [ {
+     * "value" : "${4}"
+     * } ]
+     * }
+     * }
+     * ]
+     * 
+ */ + template?: string; +}; + +export type ModelWithOneOfAndProperties = (SimpleParameter | NonAsciiStringæøåÆøÅöôêÊ字符串) & { + baz: number | null; + qux: number; +}; + +/** + * Model used to test deduplication strategy (unused) + */ +export type ParameterSimpleParameterUnused = string; + +/** + * Model used to test deduplication strategy + */ +export type PostServiceWithEmptyTagResponse = string; + +/** + * Model used to test deduplication strategy + */ +export type PostServiceWithEmptyTagResponse2 = string; + +/** + * Model used to test deduplication strategy + */ +export type DeleteFooData = string; + +/** + * Model used to test deduplication strategy + */ +export type DeleteFooData2 = string; + +/** + * Model with restricted keyword name + */ +export type Import = string; + +export type SchemaWithFormRestrictedKeys = { + description?: string; + 'x-enum-descriptions'?: string; + 'x-enum-varnames'?: string; + 'x-enumNames'?: string; + title?: string; + object?: { + description?: string; + 'x-enum-descriptions'?: string; + 'x-enum-varnames'?: string; + 'x-enumNames'?: string; + title?: string; + }; + array?: Array<{ + description?: string; + 'x-enum-descriptions'?: string; + 'x-enum-varnames'?: string; + 'x-enumNames'?: string; + title?: string; + }>; +}; + +/** + * This schema was giving PascalCase transformations a hard time + */ +export type IoK8sApimachineryPkgApisMetaV1DeleteOptions = { + /** + * Must be fulfilled before a deletion is carried out. If not possible, a 409 Conflict status will be returned. + */ + preconditions?: IoK8sApimachineryPkgApisMetaV1Preconditions; +}; + +/** + * This schema was giving PascalCase transformations a hard time + */ +export type IoK8sApimachineryPkgApisMetaV1Preconditions = { + /** + * Specifies the target ResourceVersion + */ + resourceVersion?: string; + /** + * Specifies the target UID. + */ + uid?: string; +}; + +export type AdditionalPropertiesUnknownIssue = { + [key: string]: string | number; +}; + +export type AdditionalPropertiesUnknownIssue2 = { + [key: string]: string | number; +}; + +export type AdditionalPropertiesUnknownIssue3 = string & { + entries: { + [key: string]: AdditionalPropertiesUnknownIssue; + }; +}; + +export type AdditionalPropertiesIntegerIssue = { + value: number; + [key: string]: number; +}; + +export type OneOfAllOfIssue = ((ConstValue | GenericSchemaDuplicateIssue1SystemBoolean) & _3eNum1Период) | GenericSchemaDuplicateIssue1SystemString; + +export type GenericSchemaDuplicateIssue1SystemBoolean = { + item?: boolean; + error?: string | null; + readonly hasError?: boolean; + data?: { + [key: string]: never; + }; +}; + +export type GenericSchemaDuplicateIssue1SystemString = { + item?: string | null; + error?: string | null; + readonly hasError?: boolean; +}; + +export type ExternalSharedModel = { + id: string; + name?: string; +}; + +/** + * This is a model with one property containing a reference + */ +export type ModelWithReferenceWritable = { + prop?: ModelWithPropertiesWritable; +}; + +/** + * This is a model with one property containing an array + */ +export type ModelWithArrayReadOnlyAndWriteOnlyWritable = { + prop?: Array; + propWithFile?: Array; + propWithNumber?: Array; +}; + +/** + * This is a model with one nested property + */ +export type ModelWithPropertiesWritable = { + required: string; + requiredAndNullable: string | null; + string?: string; + number?: number; + boolean?: boolean; + reference?: ModelWithString; + 'property with space'?: string; + default?: string; + try?: string; +}; + +/** + * This is a model that contains a some patterns + */ +export type ModelWithPatternWritable = { + key: string; + name: string; + id?: string; + text?: string; + patternWithSingleQuotes?: string; + patternWithNewline?: string; + patternWithBacktick?: string; + patternWithUnicode?: string; +}; + +export type FileWritable = { + /** + * Mime + */ + mime: string; +}; + +export type ModelWithReadOnlyAndWriteOnlyWritable = { + foo: string; + baz: string; +}; + +export type ModelWithAnyOfConstantSizeArrayWithNSizeAndOptionsWritable = [ + number | Import, + number | Import +]; + +export type AdditionalPropertiesUnknownIssueWritable = { + [key: string]: string | number; +}; + +export type OneOfAllOfIssueWritable = ((ConstValue | GenericSchemaDuplicateIssue1SystemBoolean) & _3eNum1Период) | GenericSchemaDuplicateIssue1SystemString; + +export type GenericSchemaDuplicateIssue1SystemBooleanWritable = { + item?: boolean; + error?: string | null; + data?: { + [key: string]: never; + }; +}; + +export type GenericSchemaDuplicateIssue1SystemStringWritable = { + item?: string | null; + error?: string | null; +}; + +/** + * This is a reusable parameter + */ +export type SimpleParameter = string; + +/** + * Parameter with illegal characters + */ +export type XFooBar = ModelWithString; + +/** + * A reusable request body + */ +export type SimpleRequestBody = ModelWithString; + +/** + * A reusable request body + */ +export type SimpleFormData = ModelWithString; + +export type ExportData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/no+tag'; +}; + +export type PatchApiVbyApiVersionNoTagData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/no+tag'; +}; + +export type PatchApiVbyApiVersionNoTagResponses = { + /** + * OK + */ + default: unknown; +}; + +export type ImportData = { + body: ModelWithReadOnlyAndWriteOnlyWritable | ModelWithArrayReadOnlyAndWriteOnlyWritable; + path?: never; + query?: never; + url: '/api/v{api-version}/no+tag'; +}; + +export type ImportResponses = { + /** + * Success + */ + 200: ModelFromZendesk; + /** + * Default success response + */ + default: ModelWithReadOnlyAndWriteOnly; +}; + +export type ImportResponse = ImportResponses[keyof ImportResponses]; + +export type FooWowData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/no+tag'; +}; + +export type FooWowResponses = { + /** + * OK + */ + default: unknown; +}; + +export type ApiVVersionODataControllerCountData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/simple/$count'; +}; + +export type ApiVVersionODataControllerCountResponses = { + /** + * Success + */ + 200: ModelFromZendesk; +}; + +export type ApiVVersionODataControllerCountResponse = ApiVVersionODataControllerCountResponses[keyof ApiVVersionODataControllerCountResponses]; + +export type GetApiVbyApiVersionSimpleOperationData = { + body?: never; + path: { + /** + * foo in method + */ + foo_param: string; + }; + query?: never; + url: '/api/v{api-version}/simple:operation'; +}; + +export type GetApiVbyApiVersionSimpleOperationErrors = { + /** + * Default error response + */ + default: ModelWithBoolean; +}; + +export type GetApiVbyApiVersionSimpleOperationError = GetApiVbyApiVersionSimpleOperationErrors[keyof GetApiVbyApiVersionSimpleOperationErrors]; + +export type GetApiVbyApiVersionSimpleOperationResponses = { + /** + * Response is a simple number + */ + 200: number; +}; + +export type GetApiVbyApiVersionSimpleOperationResponse = GetApiVbyApiVersionSimpleOperationResponses[keyof GetApiVbyApiVersionSimpleOperationResponses]; + +export type DeleteCallWithoutParametersAndResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/simple'; +}; + +export type GetCallWithoutParametersAndResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/simple'; +}; + +export type HeadCallWithoutParametersAndResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/simple'; +}; + +export type OptionsCallWithoutParametersAndResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/simple'; +}; + +export type PatchCallWithoutParametersAndResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/simple'; +}; + +export type PostCallWithoutParametersAndResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/simple'; +}; + +export type PutCallWithoutParametersAndResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/simple'; +}; + +export type DeleteFooData3 = { + body?: never; + headers: { + /** + * Parameter with illegal characters + */ + 'x-Foo-Bar': ModelWithString; + }; + path: { + /** + * foo in method + */ + foo_param: string; + /** + * bar in method + */ + BarParam: string; + }; + query?: never; + url: '/api/v{api-version}/foo/{foo_param}/bar/{BarParam}'; +}; + +export type CallWithDescriptionsData = { + body?: never; + path?: never; + query?: { + /** + * Testing multiline comments in string: First line + * Second line + * + * Fourth line + */ + parameterWithBreaks?: string; + /** + * Testing backticks in string: `backticks` and ```multiple backticks``` should work + */ + parameterWithBackticks?: string; + /** + * Testing slashes in string: \backwards\\\ and /forwards/// should work + */ + parameterWithSlashes?: string; + /** + * Testing expression placeholders in string: ${expression} should work + */ + parameterWithExpressionPlaceholders?: string; + /** + * Testing quotes in string: 'single quote''' and "double quotes""" should work + */ + parameterWithQuotes?: string; + /** + * Testing reserved characters in string: * inline * and ** inline ** should work + */ + parameterWithReservedCharacters?: string; + }; + url: '/api/v{api-version}/descriptions'; +}; + +export type DeprecatedCallData = { + body?: never; + headers: { + /** + * This parameter is deprecated + * + * @deprecated + */ + parameter: DeprecatedModel | null; + }; + path?: never; + query?: never; + url: '/api/v{api-version}/parameters/deprecated'; +}; + +export type CallWithParametersData = { + /** + * This is the parameter that goes into the body + */ + body: { + [key: string]: unknown; + } | null; + headers: { + /** + * This is the parameter that goes into the header + */ + parameterHeader: string | null; + }; + path: { + /** + * This is the parameter that goes into the path + */ + parameterPath: string | null; + /** + * api-version should be required in standalone clients + */ + 'api-version': string | null; + }; + query: { + foo_ref_enum?: ModelWithNestedArrayEnumsDataFoo; + foo_all_of_enum: ModelWithNestedArrayEnumsDataFoo; + /** + * This is the parameter that goes into the query params + */ + cursor: string | null; + }; + url: '/api/v{api-version}/parameters/{parameterPath}'; +}; + +export type CallWithWeirdParameterNamesData = { + /** + * This is the parameter that goes into the body + */ + body: ModelWithString | null; + headers: { + /** + * This is the parameter that goes into the request header + */ + 'parameter.header': string | null; + }; + path: { + /** + * This is the parameter that goes into the path + */ + 'parameter.path.1'?: string; + /** + * This is the parameter that goes into the path + */ + 'parameter-path-2'?: string; + /** + * This is the parameter that goes into the path + */ + 'PARAMETER-PATH-3'?: string; + /** + * api-version should be required in standalone clients + */ + 'api-version': string | null; + }; + query: { + /** + * This is the parameter with a reserved keyword + */ + default?: string; + /** + * This is the parameter that goes into the request query params + */ + 'parameter-query': string | null; + }; + url: '/api/v{api-version}/parameters/{parameter.path.1}/{parameter-path-2}/{PARAMETER-PATH-3}'; +}; + +export type GetCallWithOptionalParamData = { + /** + * This is a required parameter + */ + body: ModelWithOneOfEnum; + path?: never; + query?: { + /** + * This is an optional parameter + */ + page?: number; + }; + url: '/api/v{api-version}/parameters'; +}; + +export type PostCallWithOptionalParamData = { + /** + * This is an optional parameter + */ + body?: { + offset?: number | null; + }; + path?: never; + query: { + /** + * This is a required parameter + */ + parameter: Pageable; + }; + url: '/api/v{api-version}/parameters'; +}; + +export type PostCallWithOptionalParamResponses = { + /** + * Response is a simple number + */ + 200: number; + /** + * Success + */ + 204: void; +}; + +export type PostCallWithOptionalParamResponse = PostCallWithOptionalParamResponses[keyof PostCallWithOptionalParamResponses]; + +export type PostApiVbyApiVersionRequestBodyData = { + /** + * A reusable request body + */ + body?: SimpleRequestBody; + path?: never; + query?: { + /** + * This is a reusable parameter + */ + parameter?: string; + }; + url: '/api/v{api-version}/requestBody'; +}; + +export type PostApiVbyApiVersionFormDataData = { + /** + * A reusable request body + */ + body?: SimpleFormData; + path?: never; + query?: { + /** + * This is a reusable parameter + */ + parameter?: string; + }; + url: '/api/v{api-version}/formData'; +}; + +export type CallWithDefaultParametersData = { + body?: never; + path?: never; + query?: { + /** + * This is a simple string with default value + */ + parameterString?: string | null; + /** + * This is a simple number with default value + */ + parameterNumber?: number | null; + /** + * This is a simple boolean with default value + */ + parameterBoolean?: boolean | null; + /** + * This is a simple enum with default value + */ + parameterEnum?: 'Success' | 'Warning' | 'Error'; + /** + * This is a simple model with default value + */ + parameterModel?: ModelWithString | null; + }; + url: '/api/v{api-version}/defaults'; +}; + +export type CallWithDefaultOptionalParametersData = { + body?: never; + path?: never; + query?: { + /** + * This is a simple string that is optional with default value + */ + parameterString?: string; + /** + * This is a simple number that is optional with default value + */ + parameterNumber?: number; + /** + * This is a simple boolean that is optional with default value + */ + parameterBoolean?: boolean; + /** + * This is a simple enum that is optional with default value + */ + parameterEnum?: 'Success' | 'Warning' | 'Error'; + /** + * This is a simple model that is optional with default value + */ + parameterModel?: ModelWithString; + }; + url: '/api/v{api-version}/defaults'; +}; + +export type CallToTestOrderOfParamsData = { + body?: never; + path?: never; + query: { + /** + * This is a optional string with default + */ + parameterOptionalStringWithDefault?: string; + /** + * This is a optional string with empty default + */ + parameterOptionalStringWithEmptyDefault?: string; + /** + * This is a optional string with no default + */ + parameterOptionalStringWithNoDefault?: string; + /** + * This is a string with default + */ + parameterStringWithDefault: string; + /** + * This is a string with empty default + */ + parameterStringWithEmptyDefault: string; + /** + * This is a string with no default + */ + parameterStringWithNoDefault: string; + /** + * This is a string that can be null with no default + */ + parameterStringNullableWithNoDefault?: string | null; + /** + * This is a string that can be null with default + */ + parameterStringNullableWithDefault?: string | null; + }; + url: '/api/v{api-version}/defaults'; +}; + +export type DuplicateNameData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/duplicate'; +}; + +export type DuplicateName2Data = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/duplicate'; +}; + +export type DuplicateName3Data = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/duplicate'; +}; + +export type DuplicateName4Data = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/duplicate'; +}; + +export type CallWithNoContentResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/no-content'; +}; + +export type CallWithNoContentResponseResponses = { + /** + * Success + */ + 204: void; +}; + +export type CallWithNoContentResponseResponse = CallWithNoContentResponseResponses[keyof CallWithNoContentResponseResponses]; + +export type CallWithResponseAndNoContentResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/multiple-tags/response-and-no-content'; +}; + +export type CallWithResponseAndNoContentResponseResponses = { + /** + * Response is a simple number + */ + 200: number; + /** + * Success + */ + 204: void; +}; + +export type CallWithResponseAndNoContentResponseResponse = CallWithResponseAndNoContentResponseResponses[keyof CallWithResponseAndNoContentResponseResponses]; + +export type DummyAData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/multiple-tags/a'; +}; + +export type DummyAResponses = { + 200: _400; +}; + +export type DummyAResponse = DummyAResponses[keyof DummyAResponses]; + +export type DummyBData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/multiple-tags/b'; +}; + +export type DummyBResponses = { + /** + * Success + */ + 204: void; +}; + +export type DummyBResponse = DummyBResponses[keyof DummyBResponses]; + +export type CallWithResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/response'; +}; + +export type CallWithResponseResponses = { + default: Import; +}; + +export type CallWithResponseResponse = CallWithResponseResponses[keyof CallWithResponseResponses]; + +export type CallWithDuplicateResponsesData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/response'; +}; + +export type CallWithDuplicateResponsesErrors = { + /** + * Message for 500 error + */ + 500: ModelWithStringError; + /** + * Message for 501 error + */ + 501: ModelWithStringError; + /** + * Message for 502 error + */ + 502: ModelWithStringError; + /** + * Message for 4XX errors + */ + '4XX': DictionaryWithArray; + /** + * Default error response + */ + default: ModelWithBoolean; +}; + +export type CallWithDuplicateResponsesError = CallWithDuplicateResponsesErrors[keyof CallWithDuplicateResponsesErrors]; + +export type CallWithDuplicateResponsesResponses = { + /** + * Message for 200 response + */ + 200: ModelWithBoolean & ModelWithInteger; + /** + * Message for 201 response + */ + 201: ModelWithString; + /** + * Message for 202 response + */ + 202: ModelWithString; +}; + +export type CallWithDuplicateResponsesResponse = CallWithDuplicateResponsesResponses[keyof CallWithDuplicateResponsesResponses]; + +export type CallWithResponsesData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/response'; +}; + +export type CallWithResponsesErrors = { + /** + * Message for 500 error + */ + 500: ModelWithStringError; + /** + * Message for 501 error + */ + 501: ModelWithStringError; + /** + * Message for 502 error + */ + 502: ModelWithStringError; + /** + * Message for default response + */ + default: ModelWithStringError; +}; + +export type CallWithResponsesError = CallWithResponsesErrors[keyof CallWithResponsesErrors]; + +export type CallWithResponsesResponses = { + /** + * Message for 200 response + */ + 200: { + readonly '@namespace.string'?: string; + readonly '@namespace.integer'?: number; + readonly value?: Array; + }; + /** + * Message for 201 response + */ + 201: ModelThatExtends; + /** + * Message for 202 response + */ + 202: ModelThatExtendsExtends; +}; + +export type CallWithResponsesResponse = CallWithResponsesResponses[keyof CallWithResponsesResponses]; + +export type CollectionFormatData = { + body?: never; + path?: never; + query: { + /** + * This is an array parameter that is sent as csv format (comma-separated values) + */ + parameterArrayCSV: Array | null; + /** + * This is an array parameter that is sent as ssv format (space-separated values) + */ + parameterArraySSV: Array | null; + /** + * This is an array parameter that is sent as tsv format (tab-separated values) + */ + parameterArrayTSV: Array | null; + /** + * This is an array parameter that is sent as pipes format (pipe-separated values) + */ + parameterArrayPipes: Array | null; + /** + * This is an array parameter that is sent as multi format (multiple parameter instances) + */ + parameterArrayMulti: Array | null; + }; + url: '/api/v{api-version}/collectionFormat'; +}; + +export type TypesData = { + body?: never; + path?: { + /** + * This is a number parameter + */ + id?: number; + }; + query: { + /** + * This is a number parameter + */ + parameterNumber: number; + /** + * This is a string parameter + */ + parameterString: string | null; + /** + * This is a boolean parameter + */ + parameterBoolean: boolean | null; + /** + * This is an object parameter + */ + parameterObject: { + [key: string]: unknown; + } | null; + /** + * This is an array parameter + */ + parameterArray: Array | null; + /** + * This is a dictionary parameter + */ + parameterDictionary: { + [key: string]: unknown; + } | null; + /** + * This is an enum parameter + */ + parameterEnum: 'Success' | 'Warning' | 'Error' | null; + }; + url: '/api/v{api-version}/types'; +}; + +export type TypesResponses = { + /** + * Response is a simple number + */ + 200: number; + /** + * Response is a simple string + */ + 201: string; + /** + * Response is a simple boolean + */ + 202: boolean; + /** + * Response is a simple object + */ + 203: { + [key: string]: unknown; + }; +}; + +export type TypesResponse = TypesResponses[keyof TypesResponses]; + +export type UploadFileData = { + body: Blob | File; + path: { + /** + * api-version should be required in standalone clients + */ + 'api-version': string | null; + }; + query?: never; + url: '/api/v{api-version}/upload'; +}; + +export type UploadFileResponses = { + 200: boolean; +}; + +export type UploadFileResponse = UploadFileResponses[keyof UploadFileResponses]; + +export type FileResponseData = { + body?: never; + path: { + id: string; + /** + * api-version should be required in standalone clients + */ + 'api-version': string; + }; + query?: never; + url: '/api/v{api-version}/file/{id}'; +}; + +export type FileResponseResponses = { + /** + * Success + */ + 200: Blob | File; +}; + +export type FileResponseResponse = FileResponseResponses[keyof FileResponseResponses]; + +export type ComplexTypesData = { + body?: never; + path?: never; + query: { + /** + * Parameter containing object + */ + parameterObject: { + first?: { + second?: { + third?: string; + }; + }; + }; + /** + * Parameter containing reference + */ + parameterReference: ModelWithString; + }; + url: '/api/v{api-version}/complex'; +}; + +export type ComplexTypesErrors = { + /** + * 400 `server` error + */ + 400: unknown; + /** + * 500 server error + */ + 500: unknown; +}; + +export type ComplexTypesResponses = { + /** + * Successful response + */ + 200: Array; +}; + +export type ComplexTypesResponse = ComplexTypesResponses[keyof ComplexTypesResponses]; + +export type MultipartResponseData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/multipart'; +}; + +export type MultipartResponseResponses = { + /** + * OK + */ + 200: { + file?: Blob | File; + metadata?: { + foo?: string; + bar?: string; + }; + }; +}; + +export type MultipartResponseResponse = MultipartResponseResponses[keyof MultipartResponseResponses]; + +export type MultipartRequestData = { + body?: { + content?: Blob | File; + data?: ModelWithString | null; + }; + path?: never; + query?: never; + url: '/api/v{api-version}/multipart'; +}; + +export type ComplexParamsData = { + body?: { + readonly key: string | null; + name: string | null; + enabled?: boolean; + type: 'Monkey' | 'Horse' | 'Bird'; + listOfModels?: Array | null; + listOfStrings?: Array | null; + parameters: ModelWithString | ModelWithEnum | ModelWithArray | ModelWithDictionary; + readonly user?: { + readonly id?: number; + readonly name?: string | null; + }; + }; + path: { + id: number; + /** + * api-version should be required in standalone clients + */ + 'api-version': string; + }; + query?: never; + url: '/api/v{api-version}/complex/{id}'; +}; + +export type ComplexParamsResponses = { + /** + * Success + */ + 200: ModelWithString; +}; + +export type ComplexParamsResponse = ComplexParamsResponses[keyof ComplexParamsResponses]; + +export type CallWithResultFromHeaderData = { + body?: never; + path?: never; + query?: never; + url: '/api/v{api-version}/header'; +}; + +export type CallWithResultFromHeaderErrors = { + /** + * 400 server error + */ + 400: unknown; + /** + * 500 server error + */ + 500: unknown; +}; + +export type CallWithResultFromHeaderResponses = { + /** + * Successful response + */ + 200: unknown; +}; + +export type TestErrorCodeData = { + body?: never; + path?: never; + query: { + /** + * Status code to return + */ + status: number; + }; + url: '/api/v{api-version}/error'; +}; + +export type TestErrorCodeErrors = { + /** + * Custom message: Internal Server Error + */ + 500: unknown; + /** + * Custom message: Not Implemented + */ + 501: unknown; + /** + * Custom message: Bad Gateway + */ + 502: unknown; + /** + * Custom message: Service Unavailable + */ + 503: unknown; +}; + +export type TestErrorCodeResponses = { + /** + * Custom message: Successful response + */ + 200: unknown; +}; + +export type NonAsciiæøåÆøÅöôêÊ字符串Data = { + body?: never; + path?: never; + query: { + /** + * Dummy input param + */ + nonAsciiParamæøåÆØÅöôêÊ: number; + }; + url: '/api/v{api-version}/non-ascii-æøåÆØÅöôêÊ字符串'; +}; + +export type NonAsciiæøåÆøÅöôêÊ字符串Responses = { + /** + * Successful response + */ + 200: Array; +}; + +export type NonAsciiæøåÆøÅöôêÊ字符串Response = NonAsciiæøåÆøÅöôêÊ字符串Responses[keyof NonAsciiæøåÆøÅöôêÊ字符串Responses]; + +export type PutWithFormUrlEncodedData = { + body: ArrayWithStrings; + path?: never; + query?: never; + url: '/api/v{api-version}/non-ascii-æøåÆØÅöôêÊ字符串'; +}; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example-disabled/index.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example-disabled/index.ts new file mode 100644 index 0000000000..b545604fba --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example-disabled/index.ts @@ -0,0 +1,3 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type { ClientOptions, GetFooData, GetFooResponse, GetFooResponses, Person, PostFooData, PostFooResponse, PostFooResponses } from './types.gen'; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example-disabled/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example-disabled/msw.gen.ts new file mode 100644 index 0000000000..6bc96de46f --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example-disabled/msw.gen.ts @@ -0,0 +1,75 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions } from 'msw'; + +import type { GetFooResponses, PostFooData, PostFooResponses } from './types.gen'; + +const resolveToNull = () => new HttpResponse(null); + +type ToResponseUnion = { + [K in Extract]: { + status: K; + result: T[K]; + }; +}[Extract]; + +type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; + +export type SingleHandlerFactories = { + getFooMock: HttpHandlerFactory<{ + result: GetFooResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + postFooMock: HttpHandlerFactory<{ + result: PostFooResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; +}; + +export type GetAllMocksOptions = { + onMissingMock?: 'error' | 'skip'; + overrides?: { + [K in keyof SingleHandlerFactories]?: Parameters[0]; + }; +}; + +export type MswHandlerFactory = SingleHandlerFactories & { + getAllMocks: (options?: GetAllMocksOptions) => Array; +}; + +export const createMswHandlerFactory = (config?: { + baseUrl?: string; +}): MswHandlerFactory => { + const baseUrl = config?.baseUrl ?? ''; + const mocks: SingleHandlerFactories = { + getFooMock: (res, options) => http.get(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + postFooMock: (res, options) => http.post(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options) + }; + const getAllMocks = (options?: GetAllMocksOptions): Array => { + const onMissingMock = options?.onMissingMock ?? 'skip'; + const overrides = options?.overrides; + const handlers: Array = []; + const addRequiredHandler = (handler: (value: Value | (() => HttpResponse)) => HttpHandler, override: Value | undefined) => { + if (override != null) { + handlers.push(handler(override)); + } + else { + if (onMissingMock === 'error') { + handlers.push(handler(() => new HttpResponse('[heyapi-msw] The mock of this request is not implemented.', { status: 501 }))); + } + } + }; + addRequiredHandler(mocks.getFooMock, overrides?.getFooMock); + addRequiredHandler(mocks.postFooMock, overrides?.postFooMock); + return handlers; + }; + return { ...mocks, getAllMocks }; +}; + +const _defaults = createMswHandlerFactory({ baseUrl: '*' }); + +export const getFooMock = _defaults.getFooMock; + +export const postFooMock = _defaults.postFooMock; + +export const getAllMocks = _defaults.getAllMocks; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example-disabled/types.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example-disabled/types.gen.ts new file mode 100644 index 0000000000..70782e584a --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example-disabled/types.gen.ts @@ -0,0 +1,50 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type ClientOptions = { + baseUrl: `${string}://${string}` | (string & {}); +}; + +export type Person = { + firstName?: string; + lastName?: unknown; + age?: number; +}; + +export type GetFooData = { + body?: never; + path?: never; + query?: never; + url: '/foo'; +}; + +export type GetFooResponses = { + /** + * OK + */ + 200: Person; +}; + +export type GetFooResponse = GetFooResponses[keyof GetFooResponses]; + +export type PostFooData = { + body: string; + path?: never; + query?: never; + url: '/foo'; +}; + +export type PostFooResponses = { + /** + * OK + */ + 200: { + fullName?: string; + age?: number; + }; + /** + * SUCCESSFUL + */ + 204: void; +}; + +export type PostFooResponse = PostFooResponses[keyof PostFooResponses]; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example/index.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example/index.ts new file mode 100644 index 0000000000..b545604fba --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example/index.ts @@ -0,0 +1,3 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type { ClientOptions, GetFooData, GetFooResponse, GetFooResponses, Person, PostFooData, PostFooResponse, PostFooResponses } from './types.gen'; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example/msw.gen.ts new file mode 100644 index 0000000000..c5bc51f48e --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example/msw.gen.ts @@ -0,0 +1,68 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions } from 'msw'; + +import type { GetFooResponses, PostFooData, PostFooResponses } from './types.gen'; + +const resolveToNull = () => new HttpResponse(null); + +type ToResponseUnion = { + [K in Extract]: { + status: K; + result: T[K]; + }; +}[Extract]; + +type OptionalHttpHandlerFactory = (responseOrResolver?: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; + +export type SingleHandlerFactories = { + getFooMock: OptionalHttpHandlerFactory<{ + result: GetFooResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; + postFooMock: OptionalHttpHandlerFactory<{ + result: PostFooResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; +}; + +export type GetAllMocksOptions = { + onMissingMock?: 'error' | 'skip'; + overrides?: { + [K in keyof SingleHandlerFactories]?: Parameters[0]; + }; +}; + +export type MswHandlerFactory = SingleHandlerFactories & { + getAllMocks: (options?: GetAllMocksOptions) => Array; +}; + +export const createMswHandlerFactory = (config?: { + baseUrl?: string; +}): MswHandlerFactory => { + const baseUrl = config?.baseUrl ?? ''; + const mocks: SingleHandlerFactories = { + getFooMock: (res = { result: { + firstName: 'Marry', + lastName: 'Jane', + age: 30 + }, status: 200 }, options) => http.get(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), + postFooMock: (res = { result: { fullName: 'John Doe', age: 34 }, status: 200 }, options) => http.post(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options) + }; + const getAllMocks = (options?: GetAllMocksOptions): Array => { + const overrides = options?.overrides; + const handlers: Array = []; + handlers.push(mocks.getFooMock(overrides?.getFooMock)); + handlers.push(mocks.postFooMock(overrides?.postFooMock)); + return handlers; + }; + return { ...mocks, getAllMocks }; +}; + +const _defaults = createMswHandlerFactory({ baseUrl: '*' }); + +export const getFooMock = _defaults.getFooMock; + +export const postFooMock = _defaults.postFooMock; + +export const getAllMocks = _defaults.getAllMocks; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example/types.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example/types.gen.ts new file mode 100644 index 0000000000..70782e584a --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example/types.gen.ts @@ -0,0 +1,50 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type ClientOptions = { + baseUrl: `${string}://${string}` | (string & {}); +}; + +export type Person = { + firstName?: string; + lastName?: unknown; + age?: number; +}; + +export type GetFooData = { + body?: never; + path?: never; + query?: never; + url: '/foo'; +}; + +export type GetFooResponses = { + /** + * OK + */ + 200: Person; +}; + +export type GetFooResponse = GetFooResponses[keyof GetFooResponses]; + +export type PostFooData = { + body: string; + path?: never; + query?: never; + url: '/foo'; +}; + +export type PostFooResponses = { + /** + * OK + */ + 200: { + fullName?: string; + age?: number; + }; + /** + * SUCCESSFUL + */ + 204: void; +}; + +export type PostFooResponse = PostFooResponses[keyof PostFooResponses]; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-types/index.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-types/index.ts new file mode 100644 index 0000000000..f389f85547 --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-types/index.ts @@ -0,0 +1,3 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type { ClientOptions, GetFooData, GetFooResponse, GetFooResponses } from './types.gen'; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-types/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-types/msw.gen.ts new file mode 100644 index 0000000000..d67d985f27 --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-types/msw.gen.ts @@ -0,0 +1,56 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions } from 'msw'; + +import type { GetFooResponses } from './types.gen'; + +const resolveToNull = () => new HttpResponse(null); + +type ToResponseUnion = { + [K in Extract]: { + status: K; + result: T[K]; + }; +}[Extract]; + +type OptionalHttpHandlerFactory = (responseOrResolver?: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; + +export type SingleHandlerFactories = { + getFooMock: OptionalHttpHandlerFactory<{ + result: GetFooResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; +}; + +export type GetAllMocksOptions = { + onMissingMock?: 'error' | 'skip'; + overrides?: { + [K in keyof SingleHandlerFactories]?: Parameters[0]; + }; +}; + +export type MswHandlerFactory = SingleHandlerFactories & { + getAllMocks: (options?: GetAllMocksOptions) => Array; +}; + +export const createMswHandlerFactory = (config?: { + baseUrl?: string; +}): MswHandlerFactory => { + const baseUrl = config?.baseUrl ?? ''; + const mocks: SingleHandlerFactories = { + getFooMock: (res = { result: { name: 'Alice' }, status: 200 }, options) => http.get(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options) + }; + const getAllMocks = (options?: GetAllMocksOptions): Array => { + const overrides = options?.overrides; + const handlers: Array = []; + handlers.push(mocks.getFooMock(overrides?.getFooMock)); + return handlers; + }; + return { ...mocks, getAllMocks }; +}; + +const _defaults = createMswHandlerFactory({ baseUrl: '*' }); + +export const getFooMock = _defaults.getFooMock; + +export const getAllMocks = _defaults.getAllMocks; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-types/types.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-types/types.gen.ts new file mode 100644 index 0000000000..a0b37c70a4 --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-types/types.gen.ts @@ -0,0 +1,23 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type ClientOptions = { + baseUrl: `${string}://${string}` | (string & {}); +}; + +export type GetFooData = { + body?: never; + path?: never; + query?: never; + url: '/foo'; +}; + +export type GetFooResponses = { + /** + * OK + */ + 200: { + name?: string; + }; +}; + +export type GetFooResponse = GetFooResponses[keyof GetFooResponses]; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/servers/index.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/servers/index.ts new file mode 100644 index 0000000000..f389f85547 --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/servers/index.ts @@ -0,0 +1,3 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type { ClientOptions, GetFooData, GetFooResponse, GetFooResponses } from './types.gen'; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/servers/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/servers/msw.gen.ts new file mode 100644 index 0000000000..e9a5d27215 --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/servers/msw.gen.ts @@ -0,0 +1,67 @@ +// This file is auto-generated by @hey-api/openapi-ts + +import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions } from 'msw'; + +import type { GetFooResponses } from './types.gen'; + +const resolveToNull = () => new HttpResponse(null); + +type ToResponseUnion = { + [K in Extract]: { + status: K; + result: T[K]; + }; +}[Extract]; + +type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; + +export type SingleHandlerFactories = { + getFooMock: HttpHandlerFactory<{ + result: GetFooResponses[200]; + status?: 200; + } | ToResponseUnion | HttpResponseResolver>; +}; + +export type GetAllMocksOptions = { + onMissingMock?: 'error' | 'skip'; + overrides?: { + [K in keyof SingleHandlerFactories]?: Parameters[0]; + }; +}; + +export type MswHandlerFactory = SingleHandlerFactories & { + getAllMocks: (options?: GetAllMocksOptions) => Array; +}; + +export const createMswHandlerFactory = (config?: { + baseUrl?: string; +}): MswHandlerFactory => { + const baseUrl = config?.baseUrl ?? 'https://foo.com/v1'; + const mocks: SingleHandlerFactories = { + getFooMock: (res, options) => http.get(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options) + }; + const getAllMocks = (options?: GetAllMocksOptions): Array => { + const onMissingMock = options?.onMissingMock ?? 'skip'; + const overrides = options?.overrides; + const handlers: Array = []; + const addRequiredHandler = (handler: (value: Value | (() => HttpResponse)) => HttpHandler, override: Value | undefined) => { + if (override != null) { + handlers.push(handler(override)); + } + else { + if (onMissingMock === 'error') { + handlers.push(handler(() => new HttpResponse('[heyapi-msw] The mock of this request is not implemented.', { status: 501 }))); + } + } + }; + addRequiredHandler(mocks.getFooMock, overrides?.getFooMock); + return handlers; + }; + return { ...mocks, getAllMocks }; +}; + +const _defaults = createMswHandlerFactory({ baseUrl: '*' }); + +export const getFooMock = _defaults.getFooMock; + +export const getAllMocks = _defaults.getAllMocks; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/servers/types.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/servers/types.gen.ts new file mode 100644 index 0000000000..d7a0ac4610 --- /dev/null +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/servers/types.gen.ts @@ -0,0 +1,21 @@ +// This file is auto-generated by @hey-api/openapi-ts + +export type ClientOptions = { + baseUrl: 'https://foo.com/v1' | `${string}://${string}/v1` | (string & {}); +}; + +export type GetFooData = { + body?: never; + path?: never; + query?: never; + url: '/foo'; +}; + +export type GetFooResponses = { + /** + * OK + */ + 200: string; +}; + +export type GetFooResponse = GetFooResponses[keyof GetFooResponses]; diff --git a/packages/openapi-ts-tests/main/test/plugins.test.ts b/packages/openapi-ts-tests/main/test/plugins.test.ts index 426e15a52e..4eab34e3bd 100644 --- a/packages/openapi-ts-tests/main/test/plugins.test.ts +++ b/packages/openapi-ts-tests/main/test/plugins.test.ts @@ -9,7 +9,7 @@ import { getFilePaths, getSpecsPath } from '../../utils'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -const versions = ['2.0.x', '3.0.x', '3.1.x']; +const versions = ['2.0.x', '3.0.x', '3.1.x'] as const; for (const version of versions) { const namespace = 'plugins'; @@ -468,6 +468,47 @@ for (const version of versions) { }), description: 'generate Fastify types with Fastify plugin', }, + { + config: createConfig({ + output: 'default', + plugins: ['msw'], + }), + description: 'generate MSW mock handlers with MSW plugin', + }, + { + config: createConfig({ + input: 'response-example.yaml', + output: 'response-example', + plugins: ['msw'], + }), + description: 'generate MSW mock handlers from spec with example with MSW plugin', + }, + { + config: createConfig({ + input: 'response-example.yaml', + output: 'response-example-disabled', + plugins: [{ name: 'msw', valueSources: [] }], + }), + description: + 'generate MSW mock handlers from spec with example with MSW plugin but disabled', + }, + version !== '2.0.x' && { + config: createConfig({ + input: 'response-types.yaml', + output: 'response-types', + plugins: ['msw'], + }), + description: + 'generate MSW mock handlers from spec with multiple response types with MSW plugin', + }, + { + config: createConfig({ + input: 'servers.yaml', + output: 'servers', + plugins: ['msw'], + }), + description: 'generate MSW mock handlers from spec with servers field', + }, { config: createConfig({ input: 'transforms-read-write.yaml', @@ -580,7 +621,7 @@ for (const version of versions) { }), description: 'generate Angular requests and resources (class)', }, - ]; + ].filter((val) => typeof val === 'object'); it.each(scenarios)('$description', async ({ config }) => { await createClient(config); diff --git a/packages/openapi-ts/package.json b/packages/openapi-ts/package.json index cbbf1dfd09..b727bd9271 100644 --- a/packages/openapi-ts/package.json +++ b/packages/openapi-ts/package.json @@ -90,6 +90,7 @@ "axios": "1.13.4", "eslint": "9.39.1", "ky": "1.14.3", + "msw": "2.10.2", "nuxt": "3.14.1592", "ofetch": "1.5.1", "rxjs": "7.8.2", diff --git a/packages/openapi-ts/src/index.ts b/packages/openapi-ts/src/index.ts index d473eaa6d0..8ab250aea0 100644 --- a/packages/openapi-ts/src/index.ts +++ b/packages/openapi-ts/src/index.ts @@ -47,6 +47,7 @@ declare module '@hey-api/codegen-core' { | 'arktype' | 'fastify' | 'json-schema' + | 'msw' | 'sdk' | 'typescript' | 'valibot' @@ -80,6 +81,7 @@ declare module '@hey-api/shared' { '@tanstack/vue-query': Plugins.TanStackVueQuery.Types['Types']; arktype: Plugins.Arktype.Types['Types']; fastify: Plugins.Fastify.Types['Types']; + msw: Plugins.Msw.Types['Types']; nestjs: Plugins.NestJs.Types['Types']; orpc: Plugins.Orpc.Types['Types']; swr: Plugins.Swr.Types['Types']; @@ -142,6 +144,7 @@ import type { TanStackSvelteQueryPlugin } from './plugins/@tanstack/svelte-query import type { TanStackVueQueryPlugin } from './plugins/@tanstack/vue-query'; import type { ArktypePlugin } from './plugins/arktype'; import type { FastifyPlugin } from './plugins/fastify'; +import type { MswPlugin } from './plugins/msw'; import type { NestJsPlugin } from './plugins/nestjs'; import type { OrpcPlugin } from './plugins/orpc'; import type { SwrPlugin } from './plugins/swr'; @@ -264,6 +267,10 @@ export namespace Plugins { export type Types = HeyApiTypeScriptPlugin; } + export namespace Msw { + export type Types = MswPlugin; + } + export namespace NestJs { export type Types = NestJsPlugin; } diff --git a/packages/openapi-ts/src/plugins/config.ts b/packages/openapi-ts/src/plugins/config.ts index 4d0abc5795..5e53828ed1 100644 --- a/packages/openapi-ts/src/plugins/config.ts +++ b/packages/openapi-ts/src/plugins/config.ts @@ -22,6 +22,7 @@ import { defaultConfig as tanStackSvelteQuery } from '../plugins/@tanstack/svelt import { defaultConfig as tanStackVueQuery } from '../plugins/@tanstack/vue-query'; import { defaultConfig as arktype } from '../plugins/arktype'; import { defaultConfig as fastify } from '../plugins/fastify'; +import { defaultConfig as msw } from '../plugins/msw'; import { defaultConfig as nestjs } from '../plugins/nestjs'; import { defaultConfig as orpc } from '../plugins/orpc'; import { defaultConfig as swr } from '../plugins/swr'; @@ -53,6 +54,7 @@ export const defaultPluginConfigs: { '@tanstack/vue-query': tanStackVueQuery, arktype, fastify, + msw, nestjs, orpc, swr, diff --git a/packages/openapi-ts/src/plugins/msw/computeDominantResponse.ts b/packages/openapi-ts/src/plugins/msw/computeDominantResponse.ts new file mode 100644 index 0000000000..224db9fce0 --- /dev/null +++ b/packages/openapi-ts/src/plugins/msw/computeDominantResponse.ts @@ -0,0 +1,145 @@ +import { type IR, statusCodeToGroup } from '@hey-api/shared'; + +import type { MswPlugin } from './types'; + +export type ResponseKind = 'binary' | 'json' | 'text' | 'void'; + +export interface DominantResponse { + example: unknown; + kind: ResponseKind; + statusCode: number | undefined; +} + +const isValidExample = (example: unknown): boolean => { + if (example === undefined) { + return false; + } + if (example === null) { + return true; + } + const type = typeof example; + if (type === 'string' || type === 'number' || type === 'boolean') { + return true; + } + if (Array.isArray(example)) { + return example.every(isValidExample); + } + if (type === 'object') { + return Object.values(example as Record).every(isValidExample); + } + return false; +}; + +const KIND_PRIORITY: Record = { + binary: 1, + json: 3, + text: 2, + void: 0, +}; + +interface ResponseCandidate { + example: unknown; + kind: ResponseKind; + statusCode: number; +} + +const computeResponse = ({ + plugin, + response, + statusCode, +}: { + plugin: MswPlugin['Instance']; + response: IR.ResponseObject; + statusCode: string; +}): ResponseCandidate => { + const numericStatus = Number(statusCode); + + if (response.schema.type === 'void') { + return { example: undefined, kind: 'void', statusCode: numericStatus }; + } + + // In 2.0, empty responses get type 'unknown' (with inherited mediaType from + // `produces`). A bare 'unknown' without a $ref indicates no real content. + if (response.schema.type === 'unknown' && !response.schema.$ref) { + return { example: undefined, kind: 'void', statusCode: numericStatus }; + } + + let schema = response.schema; + if (schema.$ref) { + schema = plugin.context.resolveIrRef(schema.$ref); + } + + const example = isValidExample(schema.example) ? schema.example : undefined; + + if (schema.format === 'binary') { + return { example, kind: 'binary', statusCode: numericStatus }; + } + + const kind = mediaTypeToKind(response.mediaType); + return { example, kind, statusCode: numericStatus }; +}; + +const mediaTypeToKind = (mediaType: string | undefined): ResponseKind => { + if (!mediaType) { + return 'json'; + } + + const cleanMediaType = mediaType.split(';')[0]?.trim() ?? ''; + + if ( + cleanMediaType.startsWith('application/octet-stream') || + cleanMediaType.startsWith('audio/') || + cleanMediaType.startsWith('image/') || + cleanMediaType.startsWith('video/') + ) { + return 'binary'; + } + + if (cleanMediaType.startsWith('application/json') || cleanMediaType.endsWith('+json')) { + return 'json'; + } + + if (cleanMediaType.startsWith('text/')) { + return 'text'; + } + + // unknown media type, default to json + return 'json'; +}; + +export const computeDominantResponse = ({ + operation, + plugin, +}: { + operation: IR.OperationObject; + plugin: MswPlugin['Instance']; +}): DominantResponse => { + const candidates: Array = []; + + for (const statusCode in operation.responses) { + if (statusCodeToGroup({ statusCode }) !== '2XX') { + continue; + } + candidates.push( + computeResponse({ + plugin, + response: operation.responses[statusCode]!, + statusCode, + }), + ); + } + + if (candidates.length === 0) { + return { example: undefined, kind: 'void', statusCode: undefined }; + } + + const dominant = candidates.reduce((best, cur) => + KIND_PRIORITY[cur.kind] > KIND_PRIORITY[best.kind] ? cur : best, + ); + + return { + example: dominant.example, + kind: dominant.kind, + statusCode: dominant.statusCode, + }; +}; diff --git a/packages/openapi-ts/src/plugins/msw/config.ts b/packages/openapi-ts/src/plugins/msw/config.ts new file mode 100644 index 0000000000..fe00493720 --- /dev/null +++ b/packages/openapi-ts/src/plugins/msw/config.ts @@ -0,0 +1,20 @@ +import { definePluginConfig } from '@hey-api/shared'; + +import { handler } from './plugin'; +import type { MswPlugin } from './types'; + +export const defaultConfig: MswPlugin['Config'] = { + config: { + includeInEntry: false, + valueSources: ['example'], + }, + dependencies: ['@hey-api/typescript'], + handler, + name: 'msw', + tags: ['mocker'], +}; + +/** + * Type helper for `msw` plugin, returns {@link Plugin.Config} object + */ +export const defineConfig = definePluginConfig(defaultConfig); diff --git a/packages/openapi-ts/src/plugins/msw/handlerCreator.ts b/packages/openapi-ts/src/plugins/msw/handlerCreator.ts new file mode 100644 index 0000000000..7b393605e2 --- /dev/null +++ b/packages/openapi-ts/src/plugins/msw/handlerCreator.ts @@ -0,0 +1,406 @@ +import type { IR } from '@hey-api/shared'; + +import { $ } from '../../ts-dsl'; +import { computeDominantResponse, type DominantResponse } from './computeDominantResponse'; +import type { MswPlugin } from './types'; + +const emitToResponseUnion = (plugin: MswPlugin['Instance']) => { + const symbol = plugin.symbol('ToResponseUnion', { + meta: { + category: 'type', + resource: 'to-response-union', + }, + }); + const extractKeyofTNumber = $.type('Extract', (t) => + t.generic($.type('keyof T')).generic($.type('number')), + ); + const toResponseUnionType = $.type + .alias(symbol) + .generic('T') + .type( + $.type.idx( + $.type + .mapped('K') + .key(extractKeyofTNumber) + .type( + $.type + .object() + .prop('status', (p) => p.type('K')) + .prop('result', (p) => p.type($.type.idx($.type('T'), $.type('K')))), + ), + $.type('Extract', (t) => t.generic($.type('keyof T')).generic($.type('number'))), + ), + ); + plugin.node(toResponseUnionType); +}; + +const emitHandlerFactory = (plugin: MswPlugin['Instance']) => { + const symbol = plugin.symbol('HttpHandlerFactory', { + meta: { + category: 'type', + resource: 'http-handler-factory', + }, + }); + const symbolHttpHandler = plugin.external('msw.HttpHandler'); + const symbolRequestHandlerOptions = plugin.external('msw.RequestHandlerOptions'); + const handlerFactoryType = $.type + .alias(symbol) + .generic('ResponseOrResolver') + .type( + $.type + .func() + .param('responseOrResolver', (p) => p.type('ResponseOrResolver')) + .param('options', (p) => p.type($.type(symbolRequestHandlerOptions)).optional()) + .returns($.type(symbolHttpHandler)), + ); + plugin.node(handlerFactoryType); +}; + +const emitOptionalParamHandlerFactory = (plugin: MswPlugin['Instance']) => { + const symbol = plugin.symbol('OptionalHttpHandlerFactory', { + meta: { + category: 'type', + resource: 'optional-http-handler-factory', + }, + }); + const symbolHttpHandler = plugin.external('msw.HttpHandler'); + const symbolRequestHandlerOptions = plugin.external('msw.RequestHandlerOptions'); + const optionalHandlerFactoryType = $.type + .alias(symbol) + .generic('ResponseOrResolver') + .type( + $.type + .func() + .param('responseOrResolver', (p) => p.type('ResponseOrResolver').optional()) + .param('options', (p) => p.type($.type(symbolRequestHandlerOptions)).optional()) + .returns($.type(symbolHttpHandler)), + ); + plugin.node(optionalHandlerFactoryType); +}; + +// path-to-regexp v6 (used by MSW) only allows word characters in param names. +// So transform what's necessary: replace non-word chars with camelCase transitions, +// preserving the original casing to stay consistent with the TypeScript plugin's types. +const sanitizeParamName = (name: string) => + name.replace(/\W+(.)?/g, (_, char?: string) => (char ? char.toUpperCase() : '')); + +const extractPathParamNames = (path: string) => { + const names: Array = []; + for (const match of path.matchAll(/\{([^}]+)\}/g)) { + names.push(match[1]!); + } + return names; +}; + +const toMswPath = (path: string) => + path + .replace(/\{([^}]+)\}/g, (_, name: string) => `\0${sanitizeParamName(name)}`) + .replace(/:/g, String.raw`\:`) + .replace(/\0/g, ':'); + +const httpMethodMap: Record = { + delete: 'delete', + get: 'get', + head: 'head', + options: 'options', + patch: 'patch', + post: 'post', + put: 'put', + trace: 'trace', +}; + +/** + * Builds the response override expression for the `res` parameter. + * When `res` is an object with a `result` property, it uses + * `res.result` as the value and `res.status` as the status code. + */ +const buildResponseOverrideExpr = ({ + dominantResponse: { kind: responseKind, statusCode: responseStatusCode }, + responseOrFnName, + symbolHttpResponse, +}: { + dominantResponse: DominantResponse; + responseOrFnName: string; + symbolHttpResponse: ReturnType; +}) => { + const statusOption = $.object().prop( + 'status', + responseStatusCode + ? $.binary($.attr(responseOrFnName, 'status'), '??', $.literal(responseStatusCode)) + : $.attr(responseOrFnName, 'status'), + ); + const resultExpr = $.attr(responseOrFnName, 'result'); + + switch (responseKind) { + case 'void': { + return $.func((f) => + f.do( + $.new( + symbolHttpResponse, + $.binary(resultExpr, '??', $.literal(null)), + statusOption, + ).return(), + ), + ); + } + case 'json': { + return $.func((f) => + f.do( + $(symbolHttpResponse) + .attr('json') + .call($.binary(resultExpr, '??', $.literal(null)), statusOption) + .return(), + ), + ); + } + case 'text': { + return $.func((f) => + f.do( + $(symbolHttpResponse) + .attr('text') + .call($.binary(resultExpr, '??', $.literal(null)), statusOption) + .return(), + ), + ); + } + case 'binary': { + return $.func((f) => + f.do( + $.new( + symbolHttpResponse, + $.binary(resultExpr, '??', $.literal(null)), + statusOption, + ).return(), + ), + ); + } + } +}; + +/** + * Builds an arrow function that creates an MSW handler for a single operation. + * The response method and status code are inferred from the operation's responses. + */ +const createHandlerCreatorFn = ({ + dominantResponse, + hasResponseOverride, + method, + operation, + symbolHttp, + symbolHttpResponse, + symbolResolveToNull, +}: { + dominantResponse: DominantResponse; + hasResponseOverride: boolean; + method: string; + operation: IR.OperationObject; + symbolHttp: ReturnType; + symbolHttpResponse: ReturnType; + symbolResolveToNull: ReturnType; +}) => { + const responseOrFnName = 'res'; + const optionsName = 'options'; + + const fallbackTernary = $.ternary( + $.binary($.typeofExpr(responseOrFnName), '===', $.literal('function')), + ) + .do(responseOrFnName) + .otherwise($(symbolResolveToNull)); + + const resolverArg = hasResponseOverride + ? $.ternary( + $.binary( + $.binary($.typeofExpr(responseOrFnName), '===', $.literal('object')), + '&&', + $.attr(responseOrFnName, 'result'), + ), + ) + .do( + buildResponseOverrideExpr({ + dominantResponse, + responseOrFnName, + symbolHttpResponse, + }), + ) + .otherwise(fallbackTernary) + : fallbackTernary; + + const httpCall = $(symbolHttp) + .attr(method) + .call( + $.template($('baseUrl')).add($.literal(toMswPath(operation.path))), + resolverArg, + optionsName, + ); + + return $.func((f) => { + if (dominantResponse.example != null && dominantResponse.statusCode != null) { + const status = dominantResponse.statusCode; + const example = dominantResponse.example; + f.param(responseOrFnName, (p) => p.assign($.fromValue({ result: example, status }))); + } else { + f.param(responseOrFnName); + } + f.param(optionsName); + f.do(httpCall.return()); + }); +}; + +export const operationToHandlerCreator = ({ + examples, + operation, + plugin, +}: { + examples: boolean; + operation: IR.OperationObject; + plugin: MswPlugin['Instance']; +}) => { + const method = httpMethodMap[operation.method]; + if (!method) { + return; + } + + const symbolHttp = plugin.external('msw.http'); + const symbolHttpResponse = plugin.external('msw.HttpResponse'); + const symbolHttpResponseResolver = plugin.external('msw.HttpResponseResolver'); + const symbolHttpHandlerFactory = plugin.referenceSymbol({ + category: 'type', + resource: 'http-handler-factory', + }); + const symbolOptionalHttpHandlerFactory = plugin.referenceSymbol({ + category: 'type', + resource: 'optional-http-handler-factory', + }); + const symbolToResponseUnion = plugin.referenceSymbol({ + category: 'type', + resource: 'to-response-union', + }); + const symbolResolveToNull = plugin.referenceSymbol({ + category: 'function', + resource: 'resolve-to-null', + }); + + // Query response type from @hey-api/typescript + const symbolResponsesType = plugin.querySymbol({ + category: 'type', + resource: 'operation', + resourceId: operation.id, + role: 'responses', + }); + let responsesOverrideType: ReturnType | undefined; + if (symbolResponsesType) { + if (!plugin.getSymbol({ category: 'type', resource: 'to-response-union' })) { + emitToResponseUnion(plugin); + } + responsesOverrideType = $.type(symbolToResponseUnion, (t) => t.generic(symbolResponsesType)); + } + + // Query data type for parameters + const symbolDataType = plugin.querySymbol({ + category: 'type', + resource: 'operation', + resourceId: operation.id, + role: 'data', + tool: 'typescript', + }); + + // Build HttpResponseResolver generics + const hasPathParams = + operation.parameters?.path && Object.keys(operation.parameters.path).length > 0; + const hasBody = !!operation.body; + + let pathParamsType: ReturnType | ReturnType | undefined; + if (hasPathParams) { + // Generate inline object type with sanitized param names derived from the + // path string (not the IR keys, which are lowercased and may diverge from + // the original spec names that the TypeScript plugin preserves). + const objType = $.type.object(); + for (const name of extractPathParamNames(operation.path)) { + // OpenAPI 3.x path params are always single-segment, so MSW (path-to-regexp v6) + // will always provide a single string. Multi-segment params ({path+}) are proposed + // for OpenAPI 4.0 — revisit this if/when that lands. + objType.prop(sanitizeParamName(name), (p) => p.type('string')); + } + pathParamsType = objType; + } + + let bodyType: ReturnType | ReturnType | undefined; + if (hasBody && symbolDataType) { + bodyType = $.type.idx($.type(symbolDataType), $.type.literal('body')); + } + + // Build the resolver type: HttpResponseResolver + // Omit response type generic to avoid MSW's DefaultBodyType constraint issues + const hasResolverGenerics = pathParamsType || bodyType; + const resolverType = hasResolverGenerics + ? $.type(symbolHttpResponseResolver, (t) => + t.generics(pathParamsType ?? $.type('never'), bodyType ?? $.type('never')), + ) + : $.type(symbolHttpResponseResolver); + + const dominantResponse = computeDominantResponse({ operation, plugin }); + + // When examples are disabled, strip the example from the dominant response + if (!examples) { + dominantResponse.example = undefined; + } + + const handlerCreator = createHandlerCreatorFn({ + dominantResponse, + hasResponseOverride: dominantResponse.statusCode != null, + method, + operation, + symbolHttp, + symbolHttpResponse, + symbolResolveToNull, + }); + + const isOptional = + // if there is no dominantResponse, it means there is no status code definition + // so we can set the default response as null + !(dominantResponse.statusCode != null && responsesOverrideType) || + // if there is example, the param is optional because example can be used + // if it's void, the param is optional because we can define the default (`null`) + dominantResponse.example != null || + dominantResponse.kind === 'void'; + + let responseOrResolverType: ReturnType | ReturnType; + if (dominantResponse.statusCode != null && responsesOverrideType && symbolResponsesType) { + const dominantResponseType = $.type + .object() + .prop('result', (p) => + p.type( + $.type.idx($.type(symbolResponsesType), $.type.literal(dominantResponse.statusCode!)), + ), + ) + .prop('status', (p) => p.optional().type($.type.literal(dominantResponse.statusCode!))); + responseOrResolverType = $.type.or( + dominantResponseType, + $.type.or(responsesOverrideType, resolverType), + ); + } else { + responseOrResolverType = resolverType; + } + + let handlerType: ReturnType; + if (isOptional) { + if (!plugin.getSymbol({ category: 'type', resource: 'optional-http-handler-factory' })) { + emitOptionalParamHandlerFactory(plugin); + } + handlerType = $.type(symbolOptionalHttpHandlerFactory, (t) => + t.generic(responseOrResolverType), + ); + } else { + if (!plugin.getSymbol({ category: 'type', resource: 'http-handler-factory' })) { + emitHandlerFactory(plugin); + } + handlerType = $.type(symbolHttpHandlerFactory, (t) => t.generic(responseOrResolverType)); + } + + return { + isOptional, + name: `${operation.id}Mock`, + type: handlerType, + value: handlerCreator, + }; +}; diff --git a/packages/openapi-ts/src/plugins/msw/index.ts b/packages/openapi-ts/src/plugins/msw/index.ts new file mode 100644 index 0000000000..bccf6b6079 --- /dev/null +++ b/packages/openapi-ts/src/plugins/msw/index.ts @@ -0,0 +1,2 @@ +export { defaultConfig, defineConfig } from './config'; +export type { MswPlugin } from './types'; diff --git a/packages/openapi-ts/src/plugins/msw/plugin.ts b/packages/openapi-ts/src/plugins/msw/plugin.ts new file mode 100644 index 0000000000..cfd9601b13 --- /dev/null +++ b/packages/openapi-ts/src/plugins/msw/plugin.ts @@ -0,0 +1,316 @@ +import { parseUrl } from '@hey-api/shared'; + +import { $ } from '../../ts-dsl'; +import { operationToHandlerCreator } from './handlerCreator'; +import type { MswPlugin } from './types'; + +export const handler: MswPlugin['Handler'] = ({ plugin }) => { + // Register external MSW symbols + plugin.symbol('http', { + external: 'msw', + meta: { + category: 'external', + resource: 'msw.http', + tool: 'msw', + }, + }); + + const symbolHttpHandler = plugin.symbol('HttpHandler', { + external: 'msw', + kind: 'type', + meta: { + category: 'external', + resource: 'msw.HttpHandler', + tool: 'msw', + }, + }); + + const symbolHttpResponse = plugin.symbol('HttpResponse', { + external: 'msw', + meta: { + category: 'external', + resource: 'msw.HttpResponse', + tool: 'msw', + }, + }); + + plugin.symbol('HttpResponseResolver', { + external: 'msw', + kind: 'type', + meta: { + category: 'external', + resource: 'msw.HttpResponseResolver', + tool: 'msw', + }, + }); + + plugin.symbol('RequestHandlerOptions', { + external: 'msw', + kind: 'type', + meta: { + category: 'external', + resource: 'msw.RequestHandlerOptions', + tool: 'msw', + }, + }); + + // Generate resolveToNull helper + // const resolveToNull = () => new HttpResponse(null) + const symbolResolveToNull = plugin.symbol('resolveToNull', { + meta: { + category: 'function', + resource: 'resolve-to-null', + }, + }); + const resolveToNullFn = $.const(symbolResolveToNull).assign( + $.func((f) => f.do($.new(symbolHttpResponse, $.literal(null)).return())), + ); + plugin.node(resolveToNullFn); + + // Resolve default baseUrl from spec servers + let defaultBaseUrl = ''; + const { servers } = plugin.context.ir; + const firstServer = servers?.[0]; + if (firstServer) { + const serverUrl = firstServer.url; + const url = parseUrl(serverUrl); + if (url.protocol && url.host && !serverUrl.includes('{')) { + defaultBaseUrl = serverUrl; + } else if (serverUrl !== '/' && serverUrl.startsWith('/')) { + defaultBaseUrl = serverUrl.endsWith('/') ? serverUrl.slice(0, -1) : serverUrl; + } + } + + // Generate createMswHandlerFactory + const symbolFactory = plugin.symbol('createMswHandlerFactory'); + const ofObject = $.object().pretty(); + const singleHandlerFactoriesType = $.type.object(); + const handlerMeta: Array<{ isOptional: boolean; name: string }> = []; + + plugin.forEach( + 'operation', + ({ operation }) => { + const handlerCreator = operationToHandlerCreator({ + examples: plugin.config.valueSources?.includes('example') ?? true, + operation, + plugin, + }); + if (handlerCreator) { + ofObject.prop(handlerCreator.name, handlerCreator.value); + singleHandlerFactoriesType.prop(handlerCreator.name, (p) => p.type(handlerCreator.type)); + handlerMeta.push({ isOptional: handlerCreator.isOptional, name: handlerCreator.name }); + } + }, + { + order: 'declarations', + }, + ); + + // Emit SingleHandlerFactories type + const symbolSingleHandlerFactories = plugin.symbol('SingleHandlerFactories'); + plugin.node($.type.alias(symbolSingleHandlerFactories).export().type(singleHandlerFactoriesType)); + + // Emit GetAllMocksOptions type + const symbolGetAllMocksOptions = plugin.symbol('GetAllMocksOptions'); + plugin.node( + $.type + .alias(symbolGetAllMocksOptions) + .export() + .type( + $.type + .object() + .prop('onMissingMock', (p) => + p.required(false).type($.type.or($.type.literal('error'), $.type.literal('skip'))), + ) + .prop('overrides', (p) => + p.required(false).type( + $.type + .mapped('K') + .key($.type.operator().keyof($.type(symbolSingleHandlerFactories))) + .optional() + .type( + $.type.idx( + $.type('Parameters', (t) => + t.generic($.type.idx($.type(symbolSingleHandlerFactories), $.type('K'))), + ), + $.type.literal(0), + ), + ), + ), + ), + ), + ); + + // Emit MswHandlerFactory type + const symbolMswHandlerFactory = plugin.symbol('MswHandlerFactory'); + plugin.node( + $.type + .alias(symbolMswHandlerFactory) + .export() + .type( + $.type.and( + $.type(symbolSingleHandlerFactories), + $.type.object().prop('getAllMocks', (p) => + p.type( + $.type + .func() + .param('options', (pp) => pp.type($.type(symbolGetAllMocksOptions)).optional()) + .returns($.type('Array', (t) => t.generic($.type(symbolHttpHandler)))), + ), + ), + ), + ), + ); + + // Build getAllMocks function body + const getAllMocksBodyStmts: Array = []; + const hasRequiredHandlers = handlerMeta.some((h) => !h.isOptional); + + if (hasRequiredHandlers) { + getAllMocksBodyStmts.push( + $.const('onMissingMock').assign( + $.binary($.attr($('options'), 'onMissingMock').optional(), '??', $.literal('skip')), + ), + ); + } + + getAllMocksBodyStmts.push( + $.const('overrides').assign($.attr($('options'), 'overrides').optional()), + ); + + getAllMocksBodyStmts.push( + $.const('handlers') + .type($.type('Array', (t) => t.generic($.type(symbolHttpHandler)))) + .assign($.array()), + ); + + // Generate addRequiredHandler helper when there are required handlers + if (hasRequiredHandlers) { + const errorResolver = $.func((ef) => + ef.do( + $.new( + symbolHttpResponse, + $.literal('[heyapi-msw] The mock of this request is not implemented.'), + $.object().prop('status', $.literal(501)), + ).return(), + ), + ); + + // handler: (value: Value | (() => HttpResponse)) => HttpHandler + const handlerParamType = $.type + .func() + .param('value', (pp) => + pp.type( + $.type.or( + 'Value', + $.type.func().returns($.type(symbolHttpResponse, (t) => t.generic('any'))), + ), + ), + ) + .returns($.type(symbolHttpHandler)); + + getAllMocksBodyStmts.push( + $.const('addRequiredHandler').assign( + $.func((f) => + f + .generic('Value') + .param('handler', (p) => p.type(handlerParamType)) + .param('override', (p) => p.type($.type.or('Value', 'undefined'))) + .do( + $.if($.binary($('override'), '!=', $.literal(null))) + .do( + $.stmt( + $('handlers') + .attr('push') + .call($('handler').call($('override'))), + ), + ) + .otherwise( + $.if($.binary($('onMissingMock'), '===', $.literal('error'))).do( + $.stmt($('handlers').attr('push').call($('handler').call(errorResolver))), + ), + ), + ), + ), + ), + ); + } + + for (const handler of handlerMeta) { + if (handler.isOptional) { + getAllMocksBodyStmts.push( + $.stmt( + $('handlers') + .attr('push') + .call( + $('mocks') + .attr(handler.name) + .call($.attr($('overrides'), handler.name).optional()), + ), + ), + ); + } else { + getAllMocksBodyStmts.push( + $.stmt( + $('addRequiredHandler').call( + $('mocks').attr(handler.name), + $.attr($('overrides'), handler.name).optional(), + ), + ), + ); + } + } + + getAllMocksBodyStmts.push($.return($('handlers'))); + + const getAllMocksFn = $.func((f) => { + f.param('options', (p) => p.required(false).type($.type(symbolGetAllMocksOptions))); + f.returns($.type('Array', (t) => t.generic($.type(symbolHttpHandler)))); + f.do(...getAllMocksBodyStmts); + }); + + const factoryFn = $.const(symbolFactory) + .export() + .assign( + $.func((f) => + f + .param('config', (p) => + p + .required(false) + .type($.type.object().prop('baseUrl', (p) => p.required(false).type('string'))), + ) + .returns($.type(symbolMswHandlerFactory)) + .do( + $.const('baseUrl').assign( + $.binary($.attr($('config'), 'baseUrl').optional(), '??', $.literal(defaultBaseUrl)), + ), + $.const('mocks').type('SingleHandlerFactories').assign(ofObject), + $.const('getAllMocks').assign(getAllMocksFn), + $.return($.object().spread('mocks').prop('getAllMocks', 'getAllMocks')), + ), + ), + ); + plugin.node(factoryFn); + + // Export individual handlers with wildcard baseUrl for convenient direct imports + const symbolDefaults = plugin.symbol('_defaults'); + plugin.node( + $.const(symbolDefaults).assign( + $(symbolFactory).call($.object().prop('baseUrl', $.literal('*'))), + ), + ); + for (const handler of handlerMeta) { + const sym = plugin.symbol(handler.name); + plugin.node( + $.const(sym) + .export() + .assign($.attr($(symbolDefaults), handler.name)), + ); + } + const symbolGetAllMocksExport = plugin.symbol('getAllMocks'); + plugin.node( + $.const(symbolGetAllMocksExport) + .export() + .assign($.attr($(symbolDefaults), 'getAllMocks')), + ); +}; diff --git a/packages/openapi-ts/src/plugins/msw/types.ts b/packages/openapi-ts/src/plugins/msw/types.ts new file mode 100644 index 0000000000..9877951860 --- /dev/null +++ b/packages/openapi-ts/src/plugins/msw/types.ts @@ -0,0 +1,19 @@ +import type { DefinePlugin, Plugin } from '@hey-api/shared'; + +export type UserConfig = Plugin.Name<'msw'> & + Plugin.Hooks & + Plugin.UserExports & { + /** + * Sources for inferring default parameter values in generated handler + * factories. Order determines priority (earlier entries take precedence). + * + * - `'example'` - use OpenAPI example values + * + * @default ['example'] + */ + valueSources?: ReadonlyArray<'example'>; + }; + +export type Config = UserConfig; + +export type MswPlugin = DefinePlugin; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 72ef325ade..3be467aa09 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -48,7 +48,7 @@ importers: version: 7.0.0-dev.20260321.1 '@vitest/coverage-v8': specifier: 4.1.0 - version: 4.1.0(vitest@4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))) + version: 4.1.0(vitest@4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))) eslint: specifier: 9.39.2 version: 9.39.2(jiti@2.6.1) @@ -96,7 +96,7 @@ importers: version: 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) vitest: specifier: 4.1.0 - version: 4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) dev: devDependencies: @@ -145,6 +145,9 @@ importers: arktype: specifier: 2.2.0 version: 2.2.0 + msw: + specifier: 2.10.2 + version: 2.10.2(@types/node@25.2.1)(typescript@5.9.3) nuxt: specifier: 3.21.0 version: 3.21.0(@netlify/blobs@9.1.2)(@parcel/watcher@2.5.1)(@types/node@25.2.1)(@vue/compiler-sfc@3.5.27)(cac@6.7.14)(db0@0.3.4)(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.9.2)(less@4.4.2)(magicast@0.5.2)(optionator@0.9.4)(rolldown@1.0.0-rc.9)(rollup@4.56.0)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue-tsc@3.2.4(typescript@5.9.3))(yaml@2.8.2) @@ -233,7 +236,7 @@ importers: devDependencies: '@angular-devkit/build-angular': specifier: 21.1.2 - version: 21.1.2(b9fcfc698b20164011953e0b05a5c087) + version: 21.1.2(f1f0187b9a28baac9b02f8c93bfba118) '@angular/cli': specifier: 21.1.2 version: 21.1.2(@types/node@24.10.10)(chokidar@5.0.0)(hono@4.11.8) @@ -327,7 +330,7 @@ importers: devDependencies: '@angular-devkit/build-angular': specifier: 21.1.2 - version: 21.1.2(e7024e150686e3bbe2cdedb5695d6284) + version: 21.1.2(a3942970943f268369c4c88439aad5ea) '@angular/cli': specifier: 21.1.2 version: 21.1.2(@types/node@24.10.10)(chokidar@5.0.0)(hono@4.11.8) @@ -470,7 +473,7 @@ importers: version: 7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) vitest: specifier: 4.0.18 - version: 4.0.18(@types/node@25.2.1)(jiti@2.6.1)(jsdom@28.0.0)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 4.0.18(@types/node@25.2.1)(jiti@2.6.1)(jsdom@28.0.0)(less@4.4.2)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) examples/openapi-ts-fetch: dependencies: @@ -520,6 +523,9 @@ importers: eslint-plugin-react-refresh: specifier: 0.4.7 version: 0.4.7(eslint@9.17.0(jiti@2.6.1)) + msw: + specifier: 2.10.2 + version: 2.10.2(@types/node@25.2.1)(typescript@5.9.3) oxfmt: specifier: 0.27.0 version: 0.27.0 @@ -535,6 +541,9 @@ importers: vite: specifier: 7.3.1 version: 7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vitest: + specifier: 4.0.18 + version: 4.0.18(@types/node@25.2.1)(jiti@2.6.1)(jsdom@28.0.0)(less@4.4.2)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) examples/openapi-ts-ky: dependencies: @@ -650,7 +659,7 @@ importers: version: 7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) vitest: specifier: ^4.0.18 - version: 4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) examples/openapi-ts-next: dependencies: @@ -788,7 +797,7 @@ importers: version: 8.0.2(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.13(typescript@5.9.3)) vitest: specifier: 4.0.18 - version: 4.0.18(@types/node@24.10.10)(jiti@2.6.1)(jsdom@28.0.0)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 4.0.18(@types/node@24.10.10)(jiti@2.6.1)(jsdom@28.0.0)(less@4.4.2)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) vue-tsc: specifier: 3.2.4 version: 3.2.4(typescript@5.9.3) @@ -943,7 +952,7 @@ importers: version: 8.0.2(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.13(typescript@5.9.3)) vitest: specifier: 4.0.18 - version: 4.0.18(@types/node@24.10.10)(jiti@2.6.1)(jsdom@28.0.0)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 4.0.18(@types/node@24.10.10)(jiti@2.6.1)(jsdom@28.0.0)(less@4.4.2)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) vue-tsc: specifier: 3.2.4 version: 3.2.4(typescript@5.9.3) @@ -995,7 +1004,7 @@ importers: devDependencies: '@angular-devkit/build-angular': specifier: 21.1.2 - version: 21.1.2(bfb22c0d38474de5255b56daa3b8edae) + version: 21.1.2(d1d14c4ec45bbc59bdd6f28c4606c248) '@angular/cli': specifier: 21.1.2 version: 21.1.2(@types/node@25.2.1)(chokidar@5.0.0)(hono@4.11.8) @@ -1156,7 +1165,7 @@ importers: version: 7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) vitest: specifier: 4.0.18 - version: 4.0.18(@types/node@25.2.1)(jiti@2.6.1)(jsdom@28.0.0)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 4.0.18(@types/node@25.2.1)(jiti@2.6.1)(jsdom@28.0.0)(less@4.4.2)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) examples/openapi-ts-tanstack-vue-query: dependencies: @@ -1241,7 +1250,7 @@ importers: version: 8.0.2(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.13(typescript@5.9.3)) vitest: specifier: 4.0.18 - version: 4.0.18(@types/node@24.10.10)(jiti@2.6.1)(jsdom@28.0.0)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + version: 4.0.18(@types/node@24.10.10)(jiti@2.6.1)(jsdom@28.0.0)(less@4.4.2)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) vue-tsc: specifier: 3.2.4 version: 3.2.4(typescript@5.9.3) @@ -1328,7 +1337,7 @@ importers: version: 3.16.2 '@nuxt/test-utils': specifier: 4.0.0 - version: 4.0.0(@vue/test-utils@2.4.6)(jsdom@28.0.0)(magicast@0.3.5)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))) + version: 4.0.0(@vue/test-utils@2.4.6)(jsdom@28.0.0)(magicast@0.3.5)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))) vite: specifier: 7.3.1 version: 7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) @@ -1448,6 +1457,9 @@ importers: ky: specifier: 1.14.3 version: 1.14.3 + msw: + specifier: 2.10.2 + version: 2.10.2(@types/node@25.2.1)(typescript@5.9.3) nuxt: specifier: 3.14.1592 version: 3.14.1592(@netlify/blobs@9.1.2)(@parcel/watcher@2.5.1)(@types/node@25.2.1)(db0@0.3.4)(encoding@0.1.13)(eslint@9.39.1(jiti@2.6.1))(ioredis@5.9.2)(less@4.4.2)(magicast@0.3.5)(optionator@0.9.4)(rolldown@1.0.0-rc.9)(rollup@4.56.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue-tsc@3.2.4(typescript@5.9.3)) @@ -1474,7 +1486,7 @@ importers: devDependencies: '@angular-devkit/build-angular': specifier: 21.1.2 - version: 21.1.2(bfb22c0d38474de5255b56daa3b8edae) + version: 21.1.2(d1d14c4ec45bbc59bdd6f28c4606c248) '@angular/animations': specifier: 21.1.2 version: 21.1.2(@angular/core@21.1.2(@angular/compiler@21.1.2)(rxjs@7.8.2)(zone.js@0.16.0)) @@ -1559,6 +1571,9 @@ importers: ky: specifier: 1.14.3 version: 1.14.3 + msw: + specifier: 2.10.2 + version: 2.10.2(@types/node@25.2.1)(typescript@5.9.3) node-fetch: specifier: 3.3.2 version: 3.3.2 @@ -2769,6 +2784,15 @@ packages: '@braidai/lang@1.1.2': resolution: {integrity: sha512-qBcknbBufNHlui137Hft8xauQMTZDKdophmLFv05r2eNmdIv/MlPuP4TdUknHG68UdWLgVZwgxVe735HzJNIwA==} + '@bundled-es-modules/cookie@2.0.1': + resolution: {integrity: sha512-8o+5fRPLNbjbdGRRmJj3h6Hh1AQJf2dk3qQ/5ZFb+PXkRNiSoMGGUKlsgLfrxneb72axVJyIYji64E2+nNfYyw==} + + '@bundled-es-modules/statuses@1.0.1': + resolution: {integrity: sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==} + + '@bundled-es-modules/tough-cookie@0.1.6': + resolution: {integrity: sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==} + '@changesets/apply-release-plan@7.1.0': resolution: {integrity: sha512-yq8ML3YS7koKQ/9bk1PqO0HMzApIFNwjlwCnwFEXMzNe8NpzeeYYKCmnhWJGkN8g7E51MnWaSbqRcTcdIxUgnQ==} @@ -4683,6 +4707,10 @@ packages: cpu: [x64] os: [win32] + '@mswjs/interceptors@0.39.8': + resolution: {integrity: sha512-2+BzZbjRO7Ct61k8fMNHEtoKjeWI9pIlHFTqBwZ5icHpqszIgEZbjb1MW5Z0+bITTCTl3gk4PDBxs9tA/csXvA==} + engines: {node: '>=18'} + '@napi-rs/nice-android-arm-eabi@1.1.1': resolution: {integrity: sha512-kjirL3N6TnRPv5iuHw36wnucNqXAO46dzK9oPb0wj076R5Xm8PfUVA9nAFB5ZNMmfJQJVKACAPd/Z2KYMppthw==} engines: {node: '>= 10'} @@ -5160,6 +5188,15 @@ packages: '@one-ini/wasm@0.1.1': resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} + '@open-draft/deferred-promise@2.2.0': + resolution: {integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==} + + '@open-draft/logger@0.3.0': + resolution: {integrity: sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==} + + '@open-draft/until@2.1.0': + resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==} + '@opencode-ai/sdk@1.2.27': resolution: {integrity: sha512-Wk0o/I+Fo+wE3zgvlJDs8Fb67KlKqX0PrV8dK5adSDkANq6r4Z25zXJg2iOir+a8ntg3rAcpel1OY4FV/TwRUA==} @@ -7668,6 +7705,9 @@ packages: '@types/sockjs@0.3.36': resolution: {integrity: sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==} + '@types/statuses@2.0.6': + resolution: {integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==} + '@types/tough-cookie@4.0.5': resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} @@ -10340,10 +10380,6 @@ packages: resolution: {integrity: sha512-jpWzZ1ZhwUmeWRhS7Qv3mhpOhLfwI+uAX4e5fOcXqwMR7EcJ0pj2kV1CVzHVMX/LphnKWD3LObjZCoJ71lKpHw==} engines: {node: ^18.19.0 || >=20.5.0} - expect-type@1.2.2: - resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} - engines: {node: '>=12.0.0'} - expect-type@1.3.0: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} @@ -10797,6 +10833,10 @@ packages: graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + graphql@16.13.1: + resolution: {integrity: sha512-gGgrVCoDKlIZ8fIqXBBb0pPKqDgki0Z/FSKNiQzSGj2uEYHr1tq5wmBegGwJx6QB5S5cM0khSBpi/JFHMCvsmQ==} + engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + gray-matter@4.0.3: resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==} engines: {node: '>=6.0'} @@ -10859,6 +10899,9 @@ packages: hast-util-whitespace@3.0.0: resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + headers-polyfill@4.0.3: + resolution: {integrity: sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==} + highlight.js@10.7.3: resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} @@ -11220,6 +11263,9 @@ packages: resolution: {integrity: sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==} engines: {node: '>=16'} + is-node-process@1.2.0: + resolution: {integrity: sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==} + is-number-object@1.1.1: resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} engines: {node: '>= 0.4'} @@ -12214,6 +12260,16 @@ packages: msgpackr@1.11.5: resolution: {integrity: sha512-UjkUHN0yqp9RWKy0Lplhh+wlpdt9oQBYgULZOiFhV3VclSF1JnSQWZ5r9gORQlNYaUKQoR8itv7g7z1xDDuACA==} + msw@2.10.2: + resolution: {integrity: sha512-RCKM6IZseZQCWcSWlutdf590M8nVfRHG1ImwzOtwz8IYxgT4zhUO0rfTcTvDGiaFE0Rhcc+h43lcF3Jc9gFtwQ==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + typescript: '>= 4.8.x' + peerDependenciesMeta: + typescript: + optional: true + muggle-string@0.4.1: resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} @@ -12663,6 +12719,9 @@ packages: outdent@0.5.0: resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} + outvariant@1.4.3: + resolution: {integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==} + own-keys@1.0.1: resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} engines: {node: '>= 0.4'} @@ -13370,6 +13429,9 @@ packages: prr@1.0.1: resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} + psl@1.15.0: + resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} + pump@3.0.3: resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} @@ -13402,6 +13464,9 @@ packages: quansync@1.0.0: resolution: {integrity: sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA==} + querystringify@2.2.0: + resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -14213,6 +14278,9 @@ packages: streamx@2.22.1: resolution: {integrity: sha512-znKXEBxfatz2GBNK02kRnCXjV+AA4kjZIUxeWSr3UGirZMJfTE9uiwKHobnbgxWyL/JWro8tTq+vOqAK1/qbSA==} + strict-event-emitter@0.5.1: + resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==} + string-argv@0.3.2: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} engines: {node: '>=0.6.19'} @@ -14574,6 +14642,10 @@ packages: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} + tough-cookie@4.1.4: + resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==} + engines: {node: '>=6'} + tough-cookie@6.0.0: resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==} engines: {node: '>=16'} @@ -14938,6 +15010,10 @@ packages: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} + universalify@0.2.0: + resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} + engines: {node: '>= 4.0.0'} + universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} @@ -15175,6 +15251,9 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + url-parse@1.5.10: + resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + urlpattern-polyfill@10.1.0: resolution: {integrity: sha512-IGjKp/o0NL3Bso1PymYURCJxMPNAf/ILOpendP9f5B6e1rTJgdgiOvgfoT8VxCAdY+Wisb9uhGaJJf3yZ2V9nw==} @@ -16160,13 +16239,13 @@ snapshots: transitivePeerDependencies: - chokidar - '@angular-devkit/build-angular@21.1.2(b9fcfc698b20164011953e0b05a5c087)': + '@angular-devkit/build-angular@21.1.2(a3942970943f268369c4c88439aad5ea)': dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.2101.2(chokidar@5.0.0) '@angular-devkit/build-webpack': 0.2101.2(chokidar@5.0.0)(webpack-dev-server@5.2.2(tslib@2.8.1)(webpack@5.104.1(@swc/core@1.15.18)(esbuild@0.27.2)))(webpack@5.104.1(@swc/core@1.15.18)(esbuild@0.27.2)) '@angular-devkit/core': 21.1.2(chokidar@5.0.0) - '@angular/build': 21.1.2(715bbcce77c47a418ef6cc48ef7ededc) + '@angular/build': 21.1.2(fa3d27d2bfba2058220c00fd3fb69db1) '@angular/compiler-cli': 21.1.2(@angular/compiler@21.1.2)(typescript@5.9.3) '@babel/core': 7.28.5 '@babel/generator': 7.28.5 @@ -16249,13 +16328,13 @@ snapshots: - webpack-cli - yaml - '@angular-devkit/build-angular@21.1.2(bfb22c0d38474de5255b56daa3b8edae)': + '@angular-devkit/build-angular@21.1.2(d1d14c4ec45bbc59bdd6f28c4606c248)': dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.2101.2(chokidar@5.0.0) '@angular-devkit/build-webpack': 0.2101.2(chokidar@5.0.0)(webpack-dev-server@5.2.2(tslib@2.8.1)(webpack@5.104.1(@swc/core@1.15.18)(esbuild@0.27.2)))(webpack@5.104.1(@swc/core@1.15.18)(esbuild@0.27.2)) '@angular-devkit/core': 21.1.2(chokidar@5.0.0) - '@angular/build': 21.1.2(4ae04ca60d5e69e646f2e6985d14766b) + '@angular/build': 21.1.2(ca7d45c5c89e8f8891af69ebb1866aaf) '@angular/compiler-cli': 21.1.2(@angular/compiler@21.1.2)(typescript@5.9.3) '@babel/core': 7.28.5 '@babel/generator': 7.28.5 @@ -16338,13 +16417,13 @@ snapshots: - webpack-cli - yaml - '@angular-devkit/build-angular@21.1.2(e7024e150686e3bbe2cdedb5695d6284)': + '@angular-devkit/build-angular@21.1.2(f1f0187b9a28baac9b02f8c93bfba118)': dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.2101.2(chokidar@5.0.0) '@angular-devkit/build-webpack': 0.2101.2(chokidar@5.0.0)(webpack-dev-server@5.2.2(tslib@2.8.1)(webpack@5.104.1(@swc/core@1.15.18)(esbuild@0.27.2)))(webpack@5.104.1(@swc/core@1.15.18)(esbuild@0.27.2)) '@angular-devkit/core': 21.1.2(chokidar@5.0.0) - '@angular/build': 21.1.2(b8a91db99523b9ce3edfd9b854e0f81b) + '@angular/build': 21.1.2(59f40ca61b5d02419ec13dbea9cd06eb) '@angular/compiler-cli': 21.1.2(@angular/compiler@21.1.2)(typescript@5.9.3) '@babel/core': 7.28.5 '@babel/generator': 7.28.5 @@ -16462,7 +16541,7 @@ snapshots: '@angular/core': 21.1.2(@angular/compiler@21.1.2)(rxjs@7.8.2)(zone.js@0.16.0) tslib: 2.8.1 - '@angular/build@21.1.2(4ae04ca60d5e69e646f2e6985d14766b)': + '@angular/build@21.1.2(59f40ca61b5d02419ec13dbea9cd06eb)': dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.2101.2(chokidar@5.0.0) @@ -16471,8 +16550,8 @@ snapshots: '@babel/core': 7.28.5 '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-split-export-declaration': 7.24.7 - '@inquirer/confirm': 5.1.21(@types/node@25.2.1) - '@vitejs/plugin-basic-ssl': 2.1.0(vite@7.3.0(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + '@inquirer/confirm': 5.1.21(@types/node@24.10.10) + '@vitejs/plugin-basic-ssl': 2.1.0(vite@7.3.0(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) beasties: 0.3.5 browserslist: 4.28.1 esbuild: 0.27.2 @@ -16493,7 +16572,7 @@ snapshots: tslib: 2.8.1 typescript: 5.9.3 undici: 7.18.2 - vite: 7.3.0(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.0(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) watchpack: 2.5.0 optionalDependencies: '@angular/core': 21.1.2(@angular/compiler@21.1.2)(rxjs@7.8.2)(zone.js@0.16.0) @@ -16504,8 +16583,8 @@ snapshots: less: 4.4.2 lmdb: 3.4.4 postcss: 8.5.6 - tailwindcss: 3.4.14(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.2.1)(typescript@5.9.3)) - vitest: 4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + tailwindcss: 3.4.14(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@24.10.10)(typescript@5.9.3)) + vitest: 4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.0(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) transitivePeerDependencies: - '@types/node' - chokidar @@ -16519,7 +16598,7 @@ snapshots: - tsx - yaml - '@angular/build@21.1.2(715bbcce77c47a418ef6cc48ef7ededc)': + '@angular/build@21.1.2(ca7d45c5c89e8f8891af69ebb1866aaf)': dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.2101.2(chokidar@5.0.0) @@ -16528,8 +16607,8 @@ snapshots: '@babel/core': 7.28.5 '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-split-export-declaration': 7.24.7 - '@inquirer/confirm': 5.1.21(@types/node@24.10.10) - '@vitejs/plugin-basic-ssl': 2.1.0(vite@7.3.0(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + '@inquirer/confirm': 5.1.21(@types/node@25.2.1) + '@vitejs/plugin-basic-ssl': 2.1.0(vite@7.3.0(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) beasties: 0.3.5 browserslist: 4.28.1 esbuild: 0.27.2 @@ -16550,7 +16629,7 @@ snapshots: tslib: 2.8.1 typescript: 5.9.3 undici: 7.18.2 - vite: 7.3.0(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.0(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) watchpack: 2.5.0 optionalDependencies: '@angular/core': 21.1.2(@angular/compiler@21.1.2)(rxjs@7.8.2)(zone.js@0.16.0) @@ -16561,8 +16640,8 @@ snapshots: less: 4.4.2 lmdb: 3.4.4 postcss: 8.5.6 - tailwindcss: 3.4.14(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@24.10.10)(typescript@5.9.3)) - vitest: 4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(vite@7.3.0(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + tailwindcss: 3.4.14(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.2.1)(typescript@5.9.3)) + vitest: 4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) transitivePeerDependencies: - '@types/node' - chokidar @@ -16576,7 +16655,7 @@ snapshots: - tsx - yaml - '@angular/build@21.1.2(b8a91db99523b9ce3edfd9b854e0f81b)': + '@angular/build@21.1.2(fa3d27d2bfba2058220c00fd3fb69db1)': dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.2101.2(chokidar@5.0.0) @@ -16619,7 +16698,7 @@ snapshots: lmdb: 3.4.4 postcss: 8.5.6 tailwindcss: 3.4.14(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@24.10.10)(typescript@5.9.3)) - vitest: 4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + vitest: 4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) transitivePeerDependencies: - '@types/node' - chokidar @@ -17828,6 +17907,19 @@ snapshots: '@braidai/lang@1.1.2': {} + '@bundled-es-modules/cookie@2.0.1': + dependencies: + cookie: 0.7.2 + + '@bundled-es-modules/statuses@1.0.1': + dependencies: + statuses: 2.0.2 + + '@bundled-es-modules/tough-cookie@0.1.6': + dependencies: + '@types/tough-cookie': 4.0.5 + tough-cookie: 4.1.4 + '@changesets/apply-release-plan@7.1.0': dependencies: '@changesets/config': 3.1.3 @@ -19455,6 +19547,15 @@ snapshots: '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3': optional: true + '@mswjs/interceptors@0.39.8': + dependencies: + '@open-draft/deferred-promise': 2.2.0 + '@open-draft/logger': 0.3.0 + '@open-draft/until': 2.1.0 + is-node-process: 1.2.0 + outvariant: 1.4.3 + strict-event-emitter: 0.5.1 + '@napi-rs/nice-android-arm-eabi@1.1.1': optional: true @@ -20338,7 +20439,7 @@ snapshots: transitivePeerDependencies: - magicast - '@nuxt/test-utils@4.0.0(@vue/test-utils@2.4.6)(jsdom@28.0.0)(magicast@0.3.5)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))': + '@nuxt/test-utils@4.0.0(@vue/test-utils@2.4.6)(jsdom@28.0.0)(magicast@0.3.5)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))': dependencies: '@clack/prompts': 1.0.0 '@nuxt/devtools-kit': 2.7.0(magicast@0.3.5)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) @@ -20367,12 +20468,12 @@ snapshots: tinyexec: 1.0.2 ufo: 1.6.3 unplugin: 3.0.0 - vitest-environment-nuxt: 1.0.1(@vue/test-utils@2.4.6)(jsdom@28.0.0)(magicast@0.3.5)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))) + vitest-environment-nuxt: 1.0.1(@vue/test-utils@2.4.6)(jsdom@28.0.0)(magicast@0.3.5)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))) vue: 3.5.27(typescript@5.9.3) optionalDependencies: '@vue/test-utils': 2.4.6 jsdom: 28.0.0 - vitest: 4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + vitest: 4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) transitivePeerDependencies: - crossws - magicast @@ -20624,6 +20725,15 @@ snapshots: '@one-ini/wasm@0.1.1': {} + '@open-draft/deferred-promise@2.2.0': {} + + '@open-draft/logger@0.3.0': + dependencies: + is-node-process: 1.2.0 + outvariant: 1.4.3 + + '@open-draft/until@2.1.0': {} + '@opencode-ai/sdk@1.2.27': {} '@orpc/client@1.13.9': @@ -22726,6 +22836,8 @@ snapshots: dependencies: '@types/node': 24.10.10 + '@types/statuses@2.0.6': {} + '@types/tough-cookie@4.0.5': {} '@types/triple-beam@1.3.5': {} @@ -23281,7 +23393,7 @@ snapshots: vite: 7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) vue: 3.5.27(typescript@5.9.3) - '@vitest/coverage-v8@4.1.0(vitest@4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))': + '@vitest/coverage-v8@4.1.0(vitest@4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))': dependencies: '@bcoe/v8-coverage': 1.0.2 '@vitest/utils': 4.1.0 @@ -23293,7 +23405,7 @@ snapshots: obug: 2.1.1 std-env: 4.0.0 tinyrainbow: 3.0.3 - vitest: 4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + vitest: 4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) '@vitest/expect@4.0.18': dependencies: @@ -23313,45 +23425,50 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.0.3 - '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/mocker@4.0.18(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@vitest/spy': 4.0.18 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: + msw: 2.10.2(@types/node@24.10.10)(typescript@5.9.3) vite: 7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/mocker@4.0.18(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@vitest/spy': 4.0.18 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: + msw: 2.10.2(@types/node@25.2.1)(typescript@5.9.3) vite: 7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - '@vitest/mocker@4.1.0(vite@7.3.0(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/mocker@4.1.0(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.0(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@vitest/spy': 4.1.0 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: + msw: 2.10.2(@types/node@24.10.10)(typescript@5.9.3) vite: 7.3.0(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) optional: true - '@vitest/mocker@4.1.0(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/mocker@4.1.0(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@vitest/spy': 4.1.0 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: + msw: 2.10.2(@types/node@24.10.10)(typescript@5.9.3) vite: 7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - '@vitest/mocker@4.1.0(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/mocker@4.1.0(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@vitest/spy': 4.1.0 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: + msw: 2.10.2(@types/node@25.2.1)(typescript@5.9.3) vite: 7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) '@vitest/pretty-format@4.0.18': @@ -26262,8 +26379,6 @@ snapshots: strip-final-newline: 4.0.0 yoctocolors: 2.1.2 - expect-type@1.2.2: {} - expect-type@1.3.0: {} exponential-backoff@3.1.2: {} @@ -26885,6 +27000,8 @@ snapshots: graphemer@1.4.0: {} + graphql@16.13.1: {} + gray-matter@4.0.3: dependencies: js-yaml: 3.14.1 @@ -26969,6 +27086,8 @@ snapshots: dependencies: '@types/hast': 3.0.4 + headers-polyfill@4.0.3: {} + highlight.js@10.7.3: {} hono@4.11.8: {} @@ -27342,6 +27461,8 @@ snapshots: is-network-error@1.1.0: {} + is-node-process@1.2.0: {} + is-number-object@1.1.1: dependencies: call-bound: 1.0.4 @@ -28508,6 +28629,57 @@ snapshots: msgpackr-extract: 3.0.3 optional: true + msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3): + dependencies: + '@bundled-es-modules/cookie': 2.0.1 + '@bundled-es-modules/statuses': 1.0.1 + '@bundled-es-modules/tough-cookie': 0.1.6 + '@inquirer/confirm': 5.1.21(@types/node@24.10.10) + '@mswjs/interceptors': 0.39.8 + '@open-draft/deferred-promise': 2.2.0 + '@open-draft/until': 2.1.0 + '@types/cookie': 0.6.0 + '@types/statuses': 2.0.6 + graphql: 16.13.1 + headers-polyfill: 4.0.3 + is-node-process: 1.2.0 + outvariant: 1.4.3 + path-to-regexp: 6.3.0 + picocolors: 1.1.1 + strict-event-emitter: 0.5.1 + type-fest: 4.41.0 + yargs: 17.7.2 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - '@types/node' + optional: true + + msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3): + dependencies: + '@bundled-es-modules/cookie': 2.0.1 + '@bundled-es-modules/statuses': 1.0.1 + '@bundled-es-modules/tough-cookie': 0.1.6 + '@inquirer/confirm': 5.1.21(@types/node@25.2.1) + '@mswjs/interceptors': 0.39.8 + '@open-draft/deferred-promise': 2.2.0 + '@open-draft/until': 2.1.0 + '@types/cookie': 0.6.0 + '@types/statuses': 2.0.6 + graphql: 16.13.1 + headers-polyfill: 4.0.3 + is-node-process: 1.2.0 + outvariant: 1.4.3 + path-to-regexp: 6.3.0 + picocolors: 1.1.1 + strict-event-emitter: 0.5.1 + type-fest: 4.41.0 + yargs: 17.7.2 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - '@types/node' + muggle-string@0.4.1: {} multer@2.1.1: @@ -29639,6 +29811,8 @@ snapshots: outdent@0.5.0: {} + outvariant@1.4.3: {} + own-keys@1.0.1: dependencies: get-intrinsic: 1.3.0 @@ -30437,6 +30611,10 @@ snapshots: prr@1.0.1: optional: true + psl@1.15.0: + dependencies: + punycode: 2.3.1 + pump@3.0.3: dependencies: end-of-stream: 1.4.5 @@ -30462,6 +30640,8 @@ snapshots: quansync@1.0.0: {} + querystringify@2.2.0: {} + queue-microtask@1.2.3: {} quick-format-unescaped@4.0.4: {} @@ -31510,6 +31690,8 @@ snapshots: optionalDependencies: bare-events: 2.6.1 + strict-event-emitter@0.5.1: {} + string-argv@0.3.2: {} string-width@4.2.3: @@ -32000,6 +32182,13 @@ snapshots: totalist@3.0.1: {} + tough-cookie@4.1.4: + dependencies: + psl: 1.15.0 + punycode: 2.3.1 + universalify: 0.2.0 + url-parse: 1.5.10 + tough-cookie@6.0.0: dependencies: tldts: 7.0.22 @@ -32508,6 +32697,8 @@ snapshots: universalify@0.1.2: {} + universalify@0.2.0: {} + universalify@2.0.1: {} unixify@1.0.0: @@ -32792,6 +32983,11 @@ snapshots: dependencies: punycode: 2.3.1 + url-parse@1.5.10: + dependencies: + querystringify: 2.2.0 + requires-port: 1.0.0 + urlpattern-polyfill@10.1.0: {} urlpattern-polyfill@8.0.2: {} @@ -33259,9 +33455,9 @@ snapshots: - universal-cookie - yaml - vitest-environment-nuxt@1.0.1(@vue/test-utils@2.4.6)(jsdom@28.0.0)(magicast@0.3.5)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))): + vitest-environment-nuxt@1.0.1(@vue/test-utils@2.4.6)(jsdom@28.0.0)(magicast@0.3.5)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))): dependencies: - '@nuxt/test-utils': 4.0.0(@vue/test-utils@2.4.6)(jsdom@28.0.0)(magicast@0.3.5)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))) + '@nuxt/test-utils': 4.0.0(@vue/test-utils@2.4.6)(jsdom@28.0.0)(magicast@0.3.5)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))) transitivePeerDependencies: - '@cucumber/cucumber' - '@jest/globals' @@ -33278,24 +33474,24 @@ snapshots: - vite - vitest - vitest@4.0.18(@types/node@24.10.10)(jiti@2.6.1)(jsdom@28.0.0)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): + vitest@4.0.18(@types/node@24.10.10)(jiti@2.6.1)(jsdom@28.0.0)(less@4.4.2)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): dependencies: '@vitest/expect': 4.0.18 - '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + '@vitest/mocker': 4.0.18(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) '@vitest/pretty-format': 4.0.18 '@vitest/runner': 4.0.18 '@vitest/snapshot': 4.0.18 '@vitest/spy': 4.0.18 '@vitest/utils': 4.0.18 es-module-lexer: 1.7.0 - expect-type: 1.2.2 + expect-type: 1.3.0 magic-string: 0.30.21 obug: 2.1.1 pathe: 2.0.3 picomatch: 4.0.3 std-env: 3.10.0 tinybench: 2.9.0 - tinyexec: 1.0.2 + tinyexec: 1.0.4 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 vite: 7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) @@ -33316,24 +33512,24 @@ snapshots: - tsx - yaml - vitest@4.0.18(@types/node@25.2.1)(jiti@2.6.1)(jsdom@28.0.0)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): + vitest@4.0.18(@types/node@25.2.1)(jiti@2.6.1)(jsdom@28.0.0)(less@4.4.2)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): dependencies: '@vitest/expect': 4.0.18 - '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + '@vitest/mocker': 4.0.18(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) '@vitest/pretty-format': 4.0.18 '@vitest/runner': 4.0.18 '@vitest/snapshot': 4.0.18 '@vitest/spy': 4.0.18 '@vitest/utils': 4.0.18 es-module-lexer: 1.7.0 - expect-type: 1.2.2 + expect-type: 1.3.0 magic-string: 0.30.21 obug: 2.1.1 pathe: 2.0.3 picomatch: 4.0.3 std-env: 3.10.0 tinybench: 2.9.0 - tinyexec: 1.0.2 + tinyexec: 1.0.4 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 vite: 7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) @@ -33354,10 +33550,10 @@ snapshots: - tsx - yaml - vitest@4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(vite@7.3.0(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)): + vitest@4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.0(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)): dependencies: '@vitest/expect': 4.1.0 - '@vitest/mocker': 4.1.0(vite@7.3.0(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + '@vitest/mocker': 4.1.0(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.0(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) '@vitest/pretty-format': 4.1.0 '@vitest/runner': 4.1.0 '@vitest/snapshot': 4.1.0 @@ -33383,10 +33579,10 @@ snapshots: - msw optional: true - vitest@4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)): + vitest@4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)): dependencies: '@vitest/expect': 4.1.0 - '@vitest/mocker': 4.1.0(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + '@vitest/mocker': 4.1.0(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) '@vitest/pretty-format': 4.1.0 '@vitest/runner': 4.1.0 '@vitest/snapshot': 4.1.0 @@ -33411,10 +33607,10 @@ snapshots: transitivePeerDependencies: - msw - vitest@4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)): + vitest@4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)): dependencies: '@vitest/expect': 4.1.0 - '@vitest/mocker': 4.1.0(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + '@vitest/mocker': 4.1.0(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) '@vitest/pretty-format': 4.1.0 '@vitest/runner': 4.1.0 '@vitest/snapshot': 4.1.0 diff --git a/specs/2.0.x/response-example.yaml b/specs/2.0.x/response-example.yaml new file mode 100644 index 0000000000..542075891c --- /dev/null +++ b/specs/2.0.x/response-example.yaml @@ -0,0 +1,54 @@ +swagger: 2.0 +info: + title: OpenAPI 2.0 body response application/json inline example + version: 1 +paths: + /foo: + post: + consumes: + - text/plain + produces: + - application/json + parameters: + - name: body + in: body + required: true + schema: + type: string + responses: + '200': + description: OK + schema: + type: object + properties: + fullName: + type: string + age: + type: number + example: + fullName: 'John Doe' + age: 34 + '204': + description: SUCCESSFUL + get: + produces: + - application/json + responses: + '200': + description: OK + schema: + $ref: '#/definitions/Person' +definitions: + Person: + type: object + properties: + firstName: + type: string + lastName: + type: string + age: + type: number + example: + firstName: 'Marry' + lastName: 'Jane' + age: 30 diff --git a/specs/3.0.x/response-example.yaml b/specs/3.0.x/response-example.yaml new file mode 100644 index 0000000000..2fd4275202 --- /dev/null +++ b/specs/3.0.x/response-example.yaml @@ -0,0 +1,53 @@ +openapi: 3.0.4 +info: + title: OpenAPI 3.0.4 body response application/json inline example + version: 1 +paths: + /foo: + post: + requestBody: + content: + 'text/plain': + schema: + type: string + required: true + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + fullName: + type: string + age: + type: number + example: + fullName: 'John Doe' + age: 34 + '204': + description: SUCCESSFUL + get: + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Person' +components: + schemas: + Person: + type: object + properties: + firstName: + type: string + lastName: + type: string + age: + type: number + example: + firstName: 'Marry' + lastName: 'Jane' + age: 30 diff --git a/specs/3.0.x/response-types.yaml b/specs/3.0.x/response-types.yaml new file mode 100644 index 0000000000..7d21afd1fd --- /dev/null +++ b/specs/3.0.x/response-types.yaml @@ -0,0 +1,26 @@ +openapi: 3.0.4 +info: + title: OpenAPI 3.0.4 response types + version: '1' +paths: + /foo: + get: + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + name: + type: string + example: + name: 'Alice' + text/plain: + schema: + type: string + application/octet-stream: + schema: + type: string + format: binary diff --git a/specs/3.1.x/response-example.yaml b/specs/3.1.x/response-example.yaml new file mode 100644 index 0000000000..1f8df45c75 --- /dev/null +++ b/specs/3.1.x/response-example.yaml @@ -0,0 +1,53 @@ +openapi: 3.1.1 +info: + title: OpenAPI 3.1.1 body response application/json inline example + version: 1 +paths: + /foo: + post: + requestBody: + content: + 'text/plain': + schema: + type: string + required: true + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + fullName: + type: string + age: + type: number + example: + fullName: 'John Doe' + age: 34 + '204': + description: SUCCESSFUL + get: + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Person' +components: + schemas: + Person: + type: object + properties: + firstName: + type: string + lastName: + type: string; + age: + type: number + example: + firstName: 'Marry' + lastName: 'Jane' + age: 30 diff --git a/specs/3.1.x/response-types.yaml b/specs/3.1.x/response-types.yaml new file mode 100644 index 0000000000..fde681eb30 --- /dev/null +++ b/specs/3.1.x/response-types.yaml @@ -0,0 +1,26 @@ +openapi: 3.1.0 +info: + title: OpenAPI 3.1.0 response types + version: '1' +paths: + /foo: + get: + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + name: + type: string + example: + name: 'Alice' + text/plain: + schema: + type: string + application/octet-stream: + schema: + type: string + format: binary From e0a95e9e5c8d74db7d317049403d0b712728a527 Mon Sep 17 00:00:00 2001 From: Malcolm Kee Date: Sun, 22 Mar 2026 21:40:17 +1100 Subject: [PATCH 02/16] fix: sort handler --- .../openapi-ts-fetch/src/client/msw.gen.ts | 18 +++--- .../2.0.x/plugins/msw/default/msw.gen.ts | 10 ++-- .../3.0.x/plugins/msw/default/msw.gen.ts | 20 +++---- .../3.1.x/plugins/msw/default/msw.gen.ts | 20 +++---- packages/openapi-ts/src/plugins/msw/plugin.ts | 11 +++- .../plugins/msw/sortHandlersBySpecificity.ts | 56 +++++++++++++++++++ 6 files changed, 98 insertions(+), 37 deletions(-) create mode 100644 packages/openapi-ts/src/plugins/msw/sortHandlersBySpecificity.ts diff --git a/examples/openapi-ts-fetch/src/client/msw.gen.ts b/examples/openapi-ts-fetch/src/client/msw.gen.ts index 3730745d52..4ef49026b0 100644 --- a/examples/openapi-ts-fetch/src/client/msw.gen.ts +++ b/examples/openapi-ts-fetch/src/client/msw.gen.ts @@ -484,25 +484,25 @@ export const createMswHandlerFactory = (config?: { baseUrl?: string }): MswHandl } } }; - addRequiredHandler(mocks.addPetMock, overrides?.addPetMock); - addRequiredHandler(mocks.updatePetMock, overrides?.updatePetMock); + handlers.push(mocks.deleteOrderMock(overrides?.deleteOrderMock)); + addRequiredHandler(mocks.getOrderByIdMock, overrides?.getOrderByIdMock); + addRequiredHandler(mocks.uploadFileMock, overrides?.uploadFileMock); addRequiredHandler(mocks.findPetsByStatusMock, overrides?.findPetsByStatusMock); addRequiredHandler(mocks.findPetsByTagsMock, overrides?.findPetsByTagsMock); - handlers.push(mocks.deletePetMock(overrides?.deletePetMock)); - addRequiredHandler(mocks.getPetByIdMock, overrides?.getPetByIdMock); - addRequiredHandler(mocks.updatePetWithFormMock, overrides?.updatePetWithFormMock); - addRequiredHandler(mocks.uploadFileMock, overrides?.uploadFileMock); addRequiredHandler(mocks.getInventoryMock, overrides?.getInventoryMock); addRequiredHandler(mocks.placeOrderMock, overrides?.placeOrderMock); - handlers.push(mocks.deleteOrderMock(overrides?.deleteOrderMock)); - addRequiredHandler(mocks.getOrderByIdMock, overrides?.getOrderByIdMock); - addRequiredHandler(mocks.createUserMock, overrides?.createUserMock); addRequiredHandler(mocks.createUsersWithListInputMock, overrides?.createUsersWithListInputMock); addRequiredHandler(mocks.loginUserMock, overrides?.loginUserMock); handlers.push(mocks.logoutUserMock(overrides?.logoutUserMock)); + handlers.push(mocks.deletePetMock(overrides?.deletePetMock)); + addRequiredHandler(mocks.getPetByIdMock, overrides?.getPetByIdMock); + addRequiredHandler(mocks.updatePetWithFormMock, overrides?.updatePetWithFormMock); handlers.push(mocks.deleteUserMock(overrides?.deleteUserMock)); addRequiredHandler(mocks.getUserByNameMock, overrides?.getUserByNameMock); handlers.push(mocks.updateUserMock(overrides?.updateUserMock)); + addRequiredHandler(mocks.addPetMock, overrides?.addPetMock); + addRequiredHandler(mocks.updatePetMock, overrides?.updatePetMock); + addRequiredHandler(mocks.createUserMock, overrides?.createUserMock); return handlers; }; return { ...mocks, getAllMocks }; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/msw.gen.ts index 1057a046f8..7df171607e 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/msw.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/msw.gen.ts @@ -165,6 +165,11 @@ export const createMswHandlerFactory = (config?: { } } }; + handlers.push(mocks.callWithWeirdParameterNamesMock(overrides?.callWithWeirdParameterNamesMock)); + addRequiredHandler(mocks.callWithResponseAndNoContentResponseMock, overrides?.callWithResponseAndNoContentResponseMock); + handlers.push(mocks.dummyAMock(overrides?.dummyAMock)); + handlers.push(mocks.dummyBMock(overrides?.dummyBMock)); + handlers.push(mocks.callWithParametersMock(overrides?.callWithParametersMock)); handlers.push(mocks.serviceWithEmptyTagMock(overrides?.serviceWithEmptyTagMock)); handlers.push(mocks.patchApiVbyApiVersionNoTagMock(overrides?.patchApiVbyApiVersionNoTagMock)); handlers.push(mocks.fooWowMock(overrides?.fooWowMock)); @@ -176,8 +181,6 @@ export const createMswHandlerFactory = (config?: { handlers.push(mocks.postCallWithoutParametersAndResponseMock(overrides?.postCallWithoutParametersAndResponseMock)); handlers.push(mocks.putCallWithoutParametersAndResponseMock(overrides?.putCallWithoutParametersAndResponseMock)); handlers.push(mocks.callWithDescriptionsMock(overrides?.callWithDescriptionsMock)); - handlers.push(mocks.callWithParametersMock(overrides?.callWithParametersMock)); - handlers.push(mocks.callWithWeirdParameterNamesMock(overrides?.callWithWeirdParameterNamesMock)); handlers.push(mocks.callWithDefaultParametersMock(overrides?.callWithDefaultParametersMock)); handlers.push(mocks.callWithDefaultOptionalParametersMock(overrides?.callWithDefaultOptionalParametersMock)); handlers.push(mocks.callToTestOrderOfParamsMock(overrides?.callToTestOrderOfParamsMock)); @@ -186,9 +189,6 @@ export const createMswHandlerFactory = (config?: { handlers.push(mocks.duplicateName3Mock(overrides?.duplicateName3Mock)); handlers.push(mocks.duplicateName4Mock(overrides?.duplicateName4Mock)); handlers.push(mocks.callWithNoContentResponseMock(overrides?.callWithNoContentResponseMock)); - addRequiredHandler(mocks.callWithResponseAndNoContentResponseMock, overrides?.callWithResponseAndNoContentResponseMock); - handlers.push(mocks.dummyAMock(overrides?.dummyAMock)); - handlers.push(mocks.dummyBMock(overrides?.dummyBMock)); handlers.push(mocks.callWithResponseMock(overrides?.callWithResponseMock)); addRequiredHandler(mocks.callWithDuplicateResponsesMock, overrides?.callWithDuplicateResponsesMock); addRequiredHandler(mocks.callWithResponsesMock, overrides?.callWithResponsesMock); diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/default/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/default/msw.gen.ts index f1e386dcf4..310e26b949 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/default/msw.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/default/msw.gen.ts @@ -228,11 +228,20 @@ export const createMswHandlerFactory = (config?: { } } }; + handlers.push(mocks.deleteFooMock(overrides?.deleteFooMock)); + handlers.push(mocks.callWithWeirdParameterNamesMock(overrides?.callWithWeirdParameterNamesMock)); + addRequiredHandler(mocks.apiVVersionODataControllerCountMock, overrides?.apiVVersionODataControllerCountMock); + handlers.push(mocks.deprecatedCallMock(overrides?.deprecatedCallMock)); + addRequiredHandler(mocks.callWithResponseAndNoContentResponseMock, overrides?.callWithResponseAndNoContentResponseMock); + addRequiredHandler(mocks.dummyAMock, overrides?.dummyAMock); + handlers.push(mocks.dummyBMock(overrides?.dummyBMock)); + handlers.push(mocks.callWithParametersMock(overrides?.callWithParametersMock)); + addRequiredHandler(mocks.fileResponseMock, overrides?.fileResponseMock); + addRequiredHandler(mocks.complexParamsMock, overrides?.complexParamsMock); handlers.push(mocks.exportMock(overrides?.exportMock)); handlers.push(mocks.patchApiVbyApiVersionNoTagMock(overrides?.patchApiVbyApiVersionNoTagMock)); addRequiredHandler(mocks.importMock, overrides?.importMock); handlers.push(mocks.fooWowMock(overrides?.fooWowMock)); - addRequiredHandler(mocks.apiVVersionODataControllerCountMock, overrides?.apiVVersionODataControllerCountMock); addRequiredHandler(mocks.getApiVbyApiVersionSimpleOperationMock, overrides?.getApiVbyApiVersionSimpleOperationMock); handlers.push(mocks.deleteCallWithoutParametersAndResponseMock(overrides?.deleteCallWithoutParametersAndResponseMock)); handlers.push(mocks.getCallWithoutParametersAndResponseMock(overrides?.getCallWithoutParametersAndResponseMock)); @@ -241,11 +250,7 @@ export const createMswHandlerFactory = (config?: { handlers.push(mocks.patchCallWithoutParametersAndResponseMock(overrides?.patchCallWithoutParametersAndResponseMock)); handlers.push(mocks.postCallWithoutParametersAndResponseMock(overrides?.postCallWithoutParametersAndResponseMock)); handlers.push(mocks.putCallWithoutParametersAndResponseMock(overrides?.putCallWithoutParametersAndResponseMock)); - handlers.push(mocks.deleteFooMock(overrides?.deleteFooMock)); handlers.push(mocks.callWithDescriptionsMock(overrides?.callWithDescriptionsMock)); - handlers.push(mocks.deprecatedCallMock(overrides?.deprecatedCallMock)); - handlers.push(mocks.callWithParametersMock(overrides?.callWithParametersMock)); - handlers.push(mocks.callWithWeirdParameterNamesMock(overrides?.callWithWeirdParameterNamesMock)); handlers.push(mocks.getCallWithOptionalParamMock(overrides?.getCallWithOptionalParamMock)); addRequiredHandler(mocks.postCallWithOptionalParamMock, overrides?.postCallWithOptionalParamMock); handlers.push(mocks.postApiVbyApiVersionRequestBodyMock(overrides?.postApiVbyApiVersionRequestBodyMock)); @@ -258,20 +263,15 @@ export const createMswHandlerFactory = (config?: { handlers.push(mocks.duplicateName3Mock(overrides?.duplicateName3Mock)); handlers.push(mocks.duplicateName4Mock(overrides?.duplicateName4Mock)); handlers.push(mocks.callWithNoContentResponseMock(overrides?.callWithNoContentResponseMock)); - addRequiredHandler(mocks.callWithResponseAndNoContentResponseMock, overrides?.callWithResponseAndNoContentResponseMock); - addRequiredHandler(mocks.dummyAMock, overrides?.dummyAMock); - handlers.push(mocks.dummyBMock(overrides?.dummyBMock)); handlers.push(mocks.callWithResponseMock(overrides?.callWithResponseMock)); addRequiredHandler(mocks.callWithDuplicateResponsesMock, overrides?.callWithDuplicateResponsesMock); addRequiredHandler(mocks.callWithResponsesMock, overrides?.callWithResponsesMock); handlers.push(mocks.collectionFormatMock(overrides?.collectionFormatMock)); addRequiredHandler(mocks.typesMock, overrides?.typesMock); addRequiredHandler(mocks.uploadFileMock, overrides?.uploadFileMock); - addRequiredHandler(mocks.fileResponseMock, overrides?.fileResponseMock); addRequiredHandler(mocks.complexTypesMock, overrides?.complexTypesMock); addRequiredHandler(mocks.multipartResponseMock, overrides?.multipartResponseMock); handlers.push(mocks.multipartRequestMock(overrides?.multipartRequestMock)); - addRequiredHandler(mocks.complexParamsMock, overrides?.complexParamsMock); handlers.push(mocks.callWithResultFromHeaderMock(overrides?.callWithResultFromHeaderMock)); handlers.push(mocks.testErrorCodeMock(overrides?.testErrorCodeMock)); addRequiredHandler(mocks.nonAsciiæøåÆøÅöôêÊ字符串Mock, overrides?.nonAsciiæøåÆøÅöôêÊ字符串Mock); diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/default/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/default/msw.gen.ts index f1e386dcf4..310e26b949 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/default/msw.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/default/msw.gen.ts @@ -228,11 +228,20 @@ export const createMswHandlerFactory = (config?: { } } }; + handlers.push(mocks.deleteFooMock(overrides?.deleteFooMock)); + handlers.push(mocks.callWithWeirdParameterNamesMock(overrides?.callWithWeirdParameterNamesMock)); + addRequiredHandler(mocks.apiVVersionODataControllerCountMock, overrides?.apiVVersionODataControllerCountMock); + handlers.push(mocks.deprecatedCallMock(overrides?.deprecatedCallMock)); + addRequiredHandler(mocks.callWithResponseAndNoContentResponseMock, overrides?.callWithResponseAndNoContentResponseMock); + addRequiredHandler(mocks.dummyAMock, overrides?.dummyAMock); + handlers.push(mocks.dummyBMock(overrides?.dummyBMock)); + handlers.push(mocks.callWithParametersMock(overrides?.callWithParametersMock)); + addRequiredHandler(mocks.fileResponseMock, overrides?.fileResponseMock); + addRequiredHandler(mocks.complexParamsMock, overrides?.complexParamsMock); handlers.push(mocks.exportMock(overrides?.exportMock)); handlers.push(mocks.patchApiVbyApiVersionNoTagMock(overrides?.patchApiVbyApiVersionNoTagMock)); addRequiredHandler(mocks.importMock, overrides?.importMock); handlers.push(mocks.fooWowMock(overrides?.fooWowMock)); - addRequiredHandler(mocks.apiVVersionODataControllerCountMock, overrides?.apiVVersionODataControllerCountMock); addRequiredHandler(mocks.getApiVbyApiVersionSimpleOperationMock, overrides?.getApiVbyApiVersionSimpleOperationMock); handlers.push(mocks.deleteCallWithoutParametersAndResponseMock(overrides?.deleteCallWithoutParametersAndResponseMock)); handlers.push(mocks.getCallWithoutParametersAndResponseMock(overrides?.getCallWithoutParametersAndResponseMock)); @@ -241,11 +250,7 @@ export const createMswHandlerFactory = (config?: { handlers.push(mocks.patchCallWithoutParametersAndResponseMock(overrides?.patchCallWithoutParametersAndResponseMock)); handlers.push(mocks.postCallWithoutParametersAndResponseMock(overrides?.postCallWithoutParametersAndResponseMock)); handlers.push(mocks.putCallWithoutParametersAndResponseMock(overrides?.putCallWithoutParametersAndResponseMock)); - handlers.push(mocks.deleteFooMock(overrides?.deleteFooMock)); handlers.push(mocks.callWithDescriptionsMock(overrides?.callWithDescriptionsMock)); - handlers.push(mocks.deprecatedCallMock(overrides?.deprecatedCallMock)); - handlers.push(mocks.callWithParametersMock(overrides?.callWithParametersMock)); - handlers.push(mocks.callWithWeirdParameterNamesMock(overrides?.callWithWeirdParameterNamesMock)); handlers.push(mocks.getCallWithOptionalParamMock(overrides?.getCallWithOptionalParamMock)); addRequiredHandler(mocks.postCallWithOptionalParamMock, overrides?.postCallWithOptionalParamMock); handlers.push(mocks.postApiVbyApiVersionRequestBodyMock(overrides?.postApiVbyApiVersionRequestBodyMock)); @@ -258,20 +263,15 @@ export const createMswHandlerFactory = (config?: { handlers.push(mocks.duplicateName3Mock(overrides?.duplicateName3Mock)); handlers.push(mocks.duplicateName4Mock(overrides?.duplicateName4Mock)); handlers.push(mocks.callWithNoContentResponseMock(overrides?.callWithNoContentResponseMock)); - addRequiredHandler(mocks.callWithResponseAndNoContentResponseMock, overrides?.callWithResponseAndNoContentResponseMock); - addRequiredHandler(mocks.dummyAMock, overrides?.dummyAMock); - handlers.push(mocks.dummyBMock(overrides?.dummyBMock)); handlers.push(mocks.callWithResponseMock(overrides?.callWithResponseMock)); addRequiredHandler(mocks.callWithDuplicateResponsesMock, overrides?.callWithDuplicateResponsesMock); addRequiredHandler(mocks.callWithResponsesMock, overrides?.callWithResponsesMock); handlers.push(mocks.collectionFormatMock(overrides?.collectionFormatMock)); addRequiredHandler(mocks.typesMock, overrides?.typesMock); addRequiredHandler(mocks.uploadFileMock, overrides?.uploadFileMock); - addRequiredHandler(mocks.fileResponseMock, overrides?.fileResponseMock); addRequiredHandler(mocks.complexTypesMock, overrides?.complexTypesMock); addRequiredHandler(mocks.multipartResponseMock, overrides?.multipartResponseMock); handlers.push(mocks.multipartRequestMock(overrides?.multipartRequestMock)); - addRequiredHandler(mocks.complexParamsMock, overrides?.complexParamsMock); handlers.push(mocks.callWithResultFromHeaderMock(overrides?.callWithResultFromHeaderMock)); handlers.push(mocks.testErrorCodeMock(overrides?.testErrorCodeMock)); addRequiredHandler(mocks.nonAsciiæøåÆøÅöôêÊ字符串Mock, overrides?.nonAsciiæøåÆøÅöôêÊ字符串Mock); diff --git a/packages/openapi-ts/src/plugins/msw/plugin.ts b/packages/openapi-ts/src/plugins/msw/plugin.ts index cfd9601b13..aafb71e9e8 100644 --- a/packages/openapi-ts/src/plugins/msw/plugin.ts +++ b/packages/openapi-ts/src/plugins/msw/plugin.ts @@ -2,6 +2,7 @@ import { parseUrl } from '@hey-api/shared'; import { $ } from '../../ts-dsl'; import { operationToHandlerCreator } from './handlerCreator'; +import { sortHandlersBySpecificity } from './sortHandlersBySpecificity'; import type { MswPlugin } from './types'; export const handler: MswPlugin['Handler'] = ({ plugin }) => { @@ -85,7 +86,7 @@ export const handler: MswPlugin['Handler'] = ({ plugin }) => { const symbolFactory = plugin.symbol('createMswHandlerFactory'); const ofObject = $.object().pretty(); const singleHandlerFactoriesType = $.type.object(); - const handlerMeta: Array<{ isOptional: boolean; name: string }> = []; + const handlerMeta: Array<{ isOptional: boolean; name: string; path: string }> = []; plugin.forEach( 'operation', @@ -98,7 +99,11 @@ export const handler: MswPlugin['Handler'] = ({ plugin }) => { if (handlerCreator) { ofObject.prop(handlerCreator.name, handlerCreator.value); singleHandlerFactoriesType.prop(handlerCreator.name, (p) => p.type(handlerCreator.type)); - handlerMeta.push({ isOptional: handlerCreator.isOptional, name: handlerCreator.name }); + handlerMeta.push({ + isOptional: handlerCreator.isOptional, + name: handlerCreator.name, + path: operation.path, + }); } }, { @@ -236,7 +241,7 @@ export const handler: MswPlugin['Handler'] = ({ plugin }) => { ); } - for (const handler of handlerMeta) { + for (const handler of sortHandlersBySpecificity(handlerMeta)) { if (handler.isOptional) { getAllMocksBodyStmts.push( $.stmt( diff --git a/packages/openapi-ts/src/plugins/msw/sortHandlersBySpecificity.ts b/packages/openapi-ts/src/plugins/msw/sortHandlersBySpecificity.ts new file mode 100644 index 0000000000..7d68b51d3f --- /dev/null +++ b/packages/openapi-ts/src/plugins/msw/sortHandlersBySpecificity.ts @@ -0,0 +1,56 @@ +interface HandlerMeta { + name: string; + path: string; +} + +/** + * Returns 1 for a static segment, 0 for a parameterized segment. + * Works with OpenAPI `{param}` format. + */ +const segmentScore = (segment: string): number => (/\{[^}]+\}/.test(segment) ? 0 : 1); + +/** + * Sorts handler metadata by route specificity so that more specific routes + * appear before less specific ones in the generated `getAllMocks` handler array. + * + * MSW matches handlers top-to-bottom, so without sorting a dynamic route like + * `/api/permissions/:userId` would shadow `/api/permissions/all`. + * + * Algorithm inspired by React Router v6 and route-sort: + * @see https://reactrouter.com/explanation/route-matching + * @see https://github.com/lukeed/route-sort + * + * Rules, applied in priority order: + * 1. More path segments (deeper routes) come first. + * 2. At equal depth, static segments beat dynamic ones (left-to-right). + * 3. At equal specificity, preserve original declaration order (stable sort). + */ +export const sortHandlersBySpecificity = ( + handlers: ReadonlyArray, +): Array => { + const indexed = handlers.map((handler, index) => ({ handler, index })); + + indexed.sort((a, b) => { + const segmentsA = a.handler.path.split('/').filter(Boolean); + const segmentsB = b.handler.path.split('/').filter(Boolean); + + // Rule 1: deeper routes are more specific + if (segmentsA.length !== segmentsB.length) { + return segmentsB.length - segmentsA.length; + } + + // Rule 2: at equal depth, static segments beat dynamic ones (left-to-right) + for (let i = 0; i < segmentsA.length; i++) { + const scoreA = segmentScore(segmentsA[i]!); + const scoreB = segmentScore(segmentsB[i]!); + if (scoreA !== scoreB) { + return scoreB - scoreA; + } + } + + // Rule 3: preserve declaration order + return a.index - b.index; + }); + + return indexed.map((entry) => entry.handler); +}; From 4269ed69ceae69e04e8235fb5a4a4b0ce3a31cad Mon Sep 17 00:00:00 2001 From: Malcolm Kee Date: Wed, 25 Mar 2026 00:15:35 +1100 Subject: [PATCH 03/16] refactor: simplify types --- .../openapi-ts-fetch/src/client/msw.gen.ts | 26 --------------- .../2.0.x/plugins/msw/default/msw.gen.ts | 16 +++++----- .../msw/response-example-disabled/msw.gen.ts | 6 ++-- .../plugins/msw/response-example/msw.gen.ts | 6 ++-- .../2.0.x/plugins/msw/servers/msw.gen.ts | 9 +----- .../3.0.x/plugins/msw/default/msw.gen.ts | 32 +++++++++---------- .../msw/response-example-disabled/msw.gen.ts | 6 ++-- .../plugins/msw/response-example/msw.gen.ts | 6 ++-- .../plugins/msw/response-types/msw.gen.ts | 9 +----- .../3.0.x/plugins/msw/servers/msw.gen.ts | 9 +----- .../3.1.x/plugins/msw/default/msw.gen.ts | 32 +++++++++---------- .../msw/response-example-disabled/msw.gen.ts | 6 ++-- .../plugins/msw/response-example/msw.gen.ts | 6 ++-- .../plugins/msw/response-types/msw.gen.ts | 9 +----- .../3.1.x/plugins/msw/servers/msw.gen.ts | 9 +----- .../plugins/msw/computeDominantResponse.ts | 4 ++- .../src/plugins/msw/handlerCreator.ts | 13 ++++---- 17 files changed, 73 insertions(+), 131 deletions(-) diff --git a/examples/openapi-ts-fetch/src/client/msw.gen.ts b/examples/openapi-ts-fetch/src/client/msw.gen.ts index 4ef49026b0..6395f74f8d 100644 --- a/examples/openapi-ts-fetch/src/client/msw.gen.ts +++ b/examples/openapi-ts-fetch/src/client/msw.gen.ts @@ -39,13 +39,6 @@ import type { const resolveToNull = () => new HttpResponse(null); -type ToResponseUnion = { - [K in Extract]: { - result: T[K]; - status: K; - }; -}[Extract]; - type HttpHandlerFactory = ( responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions, @@ -62,7 +55,6 @@ export type SingleHandlerFactories = { result: AddPetResponses[200]; status?: 200; } - | ToResponseUnion | HttpResponseResolver >; createUserMock: HttpHandlerFactory< @@ -70,7 +62,6 @@ export type SingleHandlerFactories = { result: CreateUserResponses[200]; status?: 200; } - | ToResponseUnion | HttpResponseResolver >; createUsersWithListInputMock: HttpHandlerFactory< @@ -78,7 +69,6 @@ export type SingleHandlerFactories = { result: CreateUsersWithListInputResponses[200]; status?: 200; } - | ToResponseUnion | HttpResponseResolver >; deleteOrderMock: OptionalHttpHandlerFactory< @@ -86,7 +76,6 @@ export type SingleHandlerFactories = { result: DeleteOrderResponses[200]; status?: 200; } - | ToResponseUnion | HttpResponseResolver< { orderId: string; @@ -99,7 +88,6 @@ export type SingleHandlerFactories = { result: DeletePetResponses[200]; status?: 200; } - | ToResponseUnion | HttpResponseResolver< { petId: string; @@ -112,7 +100,6 @@ export type SingleHandlerFactories = { result: DeleteUserResponses[200]; status?: 200; } - | ToResponseUnion | HttpResponseResolver< { username: string; @@ -125,7 +112,6 @@ export type SingleHandlerFactories = { result: FindPetsByStatusResponses[200]; status?: 200; } - | ToResponseUnion | HttpResponseResolver >; findPetsByTagsMock: HttpHandlerFactory< @@ -133,7 +119,6 @@ export type SingleHandlerFactories = { result: FindPetsByTagsResponses[200]; status?: 200; } - | ToResponseUnion | HttpResponseResolver >; getInventoryMock: HttpHandlerFactory< @@ -141,7 +126,6 @@ export type SingleHandlerFactories = { result: GetInventoryResponses[200]; status?: 200; } - | ToResponseUnion | HttpResponseResolver >; getOrderByIdMock: HttpHandlerFactory< @@ -149,7 +133,6 @@ export type SingleHandlerFactories = { result: GetOrderByIdResponses[200]; status?: 200; } - | ToResponseUnion | HttpResponseResolver< { orderId: string; @@ -162,7 +145,6 @@ export type SingleHandlerFactories = { result: GetPetByIdResponses[200]; status?: 200; } - | ToResponseUnion | HttpResponseResolver< { petId: string; @@ -175,7 +157,6 @@ export type SingleHandlerFactories = { result: GetUserByNameResponses[200]; status?: 200; } - | ToResponseUnion | HttpResponseResolver< { username: string; @@ -188,7 +169,6 @@ export type SingleHandlerFactories = { result: LoginUserResponses[200]; status?: 200; } - | ToResponseUnion | HttpResponseResolver >; logoutUserMock: OptionalHttpHandlerFactory< @@ -196,7 +176,6 @@ export type SingleHandlerFactories = { result: LogoutUserResponses[200]; status?: 200; } - | ToResponseUnion | HttpResponseResolver >; placeOrderMock: HttpHandlerFactory< @@ -204,7 +183,6 @@ export type SingleHandlerFactories = { result: PlaceOrderResponses[200]; status?: 200; } - | ToResponseUnion | HttpResponseResolver >; updatePetMock: HttpHandlerFactory< @@ -212,7 +190,6 @@ export type SingleHandlerFactories = { result: UpdatePetResponses[200]; status?: 200; } - | ToResponseUnion | HttpResponseResolver >; updatePetWithFormMock: HttpHandlerFactory< @@ -220,7 +197,6 @@ export type SingleHandlerFactories = { result: UpdatePetWithFormResponses[200]; status?: 200; } - | ToResponseUnion | HttpResponseResolver< { petId: string; @@ -233,7 +209,6 @@ export type SingleHandlerFactories = { result: UpdateUserResponses[200]; status?: 200; } - | ToResponseUnion | HttpResponseResolver< { username: string; @@ -246,7 +221,6 @@ export type SingleHandlerFactories = { result: UploadFileResponses[200]; status?: 200; } - | ToResponseUnion | HttpResponseResolver< { petId: string; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/msw.gen.ts index 7df171607e..816dcf34ff 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/msw.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/msw.gen.ts @@ -49,7 +49,7 @@ export type SingleHandlerFactories = { callWithNoContentResponseMock: OptionalHttpHandlerFactory<{ result: CallWithNoContentResponseResponses[204]; status?: 204; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; callWithResponseAndNoContentResponseMock: HttpHandlerFactory<{ result: CallWithResponseAndNoContentResponseResponses[200]; status?: 200; @@ -57,11 +57,11 @@ export type SingleHandlerFactories = { dummyAMock: OptionalHttpHandlerFactory<{ result: DummyAResponses[204]; status?: 204; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; dummyBMock: OptionalHttpHandlerFactory<{ result: DummyBResponses[204]; status?: 204; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; callWithResponseMock: OptionalHttpHandlerFactory; callWithDuplicateResponsesMock: HttpHandlerFactory<{ result: CallWithDuplicateResponsesResponses[201]; @@ -81,23 +81,23 @@ export type SingleHandlerFactories = { complexTypesMock: HttpHandlerFactory<{ result: ComplexTypesResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; callWithResultFromHeaderMock: OptionalHttpHandlerFactory<{ result: CallWithResultFromHeaderResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; testErrorCodeMock: OptionalHttpHandlerFactory<{ result: TestErrorCodeResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; nonAsciiæøåÆøÅöôêÊ字符串Mock: HttpHandlerFactory<{ result: NonAsciiæøåÆøÅöôêÊ字符串Responses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; postApiVbyApiVersionBodyMock: HttpHandlerFactory<{ result: PostApiVbyApiVersionBodyResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; }; export type GetAllMocksOptions = { diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example-disabled/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example-disabled/msw.gen.ts index 6bc96de46f..a2e510c260 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example-disabled/msw.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example-disabled/msw.gen.ts @@ -6,6 +6,8 @@ import type { GetFooResponses, PostFooData, PostFooResponses } from './types.gen const resolveToNull = () => new HttpResponse(null); +type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; + type ToResponseUnion = { [K in Extract]: { status: K; @@ -13,13 +15,11 @@ type ToResponseUnion = { }; }[Extract]; -type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; - export type SingleHandlerFactories = { getFooMock: HttpHandlerFactory<{ result: GetFooResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; postFooMock: HttpHandlerFactory<{ result: PostFooResponses[200]; status?: 200; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example/msw.gen.ts index c5bc51f48e..0eac1db4bb 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example/msw.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example/msw.gen.ts @@ -6,6 +6,8 @@ import type { GetFooResponses, PostFooData, PostFooResponses } from './types.gen const resolveToNull = () => new HttpResponse(null); +type OptionalHttpHandlerFactory = (responseOrResolver?: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; + type ToResponseUnion = { [K in Extract]: { status: K; @@ -13,13 +15,11 @@ type ToResponseUnion = { }; }[Extract]; -type OptionalHttpHandlerFactory = (responseOrResolver?: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; - export type SingleHandlerFactories = { getFooMock: OptionalHttpHandlerFactory<{ result: GetFooResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; postFooMock: OptionalHttpHandlerFactory<{ result: PostFooResponses[200]; status?: 200; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/servers/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/servers/msw.gen.ts index e9a5d27215..d365ef4f29 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/servers/msw.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/servers/msw.gen.ts @@ -6,20 +6,13 @@ import type { GetFooResponses } from './types.gen'; const resolveToNull = () => new HttpResponse(null); -type ToResponseUnion = { - [K in Extract]: { - status: K; - result: T[K]; - }; -}[Extract]; - type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; export type SingleHandlerFactories = { getFooMock: HttpHandlerFactory<{ result: GetFooResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; }; export type GetAllMocksOptions = { diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/default/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/default/msw.gen.ts index 310e26b949..4f9fb98673 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/default/msw.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/default/msw.gen.ts @@ -8,6 +8,8 @@ const resolveToNull = () => new HttpResponse(null); type OptionalHttpHandlerFactory = (responseOrResolver?: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; +type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; + type ToResponseUnion = { [K in Extract]: { status: K; @@ -15,24 +17,22 @@ type ToResponseUnion = { }; }[Extract]; -type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; - export type SingleHandlerFactories = { exportMock: OptionalHttpHandlerFactory; patchApiVbyApiVersionNoTagMock: OptionalHttpHandlerFactory; importMock: HttpHandlerFactory<{ result: ImportResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; fooWowMock: OptionalHttpHandlerFactory; apiVVersionODataControllerCountMock: HttpHandlerFactory<{ result: ApiVVersionODataControllerCountResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; getApiVbyApiVersionSimpleOperationMock: HttpHandlerFactory<{ result: GetApiVbyApiVersionSimpleOperationResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver<{ + } | HttpResponseResolver<{ apiVersion: string; }, never>>; deleteCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; @@ -76,7 +76,7 @@ export type SingleHandlerFactories = { callWithNoContentResponseMock: OptionalHttpHandlerFactory<{ result: CallWithNoContentResponseResponses[204]; status?: 204; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; callWithResponseAndNoContentResponseMock: HttpHandlerFactory<{ result: CallWithResponseAndNoContentResponseResponses[200]; status?: 200; @@ -84,11 +84,11 @@ export type SingleHandlerFactories = { dummyAMock: HttpHandlerFactory<{ result: DummyAResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; dummyBMock: OptionalHttpHandlerFactory<{ result: DummyBResponses[204]; status?: 204; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; callWithResponseMock: OptionalHttpHandlerFactory; callWithDuplicateResponsesMock: HttpHandlerFactory<{ result: CallWithDuplicateResponsesResponses[200]; @@ -108,44 +108,44 @@ export type SingleHandlerFactories = { uploadFileMock: HttpHandlerFactory<{ result: UploadFileResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver<{ + } | HttpResponseResolver<{ apiVersion: string; }, UploadFileData['body']>>; fileResponseMock: HttpHandlerFactory<{ result: FileResponseResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver<{ + } | HttpResponseResolver<{ apiVersion: string; id: string; }, never>>; complexTypesMock: HttpHandlerFactory<{ result: ComplexTypesResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; multipartResponseMock: HttpHandlerFactory<{ result: MultipartResponseResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; multipartRequestMock: OptionalHttpHandlerFactory>; complexParamsMock: HttpHandlerFactory<{ result: ComplexParamsResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver<{ + } | HttpResponseResolver<{ apiVersion: string; id: string; }, ComplexParamsData['body']>>; callWithResultFromHeaderMock: OptionalHttpHandlerFactory<{ result: CallWithResultFromHeaderResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; testErrorCodeMock: OptionalHttpHandlerFactory<{ result: TestErrorCodeResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; nonAsciiæøåÆøÅöôêÊ字符串Mock: HttpHandlerFactory<{ result: NonAsciiæøåÆøÅöôêÊ字符串Responses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; putWithFormUrlEncodedMock: OptionalHttpHandlerFactory>; }; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example-disabled/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example-disabled/msw.gen.ts index 6bc96de46f..a2e510c260 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example-disabled/msw.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example-disabled/msw.gen.ts @@ -6,6 +6,8 @@ import type { GetFooResponses, PostFooData, PostFooResponses } from './types.gen const resolveToNull = () => new HttpResponse(null); +type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; + type ToResponseUnion = { [K in Extract]: { status: K; @@ -13,13 +15,11 @@ type ToResponseUnion = { }; }[Extract]; -type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; - export type SingleHandlerFactories = { getFooMock: HttpHandlerFactory<{ result: GetFooResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; postFooMock: HttpHandlerFactory<{ result: PostFooResponses[200]; status?: 200; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example/msw.gen.ts index c0552c7c42..90f967fa06 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example/msw.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example/msw.gen.ts @@ -6,6 +6,8 @@ import type { GetFooResponses, PostFooData, PostFooResponses } from './types.gen const resolveToNull = () => new HttpResponse(null); +type OptionalHttpHandlerFactory = (responseOrResolver?: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; + type ToResponseUnion = { [K in Extract]: { status: K; @@ -13,15 +15,13 @@ type ToResponseUnion = { }; }[Extract]; -type OptionalHttpHandlerFactory = (responseOrResolver?: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; - type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; export type SingleHandlerFactories = { getFooMock: OptionalHttpHandlerFactory<{ result: GetFooResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; postFooMock: HttpHandlerFactory<{ result: PostFooResponses[200]; status?: 200; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-types/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-types/msw.gen.ts index f27d2f0cd8..0e95210e4c 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-types/msw.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-types/msw.gen.ts @@ -6,20 +6,13 @@ import type { GetFooResponses } from './types.gen'; const resolveToNull = () => new HttpResponse(null); -type ToResponseUnion = { - [K in Extract]: { - status: K; - result: T[K]; - }; -}[Extract]; - type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; export type SingleHandlerFactories = { getFooMock: HttpHandlerFactory<{ result: GetFooResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; }; export type GetAllMocksOptions = { diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/servers/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/servers/msw.gen.ts index e9a5d27215..d365ef4f29 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/servers/msw.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/servers/msw.gen.ts @@ -6,20 +6,13 @@ import type { GetFooResponses } from './types.gen'; const resolveToNull = () => new HttpResponse(null); -type ToResponseUnion = { - [K in Extract]: { - status: K; - result: T[K]; - }; -}[Extract]; - type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; export type SingleHandlerFactories = { getFooMock: HttpHandlerFactory<{ result: GetFooResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; }; export type GetAllMocksOptions = { diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/default/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/default/msw.gen.ts index 310e26b949..4f9fb98673 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/default/msw.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/default/msw.gen.ts @@ -8,6 +8,8 @@ const resolveToNull = () => new HttpResponse(null); type OptionalHttpHandlerFactory = (responseOrResolver?: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; +type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; + type ToResponseUnion = { [K in Extract]: { status: K; @@ -15,24 +17,22 @@ type ToResponseUnion = { }; }[Extract]; -type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; - export type SingleHandlerFactories = { exportMock: OptionalHttpHandlerFactory; patchApiVbyApiVersionNoTagMock: OptionalHttpHandlerFactory; importMock: HttpHandlerFactory<{ result: ImportResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; fooWowMock: OptionalHttpHandlerFactory; apiVVersionODataControllerCountMock: HttpHandlerFactory<{ result: ApiVVersionODataControllerCountResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; getApiVbyApiVersionSimpleOperationMock: HttpHandlerFactory<{ result: GetApiVbyApiVersionSimpleOperationResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver<{ + } | HttpResponseResolver<{ apiVersion: string; }, never>>; deleteCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; @@ -76,7 +76,7 @@ export type SingleHandlerFactories = { callWithNoContentResponseMock: OptionalHttpHandlerFactory<{ result: CallWithNoContentResponseResponses[204]; status?: 204; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; callWithResponseAndNoContentResponseMock: HttpHandlerFactory<{ result: CallWithResponseAndNoContentResponseResponses[200]; status?: 200; @@ -84,11 +84,11 @@ export type SingleHandlerFactories = { dummyAMock: HttpHandlerFactory<{ result: DummyAResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; dummyBMock: OptionalHttpHandlerFactory<{ result: DummyBResponses[204]; status?: 204; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; callWithResponseMock: OptionalHttpHandlerFactory; callWithDuplicateResponsesMock: HttpHandlerFactory<{ result: CallWithDuplicateResponsesResponses[200]; @@ -108,44 +108,44 @@ export type SingleHandlerFactories = { uploadFileMock: HttpHandlerFactory<{ result: UploadFileResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver<{ + } | HttpResponseResolver<{ apiVersion: string; }, UploadFileData['body']>>; fileResponseMock: HttpHandlerFactory<{ result: FileResponseResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver<{ + } | HttpResponseResolver<{ apiVersion: string; id: string; }, never>>; complexTypesMock: HttpHandlerFactory<{ result: ComplexTypesResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; multipartResponseMock: HttpHandlerFactory<{ result: MultipartResponseResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; multipartRequestMock: OptionalHttpHandlerFactory>; complexParamsMock: HttpHandlerFactory<{ result: ComplexParamsResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver<{ + } | HttpResponseResolver<{ apiVersion: string; id: string; }, ComplexParamsData['body']>>; callWithResultFromHeaderMock: OptionalHttpHandlerFactory<{ result: CallWithResultFromHeaderResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; testErrorCodeMock: OptionalHttpHandlerFactory<{ result: TestErrorCodeResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; nonAsciiæøåÆøÅöôêÊ字符串Mock: HttpHandlerFactory<{ result: NonAsciiæøåÆøÅöôêÊ字符串Responses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; putWithFormUrlEncodedMock: OptionalHttpHandlerFactory>; }; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example-disabled/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example-disabled/msw.gen.ts index 6bc96de46f..a2e510c260 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example-disabled/msw.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example-disabled/msw.gen.ts @@ -6,6 +6,8 @@ import type { GetFooResponses, PostFooData, PostFooResponses } from './types.gen const resolveToNull = () => new HttpResponse(null); +type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; + type ToResponseUnion = { [K in Extract]: { status: K; @@ -13,13 +15,11 @@ type ToResponseUnion = { }; }[Extract]; -type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; - export type SingleHandlerFactories = { getFooMock: HttpHandlerFactory<{ result: GetFooResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; postFooMock: HttpHandlerFactory<{ result: PostFooResponses[200]; status?: 200; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example/msw.gen.ts index c5bc51f48e..0eac1db4bb 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example/msw.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example/msw.gen.ts @@ -6,6 +6,8 @@ import type { GetFooResponses, PostFooData, PostFooResponses } from './types.gen const resolveToNull = () => new HttpResponse(null); +type OptionalHttpHandlerFactory = (responseOrResolver?: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; + type ToResponseUnion = { [K in Extract]: { status: K; @@ -13,13 +15,11 @@ type ToResponseUnion = { }; }[Extract]; -type OptionalHttpHandlerFactory = (responseOrResolver?: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; - export type SingleHandlerFactories = { getFooMock: OptionalHttpHandlerFactory<{ result: GetFooResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; postFooMock: OptionalHttpHandlerFactory<{ result: PostFooResponses[200]; status?: 200; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-types/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-types/msw.gen.ts index d67d985f27..f557bc4708 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-types/msw.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-types/msw.gen.ts @@ -6,20 +6,13 @@ import type { GetFooResponses } from './types.gen'; const resolveToNull = () => new HttpResponse(null); -type ToResponseUnion = { - [K in Extract]: { - status: K; - result: T[K]; - }; -}[Extract]; - type OptionalHttpHandlerFactory = (responseOrResolver?: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; export type SingleHandlerFactories = { getFooMock: OptionalHttpHandlerFactory<{ result: GetFooResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; }; export type GetAllMocksOptions = { diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/servers/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/servers/msw.gen.ts index e9a5d27215..d365ef4f29 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/servers/msw.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/servers/msw.gen.ts @@ -6,20 +6,13 @@ import type { GetFooResponses } from './types.gen'; const resolveToNull = () => new HttpResponse(null); -type ToResponseUnion = { - [K in Extract]: { - status: K; - result: T[K]; - }; -}[Extract]; - type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; export type SingleHandlerFactories = { getFooMock: HttpHandlerFactory<{ result: GetFooResponses[200]; status?: 200; - } | ToResponseUnion | HttpResponseResolver>; + } | HttpResponseResolver>; }; export type GetAllMocksOptions = { diff --git a/packages/openapi-ts/src/plugins/msw/computeDominantResponse.ts b/packages/openapi-ts/src/plugins/msw/computeDominantResponse.ts index 224db9fce0..0afce179f2 100644 --- a/packages/openapi-ts/src/plugins/msw/computeDominantResponse.ts +++ b/packages/openapi-ts/src/plugins/msw/computeDominantResponse.ts @@ -5,6 +5,7 @@ import type { MswPlugin } from './types'; export type ResponseKind = 'binary' | 'json' | 'text' | 'void'; export interface DominantResponse { + allCandidates: Array; example: unknown; kind: ResponseKind; statusCode: number | undefined; @@ -130,7 +131,7 @@ export const computeDominantResponse = ({ } if (candidates.length === 0) { - return { example: undefined, kind: 'void', statusCode: undefined }; + return { allCandidates: [], example: undefined, kind: 'void', statusCode: undefined }; } const dominant = candidates.reduce((best, cur) => @@ -138,6 +139,7 @@ export const computeDominantResponse = ({ ); return { + allCandidates: candidates, example: dominant.example, kind: dominant.kind, statusCode: dominant.statusCode, diff --git a/packages/openapi-ts/src/plugins/msw/handlerCreator.ts b/packages/openapi-ts/src/plugins/msw/handlerCreator.ts index 7b393605e2..90e7d4f4b0 100644 --- a/packages/openapi-ts/src/plugins/msw/handlerCreator.ts +++ b/packages/openapi-ts/src/plugins/msw/handlerCreator.ts @@ -260,6 +260,8 @@ export const operationToHandlerCreator = ({ return; } + const dominantResponse = computeDominantResponse({ operation, plugin }); + const symbolHttp = plugin.external('msw.http'); const symbolHttpResponse = plugin.external('msw.HttpResponse'); const symbolHttpResponseResolver = plugin.external('msw.HttpResponseResolver'); @@ -288,7 +290,8 @@ export const operationToHandlerCreator = ({ role: 'responses', }); let responsesOverrideType: ReturnType | undefined; - if (symbolResponsesType) { + if (symbolResponsesType && dominantResponse.allCandidates.length > 1) { + // We only neeed to add ToResponseUnion if there are multiple responses if (!plugin.getSymbol({ category: 'type', resource: 'to-response-union' })) { emitToResponseUnion(plugin); } @@ -338,8 +341,6 @@ export const operationToHandlerCreator = ({ ) : $.type(symbolHttpResponseResolver); - const dominantResponse = computeDominantResponse({ operation, plugin }); - // When examples are disabled, strip the example from the dominant response if (!examples) { dominantResponse.example = undefined; @@ -358,14 +359,14 @@ export const operationToHandlerCreator = ({ const isOptional = // if there is no dominantResponse, it means there is no status code definition // so we can set the default response as null - !(dominantResponse.statusCode != null && responsesOverrideType) || + !(dominantResponse.statusCode != null) || // if there is example, the param is optional because example can be used // if it's void, the param is optional because we can define the default (`null`) dominantResponse.example != null || dominantResponse.kind === 'void'; let responseOrResolverType: ReturnType | ReturnType; - if (dominantResponse.statusCode != null && responsesOverrideType && symbolResponsesType) { + if (dominantResponse.statusCode != null && symbolResponsesType) { const dominantResponseType = $.type .object() .prop('result', (p) => @@ -376,7 +377,7 @@ export const operationToHandlerCreator = ({ .prop('status', (p) => p.optional().type($.type.literal(dominantResponse.statusCode!))); responseOrResolverType = $.type.or( dominantResponseType, - $.type.or(responsesOverrideType, resolverType), + responsesOverrideType ? $.type.or(responsesOverrideType, resolverType) : resolverType, ); } else { responseOrResolverType = resolverType; From 9c5018f0453b15ddd2af32db277bdf881d5313f2 Mon Sep 17 00:00:00 2001 From: Lubos Date: Wed, 25 Mar 2026 22:48:33 +0100 Subject: [PATCH 04/16] chore: clean up dependencies --- .changeset/many-memes-wish.md | 5 + dev/typescript/presets.ts | 6 +- docs/.vitepress/config/en.ts | 8 +- docs/data/people.ts | 5 + docs/openapi-ts/mocks.md | 2 +- docs/openapi-ts/plugins/msw.md | 34 +- .../openapi-ts-angular-common/package.json | 2 +- examples/openapi-ts-angular/package.json | 2 +- examples/openapi-ts-axios/package.json | 4 +- examples/openapi-ts-fastify/package.json | 6 +- examples/openapi-ts-fetch/package.json | 6 +- examples/openapi-ts-ky/package.json | 4 +- examples/openapi-ts-nestjs/package.json | 18 +- examples/openapi-ts-next/package.json | 2 +- examples/openapi-ts-ofetch/package.json | 6 +- examples/openapi-ts-openai/package.json | 4 +- examples/openapi-ts-pinia-colada/package.json | 6 +- .../package.json | 4 +- .../package.json | 6 +- .../package.json | 6 +- packages/codegen-core/package.json | 2 +- packages/openapi-python/package.json | 2 +- packages/openapi-ts-tests/main/package.json | 2 +- packages/openapi-ts/README.md | 2 +- packages/openapi-ts/package.json | 3 +- .../src/plugins/@faker-js/faker/types.ts | 17 +- packages/openapi-ts/src/plugins/msw/types.ts | 11 +- packages/shared/package.json | 2 +- pnpm-lock.yaml | 1431 ++++++----------- renovate.json | 10 - 30 files changed, 566 insertions(+), 1052 deletions(-) create mode 100644 .changeset/many-memes-wish.md diff --git a/.changeset/many-memes-wish.md b/.changeset/many-memes-wish.md new file mode 100644 index 0000000000..6e07b639e1 --- /dev/null +++ b/.changeset/many-memes-wish.md @@ -0,0 +1,5 @@ +--- +"@hey-api/openapi-ts": patch +--- + +**plugin(msw)**: initial release diff --git a/dev/typescript/presets.ts b/dev/typescript/presets.ts index 69205d7710..ae36dac09a 100644 --- a/dev/typescript/presets.ts +++ b/dev/typescript/presets.ts @@ -30,7 +30,11 @@ export const presets = { }, }, ], - msw: () => ['@hey-api/typescript', 'msw'], + msw: () => [ + /** SDK + MSW handlers */ + '@hey-api/sdk', + 'msw', + ], rpc: () => [ /** RPC-style SDK with Zod validation */ 'orpc', diff --git a/docs/.vitepress/config/en.ts b/docs/.vitepress/config/en.ts index c0dbe96200..0419ce78ec 100644 --- a/docs/.vitepress/config/en.ts +++ b/docs/.vitepress/config/en.ts @@ -188,6 +188,10 @@ export default defineConfig({ { collapsed: true, items: [ + { + link: '/openapi-ts/plugins/msw', + text: 'MSW', + }, { link: '/openapi-ts/plugins/chance', text: 'Chance soon', @@ -200,10 +204,6 @@ export default defineConfig({ link: '/openapi-ts/plugins/falso', text: 'Falso soon', }, - { - link: '/openapi-ts/plugins/msw', - text: 'MSW soon', - }, { link: '/openapi-ts/plugins/nock', text: 'Nock soon', diff --git a/docs/data/people.ts b/docs/data/people.ts index 2c5d493205..2d8e4b266a 100644 --- a/docs/data/people.ts +++ b/docs/data/people.ts @@ -18,6 +18,11 @@ export const joshHemphill: Person = { name: 'Josh Hemphill', }; +export const malcolmKee: Person = { + github: 'https://github.com/malcolm-kee', + name: 'Malcolm Kee', +}; + export const maxScopp: Person = { github: 'https://github.com/max-scopp', name: 'Max Scopp', diff --git a/docs/openapi-ts/mocks.md b/docs/openapi-ts/mocks.md index 7b702e511c..4fbc67694d 100644 --- a/docs/openapi-ts/mocks.md +++ b/docs/openapi-ts/mocks.md @@ -11,10 +11,10 @@ Realistic mock data is an important component of every robust development proces Hey API natively supports the following mocking frameworks. +- [MSW](/openapi-ts/plugins/msw) - [Chance](/openapi-ts/plugins/chance) Soon - [Faker](/openapi-ts/plugins/faker) Soon - [Falso](/openapi-ts/plugins/falso) Soon -- [MSW](/openapi-ts/plugins/msw) Soon - [Nock](/openapi-ts/plugins/nock) Soon - [Supertest](/openapi-ts/plugins/supertest) Soon diff --git a/docs/openapi-ts/plugins/msw.md b/docs/openapi-ts/plugins/msw.md index 4719b1d7bc..b2900cc7ed 100644 --- a/docs/openapi-ts/plugins/msw.md +++ b/docs/openapi-ts/plugins/msw.md @@ -4,36 +4,46 @@ description: MSW plugin for Hey API. Compatible with all our features. --- -# MSW + +

MSW v2

+ +
+ +::: warning +MSW plugin is currently in beta. The interface might change before it becomes stable. We encourage you to leave feedback on [GitHub](https://github.com/hey-api/openapi-ts/issues). +::: ### About [MSW](https://mswjs.io) is an API mocking library that allows you to write client-agnostic mocks and reuse them across any frameworks, tools, and environments. -The MSW plugin for Hey API generates type-safe mock handler factories from your OpenAPI spec, removing the tedious work of defining mock endpoints and ensuring your mocks stay in sync with your API. +The MSW plugin for Hey API generates type-safe mock handler factories from your OpenAPI spec, fully compatible with SDKs, transformers, and all core features. + +### Collaborators + + ## Features -- type-safe mock handlers generated from your OpenAPI spec +- MSW v2 support - seamless integration with `@hey-api/openapi-ts` ecosystem -- support for static response values or custom MSW resolver functions -- Helper to generate handlers for every operation at once -- typed path parameters and request bodies +- type-safe mock handlers - minimal learning curve thanks to extending the underlying technology ## Installation -::: warning -MSW plugin requires `msw@^2` as a peer dependency. Make sure to install it in your project. -::: - In your [configuration](/openapi-ts/get-started), add `msw` to your plugins and you'll be ready to generate MSW artifacts. :tada: ```js export default { - // ...other options + input: 'hey-api/backend', // sign up at app.heyapi.dev + output: 'src/client', plugins: [ // ...other plugins 'msw', // [!code ++] @@ -43,7 +53,7 @@ export default { ## Output -The MSW plugin will generate a `msw.gen.ts` file containing the following artifacts. +The MSW plugin will generate the following artifacts, depending on the input specification. ### Handler Exports diff --git a/examples/openapi-ts-angular-common/package.json b/examples/openapi-ts-angular-common/package.json index c695a4546c..2b206e2652 100644 --- a/examples/openapi-ts-angular-common/package.json +++ b/examples/openapi-ts-angular-common/package.json @@ -38,7 +38,7 @@ "@types/node": "24.10.10", "@typescript-eslint/eslint-plugin": "8.29.1", "@typescript-eslint/parser": "8.29.1", - "eslint": "9.17.0", + "eslint": "9.39.2", "jasmine-core": "5.6.0", "karma": "6.4.4", "karma-chrome-launcher": "3.2.0", diff --git a/examples/openapi-ts-angular/package.json b/examples/openapi-ts-angular/package.json index c614e68230..c87d05dbb7 100644 --- a/examples/openapi-ts-angular/package.json +++ b/examples/openapi-ts-angular/package.json @@ -38,7 +38,7 @@ "@types/node": "24.10.10", "@typescript-eslint/eslint-plugin": "8.29.1", "@typescript-eslint/parser": "8.29.1", - "eslint": "9.17.0", + "eslint": "9.39.2", "jasmine-core": "5.6.0", "karma": "6.4.4", "karma-chrome-launcher": "3.2.0", diff --git a/examples/openapi-ts-axios/package.json b/examples/openapi-ts-axios/package.json index c10ea7f707..a016181b15 100644 --- a/examples/openapi-ts-axios/package.json +++ b/examples/openapi-ts-axios/package.json @@ -27,10 +27,10 @@ "@typescript-eslint/parser": "8.29.1", "@vitejs/plugin-react": "4.4.0-beta.1", "autoprefixer": "10.4.19", - "eslint": "9.17.0", + "eslint": "9.39.2", "eslint-plugin-react-hooks": "5.2.0", "eslint-plugin-react-refresh": "0.4.7", - "oxfmt": "0.27.0", + "oxfmt": "0.41.0", "postcss": "8.4.41", "tailwindcss": "3.4.9", "typescript": "5.9.3", diff --git a/examples/openapi-ts-fastify/package.json b/examples/openapi-ts-fastify/package.json index 8f16dc7140..6f83ecbf71 100644 --- a/examples/openapi-ts-fastify/package.json +++ b/examples/openapi-ts-fastify/package.json @@ -14,10 +14,10 @@ }, "devDependencies": { "@hey-api/openapi-ts": "workspace:*", - "eslint": "9.17.0", - "oxfmt": "0.27.0", + "eslint": "9.39.2", + "oxfmt": "0.41.0", "typescript": "5.9.3", "vite": "7.3.1", - "vitest": "4.0.18" + "vitest": "4.1.0" } } diff --git a/examples/openapi-ts-fetch/package.json b/examples/openapi-ts-fetch/package.json index b95dacc250..77d21dc992 100644 --- a/examples/openapi-ts-fetch/package.json +++ b/examples/openapi-ts-fetch/package.json @@ -27,15 +27,15 @@ "@typescript-eslint/parser": "8.29.1", "@vitejs/plugin-react": "4.4.0-beta.1", "autoprefixer": "10.4.19", - "eslint": "9.17.0", + "eslint": "9.39.2", "eslint-plugin-react-hooks": "5.2.0", "eslint-plugin-react-refresh": "0.4.7", "msw": "2.10.2", - "oxfmt": "0.27.0", + "oxfmt": "0.41.0", "postcss": "8.4.41", "tailwindcss": "3.4.9", "typescript": "5.9.3", "vite": "7.3.1", - "vitest": "4.0.18" + "vitest": "4.1.0" } } diff --git a/examples/openapi-ts-ky/package.json b/examples/openapi-ts-ky/package.json index 49bf073a14..eaad113822 100644 --- a/examples/openapi-ts-ky/package.json +++ b/examples/openapi-ts-ky/package.json @@ -27,10 +27,10 @@ "@typescript-eslint/parser": "8.29.1", "@vitejs/plugin-react": "4.4.0-beta.1", "autoprefixer": "10.4.19", - "eslint": "9.17.0", + "eslint": "9.39.2", "eslint-plugin-react-hooks": "5.2.0", "eslint-plugin-react-refresh": "0.4.7", - "oxfmt": "0.27.0", + "oxfmt": "0.41.0", "postcss": "8.4.41", "tailwindcss": "3.4.9", "typescript": "5.9.3", diff --git a/examples/openapi-ts-nestjs/package.json b/examples/openapi-ts-nestjs/package.json index 4b55dbf7db..fe6d3e693c 100644 --- a/examples/openapi-ts-nestjs/package.json +++ b/examples/openapi-ts-nestjs/package.json @@ -18,14 +18,14 @@ }, "devDependencies": { "@hey-api/openapi-ts": "workspace:*", - "@nestjs/testing": "^11.0.1", - "@swc-node/register": "^1.10.10", - "@swc/core": "^1.11.29", - "eslint": "^9.18.0", - "oxfmt": "^0.27.0", - "typescript": "^5.9.3", - "unplugin-swc": "^1.5.5", - "vite": "^7.3.1", - "vitest": "^4.0.18" + "@nestjs/testing": "11.0.1", + "@swc-node/register": "1.10.10", + "@swc/core": "1.11.29", + "eslint": "9.39.2", + "oxfmt": "0.41.0", + "typescript": "5.9.3", + "unplugin-swc": "1.5.5", + "vite": "7.3.1", + "vitest": "4.1.0" } } diff --git a/examples/openapi-ts-next/package.json b/examples/openapi-ts-next/package.json index 8f512ada35..d21d1a6b35 100644 --- a/examples/openapi-ts-next/package.json +++ b/examples/openapi-ts-next/package.json @@ -19,7 +19,7 @@ "@types/node": "24.10.10", "@types/react": "19.0.1", "@types/react-dom": "19.0.1", - "eslint": "9.17.0", + "eslint": "9.39.2", "eslint-config-next": "15.1.6", "postcss": "8.4.41", "tailwindcss": "3.4.9", diff --git a/examples/openapi-ts-ofetch/package.json b/examples/openapi-ts-ofetch/package.json index d0e3a19e27..1d0495f4fc 100644 --- a/examples/openapi-ts-ofetch/package.json +++ b/examples/openapi-ts-ofetch/package.json @@ -27,17 +27,17 @@ "@vue/test-utils": "2.4.6", "@vue/tsconfig": "0.8.1", "autoprefixer": "10.4.20", - "eslint": "9.17.0", + "eslint": "9.39.2", "eslint-plugin-vue": "9.32.0", "jsdom": "28.0.0", "npm-run-all2": "6.2.0", - "oxfmt": "0.27.0", + "oxfmt": "0.41.0", "postcss": "8.4.41", "tailwindcss": "3.4.9", "typescript": "5.9.3", "vite": "7.3.1", "vite-plugin-vue-devtools": "8.0.2", - "vitest": "4.0.18", + "vitest": "4.1.0", "vue-tsc": "3.2.4" } } diff --git a/examples/openapi-ts-openai/package.json b/examples/openapi-ts-openai/package.json index 9656b2a969..d1cfd9d40c 100644 --- a/examples/openapi-ts-openai/package.json +++ b/examples/openapi-ts-openai/package.json @@ -27,10 +27,10 @@ "@typescript-eslint/parser": "8.29.1", "@vitejs/plugin-react": "4.4.0-beta.1", "autoprefixer": "10.4.19", - "eslint": "9.17.0", + "eslint": "9.39.2", "eslint-plugin-react-hooks": "5.2.0", "eslint-plugin-react-refresh": "0.4.7", - "oxfmt": "0.27.0", + "oxfmt": "0.41.0", "postcss": "8.4.41", "tailwindcss": "3.4.9", "typescript": "5.9.3", diff --git a/examples/openapi-ts-pinia-colada/package.json b/examples/openapi-ts-pinia-colada/package.json index 3490230793..3fce29be9c 100644 --- a/examples/openapi-ts-pinia-colada/package.json +++ b/examples/openapi-ts-pinia-colada/package.json @@ -33,17 +33,17 @@ "@vue/test-utils": "2.4.6", "@vue/tsconfig": "0.8.1", "autoprefixer": "10.4.20", - "eslint": "9.17.0", + "eslint": "9.39.2", "eslint-plugin-vue": "9.32.0", "jsdom": "28.0.0", "npm-run-all2": "6.2.0", - "oxfmt": "0.27.0", + "oxfmt": "0.41.0", "postcss": "8.4.41", "tailwindcss": "3.4.9", "typescript": "5.9.3", "vite": "7.3.1", "vite-plugin-vue-devtools": "8.0.2", - "vitest": "4.0.18", + "vitest": "4.1.0", "vue-tsc": "3.2.4" } } diff --git a/examples/openapi-ts-tanstack-react-query/package.json b/examples/openapi-ts-tanstack-react-query/package.json index efa4ce1cf2..aef2e49db4 100644 --- a/examples/openapi-ts-tanstack-react-query/package.json +++ b/examples/openapi-ts-tanstack-react-query/package.json @@ -28,10 +28,10 @@ "@typescript-eslint/parser": "8.29.1", "@vitejs/plugin-react": "4.4.0-beta.1", "autoprefixer": "10.4.19", - "eslint": "9.17.0", + "eslint": "9.39.2", "eslint-plugin-react-hooks": "5.2.0", "eslint-plugin-react-refresh": "0.4.7", - "oxfmt": "0.27.0", + "oxfmt": "0.41.0", "postcss": "8.4.41", "tailwindcss": "3.4.9", "typescript": "5.9.3", diff --git a/examples/openapi-ts-tanstack-svelte-query/package.json b/examples/openapi-ts-tanstack-svelte-query/package.json index c66335bb65..4137e91490 100644 --- a/examples/openapi-ts-tanstack-svelte-query/package.json +++ b/examples/openapi-ts-tanstack-svelte-query/package.json @@ -26,15 +26,15 @@ "@sveltejs/kit": "2.17.1", "@sveltejs/vite-plugin-svelte": "5.0.3", "@types/eslint": "9.6.0", - "eslint": "9.17.0", + "eslint": "9.39.2", "eslint-plugin-svelte": "2.36.0", "globals": "15.14.0", - "oxfmt": "0.27.0", + "oxfmt": "0.41.0", "svelte": "5.19.9", "svelte-check": "4.1.4", "typescript": "5.9.3", "typescript-eslint": "8.29.1", "vite": "7.3.1", - "vitest": "4.0.18" + "vitest": "4.1.0" } } diff --git a/examples/openapi-ts-tanstack-vue-query/package.json b/examples/openapi-ts-tanstack-vue-query/package.json index 681ff689ca..80e81b86c6 100644 --- a/examples/openapi-ts-tanstack-vue-query/package.json +++ b/examples/openapi-ts-tanstack-vue-query/package.json @@ -33,17 +33,17 @@ "@vue/test-utils": "2.4.6", "@vue/tsconfig": "0.8.1", "autoprefixer": "10.4.20", - "eslint": "9.17.0", + "eslint": "9.39.2", "eslint-plugin-vue": "9.32.0", "jsdom": "28.0.0", "npm-run-all2": "6.2.0", - "oxfmt": "0.27.0", + "oxfmt": "0.41.0", "postcss": "8.4.41", "tailwindcss": "3.4.9", "typescript": "5.9.3", "vite": "7.3.1", "vite-plugin-vue-devtools": "8.0.2", - "vitest": "4.0.18", + "vitest": "4.1.0", "vue-tsc": "3.2.4" } } diff --git a/packages/codegen-core/package.json b/packages/codegen-core/package.json index d6985041d1..73f80d1d12 100644 --- a/packages/codegen-core/package.json +++ b/packages/codegen-core/package.json @@ -53,7 +53,7 @@ "color-support": "1.1.3" }, "devDependencies": { - "eslint": "9.39.1", + "eslint": "9.39.2", "typescript": "5.9.3" }, "engines": { diff --git a/packages/openapi-python/package.json b/packages/openapi-python/package.json index 87b8faeb3d..b554dc8aa7 100644 --- a/packages/openapi-python/package.json +++ b/packages/openapi-python/package.json @@ -70,7 +70,7 @@ "commander": "14.0.3" }, "devDependencies": { - "eslint": "9.39.1", + "eslint": "9.39.2", "typescript": "5.9.3", "yaml": "2.8.2" }, diff --git a/packages/openapi-ts-tests/main/package.json b/packages/openapi-ts-tests/main/package.json index 824f42d5bb..571364e9e0 100644 --- a/packages/openapi-ts-tests/main/package.json +++ b/packages/openapi-ts-tests/main/package.json @@ -33,7 +33,7 @@ "arktype": "2.1.29", "axios": "1.13.4", "cross-spawn": "7.0.6", - "eslint": "9.39.1", + "eslint": "9.39.2", "fastify": "5.7.4", "ky": "1.14.3", "msw": "2.10.2", diff --git a/packages/openapi-ts/README.md b/packages/openapi-ts/README.md index 27d4c3a7bf..e65948147e 100644 --- a/packages/openapi-ts/README.md +++ b/packages/openapi-ts/README.md @@ -343,6 +343,7 @@ These plugins help reduce boilerplate associated with third-party dependencies. - [`@tanstack/svelte-query`](https://heyapi.dev/openapi-ts/plugins/tanstack-query) - [`@tanstack/vue-query`](https://heyapi.dev/openapi-ts/plugins/tanstack-query) - [`fastify`](https://heyapi.dev/openapi-ts/plugins/fastify) +- [`msw`](https://heyapi.dev/openapi-ts/plugins/msw) - [`orpc`](https://heyapi.dev/openapi-ts/plugins/orpc) - [`nestjs`](https://heyapi.dev/openapi-ts/plugins/nest) - [`valibot`](https://heyapi.dev/openapi-ts/plugins/valibot) @@ -363,7 +364,6 @@ The following plugins are roadmap proposals and are not started yet. You can hel - [Hono](https://heyapi.dev/openapi-ts/plugins/hono) - [Joi](https://heyapi.dev/openapi-ts/plugins/joi) - [Koa](https://heyapi.dev/openapi-ts/plugins/koa) -- [MSW](https://heyapi.dev/openapi-ts/plugins/msw) - [Nock](https://heyapi.dev/openapi-ts/plugins/nock) - [Superstruct](https://heyapi.dev/openapi-ts/plugins/superstruct) - [Supertest](https://heyapi.dev/openapi-ts/plugins/supertest) diff --git a/packages/openapi-ts/package.json b/packages/openapi-ts/package.json index b727bd9271..e103746811 100644 --- a/packages/openapi-ts/package.json +++ b/packages/openapi-ts/package.json @@ -88,9 +88,8 @@ "@angular/platform-browser-dynamic": "21.1.2", "@angular/router": "21.1.2", "axios": "1.13.4", - "eslint": "9.39.1", + "eslint": "9.39.2", "ky": "1.14.3", - "msw": "2.10.2", "nuxt": "3.14.1592", "ofetch": "1.5.1", "rxjs": "7.8.2", diff --git a/packages/openapi-ts/src/plugins/@faker-js/faker/types.ts b/packages/openapi-ts/src/plugins/@faker-js/faker/types.ts index 7b2feacc67..f317f3a3de 100644 --- a/packages/openapi-ts/src/plugins/@faker-js/faker/types.ts +++ b/packages/openapi-ts/src/plugins/@faker-js/faker/types.ts @@ -61,22 +61,13 @@ export type Config = Plugin.Name<'@faker-js/faker'> & Plugin.Hooks & Plugin.Exports & { // Resolvers & { - /** - * Casing convention for generated names. - */ + /** Casing convention for generated names. */ case: Casing; - /** - * Configuration for reusable schema definitions. - */ + /** Configuration for reusable schema definitions. */ definitions: NamingOptions & FeatureToggle; - /** - * Faker locale for generated data. - */ + /** Faker locale for generated data. */ locale: string; - /** - * Seed for deterministic output. When set, Faker will produce - * the same values across runs. - */ + /** Seed for deterministic output. */ seed?: number; }; diff --git a/packages/openapi-ts/src/plugins/msw/types.ts b/packages/openapi-ts/src/plugins/msw/types.ts index 9877951860..323738064c 100644 --- a/packages/openapi-ts/src/plugins/msw/types.ts +++ b/packages/openapi-ts/src/plugins/msw/types.ts @@ -4,8 +4,8 @@ export type UserConfig = Plugin.Name<'msw'> & Plugin.Hooks & Plugin.UserExports & { /** - * Sources for inferring default parameter values in generated handler - * factories. Order determines priority (earlier entries take precedence). + * Sources for default parameter values in handler factories. Order determines + * priority (earlier entries take precedence). * * - `'example'` - use OpenAPI example values * @@ -14,6 +14,11 @@ export type UserConfig = Plugin.Name<'msw'> & valueSources?: ReadonlyArray<'example'>; }; -export type Config = UserConfig; +export type Config = Plugin.Name<'msw'> & + Plugin.Hooks & + Plugin.Exports & { + /** Sources for default parameter values in handler factories. */ + valueSources: ReadonlyArray<'example'>; + }; export type MswPlugin = DefinePlugin; diff --git a/packages/shared/package.json b/packages/shared/package.json index e611260368..410a9a12cd 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -53,7 +53,7 @@ "@types/bun": "1.3.8", "@types/cross-spawn": "6.0.6", "@types/semver": "7.7.1", - "eslint": "9.39.1", + "eslint": "9.39.2", "typescript": "5.9.3", "yaml": "2.8.2" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3be467aa09..2d1036df8b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -257,13 +257,13 @@ importers: version: 24.10.10 '@typescript-eslint/eslint-plugin': specifier: 8.29.1 - version: 8.29.1(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) + version: 8.29.1(@typescript-eslint/parser@8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: 8.29.1 - version: 8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) + version: 8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint: - specifier: 9.17.0 - version: 9.17.0(jiti@2.6.1) + specifier: 9.39.2 + version: 9.39.2(jiti@2.6.1) jasmine-core: specifier: 5.6.0 version: 5.6.0 @@ -351,13 +351,13 @@ importers: version: 24.10.10 '@typescript-eslint/eslint-plugin': specifier: 8.29.1 - version: 8.29.1(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) + version: 8.29.1(@typescript-eslint/parser@8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: 8.29.1 - version: 8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) + version: 8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint: - specifier: 9.17.0 - version: 9.17.0(jiti@2.6.1) + specifier: 9.39.2 + version: 9.39.2(jiti@2.6.1) jasmine-core: specifier: 5.6.0 version: 5.6.0 @@ -412,10 +412,10 @@ importers: version: 19.0.1 '@typescript-eslint/eslint-plugin': specifier: 8.29.1 - version: 8.29.1(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) + version: 8.29.1(@typescript-eslint/parser@8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: 8.29.1 - version: 8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) + version: 8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@vitejs/plugin-react': specifier: 4.4.0-beta.1 version: 4.4.0-beta.1(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) @@ -423,17 +423,17 @@ importers: specifier: 10.4.19 version: 10.4.19(postcss@8.4.41) eslint: - specifier: 9.17.0 - version: 9.17.0(jiti@2.6.1) + specifier: 9.39.2 + version: 9.39.2(jiti@2.6.1) eslint-plugin-react-hooks: specifier: 5.2.0 - version: 5.2.0(eslint@9.17.0(jiti@2.6.1)) + version: 5.2.0(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-react-refresh: specifier: 0.4.7 - version: 0.4.7(eslint@9.17.0(jiti@2.6.1)) + version: 0.4.7(eslint@9.39.2(jiti@2.6.1)) oxfmt: - specifier: 0.27.0 - version: 0.27.0 + specifier: 0.41.0 + version: 0.41.0 postcss: specifier: 8.4.41 version: 8.4.41 @@ -460,11 +460,11 @@ importers: specifier: workspace:* version: link:../../packages/openapi-ts eslint: - specifier: 9.17.0 - version: 9.17.0(jiti@2.6.1) + specifier: 9.39.2 + version: 9.39.2(jiti@2.6.1) oxfmt: - specifier: 0.27.0 - version: 0.27.0 + specifier: 0.41.0 + version: 0.41.0 typescript: specifier: 5.9.3 version: 5.9.3 @@ -472,8 +472,8 @@ importers: specifier: 7.3.1 version: 7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) vitest: - specifier: 4.0.18 - version: 4.0.18(@types/node@25.2.1)(jiti@2.6.1)(jsdom@28.0.0)(less@4.4.2)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + specifier: 4.1.0 + version: 4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) examples/openapi-ts-fetch: dependencies: @@ -504,10 +504,10 @@ importers: version: 19.0.1 '@typescript-eslint/eslint-plugin': specifier: 8.29.1 - version: 8.29.1(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) + version: 8.29.1(@typescript-eslint/parser@8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: 8.29.1 - version: 8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) + version: 8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@vitejs/plugin-react': specifier: 4.4.0-beta.1 version: 4.4.0-beta.1(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) @@ -515,20 +515,20 @@ importers: specifier: 10.4.19 version: 10.4.19(postcss@8.4.41) eslint: - specifier: 9.17.0 - version: 9.17.0(jiti@2.6.1) + specifier: 9.39.2 + version: 9.39.2(jiti@2.6.1) eslint-plugin-react-hooks: specifier: 5.2.0 - version: 5.2.0(eslint@9.17.0(jiti@2.6.1)) + version: 5.2.0(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-react-refresh: specifier: 0.4.7 - version: 0.4.7(eslint@9.17.0(jiti@2.6.1)) + version: 0.4.7(eslint@9.39.2(jiti@2.6.1)) msw: specifier: 2.10.2 version: 2.10.2(@types/node@25.2.1)(typescript@5.9.3) oxfmt: - specifier: 0.27.0 - version: 0.27.0 + specifier: 0.41.0 + version: 0.41.0 postcss: specifier: 8.4.41 version: 8.4.41 @@ -542,8 +542,8 @@ importers: specifier: 7.3.1 version: 7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) vitest: - specifier: 4.0.18 - version: 4.0.18(@types/node@25.2.1)(jiti@2.6.1)(jsdom@28.0.0)(less@4.4.2)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + specifier: 4.1.0 + version: 4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) examples/openapi-ts-ky: dependencies: @@ -577,10 +577,10 @@ importers: version: 19.0.1 '@typescript-eslint/eslint-plugin': specifier: 8.29.1 - version: 8.29.1(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) + version: 8.29.1(@typescript-eslint/parser@8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: 8.29.1 - version: 8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) + version: 8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@vitejs/plugin-react': specifier: 4.4.0-beta.1 version: 4.4.0-beta.1(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) @@ -588,17 +588,17 @@ importers: specifier: 10.4.19 version: 10.4.19(postcss@8.4.41) eslint: - specifier: 9.17.0 - version: 9.17.0(jiti@2.6.1) + specifier: 9.39.2 + version: 9.39.2(jiti@2.6.1) eslint-plugin-react-hooks: specifier: 5.2.0 - version: 5.2.0(eslint@9.17.0(jiti@2.6.1)) + version: 5.2.0(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-react-refresh: specifier: 0.4.7 - version: 0.4.7(eslint@9.17.0(jiti@2.6.1)) + version: 0.4.7(eslint@9.39.2(jiti@2.6.1)) oxfmt: - specifier: 0.27.0 - version: 0.27.0 + specifier: 0.41.0 + version: 0.41.0 postcss: specifier: 8.4.41 version: 8.4.41 @@ -634,31 +634,31 @@ importers: specifier: workspace:* version: link:../../packages/openapi-ts '@nestjs/testing': - specifier: ^11.0.1 - version: 11.1.16(@nestjs/common@11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16)(@nestjs/platform-express@11.1.16) + specifier: 11.0.1 + version: 11.0.1(@nestjs/common@11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16)(@nestjs/platform-express@11.1.16) '@swc-node/register': - specifier: ^1.10.10 - version: 1.11.1(@swc/core@1.15.18)(@swc/types@0.1.25)(typescript@5.9.3) + specifier: 1.10.10 + version: 1.10.10(@swc/core@1.11.29)(@swc/types@0.1.25)(typescript@5.9.3) '@swc/core': - specifier: ^1.11.29 - version: 1.15.18 + specifier: 1.11.29 + version: 1.11.29 eslint: - specifier: ^9.18.0 + specifier: 9.39.2 version: 9.39.2(jiti@2.6.1) oxfmt: - specifier: ^0.27.0 - version: 0.27.0 + specifier: 0.41.0 + version: 0.41.0 typescript: - specifier: ^5.9.3 + specifier: 5.9.3 version: 5.9.3 unplugin-swc: - specifier: ^1.5.5 - version: 1.5.9(@swc/core@1.15.18)(rollup@4.56.0) + specifier: 1.5.5 + version: 1.5.5(@swc/core@1.11.29)(rollup@4.56.0) vite: - specifier: ^7.3.1 + specifier: 7.3.1 version: 7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) vitest: - specifier: ^4.0.18 + specifier: 4.1.0 version: 4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) examples/openapi-ts-next: @@ -686,11 +686,11 @@ importers: specifier: 19.0.1 version: 19.0.1 eslint: - specifier: 9.17.0 - version: 9.17.0(jiti@2.6.1) + specifier: 9.39.2 + version: 9.39.2(jiti@2.6.1) eslint-config-next: specifier: 15.1.6 - version: 15.1.6(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) + version: 15.1.6(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) postcss: specifier: 8.4.41 version: 8.4.41 @@ -755,7 +755,7 @@ importers: version: 5.1.4(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.13(typescript@5.9.3)) '@vue/eslint-config-typescript': specifier: 14.6.0 - version: 14.6.0(eslint-plugin-vue@9.32.0(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) + version: 14.6.0(eslint-plugin-vue@9.32.0(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@vue/test-utils': specifier: 2.4.6 version: 2.4.6 @@ -766,11 +766,11 @@ importers: specifier: 10.4.20 version: 10.4.20(postcss@8.4.41) eslint: - specifier: 9.17.0 - version: 9.17.0(jiti@2.6.1) + specifier: 9.39.2 + version: 9.39.2(jiti@2.6.1) eslint-plugin-vue: specifier: 9.32.0 - version: 9.32.0(eslint@9.17.0(jiti@2.6.1)) + version: 9.32.0(eslint@9.39.2(jiti@2.6.1)) jsdom: specifier: 28.0.0 version: 28.0.0 @@ -778,8 +778,8 @@ importers: specifier: 6.2.0 version: 6.2.0 oxfmt: - specifier: 0.27.0 - version: 0.27.0 + specifier: 0.41.0 + version: 0.41.0 postcss: specifier: 8.4.41 version: 8.4.41 @@ -796,8 +796,8 @@ importers: specifier: 8.0.2 version: 8.0.2(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.13(typescript@5.9.3)) vitest: - specifier: 4.0.18 - version: 4.0.18(@types/node@24.10.10)(jiti@2.6.1)(jsdom@28.0.0)(less@4.4.2)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + specifier: 4.1.0 + version: 4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) vue-tsc: specifier: 3.2.4 version: 3.2.4(typescript@5.9.3) @@ -834,10 +834,10 @@ importers: version: 19.0.1 '@typescript-eslint/eslint-plugin': specifier: 8.29.1 - version: 8.29.1(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) + version: 8.29.1(@typescript-eslint/parser@8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: 8.29.1 - version: 8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) + version: 8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@vitejs/plugin-react': specifier: 4.4.0-beta.1 version: 4.4.0-beta.1(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) @@ -845,17 +845,17 @@ importers: specifier: 10.4.19 version: 10.4.19(postcss@8.4.41) eslint: - specifier: 9.17.0 - version: 9.17.0(jiti@2.6.1) + specifier: 9.39.2 + version: 9.39.2(jiti@2.6.1) eslint-plugin-react-hooks: specifier: 5.2.0 - version: 5.2.0(eslint@9.17.0(jiti@2.6.1)) + version: 5.2.0(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-react-refresh: specifier: 0.4.7 - version: 0.4.7(eslint@9.17.0(jiti@2.6.1)) + version: 0.4.7(eslint@9.39.2(jiti@2.6.1)) oxfmt: - specifier: 0.27.0 - version: 0.27.0 + specifier: 0.41.0 + version: 0.41.0 postcss: specifier: 8.4.41 version: 8.4.41 @@ -910,7 +910,7 @@ importers: version: 5.1.4(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.13(typescript@5.9.3)) '@vue/eslint-config-typescript': specifier: 14.6.0 - version: 14.6.0(eslint-plugin-vue@9.32.0(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) + version: 14.6.0(eslint-plugin-vue@9.32.0(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@vue/test-utils': specifier: 2.4.6 version: 2.4.6 @@ -921,11 +921,11 @@ importers: specifier: 10.4.20 version: 10.4.20(postcss@8.4.41) eslint: - specifier: 9.17.0 - version: 9.17.0(jiti@2.6.1) + specifier: 9.39.2 + version: 9.39.2(jiti@2.6.1) eslint-plugin-vue: specifier: 9.32.0 - version: 9.32.0(eslint@9.17.0(jiti@2.6.1)) + version: 9.32.0(eslint@9.39.2(jiti@2.6.1)) jsdom: specifier: 28.0.0 version: 28.0.0 @@ -933,8 +933,8 @@ importers: specifier: 6.2.0 version: 6.2.0 oxfmt: - specifier: 0.27.0 - version: 0.27.0 + specifier: 0.41.0 + version: 0.41.0 postcss: specifier: 8.4.41 version: 8.4.41 @@ -951,8 +951,8 @@ importers: specifier: 8.0.2 version: 8.0.2(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.13(typescript@5.9.3)) vitest: - specifier: 4.0.18 - version: 4.0.18(@types/node@24.10.10)(jiti@2.6.1)(jsdom@28.0.0)(less@4.4.2)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + specifier: 4.1.0 + version: 4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) vue-tsc: specifier: 3.2.4 version: 3.2.4(typescript@5.9.3) @@ -1074,10 +1074,10 @@ importers: version: 19.0.1 '@typescript-eslint/eslint-plugin': specifier: 8.29.1 - version: 8.29.1(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) + version: 8.29.1(@typescript-eslint/parser@8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: 8.29.1 - version: 8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) + version: 8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@vitejs/plugin-react': specifier: 4.4.0-beta.1 version: 4.4.0-beta.1(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) @@ -1085,17 +1085,17 @@ importers: specifier: 10.4.19 version: 10.4.19(postcss@8.4.41) eslint: - specifier: 9.17.0 - version: 9.17.0(jiti@2.6.1) + specifier: 9.39.2 + version: 9.39.2(jiti@2.6.1) eslint-plugin-react-hooks: specifier: 5.2.0 - version: 5.2.0(eslint@9.17.0(jiti@2.6.1)) + version: 5.2.0(eslint@9.39.2(jiti@2.6.1)) eslint-plugin-react-refresh: specifier: 0.4.7 - version: 0.4.7(eslint@9.17.0(jiti@2.6.1)) + version: 0.4.7(eslint@9.39.2(jiti@2.6.1)) oxfmt: - specifier: 0.27.0 - version: 0.27.0 + specifier: 0.41.0 + version: 0.41.0 postcss: specifier: 8.4.41 version: 8.4.41 @@ -1137,17 +1137,17 @@ importers: specifier: 9.6.0 version: 9.6.0 eslint: - specifier: 9.17.0 - version: 9.17.0(jiti@2.6.1) + specifier: 9.39.2 + version: 9.39.2(jiti@2.6.1) eslint-plugin-svelte: specifier: 2.36.0 - version: 2.36.0(eslint@9.17.0(jiti@2.6.1))(svelte@5.19.9)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.2.1)(typescript@5.9.3)) + version: 2.36.0(eslint@9.39.2(jiti@2.6.1))(svelte@5.19.9)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.2.1)(typescript@5.9.3)) globals: specifier: 15.14.0 version: 15.14.0 oxfmt: - specifier: 0.27.0 - version: 0.27.0 + specifier: 0.41.0 + version: 0.41.0 svelte: specifier: 5.19.9 version: 5.19.9 @@ -1159,13 +1159,13 @@ importers: version: 5.9.3 typescript-eslint: specifier: 8.29.1 - version: 8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) + version: 8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) vite: specifier: 7.3.1 version: 7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) vitest: - specifier: 4.0.18 - version: 4.0.18(@types/node@25.2.1)(jiti@2.6.1)(jsdom@28.0.0)(less@4.4.2)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + specifier: 4.1.0 + version: 4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) examples/openapi-ts-tanstack-vue-query: dependencies: @@ -1208,7 +1208,7 @@ importers: version: 5.1.4(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.13(typescript@5.9.3)) '@vue/eslint-config-typescript': specifier: 14.6.0 - version: 14.6.0(eslint-plugin-vue@9.32.0(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) + version: 14.6.0(eslint-plugin-vue@9.32.0(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@vue/test-utils': specifier: 2.4.6 version: 2.4.6 @@ -1219,11 +1219,11 @@ importers: specifier: 10.4.20 version: 10.4.20(postcss@8.4.41) eslint: - specifier: 9.17.0 - version: 9.17.0(jiti@2.6.1) + specifier: 9.39.2 + version: 9.39.2(jiti@2.6.1) eslint-plugin-vue: specifier: 9.32.0 - version: 9.32.0(eslint@9.17.0(jiti@2.6.1)) + version: 9.32.0(eslint@9.39.2(jiti@2.6.1)) jsdom: specifier: 28.0.0 version: 28.0.0 @@ -1231,8 +1231,8 @@ importers: specifier: 6.2.0 version: 6.2.0 oxfmt: - specifier: 0.27.0 - version: 0.27.0 + specifier: 0.41.0 + version: 0.41.0 postcss: specifier: 8.4.41 version: 8.4.41 @@ -1249,8 +1249,8 @@ importers: specifier: 8.0.2 version: 8.0.2(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.13(typescript@5.9.3)) vitest: - specifier: 4.0.18 - version: 4.0.18(@types/node@24.10.10)(jiti@2.6.1)(jsdom@28.0.0)(less@4.4.2)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + specifier: 4.1.0 + version: 4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) vue-tsc: specifier: 3.2.4 version: 3.2.4(typescript@5.9.3) @@ -1271,8 +1271,8 @@ importers: version: 1.1.3 devDependencies: eslint: - specifier: 9.39.1 - version: 9.39.1(jiti@2.6.1) + specifier: 9.39.2 + version: 9.39.2(jiti@2.6.1) typescript: specifier: 5.9.3 version: 5.9.3 @@ -1370,8 +1370,8 @@ importers: version: 14.0.3 devDependencies: eslint: - specifier: 9.39.1 - version: 9.39.1(jiti@2.6.1) + specifier: 9.39.2 + version: 9.39.2(jiti@2.6.1) typescript: specifier: 5.9.3 version: 5.9.3 @@ -1452,17 +1452,14 @@ importers: specifier: 1.13.4 version: 1.13.4 eslint: - specifier: 9.39.1 - version: 9.39.1(jiti@2.6.1) + specifier: 9.39.2 + version: 9.39.2(jiti@2.6.1) ky: specifier: 1.14.3 version: 1.14.3 - msw: - specifier: 2.10.2 - version: 2.10.2(@types/node@25.2.1)(typescript@5.9.3) nuxt: specifier: 3.14.1592 - version: 3.14.1592(@netlify/blobs@9.1.2)(@parcel/watcher@2.5.1)(@types/node@25.2.1)(db0@0.3.4)(encoding@0.1.13)(eslint@9.39.1(jiti@2.6.1))(ioredis@5.9.2)(less@4.4.2)(magicast@0.3.5)(optionator@0.9.4)(rolldown@1.0.0-rc.9)(rollup@4.56.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue-tsc@3.2.4(typescript@5.9.3)) + version: 3.14.1592(@netlify/blobs@9.1.2)(@parcel/watcher@2.5.1)(@types/node@25.2.1)(db0@0.3.4)(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.9.2)(less@4.4.2)(magicast@0.3.5)(optionator@0.9.4)(rolldown@1.0.0-rc.9)(rollup@4.56.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue-tsc@3.2.4(typescript@5.9.3)) ofetch: specifier: 1.5.1 version: 1.5.1 @@ -1563,8 +1560,8 @@ importers: specifier: 7.0.6 version: 7.0.6 eslint: - specifier: 9.39.1 - version: 9.39.1(jiti@2.6.1) + specifier: 9.39.2 + version: 9.39.2(jiti@2.6.1) fastify: specifier: 5.7.4 version: 5.7.4 @@ -1579,7 +1576,7 @@ importers: version: 3.3.2 nuxt: specifier: 3.14.1592 - version: 3.14.1592(@netlify/blobs@9.1.2)(@parcel/watcher@2.5.1)(@types/node@25.2.1)(db0@0.3.4)(encoding@0.1.13)(eslint@9.39.1(jiti@2.6.1))(ioredis@5.9.2)(less@4.4.2)(magicast@0.3.5)(optionator@0.9.4)(rolldown@1.0.0-rc.9)(rollup@4.56.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue-tsc@3.2.4(typescript@5.9.3)) + version: 3.14.1592(@netlify/blobs@9.1.2)(@parcel/watcher@2.5.1)(@types/node@25.2.1)(db0@0.3.4)(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.9.2)(less@4.4.2)(magicast@0.3.5)(optionator@0.9.4)(rolldown@1.0.0-rc.9)(rollup@4.56.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue-tsc@3.2.4(typescript@5.9.3)) ofetch: specifier: 1.5.1 version: 1.5.1 @@ -1708,8 +1705,8 @@ importers: specifier: 7.7.1 version: 7.7.1 eslint: - specifier: 9.39.1 - version: 9.39.1(jiti@2.6.1) + specifier: 9.39.2 + version: 9.39.2(jiti@2.6.1) typescript: specifier: 5.9.3 version: 5.9.3 @@ -3866,10 +3863,6 @@ packages: resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/config-array@0.19.2': - resolution: {integrity: sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/config-array@0.21.1': resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -3878,46 +3871,22 @@ packages: resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/core@0.13.0': - resolution: {integrity: sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/core@0.17.0': resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/core@0.9.1': - resolution: {integrity: sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/eslintrc@3.3.1': resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.17.0': - resolution: {integrity: sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/js@9.39.1': - resolution: {integrity: sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.39.2': resolution: {integrity: sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/object-schema@2.1.6': - resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/object-schema@2.1.7': resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/plugin-kit@0.2.8': - resolution: {integrity: sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/plugin-kit@0.4.1': resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4870,8 +4839,8 @@ packages: '@nestjs/common': ^11.0.0 '@nestjs/core': ^11.0.0 - '@nestjs/testing@11.1.16': - resolution: {integrity: sha512-E7/aUCxzeMSJV80L5GWGIuiMyR/1ncS7uOIetAImfbS4ATE1/h2GBafk0qpk+vjFtPIbtoh9BWDGICzUEU5jDA==} + '@nestjs/testing@11.0.1': + resolution: {integrity: sha512-s1hQAC46W/qp2JJqCeqhG/uT8IBtvgIoAHklUPl7sTYSJCs745q6X2+rrOPtAewVW8CuYNhQS7/0g94QR1IHXw==} peerDependencies: '@nestjs/common': ^11.0.0 '@nestjs/core': ^11.0.0 @@ -5501,21 +5470,41 @@ packages: cpu: [arm64] os: [darwin] + '@oxc-resolver/binding-darwin-arm64@5.3.0': + resolution: {integrity: sha512-hXem5ZAguS7IlSiHg/LK0tEfLj4eUo+9U6DaFwwBEGd0L0VIF9LmuiHydRyOrdnnmi9iAAFMAn/wl2cUoiuruA==} + cpu: [arm64] + os: [darwin] + '@oxc-resolver/binding-darwin-x64@11.19.1': resolution: {integrity: sha512-cV50vE5+uAgNcFa3QY1JOeKDSkM/9ReIcc/9wn4TavhW/itkDGrXhw9jaKnkQnGbjJ198Yh5nbX/Gr2mr4Z5jQ==} cpu: [x64] os: [darwin] + '@oxc-resolver/binding-darwin-x64@5.3.0': + resolution: {integrity: sha512-wgSwfsZkRbuYCIBLxeg1bYrtKnirAy+IJF0lwfz4z08clgdNBDbfGECJe/cd0csIZPpRcvPFe8317yf31sWhtA==} + cpu: [x64] + os: [darwin] + '@oxc-resolver/binding-freebsd-x64@11.19.1': resolution: {integrity: sha512-xZOQiYGFxtk48PBKff+Zwoym7ScPAIVp4c14lfLxizO2LTTTJe5sx9vQNGrBymrf/vatSPNMD4FgsaaRigPkqw==} cpu: [x64] os: [freebsd] + '@oxc-resolver/binding-freebsd-x64@5.3.0': + resolution: {integrity: sha512-kzeE2WHgcRMmWjB071RdwEV5Pwke4o0WWslCKoh8if1puvxIxfzu3o7g6P2+v77BP5qop4cri+uvLABSO0WZjg==} + cpu: [x64] + os: [freebsd] + '@oxc-resolver/binding-linux-arm-gnueabihf@11.19.1': resolution: {integrity: sha512-lXZYWAC6kaGe/ky2su94e9jN9t6M0/6c+GrSlCqL//XO1cxi5lpAhnJYdyrKfm0ZEr/c7RNyAx3P7FSBcBd5+A==} cpu: [arm] os: [linux] + '@oxc-resolver/binding-linux-arm-gnueabihf@5.3.0': + resolution: {integrity: sha512-I8np34yZP/XfIkZNDbw3rweqVgfjmHYpNX3xnJZWg+f4mgO9/UNWBwetSaqXeDZqvIch/aHak+q4HVrQhQKCqg==} + cpu: [arm] + os: [linux] + '@oxc-resolver/binding-linux-arm-musleabihf@11.19.1': resolution: {integrity: sha512-veG1kKsuK5+t2IsO9q0DErYVSw2azvCVvWHnfTOS73WE0STdLLB7Q1bB9WR+yHPQM76ASkFyRbogWo1GR1+WbQ==} cpu: [arm] @@ -5527,12 +5516,24 @@ packages: os: [linux] libc: [glibc] + '@oxc-resolver/binding-linux-arm64-gnu@5.3.0': + resolution: {integrity: sha512-u2ndfeEUrW898eXM+qPxIN8TvTPjI90NDQBRgaxxkOfNw3xaotloeiZGz5+Yzlfxgvxr9DY9FdYkqhUhSnGhOw==} + cpu: [arm64] + os: [linux] + libc: [glibc] + '@oxc-resolver/binding-linux-arm64-musl@11.19.1': resolution: {integrity: sha512-jvo2Pjs1c9KPxMuMPIeQsgu0mOJF9rEb3y3TdpsrqwxRM+AN6/nDDwv45n5ZrUnQMsdBy5gIabioMKnQfWo9ew==} cpu: [arm64] os: [linux] libc: [musl] + '@oxc-resolver/binding-linux-arm64-musl@5.3.0': + resolution: {integrity: sha512-TzbjmFkcnESGuVItQ2diKacX8vu5G0bH3BHmIlmY4OSRLyoAlrJFwGKAHmh6C9+Amfcjo2rx8vdm7swzmsGC6Q==} + cpu: [arm64] + os: [linux] + libc: [musl] + '@oxc-resolver/binding-linux-ppc64-gnu@11.19.1': resolution: {integrity: sha512-vLmdNxWCdN7Uo5suays6A/+ywBby2PWBBPXctWPg5V0+eVuzsJxgAn6MMB4mPlshskYbppjpN2Zg83ArHze9gQ==} cpu: [ppc64] @@ -5545,6 +5546,12 @@ packages: os: [linux] libc: [glibc] + '@oxc-resolver/binding-linux-riscv64-gnu@5.3.0': + resolution: {integrity: sha512-NH3pjAqh8nuN29iRuRfTY42Vn03ctoR9VE8llfoUKUfhHUjFHYOXK5VSkhjj1usG8AeuesvqrQnLptCRQVTi/Q==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + '@oxc-resolver/binding-linux-riscv64-musl@11.19.1': resolution: {integrity: sha512-YlRdeWb9j42p29ROh+h4eg/OQ3dTJlpHSa+84pUM9+p6i3djtPz1q55yLJhgW9XfDch7FN1pQ/Vd6YP+xfRIuw==} cpu: [riscv64] @@ -5557,18 +5564,36 @@ packages: os: [linux] libc: [glibc] + '@oxc-resolver/binding-linux-s390x-gnu@5.3.0': + resolution: {integrity: sha512-tuZtkK9sJYh2MC2uhol1M/8IMTB6ZQ5jmqP2+k5XNXnOb/im94Y5uV/u2lXwVyIuKHZZHtr+0d1HrOiNahoKpw==} + cpu: [s390x] + os: [linux] + libc: [glibc] + '@oxc-resolver/binding-linux-x64-gnu@11.19.1': resolution: {integrity: sha512-NxjZe+rqWhr+RT8/Ik+5ptA3oz7tUw361Wa5RWQXKnfqwSSHdHyrw6IdcTfYuml9dM856AlKWZIUXDmA9kkiBQ==} cpu: [x64] os: [linux] libc: [glibc] + '@oxc-resolver/binding-linux-x64-gnu@5.3.0': + resolution: {integrity: sha512-VzhPYmZCtoES/ThcPdGSmMop7JlwgqtSvlgtKCW15ByV2JKyl8kHAHnPSBfpIooXb0ehFnRdxFtL9qtAEWy01g==} + cpu: [x64] + os: [linux] + libc: [glibc] + '@oxc-resolver/binding-linux-x64-musl@11.19.1': resolution: {integrity: sha512-cM/hQwsO3ReJg5kR+SpI69DMfvNCp+A/eVR4b4YClE5bVZwz8rh2Nh05InhwI5HR/9cArbEkzMjcKgTHS6UaNw==} cpu: [x64] os: [linux] libc: [musl] + '@oxc-resolver/binding-linux-x64-musl@5.3.0': + resolution: {integrity: sha512-Hi39cWzul24rGljN4Vf1lxjXzQdCrdxO5oCT7KJP4ndSlqIUODJnfnMAP1YhcnIRvNvk+5E6sZtnEmFUd/4d8Q==} + cpu: [x64] + os: [linux] + libc: [musl] + '@oxc-resolver/binding-openharmony-arm64@11.19.1': resolution: {integrity: sha512-QF080IowFB0+9Rh6RcD19bdgh49BpQHUW5TajG1qvWHvmrQznTZZjYlgE2ltLXyKY+qs4F/v5xuX1XS7Is+3qA==} cpu: [arm64] @@ -5579,11 +5604,21 @@ packages: engines: {node: '>=14.0.0'} cpu: [wasm32] + '@oxc-resolver/binding-wasm32-wasi@5.3.0': + resolution: {integrity: sha512-ddujvHhP3chmHnSXRlkPVUeYj4/B7eLZwL4yUid+df3WCbVh6DgoT9RmllZn21AhxgKtMdekDdyVJYKFd8tl4A==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + '@oxc-resolver/binding-win32-arm64-msvc@11.19.1': resolution: {integrity: sha512-nJ4AsUVZrVKwnU/QRdzPCCrO0TrabBqgJ8pJhXITdZGYOV28TIYystV1VFLbQ7DtAcaBHpocT5/ZJnF78YJPtQ==} cpu: [arm64] os: [win32] + '@oxc-resolver/binding-win32-arm64-msvc@5.3.0': + resolution: {integrity: sha512-j1YYPLvUkMVNKmIFQZZJ7q6Do4cI3htUnyxNLwDSBVhSohvPIK2VG+IdtOAlWZGa7v+phEZsHfNbXVwB0oPYFQ==} + cpu: [arm64] + os: [win32] + '@oxc-resolver/binding-win32-ia32-msvc@11.19.1': resolution: {integrity: sha512-EW+ND5q2Tl+a3pH81l1QbfgbF3HmqgwLfDfVithRFheac8OTcnbXt/JxqD2GbDkb7xYEqy1zNaVFRr3oeG8npA==} cpu: [ia32] @@ -5594,6 +5629,11 @@ packages: cpu: [x64] os: [win32] + '@oxc-resolver/binding-win32-x64-msvc@5.3.0': + resolution: {integrity: sha512-LT9eOPPUqfZscQRd5mc08RBeDWOQf+dnOrKnanMallTGPe6g7+rcAlFTA8SWoJbcD45PV8yArFtCmSQSpzHZmg==} + cpu: [x64] + os: [win32] + '@oxc-transform/binding-android-arm-eabi@0.110.0': resolution: {integrity: sha512-sE9dxvqqAax1YYJ3t7j+h5ZSI9jl6dYuDfngl6ieZUrIy5P89/8JKVgAzgp8o3wQSo7ndpJvYsi1K4ZqrmbP7w==} engines: {node: ^20.19.0 || >=22.12.0} @@ -5843,50 +5883,6 @@ packages: cpu: [x64] os: [win32] - '@oxfmt/darwin-arm64@0.27.0': - resolution: {integrity: sha512-3vwqyzNlVTVFVzHMlrqxb4tgVgHp6FYS0uIxsIZ/SeEDG0azaqiOw/2t8LlJ9f72PKRLWSey+Ak99tiKgpbsnQ==} - cpu: [arm64] - os: [darwin] - - '@oxfmt/darwin-x64@0.27.0': - resolution: {integrity: sha512-5u8mZVLm70v6l1wLZ2MmeNIEzGsruwKw5F7duePzpakPfxGtLpiFNUwe4aBUJULTP6aMzH+A4dA0JOn8lb7Luw==} - cpu: [x64] - os: [darwin] - - '@oxfmt/linux-arm64-gnu@0.27.0': - resolution: {integrity: sha512-aql/LLYriX/5Ar7o5Qivnp/qMTUPNiOCr7cFLvmvzYZa3XL0H8XtbKUfIVm+9ILR0urXQzcml+L8pLe1p8sgEg==} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@oxfmt/linux-arm64-musl@0.27.0': - resolution: {integrity: sha512-6u/kNb7hubthg4u/pn3MK/GJLwPgjDvDDnjjr7TC0/OK/xztef8ToXmycxIQ9OeDNIJJf7Z0Ss/rHnKvQOWzRw==} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@oxfmt/linux-x64-gnu@0.27.0': - resolution: {integrity: sha512-EhvDfFHO1yrK/Cu75eU1U828lBsW2cV0JITOrka5AjR3PlmnQQ03Mr9ROkWkbPmzAMklXI4Q16eO+4n+7FhS1w==} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@oxfmt/linux-x64-musl@0.27.0': - resolution: {integrity: sha512-1pgjuwMT5sCekuteYZ7LkDsto7DJouaccwjozHqdWohSj2zJpFeSP2rMaC+6JJ1KD5r9HG9sWRuHZGEaoX9uOw==} - cpu: [x64] - os: [linux] - libc: [musl] - - '@oxfmt/win32-arm64@0.27.0': - resolution: {integrity: sha512-mmuEhXZEhAYAeyjVTWwGKIA3RSb2b/He9wrXkDJPhmqp8qISUzkVg1dQmLEt4hD+wI5rzR+6vchPt521tzuRDA==} - cpu: [arm64] - os: [win32] - - '@oxfmt/win32-x64@0.27.0': - resolution: {integrity: sha512-cXKVkL1DuRq31QjwHqtBEUztyBmM9YZKdeFhsDLBURNdk1CFW42uWsmTsaqrXSoiCj7nCjfP0pwTOzxhQZra/A==} - cpu: [x64] - os: [win32] - '@parcel/watcher-android-arm64@2.5.1': resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==} engines: {node: '>= 10.0.0'} @@ -7298,14 +7294,20 @@ packages: '@swc/core': '>= 1.13.3' '@swc/types': '>= 0.1' - '@swc-node/register@1.11.1': - resolution: {integrity: sha512-VQ0hJ5jX31TVv/fhZx4xJRzd8pwn6VvzYd2tGOHHr2TfXGCBixZoqdPDXTiEoJLCTS2MmvBf6zyQZZ0M8aGQCQ==} + '@swc-node/register@1.10.10': + resolution: {integrity: sha512-jYWaI2WNEKz8KZL3sExd2KVL1JMma1/J7z+9iTpv0+fRN7LGMF8VTGGuHI2bug/ztpdZU1G44FG/Kk6ElXL9CQ==} peerDependencies: '@swc/core': '>= 1.4.13' typescript: '>= 4.3' - '@swc-node/sourcemap-support@0.6.1': - resolution: {integrity: sha512-ovltDVH5QpdHXZkW138vG4+dgcNsxfwxHVoV6BtmTbz2KKl1A8ZSlbdtxzzfNjCjbpayda8Us9eMtcHobm38dA==} + '@swc-node/sourcemap-support@0.5.1': + resolution: {integrity: sha512-JxIvIo/Hrpv0JCHSyRpetAdQ6lB27oFYhv0PKCNf1g2gUXOjpeR1exrXccRxLMuAV5WAmGFBwRnNOJqN38+qtg==} + + '@swc/core-darwin-arm64@1.11.29': + resolution: {integrity: sha512-whsCX7URzbuS5aET58c75Dloby3Gtj/ITk2vc4WW6pSDQKSPDuONsIcZ7B2ng8oz0K6ttbi4p3H/PNPQLJ4maQ==} + engines: {node: '>=10'} + cpu: [arm64] + os: [darwin] '@swc/core-darwin-arm64@1.15.18': resolution: {integrity: sha512-+mIv7uBuSaywN3C9LNuWaX1jJJ3SKfiJuE6Lr3bd+/1Iv8oMU7oLBjYMluX1UrEPzwN2qCdY6Io0yVicABoCwQ==} @@ -7313,18 +7315,37 @@ packages: cpu: [arm64] os: [darwin] + '@swc/core-darwin-x64@1.11.29': + resolution: {integrity: sha512-S3eTo/KYFk+76cWJRgX30hylN5XkSmjYtCBnM4jPLYn7L6zWYEPajsFLmruQEiTEDUg0gBEWLMNyUeghtswouw==} + engines: {node: '>=10'} + cpu: [x64] + os: [darwin] + '@swc/core-darwin-x64@1.15.18': resolution: {integrity: sha512-wZle0eaQhnzxWX5V/2kEOI6Z9vl/lTFEC6V4EWcn+5pDjhemCpQv9e/TDJ0GIoiClX8EDWRvuZwh+Z3dhL1NAg==} engines: {node: '>=10'} cpu: [x64] os: [darwin] + '@swc/core-linux-arm-gnueabihf@1.11.29': + resolution: {integrity: sha512-o9gdshbzkUMG6azldHdmKklcfrcMx+a23d/2qHQHPDLUPAN+Trd+sDQUYArK5Fcm7TlpG4sczz95ghN0DMkM7g==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + '@swc/core-linux-arm-gnueabihf@1.15.18': resolution: {integrity: sha512-ao61HGXVqrJFHAcPtF4/DegmwEkVCo4HApnotLU8ognfmU8x589z7+tcf3hU+qBiU1WOXV5fQX6W9Nzs6hjxDw==} engines: {node: '>=10'} cpu: [arm] os: [linux] + '@swc/core-linux-arm64-gnu@1.11.29': + resolution: {integrity: sha512-sLoaciOgUKQF1KX9T6hPGzvhOQaJn+3DHy4LOHeXhQqvBgr+7QcZ+hl4uixPKTzxk6hy6Hb0QOvQEdBAAR1gXw==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + '@swc/core-linux-arm64-gnu@1.15.18': resolution: {integrity: sha512-3xnctOBLIq3kj8PxOCgPrGjBLP/kNOddr6f5gukYt/1IZxsITQaU9TDyjeX6jG+FiCIHjCuWuffsyQDL5Ew1bg==} engines: {node: '>=10'} @@ -7332,6 +7353,13 @@ packages: os: [linux] libc: [glibc] + '@swc/core-linux-arm64-musl@1.11.29': + resolution: {integrity: sha512-PwjB10BC0N+Ce7RU/L23eYch6lXFHz7r3NFavIcwDNa/AAqywfxyxh13OeRy+P0cg7NDpWEETWspXeI4Ek8otw==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + libc: [musl] + '@swc/core-linux-arm64-musl@1.15.18': resolution: {integrity: sha512-0a+Lix+FSSHBSBOA0XznCcHo5/1nA6oLLjcnocvzXeqtdjnPb+SvchItHI+lfeiuj1sClYPDvPMLSLyXFaiIKw==} engines: {node: '>=10'} @@ -7339,6 +7367,13 @@ packages: os: [linux] libc: [musl] + '@swc/core-linux-x64-gnu@1.11.29': + resolution: {integrity: sha512-i62vBVoPaVe9A3mc6gJG07n0/e7FVeAvdD9uzZTtGLiuIfVfIBta8EMquzvf+POLycSk79Z6lRhGPZPJPYiQaA==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + libc: [glibc] + '@swc/core-linux-x64-gnu@1.15.18': resolution: {integrity: sha512-wG9J8vReUlpaHz4KOD/5UE1AUgirimU4UFT9oZmupUDEofxJKYb1mTA/DrMj0s78bkBiNI+7Fo2EgPuvOJfuAA==} engines: {node: '>=10'} @@ -7346,6 +7381,13 @@ packages: os: [linux] libc: [glibc] + '@swc/core-linux-x64-musl@1.11.29': + resolution: {integrity: sha512-YER0XU1xqFdK0hKkfSVX1YIyCvMDI7K07GIpefPvcfyNGs38AXKhb2byySDjbVxkdl4dycaxxhRyhQ2gKSlsFQ==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + libc: [musl] + '@swc/core-linux-x64-musl@1.15.18': resolution: {integrity: sha512-4nwbVvCphKzicwNWRmvD5iBaZj8JYsRGa4xOxJmOyHlMDpsvvJ2OR2cODlvWyGFH6BYL1MfIAK3qph3hp0Az6g==} engines: {node: '>=10'} @@ -7353,24 +7395,51 @@ packages: os: [linux] libc: [musl] + '@swc/core-win32-arm64-msvc@1.11.29': + resolution: {integrity: sha512-po+WHw+k9g6FAg5IJ+sMwtA/fIUL3zPQ4m/uJgONBATCVnDDkyW6dBA49uHNVtSEvjvhuD8DVWdFP847YTcITw==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + '@swc/core-win32-arm64-msvc@1.15.18': resolution: {integrity: sha512-zk0RYO+LjiBCat2RTMHzAWaMky0cra9loH4oRrLKLLNuL+jarxKLFDA8xTZWEkCPLjUTwlRN7d28eDLLMgtUcQ==} engines: {node: '>=10'} cpu: [arm64] os: [win32] + '@swc/core-win32-ia32-msvc@1.11.29': + resolution: {integrity: sha512-h+NjOrbqdRBYr5ItmStmQt6x3tnhqgwbj9YxdGPepbTDamFv7vFnhZR0YfB3jz3UKJ8H3uGJ65Zw1VsC+xpFkg==} + engines: {node: '>=10'} + cpu: [ia32] + os: [win32] + '@swc/core-win32-ia32-msvc@1.15.18': resolution: {integrity: sha512-yVuTrZ0RccD5+PEkpcLOBAuPbYBXS6rslENvIXfvJGXSdX5QGi1ehC4BjAMl5FkKLiam4kJECUI0l7Hq7T1vwg==} engines: {node: '>=10'} cpu: [ia32] os: [win32] + '@swc/core-win32-x64-msvc@1.11.29': + resolution: {integrity: sha512-Q8cs2BDV9wqDvqobkXOYdC+pLUSEpX/KvI0Dgfun1F+LzuLotRFuDhrvkU9ETJA6OnD2+Fn/ieHgloiKA/Mn/g==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + '@swc/core-win32-x64-msvc@1.15.18': resolution: {integrity: sha512-7NRmE4hmUQNCbYU3Hn9Tz57mK9Qq4c97ZS+YlamlK6qG9Fb5g/BB3gPDe0iLlJkns/sYv2VWSkm8c3NmbEGjbg==} engines: {node: '>=10'} cpu: [x64] os: [win32] + '@swc/core@1.11.29': + resolution: {integrity: sha512-g4mThMIpWbNhV8G2rWp5a5/Igv8/2UFRJx2yImrLGMgrDDYZIopqZ/z0jZxDgqNA1QDx93rpwNF7jGsxVWcMlA==} + engines: {node: '>=10'} + peerDependencies: + '@swc/helpers': '>=0.5.17' + peerDependenciesMeta: + '@swc/helpers': + optional: true + '@swc/core@1.15.18': resolution: {integrity: sha512-z87aF9GphWp//fnkRsqvtY+inMVPgYW3zSlXH1kJFvRT5H/wiAn+G32qW5l3oEk63KSF1x3Ov0BfHCObAmT8RA==} engines: {node: '>=10'} @@ -8117,23 +8186,9 @@ packages: '@vitest/browser': optional: true - '@vitest/expect@4.0.18': - resolution: {integrity: sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==} - '@vitest/expect@4.1.0': resolution: {integrity: sha512-EIxG7k4wlWweuCLG9Y5InKFwpMEOyrMb6ZJ1ihYu02LVj/bzUwn2VMU+13PinsjRW75XnITeFrQBMH5+dLvCDA==} - '@vitest/mocker@4.0.18': - resolution: {integrity: sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==} - peerDependencies: - msw: ^2.4.9 - vite: ^6.0.0 || ^7.0.0-0 - peerDependenciesMeta: - msw: - optional: true - vite: - optional: true - '@vitest/mocker@4.1.0': resolution: {integrity: sha512-evxREh+Hork43+Y4IOhTo+h5lGmVRyjqI739Rz4RlUPqwrkFFDF6EMvOOYjTx4E8Tl6gyCLRL8Mu7Ry12a13Tw==} peerDependencies: @@ -8145,33 +8200,18 @@ packages: vite: optional: true - '@vitest/pretty-format@4.0.18': - resolution: {integrity: sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==} - '@vitest/pretty-format@4.1.0': resolution: {integrity: sha512-3RZLZlh88Ib0J7NQTRATfc/3ZPOnSUn2uDBUoGNn5T36+bALixmzphN26OUD3LRXWkJu4H0s5vvUeqBiw+kS0A==} - '@vitest/runner@4.0.18': - resolution: {integrity: sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==} - '@vitest/runner@4.1.0': resolution: {integrity: sha512-Duvx2OzQ7d6OjchL+trw+aSrb9idh7pnNfxrklo14p3zmNL4qPCDeIJAK+eBKYjkIwG96Bc6vYuxhqDXQOWpoQ==} - '@vitest/snapshot@4.0.18': - resolution: {integrity: sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==} - '@vitest/snapshot@4.1.0': resolution: {integrity: sha512-0Vy9euT1kgsnj1CHttwi9i9o+4rRLEaPRSOJ5gyv579GJkNpgJK+B4HSv/rAWixx2wdAFci1X4CEPjiu2bXIMg==} - '@vitest/spy@4.0.18': - resolution: {integrity: sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==} - '@vitest/spy@4.1.0': resolution: {integrity: sha512-pz77k+PgNpyMDv2FV6qmk5ZVau6c3R8HC8v342T2xlFxQKTrSeYw9waIJG8KgV9fFwAtTu4ceRzMivPTH6wSxw==} - '@vitest/utils@4.0.18': - resolution: {integrity: sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==} - '@vitest/utils@4.1.0': resolution: {integrity: sha512-XfPXT6a8TZY3dcGY8EdwsBulFCIw+BeeX0RZn2x/BtiY/75YGh8FeWGG8QISN/WhaqSrE2OrlDgtF8q5uhOTmw==} @@ -10263,26 +10303,6 @@ packages: resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.17.0: - resolution: {integrity: sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - hasBin: true - peerDependencies: - jiti: '*' - peerDependenciesMeta: - jiti: - optional: true - - eslint@9.39.1: - resolution: {integrity: sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - hasBin: true - peerDependencies: - jiti: '*' - peerDependenciesMeta: - jiti: - optional: true - eslint@9.39.2: resolution: {integrity: sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -12737,6 +12757,9 @@ packages: oxc-resolver@11.19.1: resolution: {integrity: sha512-qE/CIg/spwrTBFt5aKmwe3ifeDdLfA2NESN30E42X/lII5ClF8V7Wt6WIJhcGZjp0/Q+nQ+9vgxGk//xZNX2hg==} + oxc-resolver@5.3.0: + resolution: {integrity: sha512-FHqtZx0idP5QRPSNcI5g2ItmADg7fhR3XIeWg5eRMGfp44xqRpfkdvo+EX4ZceqV9bxvl0Z8vaqMqY0gYaNYNA==} + oxc-transform@0.110.0: resolution: {integrity: sha512-/fymQNzzUoKZweH0nC5yvbI2eR0yWYusT9TEKDYVgOgYrf9Qmdez9lUFyvxKR9ycx+PTHi/reIOzqf3wkShQsw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -12746,11 +12769,6 @@ packages: peerDependencies: oxc-parser: '>=0.98.0' - oxfmt@0.27.0: - resolution: {integrity: sha512-FHR0HR3WeMKBuVEQvW3EeiRZXs/cQzNHxGbhCoAIEPr1FVcOa9GCqrKJXPqv2jkzmCg6Wqot+DvN9RzemyFJhw==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - oxfmt@0.41.0: resolution: {integrity: sha512-sKLdJZdQ3bw6x9qKiT7+eID4MNEXlDHf5ZacfIircrq6Qwjk0L6t2/JQlZZrVHTXJawK3KaMuBoJnEJPcqCEdg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -14590,10 +14608,6 @@ packages: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} - tinypool@2.0.0: - resolution: {integrity: sha512-/RX9RzeH2xU5ADE7n2Ykvmi9ED3FBGPAjw9u3zucrNNaEBIO0HPSYgL0NT7+3p147ojeSdaVu08F6hjpv31HJg==} - engines: {node: ^20.0.0 || >=22.0.0} - tinypool@2.1.0: resolution: {integrity: sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw==} engines: {node: ^20.0.0 || >=22.0.0} @@ -15026,8 +15040,8 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} - unplugin-swc@1.5.9: - resolution: {integrity: sha512-RKwK3yf0M+MN17xZfF14bdKqfx0zMXYdtOdxLiE6jHAoidupKq3jGdJYANyIM1X/VmABhh1WpdO+/f4+Ol89+g==} + unplugin-swc@1.5.5: + resolution: {integrity: sha512-BahYtYvQ/KSgOqHoy5FfQgp/oZNAB7jwERxNeFVeN/PtJhg4fpK/ybj9OwKtqGPseOadS7+TGbq6tH2DmDAYvA==} peerDependencies: '@swc/core': ^1.2.108 @@ -15614,40 +15628,6 @@ packages: vitest-environment-nuxt@1.0.1: resolution: {integrity: sha512-eBCwtIQriXW5/M49FjqNKfnlJYlG2LWMSNFsRVKomc8CaMqmhQPBS5LZ9DlgYL9T8xIVsiA6RZn2lk7vxov3Ow==} - vitest@4.0.18: - resolution: {integrity: sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==} - engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@opentelemetry/api': ^1.9.0 - '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.0.18 - '@vitest/browser-preview': 4.0.18 - '@vitest/browser-webdriverio': 4.0.18 - '@vitest/ui': 4.0.18 - happy-dom: '*' - jsdom: '*' - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@opentelemetry/api': - optional: true - '@types/node': - optional: true - '@vitest/browser-playwright': - optional: true - '@vitest/browser-preview': - optional: true - '@vitest/browser-webdriverio': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true - vitest@4.1.0: resolution: {integrity: sha512-YbDrMF9jM2Lqc++2530UourxZHmkKLxrs4+mYhEwqWS97WJ7wOYEkcr+QfRgJ3PW9wz3odRijLZjHEaRLTNbqw==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} @@ -18625,19 +18605,9 @@ snapshots: '@esbuild/win32-x64@0.27.2': optional: true - '@eslint-community/eslint-utils@4.7.0(eslint@9.17.0(jiti@2.6.1))': + '@eslint-community/eslint-utils@4.7.0(eslint@9.39.2(jiti@2.6.1))': dependencies: - eslint: 9.17.0(jiti@2.6.1) - eslint-visitor-keys: 3.4.3 - - '@eslint-community/eslint-utils@4.9.0(eslint@9.17.0(jiti@2.6.1))': - dependencies: - eslint: 9.17.0(jiti@2.6.1) - eslint-visitor-keys: 3.4.3 - - '@eslint-community/eslint-utils@4.9.0(eslint@9.39.1(jiti@2.6.1))': - dependencies: - eslint: 9.39.1(jiti@2.6.1) + eslint: 9.39.2(jiti@2.6.1) eslint-visitor-keys: 3.4.3 '@eslint-community/eslint-utils@4.9.0(eslint@9.39.2(jiti@2.6.1))': @@ -18645,11 +18615,6 @@ snapshots: eslint: 9.39.2(jiti@2.6.1) eslint-visitor-keys: 3.4.3 - '@eslint-community/eslint-utils@4.9.1(eslint@9.17.0(jiti@2.6.1))': - dependencies: - eslint: 9.17.0(jiti@2.6.1) - eslint-visitor-keys: 3.4.3 - '@eslint-community/eslint-utils@4.9.1(eslint@9.39.2(jiti@2.6.1))': dependencies: eslint: 9.39.2(jiti@2.6.1) @@ -18659,14 +18624,6 @@ snapshots: '@eslint-community/regexpp@4.12.2': {} - '@eslint/config-array@0.19.2': - dependencies: - '@eslint/object-schema': 2.1.6 - debug: 4.4.3 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - '@eslint/config-array@0.21.1': dependencies: '@eslint/object-schema': 2.1.7 @@ -18679,18 +18636,10 @@ snapshots: dependencies: '@eslint/core': 0.17.0 - '@eslint/core@0.13.0': - dependencies: - '@types/json-schema': 7.0.15 - '@eslint/core@0.17.0': dependencies: '@types/json-schema': 7.0.15 - '@eslint/core@0.9.1': - dependencies: - '@types/json-schema': 7.0.15 - '@eslint/eslintrc@3.3.1': dependencies: ajv: 6.12.6 @@ -18705,21 +18654,10 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@9.17.0': {} - - '@eslint/js@9.39.1': {} - '@eslint/js@9.39.2': {} - '@eslint/object-schema@2.1.6': {} - '@eslint/object-schema@2.1.7': {} - '@eslint/plugin-kit@0.2.8': - dependencies: - '@eslint/core': 0.13.0 - levn: 0.4.1 - '@eslint/plugin-kit@0.4.1': dependencies: '@eslint/core': 0.17.0 @@ -19682,7 +19620,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@nestjs/testing@11.1.16(@nestjs/common@11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16)(@nestjs/platform-express@11.1.16)': + '@nestjs/testing@11.0.1(@nestjs/common@11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16)(@nestjs/platform-express@11.1.16)': dependencies: '@nestjs/common': 11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/core': 11.1.16(@nestjs/common@11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.16)(reflect-metadata@0.2.2)(rxjs@7.8.2) @@ -20480,66 +20418,6 @@ snapshots: - typescript - vite - '@nuxt/vite-builder@3.14.1592(@types/node@25.2.1)(eslint@9.39.1(jiti@2.6.1))(less@4.4.2)(magicast@0.3.5)(optionator@0.9.4)(rolldown@1.0.0-rc.9)(rollup@4.56.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vue-tsc@3.2.4(typescript@5.9.3))(vue@3.5.25(typescript@5.9.3))': - dependencies: - '@nuxt/kit': 3.14.1592(magicast@0.3.5)(rollup@4.56.0) - '@rollup/plugin-replace': 6.0.2(rollup@4.56.0) - '@vitejs/plugin-vue': 5.2.1(vite@5.4.19(@types/node@25.2.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1))(vue@3.5.25(typescript@5.9.3)) - '@vitejs/plugin-vue-jsx': 4.1.1(vite@5.4.19(@types/node@25.2.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1))(vue@3.5.25(typescript@5.9.3)) - autoprefixer: 10.4.20(postcss@8.5.6) - clear: 0.1.0 - consola: 3.4.2 - cssnano: 7.1.1(postcss@8.5.6) - defu: 6.1.4 - esbuild: 0.24.2 - escape-string-regexp: 5.0.0 - estree-walker: 3.0.3 - externality: 1.0.2 - get-port-please: 3.2.0 - h3: 1.15.4 - jiti: 2.6.1 - knitwork: 1.3.0 - magic-string: 0.30.21 - mlly: 1.8.0 - ohash: 1.1.6 - pathe: 1.1.2 - perfect-debounce: 1.0.0 - pkg-types: 1.3.1 - postcss: 8.5.6 - rollup-plugin-visualizer: 5.14.0(rolldown@1.0.0-rc.9)(rollup@4.56.0) - std-env: 3.10.0 - strip-literal: 2.1.1 - ufo: 1.6.1 - unenv: 1.10.0 - unplugin: 1.16.1 - vite: 5.4.19(@types/node@25.2.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1) - vite-node: 2.1.9(@types/node@25.2.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1) - vite-plugin-checker: 0.8.0(eslint@9.39.1(jiti@2.6.1))(optionator@0.9.4)(typescript@5.9.3)(vite@5.4.19(@types/node@25.2.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1))(vue-tsc@3.2.4(typescript@5.9.3)) - vue: 3.5.25(typescript@5.9.3) - vue-bundle-renderer: 2.1.2 - transitivePeerDependencies: - - '@biomejs/biome' - - '@types/node' - - eslint - - less - - lightningcss - - magicast - - meow - - optionator - - rolldown - - rollup - - sass - - sass-embedded - - stylelint - - stylus - - sugarss - - supports-color - - terser - - typescript - - vls - - vti - - vue-tsc - '@nuxt/vite-builder@3.14.1592(@types/node@25.2.1)(eslint@9.39.2(jiti@2.6.1))(less@4.4.2)(magicast@0.3.5)(optionator@0.9.4)(rolldown@1.0.0-rc.9)(rollup@3.29.5)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vue-tsc@3.2.4(typescript@5.9.3))(vue@3.5.25(typescript@5.9.3))': dependencies: '@nuxt/kit': 3.14.1592(magicast@0.3.5)(rollup@3.29.5) @@ -20918,42 +20796,72 @@ snapshots: '@oxc-resolver/binding-darwin-arm64@11.19.1': optional: true + '@oxc-resolver/binding-darwin-arm64@5.3.0': + optional: true + '@oxc-resolver/binding-darwin-x64@11.19.1': optional: true + '@oxc-resolver/binding-darwin-x64@5.3.0': + optional: true + '@oxc-resolver/binding-freebsd-x64@11.19.1': optional: true + '@oxc-resolver/binding-freebsd-x64@5.3.0': + optional: true + '@oxc-resolver/binding-linux-arm-gnueabihf@11.19.1': optional: true + '@oxc-resolver/binding-linux-arm-gnueabihf@5.3.0': + optional: true + '@oxc-resolver/binding-linux-arm-musleabihf@11.19.1': optional: true '@oxc-resolver/binding-linux-arm64-gnu@11.19.1': optional: true + '@oxc-resolver/binding-linux-arm64-gnu@5.3.0': + optional: true + '@oxc-resolver/binding-linux-arm64-musl@11.19.1': optional: true + '@oxc-resolver/binding-linux-arm64-musl@5.3.0': + optional: true + '@oxc-resolver/binding-linux-ppc64-gnu@11.19.1': optional: true '@oxc-resolver/binding-linux-riscv64-gnu@11.19.1': optional: true + '@oxc-resolver/binding-linux-riscv64-gnu@5.3.0': + optional: true + '@oxc-resolver/binding-linux-riscv64-musl@11.19.1': optional: true '@oxc-resolver/binding-linux-s390x-gnu@11.19.1': optional: true + '@oxc-resolver/binding-linux-s390x-gnu@5.3.0': + optional: true + '@oxc-resolver/binding-linux-x64-gnu@11.19.1': optional: true + '@oxc-resolver/binding-linux-x64-gnu@5.3.0': + optional: true + '@oxc-resolver/binding-linux-x64-musl@11.19.1': optional: true + '@oxc-resolver/binding-linux-x64-musl@5.3.0': + optional: true + '@oxc-resolver/binding-openharmony-arm64@11.19.1': optional: true @@ -20962,15 +20870,26 @@ snapshots: '@napi-rs/wasm-runtime': 1.1.1 optional: true + '@oxc-resolver/binding-wasm32-wasi@5.3.0': + dependencies: + '@napi-rs/wasm-runtime': 0.2.12 + optional: true + '@oxc-resolver/binding-win32-arm64-msvc@11.19.1': optional: true + '@oxc-resolver/binding-win32-arm64-msvc@5.3.0': + optional: true + '@oxc-resolver/binding-win32-ia32-msvc@11.19.1': optional: true '@oxc-resolver/binding-win32-x64-msvc@11.19.1': optional: true + '@oxc-resolver/binding-win32-x64-msvc@5.3.0': + optional: true + '@oxc-transform/binding-android-arm-eabi@0.110.0': optional: true @@ -21090,30 +21009,6 @@ snapshots: '@oxfmt/binding-win32-x64-msvc@0.41.0': optional: true - '@oxfmt/darwin-arm64@0.27.0': - optional: true - - '@oxfmt/darwin-x64@0.27.0': - optional: true - - '@oxfmt/linux-arm64-gnu@0.27.0': - optional: true - - '@oxfmt/linux-arm64-musl@0.27.0': - optional: true - - '@oxfmt/linux-x64-gnu@0.27.0': - optional: true - - '@oxfmt/linux-x64-musl@0.27.0': - optional: true - - '@oxfmt/win32-arm64@0.27.0': - optional: true - - '@oxfmt/win32-x64@0.27.0': - optional: true - '@parcel/watcher-android-arm64@2.5.1': optional: true @@ -22132,21 +22027,21 @@ snapshots: '@rollup/plugin-replace@6.0.2(rollup@3.29.5)': dependencies: - '@rollup/pluginutils': 5.2.0(rollup@3.29.5) + '@rollup/pluginutils': 5.3.0(rollup@3.29.5) magic-string: 0.30.21 optionalDependencies: rollup: 3.29.5 '@rollup/plugin-replace@6.0.2(rollup@4.56.0)': dependencies: - '@rollup/pluginutils': 5.2.0(rollup@4.56.0) + '@rollup/pluginutils': 5.3.0(rollup@4.56.0) magic-string: 0.30.21 optionalDependencies: rollup: 4.56.0 '@rollup/plugin-replace@6.0.3(rollup@4.56.0)': dependencies: - '@rollup/pluginutils': 5.2.0(rollup@4.56.0) + '@rollup/pluginutils': 5.3.0(rollup@4.56.0) magic-string: 0.30.21 optionalDependencies: rollup: 4.56.0 @@ -22175,6 +22070,14 @@ snapshots: optionalDependencies: rollup: 4.56.0 + '@rollup/pluginutils@5.3.0(rollup@3.29.5)': + dependencies: + '@types/estree': 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.3 + optionalDependencies: + rollup: 3.29.5 + '@rollup/pluginutils@5.3.0(rollup@4.56.0)': dependencies: '@types/estree': 1.0.8 @@ -22414,19 +22317,19 @@ snapshots: transitivePeerDependencies: - supports-color - '@swc-node/core@1.14.1(@swc/core@1.15.18)(@swc/types@0.1.25)': + '@swc-node/core@1.14.1(@swc/core@1.11.29)(@swc/types@0.1.25)': dependencies: - '@swc/core': 1.15.18 + '@swc/core': 1.11.29 '@swc/types': 0.1.25 - '@swc-node/register@1.11.1(@swc/core@1.15.18)(@swc/types@0.1.25)(typescript@5.9.3)': + '@swc-node/register@1.10.10(@swc/core@1.11.29)(@swc/types@0.1.25)(typescript@5.9.3)': dependencies: - '@swc-node/core': 1.14.1(@swc/core@1.15.18)(@swc/types@0.1.25) - '@swc-node/sourcemap-support': 0.6.1 - '@swc/core': 1.15.18 + '@swc-node/core': 1.14.1(@swc/core@1.11.29)(@swc/types@0.1.25) + '@swc-node/sourcemap-support': 0.5.1 + '@swc/core': 1.11.29 colorette: 2.0.20 debug: 4.4.3 - oxc-resolver: 11.19.1 + oxc-resolver: 5.3.0 pirates: 4.0.7 tslib: 2.8.1 typescript: 5.9.3 @@ -22434,41 +22337,87 @@ snapshots: - '@swc/types' - supports-color - '@swc-node/sourcemap-support@0.6.1': + '@swc-node/sourcemap-support@0.5.1': dependencies: source-map-support: 0.5.21 tslib: 2.8.1 + '@swc/core-darwin-arm64@1.11.29': + optional: true + '@swc/core-darwin-arm64@1.15.18': optional: true + '@swc/core-darwin-x64@1.11.29': + optional: true + '@swc/core-darwin-x64@1.15.18': optional: true + '@swc/core-linux-arm-gnueabihf@1.11.29': + optional: true + '@swc/core-linux-arm-gnueabihf@1.15.18': optional: true + '@swc/core-linux-arm64-gnu@1.11.29': + optional: true + '@swc/core-linux-arm64-gnu@1.15.18': optional: true + '@swc/core-linux-arm64-musl@1.11.29': + optional: true + '@swc/core-linux-arm64-musl@1.15.18': optional: true + '@swc/core-linux-x64-gnu@1.11.29': + optional: true + '@swc/core-linux-x64-gnu@1.15.18': optional: true + '@swc/core-linux-x64-musl@1.11.29': + optional: true + '@swc/core-linux-x64-musl@1.15.18': optional: true + '@swc/core-win32-arm64-msvc@1.11.29': + optional: true + '@swc/core-win32-arm64-msvc@1.15.18': optional: true + '@swc/core-win32-ia32-msvc@1.11.29': + optional: true + '@swc/core-win32-ia32-msvc@1.15.18': optional: true + '@swc/core-win32-x64-msvc@1.11.29': + optional: true + '@swc/core-win32-x64-msvc@1.15.18': optional: true + '@swc/core@1.11.29': + dependencies: + '@swc/counter': 0.1.3 + '@swc/types': 0.1.25 + optionalDependencies: + '@swc/core-darwin-arm64': 1.11.29 + '@swc/core-darwin-x64': 1.11.29 + '@swc/core-linux-arm-gnueabihf': 1.11.29 + '@swc/core-linux-arm64-gnu': 1.11.29 + '@swc/core-linux-arm64-musl': 1.11.29 + '@swc/core-linux-x64-gnu': 1.11.29 + '@swc/core-linux-x64-musl': 1.11.29 + '@swc/core-win32-arm64-msvc': 1.11.29 + '@swc/core-win32-ia32-msvc': 1.11.29 + '@swc/core-win32-x64-msvc': 1.11.29 + '@swc/core@1.15.18': dependencies: '@swc/counter': 0.1.3 @@ -22484,6 +22433,7 @@ snapshots: '@swc/core-win32-arm64-msvc': 1.15.18 '@swc/core-win32-ia32-msvc': 1.15.18 '@swc/core-win32-x64-msvc': 1.15.18 + optional: true '@swc/counter@0.1.3': {} @@ -22855,15 +22805,15 @@ snapshots: '@types/node': 24.10.10 optional: true - '@typescript-eslint/eslint-plugin@8.29.1(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.29.1(@typescript-eslint/parser@8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/scope-manager': 8.29.1 - '@typescript-eslint/type-utils': 8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/type-utils': 8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.29.1 - eslint: 9.17.0(jiti@2.6.1) + eslint: 9.39.2(jiti@2.6.1) graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 @@ -22872,22 +22822,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@8.54.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3)': - dependencies: - '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.54.0 - '@typescript-eslint/type-utils': 8.54.0(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.54.0(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.54.0 - eslint: 9.17.0(jiti@2.6.1) - ignore: 7.0.5 - natural-compare: 1.4.0 - ts-api-utils: 2.4.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/eslint-plugin@8.54.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 @@ -22912,26 +22846,14 @@ snapshots: - supports-color - typescript - '@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/parser@8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@typescript-eslint/scope-manager': 8.29.1 '@typescript-eslint/types': 8.29.1 '@typescript-eslint/typescript-estree': 8.29.1(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.29.1 debug: 4.4.3 - eslint: 9.17.0(jiti@2.6.1) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/parser@8.54.0(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3)': - dependencies: - '@typescript-eslint/scope-manager': 8.54.0 - '@typescript-eslint/types': 8.54.0 - '@typescript-eslint/typescript-estree': 8.54.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.54.0 - debug: 4.4.3 - eslint: 9.17.0(jiti@2.6.1) + eslint: 9.39.2(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -22989,29 +22911,17 @@ snapshots: dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@typescript-eslint/typescript-estree': 8.29.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) debug: 4.4.3 - eslint: 9.17.0(jiti@2.6.1) + eslint: 9.39.2(jiti@2.6.1) ts-api-utils: 2.1.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@8.54.0(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3)': - dependencies: - '@typescript-eslint/types': 8.54.0 - '@typescript-eslint/typescript-estree': 8.54.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.54.0(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) - debug: 4.4.3 - eslint: 9.17.0(jiti@2.6.1) - ts-api-utils: 2.4.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/type-utils@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@typescript-eslint/types': 8.54.0 @@ -23106,24 +23016,13 @@ snapshots: - supports-color - typescript - '@typescript-eslint/utils@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/utils@8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.17.0(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) '@typescript-eslint/scope-manager': 8.29.1 '@typescript-eslint/types': 8.29.1 '@typescript-eslint/typescript-estree': 8.29.1(typescript@5.9.3) - eslint: 9.17.0(jiti@2.6.1) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/utils@8.54.0(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3)': - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.17.0(jiti@2.6.1)) - '@typescript-eslint/scope-manager': 8.54.0 - '@typescript-eslint/types': 8.54.0 - '@typescript-eslint/typescript-estree': 8.54.0(typescript@5.9.3) - eslint: 9.17.0(jiti@2.6.1) + eslint: 9.39.2(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -23407,15 +23306,6 @@ snapshots: tinyrainbow: 3.0.3 vitest: 4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) - '@vitest/expect@4.0.18': - dependencies: - '@standard-schema/spec': 1.1.0 - '@types/chai': 5.2.2 - '@vitest/spy': 4.0.18 - '@vitest/utils': 4.0.18 - chai: 6.2.2 - tinyrainbow: 3.0.3 - '@vitest/expect@4.1.0': dependencies: '@standard-schema/spec': 1.1.0 @@ -23425,24 +23315,6 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.0.3 - '@vitest/mocker@4.0.18(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': - dependencies: - '@vitest/spy': 4.0.18 - estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - msw: 2.10.2(@types/node@24.10.10)(typescript@5.9.3) - vite: 7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - - '@vitest/mocker@4.0.18(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': - dependencies: - '@vitest/spy': 4.0.18 - estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - msw: 2.10.2(@types/node@25.2.1)(typescript@5.9.3) - vite: 7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - '@vitest/mocker@4.1.0(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.0(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@vitest/spy': 4.1.0 @@ -23471,30 +23343,15 @@ snapshots: msw: 2.10.2(@types/node@25.2.1)(typescript@5.9.3) vite: 7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - '@vitest/pretty-format@4.0.18': - dependencies: - tinyrainbow: 3.0.3 - '@vitest/pretty-format@4.1.0': dependencies: tinyrainbow: 3.0.3 - '@vitest/runner@4.0.18': - dependencies: - '@vitest/utils': 4.0.18 - pathe: 2.0.3 - '@vitest/runner@4.1.0': dependencies: '@vitest/utils': 4.1.0 pathe: 2.0.3 - '@vitest/snapshot@4.0.18': - dependencies: - '@vitest/pretty-format': 4.0.18 - magic-string: 0.30.21 - pathe: 2.0.3 - '@vitest/snapshot@4.1.0': dependencies: '@vitest/pretty-format': 4.1.0 @@ -23502,15 +23359,8 @@ snapshots: magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.0.18': {} - '@vitest/spy@4.1.0': {} - '@vitest/utils@4.0.18': - dependencies: - '@vitest/pretty-format': 4.0.18 - tinyrainbow: 3.0.3 - '@vitest/utils@4.1.0': dependencies: '@vitest/pretty-format': 4.1.0 @@ -23855,14 +23705,14 @@ snapshots: dependencies: rfdc: 1.4.1 - '@vue/eslint-config-typescript@14.6.0(eslint-plugin-vue@9.32.0(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3)': + '@vue/eslint-config-typescript@14.6.0(eslint-plugin-vue@9.32.0(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/utils': 8.54.0(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.17.0(jiti@2.6.1) - eslint-plugin-vue: 9.32.0(eslint@9.17.0(jiti@2.6.1)) + '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1) + eslint-plugin-vue: 9.32.0(eslint@9.39.2(jiti@2.6.1)) fast-glob: 3.3.3 - typescript-eslint: 8.54.0(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) - vue-eslint-parser: 10.2.0(eslint@9.17.0(jiti@2.6.1)) + typescript-eslint: 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + vue-eslint-parser: 10.2.0(eslint@9.39.2(jiti@2.6.1)) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -25922,24 +25772,24 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-compat-utils@0.5.1(eslint@9.17.0(jiti@2.6.1)): + eslint-compat-utils@0.5.1(eslint@9.39.2(jiti@2.6.1)): dependencies: - eslint: 9.17.0(jiti@2.6.1) + eslint: 9.39.2(jiti@2.6.1) semver: 7.7.3 - eslint-config-next@15.1.6(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3): + eslint-config-next@15.1.6(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): dependencies: '@next/eslint-plugin-next': 15.1.6 '@rushstack/eslint-patch': 1.10.5 - '@typescript-eslint/eslint-plugin': 8.29.1(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.17.0(jiti@2.6.1) + '@typescript-eslint/eslint-plugin': 8.29.1(@typescript-eslint/parser@8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1)) - eslint-plugin-jsx-a11y: 6.10.2(eslint@9.17.0(jiti@2.6.1)) - eslint-plugin-react: 7.37.5(eslint@9.17.0(jiti@2.6.1)) - eslint-plugin-react-hooks: 5.2.0(eslint@9.17.0(jiti@2.6.1)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-react: 7.37.5(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-react-hooks: 5.2.0(eslint@9.39.2(jiti@2.6.1)) optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: @@ -25955,33 +25805,33 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1)): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.3 - eslint: 9.17.0(jiti@2.6.1) + eslint: 9.39.2(jiti@2.6.1) get-tsconfig: 4.13.6 is-bun-module: 2.0.0 stable-hash: 0.0.5 tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.17.0(jiti@2.6.1) + '@typescript-eslint/parser': 8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -25990,9 +25840,9 @@ snapshots: array.prototype.flatmap: 1.3.3 debug: 3.2.7 doctrine: 2.1.0 - eslint: 9.17.0(jiti@2.6.1) + eslint: 9.39.2(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1)))(eslint@9.17.0(jiti@2.6.1)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -26004,13 +25854,13 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-jsx-a11y@6.10.2(eslint@9.17.0(jiti@2.6.1)): + eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.2(jiti@2.6.1)): dependencies: aria-query: 5.3.2 array-includes: 3.1.9 @@ -26020,7 +25870,7 @@ snapshots: axobject-query: 4.1.0 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 - eslint: 9.17.0(jiti@2.6.1) + eslint: 9.39.2(jiti@2.6.1) hasown: 2.0.2 jsx-ast-utils: 3.3.5 language-tags: 1.0.9 @@ -26029,15 +25879,15 @@ snapshots: safe-regex-test: 1.1.0 string.prototype.includes: 2.0.1 - eslint-plugin-react-hooks@5.2.0(eslint@9.17.0(jiti@2.6.1)): + eslint-plugin-react-hooks@5.2.0(eslint@9.39.2(jiti@2.6.1)): dependencies: - eslint: 9.17.0(jiti@2.6.1) + eslint: 9.39.2(jiti@2.6.1) - eslint-plugin-react-refresh@0.4.7(eslint@9.17.0(jiti@2.6.1)): + eslint-plugin-react-refresh@0.4.7(eslint@9.39.2(jiti@2.6.1)): dependencies: - eslint: 9.17.0(jiti@2.6.1) + eslint: 9.39.2(jiti@2.6.1) - eslint-plugin-react@7.37.5(eslint@9.17.0(jiti@2.6.1)): + eslint-plugin-react@7.37.5(eslint@9.39.2(jiti@2.6.1)): dependencies: array-includes: 3.1.9 array.prototype.findlast: 1.2.5 @@ -26045,7 +25895,7 @@ snapshots: array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 es-iterator-helpers: 1.2.1 - eslint: 9.17.0(jiti@2.6.1) + eslint: 9.39.2(jiti@2.6.1) estraverse: 5.3.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 @@ -26075,13 +25925,13 @@ snapshots: natural-compare: 1.4.0 requireindex: 1.2.0 - eslint-plugin-svelte@2.36.0(eslint@9.17.0(jiti@2.6.1))(svelte@5.19.9)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.2.1)(typescript@5.9.3)): + eslint-plugin-svelte@2.36.0(eslint@9.39.2(jiti@2.6.1))(svelte@5.19.9)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.2.1)(typescript@5.9.3)): dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.17.0(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.7.0(eslint@9.39.2(jiti@2.6.1)) '@jridgewell/sourcemap-codec': 1.5.5 debug: 4.4.1 - eslint: 9.17.0(jiti@2.6.1) - eslint-compat-utils: 0.5.1(eslint@9.17.0(jiti@2.6.1)) + eslint: 9.39.2(jiti@2.6.1) + eslint-compat-utils: 0.5.1(eslint@9.39.2(jiti@2.6.1)) esutils: 2.0.3 known-css-properties: 0.30.0 postcss: 8.4.41 @@ -26120,16 +25970,16 @@ snapshots: optionalDependencies: '@typescript-eslint/parser': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint-plugin-vue@9.32.0(eslint@9.17.0(jiti@2.6.1)): + eslint-plugin-vue@9.32.0(eslint@9.39.2(jiti@2.6.1)): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.17.0(jiti@2.6.1)) - eslint: 9.17.0(jiti@2.6.1) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) + eslint: 9.39.2(jiti@2.6.1) globals: 13.24.0 natural-compare: 1.4.0 nth-check: 2.1.1 postcss-selector-parser: 6.1.2 semver: 7.7.2 - vue-eslint-parser: 9.4.3(eslint@9.17.0(jiti@2.6.1)) + vue-eslint-parser: 9.4.3(eslint@9.39.2(jiti@2.6.1)) xml-name-validator: 4.0.0 transitivePeerDependencies: - supports-color @@ -26155,92 +26005,10 @@ snapshots: eslint-visitor-keys@4.2.1: {} - eslint@9.17.0(jiti@2.6.1): - dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.17.0(jiti@2.6.1)) - '@eslint-community/regexpp': 4.12.1 - '@eslint/config-array': 0.19.2 - '@eslint/core': 0.9.1 - '@eslint/eslintrc': 3.3.1 - '@eslint/js': 9.17.0 - '@eslint/plugin-kit': 0.2.8 - '@humanfs/node': 0.16.6 - '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.8 - '@types/json-schema': 7.0.15 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.6 - debug: 4.4.3 - escape-string-regexp: 4.0.0 - eslint-scope: 8.4.0 - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 - esquery: 1.6.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 8.0.0 - find-up: 5.0.0 - glob-parent: 6.0.2 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - json-stable-stringify-without-jsonify: 1.0.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.4 - optionalDependencies: - jiti: 2.6.1 - transitivePeerDependencies: - - supports-color - - eslint@9.39.1(jiti@2.6.1): - dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) - '@eslint-community/regexpp': 4.12.1 - '@eslint/config-array': 0.21.1 - '@eslint/config-helpers': 0.4.2 - '@eslint/core': 0.17.0 - '@eslint/eslintrc': 3.3.1 - '@eslint/js': 9.39.1 - '@eslint/plugin-kit': 0.4.1 - '@humanfs/node': 0.16.6 - '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.8 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.6 - debug: 4.4.3 - escape-string-regexp: 4.0.0 - eslint-scope: 8.4.0 - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 - esquery: 1.6.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 8.0.0 - find-up: 5.0.0 - glob-parent: 6.0.2 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - json-stable-stringify-without-jsonify: 1.0.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.4 - optionalDependencies: - jiti: 2.6.1 - transitivePeerDependencies: - - supports-color - eslint@9.39.2(jiti@2.6.1): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) - '@eslint-community/regexpp': 4.12.1 + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) + '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.21.1 '@eslint/config-helpers': 0.4.2 '@eslint/core': 0.17.0 @@ -29250,127 +29018,6 @@ snapshots: - vue-tsc - xml2js - nuxt@3.14.1592(@netlify/blobs@9.1.2)(@parcel/watcher@2.5.1)(@types/node@25.2.1)(db0@0.3.4)(encoding@0.1.13)(eslint@9.39.1(jiti@2.6.1))(ioredis@5.9.2)(less@4.4.2)(magicast@0.3.5)(optionator@0.9.4)(rolldown@1.0.0-rc.9)(rollup@4.56.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue-tsc@3.2.4(typescript@5.9.3)): - dependencies: - '@nuxt/devalue': 2.0.2 - '@nuxt/devtools': 1.7.0(rollup@4.56.0)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3)) - '@nuxt/kit': 3.14.1592(magicast@0.3.5)(rollup@4.56.0) - '@nuxt/schema': 3.14.1592(magicast@0.3.5)(rollup@4.56.0) - '@nuxt/telemetry': 2.6.6(magicast@0.3.5) - '@nuxt/vite-builder': 3.14.1592(@types/node@25.2.1)(eslint@9.39.1(jiti@2.6.1))(less@4.4.2)(magicast@0.3.5)(optionator@0.9.4)(rolldown@1.0.0-rc.9)(rollup@4.56.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vue-tsc@3.2.4(typescript@5.9.3))(vue@3.5.25(typescript@5.9.3)) - '@unhead/dom': 1.11.20 - '@unhead/shared': 1.11.20 - '@unhead/ssr': 1.11.20 - '@unhead/vue': 1.11.20(vue@3.5.25(typescript@5.9.3)) - '@vue/shared': 3.5.25 - acorn: 8.14.0 - c12: 2.0.1(magicast@0.3.5) - chokidar: 4.0.3 - compatx: 0.1.8 - consola: 3.4.2 - cookie-es: 1.2.2 - defu: 6.1.4 - destr: 2.0.5 - devalue: 5.3.2 - errx: 0.1.0 - esbuild: 0.24.2 - escape-string-regexp: 5.0.0 - estree-walker: 3.0.3 - globby: 14.1.0 - h3: 1.15.4 - hookable: 5.5.3 - ignore: 6.0.2 - impound: 0.2.2(rollup@4.56.0) - jiti: 2.6.1 - klona: 2.0.6 - knitwork: 1.3.0 - magic-string: 0.30.21 - mlly: 1.8.0 - nanotar: 0.1.1 - nitropack: 2.12.4(@netlify/blobs@9.1.2)(encoding@0.1.13)(rolldown@1.0.0-rc.9) - nuxi: 3.28.0 - nypm: 0.3.12 - ofetch: 1.5.1 - ohash: 1.1.6 - pathe: 1.1.2 - perfect-debounce: 1.0.0 - pkg-types: 1.3.1 - radix3: 1.1.2 - scule: 1.3.0 - semver: 7.7.3 - std-env: 3.10.0 - strip-literal: 2.1.1 - tinyglobby: 0.2.10 - ufo: 1.6.1 - ultrahtml: 1.6.0 - uncrypto: 0.1.3 - unctx: 2.4.1 - unenv: 1.10.0 - unhead: 1.11.20 - unimport: 3.14.6(rollup@4.56.0) - unplugin: 1.16.1 - unplugin-vue-router: 0.10.9(rollup@4.56.0)(vue-router@4.5.0(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3)) - unstorage: 1.17.0(@netlify/blobs@9.1.2)(db0@0.3.4)(ioredis@5.9.2) - untyped: 1.5.2 - vue: 3.5.25(typescript@5.9.3) - vue-bundle-renderer: 2.1.2 - vue-devtools-stub: 0.1.0 - vue-router: 4.5.0(vue@3.5.25(typescript@5.9.3)) - optionalDependencies: - '@parcel/watcher': 2.5.1 - '@types/node': 25.2.1 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@biomejs/biome' - - '@capacitor/preferences' - - '@deno/kv' - - '@electric-sql/pglite' - - '@libsql/client' - - '@netlify/blobs' - - '@planetscale/database' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - better-sqlite3 - - bufferutil - - db0 - - drizzle-orm - - encoding - - eslint - - idb-keyval - - ioredis - - less - - lightningcss - - magicast - - meow - - mysql2 - - optionator - - rolldown - - rollup - - sass - - sass-embedded - - sqlite3 - - stylelint - - stylus - - sugarss - - supports-color - - terser - - typescript - - uploadthing - - utf-8-validate - - vite - - vls - - vti - - vue-tsc - - xml2js - nuxt@3.14.1592(@netlify/blobs@9.1.2)(@parcel/watcher@2.5.1)(@types/node@25.2.1)(db0@0.3.4)(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.9.2)(less@4.4.2)(magicast@0.3.5)(optionator@0.9.4)(rolldown@1.0.0-rc.9)(rollup@4.56.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue-tsc@3.2.4(typescript@5.9.3)): dependencies: '@nuxt/devalue': 2.0.2 @@ -29430,7 +29077,7 @@ snapshots: unhead: 1.11.20 unimport: 3.14.6(rollup@4.56.0) unplugin: 1.16.1 - unplugin-vue-router: 0.10.9(rollup@4.56.0)(vue-router@4.5.0(vue@3.5.13(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3)) + unplugin-vue-router: 0.10.9(rollup@4.56.0)(vue-router@4.5.0(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3)) unstorage: 1.17.0(@netlify/blobs@9.1.2)(db0@0.3.4)(ioredis@5.9.2) untyped: 1.5.2 vue: 3.5.25(typescript@5.9.3) @@ -29889,6 +29536,23 @@ snapshots: '@oxc-resolver/binding-win32-arm64-msvc': 11.19.1 '@oxc-resolver/binding-win32-ia32-msvc': 11.19.1 '@oxc-resolver/binding-win32-x64-msvc': 11.19.1 + optional: true + + oxc-resolver@5.3.0: + optionalDependencies: + '@oxc-resolver/binding-darwin-arm64': 5.3.0 + '@oxc-resolver/binding-darwin-x64': 5.3.0 + '@oxc-resolver/binding-freebsd-x64': 5.3.0 + '@oxc-resolver/binding-linux-arm-gnueabihf': 5.3.0 + '@oxc-resolver/binding-linux-arm64-gnu': 5.3.0 + '@oxc-resolver/binding-linux-arm64-musl': 5.3.0 + '@oxc-resolver/binding-linux-riscv64-gnu': 5.3.0 + '@oxc-resolver/binding-linux-s390x-gnu': 5.3.0 + '@oxc-resolver/binding-linux-x64-gnu': 5.3.0 + '@oxc-resolver/binding-linux-x64-musl': 5.3.0 + '@oxc-resolver/binding-wasm32-wasi': 5.3.0 + '@oxc-resolver/binding-win32-arm64-msvc': 5.3.0 + '@oxc-resolver/binding-win32-x64-msvc': 5.3.0 oxc-transform@0.110.0: optionalDependencies: @@ -29918,19 +29582,6 @@ snapshots: magic-regexp: 0.10.0 oxc-parser: 0.110.0 - oxfmt@0.27.0: - dependencies: - tinypool: 2.0.0 - optionalDependencies: - '@oxfmt/darwin-arm64': 0.27.0 - '@oxfmt/darwin-x64': 0.27.0 - '@oxfmt/linux-arm64-gnu': 0.27.0 - '@oxfmt/linux-arm64-musl': 0.27.0 - '@oxfmt/linux-x64-gnu': 0.27.0 - '@oxfmt/linux-x64-musl': 0.27.0 - '@oxfmt/win32-arm64': 0.27.0 - '@oxfmt/win32-x64': 0.27.0 - oxfmt@0.41.0: dependencies: tinypool: 2.1.0 @@ -32144,8 +31795,6 @@ snapshots: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 - tinypool@2.0.0: {} - tinypool@2.1.0: {} tinyrainbow@3.0.3: {} @@ -32407,23 +32056,12 @@ snapshots: typedarray@0.0.6: {} - typescript-eslint@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3): + typescript-eslint@8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.29.1(@typescript-eslint/parser@8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.17.0(jiti@2.6.1) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - typescript-eslint@8.54.0(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3): - dependencies: - '@typescript-eslint/eslint-plugin': 8.54.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.54.0(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.54.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.54.0(eslint@9.17.0(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.17.0(jiti@2.6.1) + '@typescript-eslint/eslint-plugin': 8.29.1(@typescript-eslint/parser@8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.29.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -32707,10 +32345,10 @@ snapshots: unpipe@1.0.0: {} - unplugin-swc@1.5.9(@swc/core@1.15.18)(rollup@4.56.0): + unplugin-swc@1.5.5(@swc/core@1.11.29)(rollup@4.56.0): dependencies: '@rollup/pluginutils': 5.3.0(rollup@4.56.0) - '@swc/core': 1.15.18 + '@swc/core': 1.11.29 load-tsconfig: 0.2.5 unplugin: 2.3.11 transitivePeerDependencies: @@ -32753,28 +32391,6 @@ snapshots: - rollup - vue - unplugin-vue-router@0.10.9(rollup@4.56.0)(vue-router@4.5.0(vue@3.5.13(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3)): - dependencies: - '@babel/types': 7.28.5 - '@rollup/pluginutils': 5.2.0(rollup@4.56.0) - '@vue-macros/common': 1.16.1(vue@3.5.25(typescript@5.9.3)) - ast-walker-scope: 0.6.2 - chokidar: 3.6.0 - fast-glob: 3.3.3 - json5: 2.2.3 - local-pkg: 0.5.1 - magic-string: 0.30.21 - mlly: 1.8.0 - pathe: 1.1.2 - scule: 1.3.0 - unplugin: 2.0.0-beta.1 - yaml: 2.8.2 - optionalDependencies: - vue-router: 4.5.0(vue@3.5.13(typescript@5.9.3)) - transitivePeerDependencies: - - rollup - - vue - unplugin-vue-router@0.10.9(rollup@4.56.0)(vue-router@4.5.0(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3)): dependencies: '@babel/types': 7.28.5 @@ -33130,29 +32746,6 @@ snapshots: typescript: 5.9.3 vue-tsc: 3.2.4(typescript@5.9.3) - vite-plugin-checker@0.8.0(eslint@9.39.1(jiti@2.6.1))(optionator@0.9.4)(typescript@5.9.3)(vite@5.4.19(@types/node@25.2.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1))(vue-tsc@3.2.4(typescript@5.9.3)): - dependencies: - '@babel/code-frame': 7.27.1 - ansi-escapes: 4.3.2 - chalk: 4.1.2 - chokidar: 3.6.0 - commander: 8.3.0 - fast-glob: 3.3.3 - fs-extra: 11.3.1 - npm-run-path: 4.0.1 - strip-ansi: 6.0.1 - tiny-invariant: 1.3.3 - vite: 5.4.19(@types/node@25.2.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1) - vscode-languageclient: 7.0.0 - vscode-languageserver: 7.0.0 - vscode-languageserver-textdocument: 1.0.12 - vscode-uri: 3.1.0 - optionalDependencies: - eslint: 9.39.1(jiti@2.6.1) - optionator: 0.9.4 - typescript: 5.9.3 - vue-tsc: 3.2.4(typescript@5.9.3) - vite-plugin-checker@0.8.0(eslint@9.39.2(jiti@2.6.1))(optionator@0.9.4)(typescript@5.9.3)(vite@5.4.19(@types/node@25.2.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1))(vue-tsc@3.2.4(typescript@5.9.3)): dependencies: '@babel/code-frame': 7.27.1 @@ -33474,82 +33067,6 @@ snapshots: - vite - vitest - vitest@4.0.18(@types/node@24.10.10)(jiti@2.6.1)(jsdom@28.0.0)(less@4.4.2)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): - dependencies: - '@vitest/expect': 4.0.18 - '@vitest/mocker': 4.0.18(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) - '@vitest/pretty-format': 4.0.18 - '@vitest/runner': 4.0.18 - '@vitest/snapshot': 4.0.18 - '@vitest/spy': 4.0.18 - '@vitest/utils': 4.0.18 - es-module-lexer: 1.7.0 - expect-type: 1.3.0 - magic-string: 0.30.21 - obug: 2.1.1 - pathe: 2.0.3 - picomatch: 4.0.3 - std-env: 3.10.0 - tinybench: 2.9.0 - tinyexec: 1.0.4 - tinyglobby: 0.2.15 - tinyrainbow: 3.0.3 - vite: 7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - why-is-node-running: 2.3.0 - optionalDependencies: - '@types/node': 24.10.10 - jsdom: 28.0.0 - transitivePeerDependencies: - - jiti - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - terser - - tsx - - yaml - - vitest@4.0.18(@types/node@25.2.1)(jiti@2.6.1)(jsdom@28.0.0)(less@4.4.2)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2): - dependencies: - '@vitest/expect': 4.0.18 - '@vitest/mocker': 4.0.18(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) - '@vitest/pretty-format': 4.0.18 - '@vitest/runner': 4.0.18 - '@vitest/snapshot': 4.0.18 - '@vitest/spy': 4.0.18 - '@vitest/utils': 4.0.18 - es-module-lexer: 1.7.0 - expect-type: 1.3.0 - magic-string: 0.30.21 - obug: 2.1.1 - pathe: 2.0.3 - picomatch: 4.0.3 - std-env: 3.10.0 - tinybench: 2.9.0 - tinyexec: 1.0.4 - tinyglobby: 0.2.15 - tinyrainbow: 3.0.3 - vite: 7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - why-is-node-running: 2.3.0 - optionalDependencies: - '@types/node': 25.2.1 - jsdom: 28.0.0 - transitivePeerDependencies: - - jiti - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - terser - - tsx - - yaml - vitest@4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.0(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)): dependencies: '@vitest/expect': 4.1.0 @@ -33680,18 +33197,6 @@ snapshots: vue-devtools-stub@0.1.0: {} - vue-eslint-parser@10.2.0(eslint@9.17.0(jiti@2.6.1)): - dependencies: - debug: 4.4.3 - eslint: 9.17.0(jiti@2.6.1) - eslint-scope: 8.4.0 - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 - esquery: 1.6.0 - semver: 7.7.3 - transitivePeerDependencies: - - supports-color - vue-eslint-parser@10.2.0(eslint@9.39.2(jiti@2.6.1)): dependencies: debug: 4.4.3 @@ -33704,10 +33209,10 @@ snapshots: transitivePeerDependencies: - supports-color - vue-eslint-parser@9.4.3(eslint@9.17.0(jiti@2.6.1)): + vue-eslint-parser@9.4.3(eslint@9.39.2(jiti@2.6.1)): dependencies: debug: 4.4.3 - eslint: 9.17.0(jiti@2.6.1) + eslint: 9.39.2(jiti@2.6.1) eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 diff --git a/renovate.json b/renovate.json index 56074ff9e8..7036cb2ac8 100644 --- a/renovate.json +++ b/renovate.json @@ -9,16 +9,6 @@ "matchPackageNames": ["zod"], "matchFileNames": ["packages/openapi-ts-tests/zod/v3/**"], "allowedVersions": "<4.0.0" - }, - { - "matchFileNames": ["examples/**"], - "groupName": "examples", - "prPriority": -1 - }, - { - "matchFileNames": ["packages/**"], - "groupName": "core packages", - "prPriority": 10 } ], "prConcurrentLimit": 4, From bbede7d19460276b4744c562372fedc609b47029 Mon Sep 17 00:00:00 2001 From: Lubos Date: Wed, 25 Mar 2026 23:53:16 +0100 Subject: [PATCH 05/16] test: move msw snapshot tests --- dev/package.json | 2 +- dev/typescript/presets.ts | 19 +- examples/openapi-ts-fetch/package.json | 2 +- examples/openapi-ts-nestjs/package.json | 10 +- .../vite.config.mjs | 9 + .../vite.config.ts | 12 - packages/openapi-ts-tests/main/package.json | 1 - .../2.0.x/plugins/msw/default/index.ts | 3 - .../2.0.x/plugins/msw/default/msw.gen.ts | 277 --- .../2.0.x/plugins/msw/default/types.gen.ts | 1190 ---------- .../response-example-disabled/types.gen.ts | 50 - .../plugins/msw/response-example/types.gen.ts | 50 - .../2.0.x/plugins/msw/servers/types.gen.ts | 21 - .../3.0.x/plugins/msw/default/types.gen.ts | 2081 ----------------- .../msw/response-example-disabled/index.ts | 3 - .../msw/response-example-disabled/msw.gen.ts | 75 - .../response-example-disabled/types.gen.ts | 50 - .../plugins/msw/response-example/index.ts | 3 - .../plugins/msw/response-example/msw.gen.ts | 81 - .../plugins/msw/response-example/types.gen.ts | 50 - .../plugins/msw/response-types/msw.gen.ts | 60 - .../3.0.x/plugins/msw/servers/index.ts | 3 - .../3.0.x/plugins/msw/servers/msw.gen.ts | 60 - .../3.1.x/plugins/msw/default/index.ts | 3 - .../3.1.x/plugins/msw/default/msw.gen.ts | 382 --- .../msw/response-example-disabled/index.ts | 3 - .../msw/response-example-disabled/msw.gen.ts | 75 - .../plugins/msw/response-example/index.ts | 3 - .../plugins/msw/response-example/msw.gen.ts | 68 - .../3.1.x/plugins/msw/response-types/index.ts | 3 - .../plugins/msw/response-types/types.gen.ts | 23 - .../3.1.x/plugins/msw/servers/index.ts | 3 - .../3.1.x/plugins/msw/servers/msw.gen.ts | 60 - .../3.1.x/plugins/msw/servers/types.gen.ts | 21 - .../main/test/plugins.test.ts | 45 +- packages/openapi-ts-tests/msw/v2/.gitignore | 5 + .../v2/__snapshots__/3.1.x}/default/index.ts | 0 .../__snapshots__/3.1.x}/default/msw.gen.ts | 0 .../__snapshots__/3.1.x}/default/types.gen.ts | 0 .../3.1.x}/response-example-disabled/index.ts | 0 .../response-example-disabled/msw.gen.ts | 0 .../response-example-disabled/types.gen.ts | 0 .../3.1.x}/response-example/index.ts | 0 .../3.1.x}/response-example/msw.gen.ts | 0 .../3.1.x}/response-example/types.gen.ts | 0 .../3.1.x/response-types}/index.ts | 0 .../3.1.x}/response-types/msw.gen.ts | 0 .../3.1.x}/response-types/types.gen.ts | 0 .../v2/__snapshots__/3.1.x/servers}/index.ts | 0 .../__snapshots__/3.1.x}/servers/msw.gen.ts | 0 .../__snapshots__/3.1.x}/servers/types.gen.ts | 0 packages/openapi-ts-tests/msw/v2/package.json | 17 + .../msw/v2/test/3.1.x.test.ts | 75 + .../openapi-ts-tests/msw/v2/test/constants.ts | 4 + .../msw/v2/test/globalTeardown.ts | 7 + .../openapi-ts-tests/msw/v2/test/utils.ts | 33 + .../openapi-ts-tests/msw/v2/tsconfig.json | 5 + packages/openapi-ts-tests/msw/v2/turbo.json | 10 + .../openapi-ts-tests/msw/v2/vitest.setup.ts | 7 + packages/openapi-ts-tests/orpc/v1/.gitignore | 4 - .../orpc/v1/test/3.0.x.test.ts | 4 +- .../orpc/v1/test/3.1.x.test.ts | 4 +- .../openapi-ts-tests/orpc/v1/test/utils.ts | 12 +- .../sdks/test/method-class-conflict.test.ts | 6 +- .../sdks/test/opencode.test.ts | 6 +- packages/openapi-ts-tests/sdks/test/utils.ts | 6 +- .../openapi-ts-tests/valibot/v1/.gitignore | 9 - .../valibot/v1/test/3.0.x.test.ts | 10 +- .../valibot/v1/test/3.1.x.test.ts | 10 +- .../valibot/v1/test/constants.ts | 4 + .../valibot/v1/test/globalTeardown.ts | 7 + .../openapi-ts-tests/valibot/v1/test/utils.ts | 23 +- .../openapi-ts-tests/valibot/v1/tsconfig.json | 1 - .../zod/v3/test/3.0.x.test.ts | 4 +- .../zod/v3/test/3.1.x.test.ts | 4 +- .../zod/v3/test/openapi.test.ts | 4 +- .../openapi-ts-tests/zod/v3/test/utils.ts | 22 +- .../zod/v4/test/3.0.x.test.ts | 4 +- .../zod/v4/test/3.1.x.test.ts | 4 +- .../zod/v4/test/formats.test.ts | 4 +- .../zod/v4/test/openapi.test.ts | 4 +- .../openapi-ts-tests/zod/v4/test/utils.ts | 22 +- pnpm-lock.yaml | 471 ++-- specs/2.0.x/response-example.yaml | 54 - specs/3.0.x/response-example.yaml | 53 - specs/3.0.x/response-types.yaml | 26 - vitest.config.ts | 10 + 87 files changed, 511 insertions(+), 5245 deletions(-) create mode 100644 examples/openapi-ts-tanstack-svelte-query/vite.config.mjs delete mode 100644 examples/openapi-ts-tanstack-svelte-query/vite.config.ts delete mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/index.ts delete mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/msw.gen.ts delete mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/types.gen.ts delete mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example-disabled/types.gen.ts delete mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example/types.gen.ts delete mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/servers/types.gen.ts delete mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/default/types.gen.ts delete mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example-disabled/index.ts delete mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example-disabled/msw.gen.ts delete mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example-disabled/types.gen.ts delete mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example/index.ts delete mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example/msw.gen.ts delete mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example/types.gen.ts delete mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-types/msw.gen.ts delete mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/servers/index.ts delete mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/servers/msw.gen.ts delete mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/default/index.ts delete mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/default/msw.gen.ts delete mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example-disabled/index.ts delete mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example-disabled/msw.gen.ts delete mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example/index.ts delete mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example/msw.gen.ts delete mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-types/index.ts delete mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-types/types.gen.ts delete mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/servers/index.ts delete mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/servers/msw.gen.ts delete mode 100644 packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/servers/types.gen.ts create mode 100644 packages/openapi-ts-tests/msw/v2/.gitignore rename packages/openapi-ts-tests/{main/test/__snapshots__/3.0.x/plugins/msw => msw/v2/__snapshots__/3.1.x}/default/index.ts (100%) rename packages/openapi-ts-tests/{main/test/__snapshots__/3.0.x/plugins/msw => msw/v2/__snapshots__/3.1.x}/default/msw.gen.ts (100%) rename packages/openapi-ts-tests/{main/test/__snapshots__/3.1.x/plugins/msw => msw/v2/__snapshots__/3.1.x}/default/types.gen.ts (100%) rename packages/openapi-ts-tests/{main/test/__snapshots__/2.0.x/plugins/msw => msw/v2/__snapshots__/3.1.x}/response-example-disabled/index.ts (100%) rename packages/openapi-ts-tests/{main/test/__snapshots__/2.0.x/plugins/msw => msw/v2/__snapshots__/3.1.x}/response-example-disabled/msw.gen.ts (100%) rename packages/openapi-ts-tests/{main/test/__snapshots__/3.1.x/plugins/msw => msw/v2/__snapshots__/3.1.x}/response-example-disabled/types.gen.ts (100%) rename packages/openapi-ts-tests/{main/test/__snapshots__/2.0.x/plugins/msw => msw/v2/__snapshots__/3.1.x}/response-example/index.ts (100%) rename packages/openapi-ts-tests/{main/test/__snapshots__/2.0.x/plugins/msw => msw/v2/__snapshots__/3.1.x}/response-example/msw.gen.ts (100%) rename packages/openapi-ts-tests/{main/test/__snapshots__/3.1.x/plugins/msw => msw/v2/__snapshots__/3.1.x}/response-example/types.gen.ts (100%) rename packages/openapi-ts-tests/{main/test/__snapshots__/2.0.x/plugins/msw/servers => msw/v2/__snapshots__/3.1.x/response-types}/index.ts (100%) rename packages/openapi-ts-tests/{main/test/__snapshots__/3.1.x/plugins/msw => msw/v2/__snapshots__/3.1.x}/response-types/msw.gen.ts (100%) rename packages/openapi-ts-tests/{main/test/__snapshots__/3.0.x/plugins/msw => msw/v2/__snapshots__/3.1.x}/response-types/types.gen.ts (100%) rename packages/openapi-ts-tests/{main/test/__snapshots__/3.0.x/plugins/msw/response-types => msw/v2/__snapshots__/3.1.x/servers}/index.ts (100%) rename packages/openapi-ts-tests/{main/test/__snapshots__/2.0.x/plugins/msw => msw/v2/__snapshots__/3.1.x}/servers/msw.gen.ts (100%) rename packages/openapi-ts-tests/{main/test/__snapshots__/3.0.x/plugins/msw => msw/v2/__snapshots__/3.1.x}/servers/types.gen.ts (100%) create mode 100644 packages/openapi-ts-tests/msw/v2/package.json create mode 100644 packages/openapi-ts-tests/msw/v2/test/3.1.x.test.ts create mode 100644 packages/openapi-ts-tests/msw/v2/test/constants.ts create mode 100644 packages/openapi-ts-tests/msw/v2/test/globalTeardown.ts create mode 100644 packages/openapi-ts-tests/msw/v2/test/utils.ts create mode 100644 packages/openapi-ts-tests/msw/v2/tsconfig.json create mode 100644 packages/openapi-ts-tests/msw/v2/turbo.json create mode 100644 packages/openapi-ts-tests/msw/v2/vitest.setup.ts create mode 100644 packages/openapi-ts-tests/valibot/v1/test/constants.ts create mode 100644 packages/openapi-ts-tests/valibot/v1/test/globalTeardown.ts delete mode 100644 specs/2.0.x/response-example.yaml delete mode 100644 specs/3.0.x/response-example.yaml delete mode 100644 specs/3.0.x/response-types.yaml diff --git a/dev/package.json b/dev/package.json index a7012d3580..d37fb99467 100644 --- a/dev/package.json +++ b/dev/package.json @@ -22,7 +22,7 @@ "@tanstack/svelte-query": "5.90.2", "@tanstack/vue-query": "5.92.9", "arktype": "2.2.0", - "msw": "2.10.2", + "msw": "2.12.14", "nuxt": "3.21.0", "swr": "2.4.1", "tsx": "4.21.0", diff --git a/dev/typescript/presets.ts b/dev/typescript/presets.ts index ae36dac09a..67ba36a279 100644 --- a/dev/typescript/presets.ts +++ b/dev/typescript/presets.ts @@ -4,6 +4,7 @@ export type PluginConfig = NonNullable[number export const presets = { angular: () => [ + /** Angular HttpClient with typed services */ { httpRequests: 'flat', name: '@angular/common', @@ -11,7 +12,9 @@ export const presets = { ], full: () => [ /** Full kitchen sink for comprehensive testing */ - '@hey-api/typescript', + { + name: '@hey-api/typescript', + }, { name: '@hey-api/sdk', paramsStructure: 'flat', @@ -32,7 +35,15 @@ export const presets = { ], msw: () => [ /** SDK + MSW handlers */ - '@hey-api/sdk', + // '@hey-api/sdk', + { + name: '@hey-api/sdk', + operations: { + containerName: 'OpenCode', + strategy: 'single', + }, + paramsStructure: 'flat', + }, 'msw', ], rpc: () => [ @@ -42,7 +53,6 @@ export const presets = { ], sdk: () => [ /** SDK with types */ - '@hey-api/typescript', { name: '@hey-api/sdk', operations: { @@ -54,8 +64,6 @@ export const presets = { ], tanstack: () => [ /** SDK + TanStack Query */ - '@hey-api/typescript', - '@hey-api/sdk', { name: '@tanstack/react-query', queryKeys: { @@ -69,7 +77,6 @@ export const presets = { ], validated: () => [ /** SDK + Zod validation */ - '@hey-api/typescript', { name: '@hey-api/sdk', validator: 'zod', diff --git a/examples/openapi-ts-fetch/package.json b/examples/openapi-ts-fetch/package.json index 77d21dc992..337c70b099 100644 --- a/examples/openapi-ts-fetch/package.json +++ b/examples/openapi-ts-fetch/package.json @@ -30,7 +30,7 @@ "eslint": "9.39.2", "eslint-plugin-react-hooks": "5.2.0", "eslint-plugin-react-refresh": "0.4.7", - "msw": "2.10.2", + "msw": "2.12.14", "oxfmt": "0.41.0", "postcss": "8.4.41", "tailwindcss": "3.4.9", diff --git a/examples/openapi-ts-nestjs/package.json b/examples/openapi-ts-nestjs/package.json index fe6d3e693c..1a6e4353c5 100644 --- a/examples/openapi-ts-nestjs/package.json +++ b/examples/openapi-ts-nestjs/package.json @@ -10,11 +10,11 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@nestjs/common": "^11.0.1", - "@nestjs/core": "^11.0.1", - "@nestjs/platform-express": "^11.0.1", - "reflect-metadata": "^0.2.2", - "rxjs": "^7.8.1" + "@nestjs/common": "11.0.1", + "@nestjs/core": "11.0.1", + "@nestjs/platform-express": "11.0.1", + "reflect-metadata": "0.2.2", + "rxjs": "7.8.2" }, "devDependencies": { "@hey-api/openapi-ts": "workspace:*", diff --git a/examples/openapi-ts-tanstack-svelte-query/vite.config.mjs b/examples/openapi-ts-tanstack-svelte-query/vite.config.mjs new file mode 100644 index 0000000000..5edbb389fd --- /dev/null +++ b/examples/openapi-ts-tanstack-svelte-query/vite.config.mjs @@ -0,0 +1,9 @@ +import { sveltekit } from '@sveltejs/kit/vite'; +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + plugins: [sveltekit()], + test: { + include: ['src/**/*.{test,spec}.{js,ts}'], + }, +}); diff --git a/examples/openapi-ts-tanstack-svelte-query/vite.config.ts b/examples/openapi-ts-tanstack-svelte-query/vite.config.ts deleted file mode 100644 index b34311d0be..0000000000 --- a/examples/openapi-ts-tanstack-svelte-query/vite.config.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { sveltekit } from '@sveltejs/kit/vite'; -import { defineProject } from 'vitest/config'; - -export default async () => { - const sveltekitPlugins = await sveltekit(); - return defineProject({ - plugins: [sveltekitPlugins], - test: { - include: ['src/**/*.{test,spec}.{js,ts}'], - }, - }); -}; diff --git a/packages/openapi-ts-tests/main/package.json b/packages/openapi-ts-tests/main/package.json index 571364e9e0..347557469c 100644 --- a/packages/openapi-ts-tests/main/package.json +++ b/packages/openapi-ts-tests/main/package.json @@ -36,7 +36,6 @@ "eslint": "9.39.2", "fastify": "5.7.4", "ky": "1.14.3", - "msw": "2.10.2", "node-fetch": "3.3.2", "nuxt": "3.14.1592", "ofetch": "1.5.1", diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/index.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/index.ts deleted file mode 100644 index c42215da06..0000000000 --- a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -export type { ArrayWithArray, ArrayWithBooleans, ArrayWithNumbers, ArrayWithProperties, ArrayWithReferences, ArrayWithStrings, CallToTestOrderOfParamsData, CallWithDefaultOptionalParametersData, CallWithDefaultParametersData, CallWithDescriptionsData, CallWithDuplicateResponsesData, CallWithDuplicateResponsesError, CallWithDuplicateResponsesErrors, CallWithDuplicateResponsesResponse, CallWithDuplicateResponsesResponses, CallWithNoContentResponseData, CallWithNoContentResponseResponses, CallWithParametersData, CallWithResponseAndNoContentResponseData, CallWithResponseAndNoContentResponseResponse, CallWithResponseAndNoContentResponseResponses, CallWithResponseData, CallWithResponseResponse, CallWithResponseResponses, CallWithResponsesData, CallWithResponsesError, CallWithResponsesErrors, CallWithResponsesResponse, CallWithResponsesResponses, CallWithResultFromHeaderData, CallWithResultFromHeaderErrors, CallWithResultFromHeaderResponses, CallWithWeirdParameterNamesData, ClientOptions, CollectionFormatData, CommentWithBackticks, CommentWithBackticksAndQuotes, CommentWithBreaks, CommentWithExpressionPlaceholders, CommentWithQuotes, CommentWithReservedCharacters, CommentWithSlashes, ComplexTypesData, ComplexTypesErrors, ComplexTypesResponse, ComplexTypesResponses, Date, Default, DeleteCallWithoutParametersAndResponseData, DictionaryWithArray, DictionaryWithDictionary, DictionaryWithProperties, DictionaryWithReference, DictionaryWithString, DummyAData, DummyAResponses, DummyBData, DummyBResponses, DuplicateName2Data, DuplicateName3Data, DuplicateName4Data, DuplicateNameData, EnumFromDescription, EnumWithExtensions, EnumWithNumbers, EnumWithStrings, ExternalRefA, ExternalRefB, ExternalSharedModel, FailureFailure, FooWowData, FooWowResponses, GetCallWithoutParametersAndResponseData, HeadCallWithoutParametersAndResponseData, ModelThatExtends, ModelThatExtendsExtends, ModelWithArray, ModelWithBoolean, ModelWithCircularReference, ModelWithDictionary, ModelWithDuplicateImports, ModelWithDuplicateProperties, ModelWithEnum, ModelWithEnumFromDescription, ModelWithInteger, ModelWithNestedEnums, ModelWithNestedProperties, ModelWithNullableString, ModelWithOrderedProperties, ModelWithPattern, ModelWithPatternWritable, ModelWithProperties, ModelWithPropertiesWritable, ModelWithReference, ModelWithReferenceWritable, ModelWithString, ModelWithStringError, NonAsciiæøåÆøÅöôêÊ字符串Data, NonAsciiæøåÆøÅöôêÊ字符串Response, NonAsciiæøåÆøÅöôêÊ字符串Responses, NonAsciiStringæøåÆøÅöôêÊ字符串, OptionsCallWithoutParametersAndResponseData, ParameterActivityParams, PatchApiVbyApiVersionNoTagData, PatchApiVbyApiVersionNoTagResponses, PatchCallWithoutParametersAndResponseData, PostApiVbyApiVersionBodyData, PostApiVbyApiVersionBodyError, PostApiVbyApiVersionBodyErrors, PostApiVbyApiVersionBodyResponse, PostApiVbyApiVersionBodyResponses, PostCallWithoutParametersAndResponseData, PutCallWithoutParametersAndResponseData, ResponsePostActivityResponse, ServiceWithEmptyTagData, SimpleBoolean, SimpleFile, SimpleInteger, SimpleReference, SimpleString, SimpleStringWithPattern, TestErrorCodeData, TestErrorCodeErrors, TestErrorCodeResponses, TypesData, TypesResponse, TypesResponses } from './types.gen'; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/msw.gen.ts deleted file mode 100644 index 816dcf34ff..0000000000 --- a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/msw.gen.ts +++ /dev/null @@ -1,277 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions } from 'msw'; - -import type { CallWithDuplicateResponsesResponses, CallWithNoContentResponseResponses, CallWithResponseAndNoContentResponseResponses, CallWithResponsesResponses, CallWithResultFromHeaderResponses, CallWithWeirdParameterNamesData, ComplexTypesResponses, DummyAResponses, DummyBResponses, NonAsciiæøåÆøÅöôêÊ字符串Responses, PostApiVbyApiVersionBodyData, PostApiVbyApiVersionBodyResponses, TestErrorCodeResponses, TypesResponses } from './types.gen'; - -const resolveToNull = () => new HttpResponse(null); - -type OptionalHttpHandlerFactory = (responseOrResolver?: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; - -type ToResponseUnion = { - [K in Extract]: { - status: K; - result: T[K]; - }; -}[Extract]; - -type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; - -export type SingleHandlerFactories = { - serviceWithEmptyTagMock: OptionalHttpHandlerFactory; - patchApiVbyApiVersionNoTagMock: OptionalHttpHandlerFactory; - fooWowMock: OptionalHttpHandlerFactory; - deleteCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; - getCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; - headCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; - optionsCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; - patchCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; - postCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; - putCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; - callWithDescriptionsMock: OptionalHttpHandlerFactory; - callWithParametersMock: OptionalHttpHandlerFactory>; - callWithWeirdParameterNamesMock: OptionalHttpHandlerFactory>; - callWithDefaultParametersMock: OptionalHttpHandlerFactory; - callWithDefaultOptionalParametersMock: OptionalHttpHandlerFactory; - callToTestOrderOfParamsMock: OptionalHttpHandlerFactory; - duplicateNameMock: OptionalHttpHandlerFactory; - duplicateName2Mock: OptionalHttpHandlerFactory; - duplicateName3Mock: OptionalHttpHandlerFactory; - duplicateName4Mock: OptionalHttpHandlerFactory; - callWithNoContentResponseMock: OptionalHttpHandlerFactory<{ - result: CallWithNoContentResponseResponses[204]; - status?: 204; - } | HttpResponseResolver>; - callWithResponseAndNoContentResponseMock: HttpHandlerFactory<{ - result: CallWithResponseAndNoContentResponseResponses[200]; - status?: 200; - } | ToResponseUnion | HttpResponseResolver>; - dummyAMock: OptionalHttpHandlerFactory<{ - result: DummyAResponses[204]; - status?: 204; - } | HttpResponseResolver>; - dummyBMock: OptionalHttpHandlerFactory<{ - result: DummyBResponses[204]; - status?: 204; - } | HttpResponseResolver>; - callWithResponseMock: OptionalHttpHandlerFactory; - callWithDuplicateResponsesMock: HttpHandlerFactory<{ - result: CallWithDuplicateResponsesResponses[201]; - status?: 201; - } | ToResponseUnion | HttpResponseResolver>; - callWithResponsesMock: HttpHandlerFactory<{ - result: CallWithResponsesResponses[200]; - status?: 200; - } | ToResponseUnion | HttpResponseResolver>; - collectionFormatMock: OptionalHttpHandlerFactory; - typesMock: HttpHandlerFactory<{ - result: TypesResponses[200]; - status?: 200; - } | ToResponseUnion | HttpResponseResolver<{ - apiVersion: string; - }, never>>; - complexTypesMock: HttpHandlerFactory<{ - result: ComplexTypesResponses[200]; - status?: 200; - } | HttpResponseResolver>; - callWithResultFromHeaderMock: OptionalHttpHandlerFactory<{ - result: CallWithResultFromHeaderResponses[200]; - status?: 200; - } | HttpResponseResolver>; - testErrorCodeMock: OptionalHttpHandlerFactory<{ - result: TestErrorCodeResponses[200]; - status?: 200; - } | HttpResponseResolver>; - nonAsciiæøåÆøÅöôêÊ字符串Mock: HttpHandlerFactory<{ - result: NonAsciiæøåÆøÅöôêÊ字符串Responses[200]; - status?: 200; - } | HttpResponseResolver>; - postApiVbyApiVersionBodyMock: HttpHandlerFactory<{ - result: PostApiVbyApiVersionBodyResponses[200]; - status?: 200; - } | HttpResponseResolver>; -}; - -export type GetAllMocksOptions = { - onMissingMock?: 'error' | 'skip'; - overrides?: { - [K in keyof SingleHandlerFactories]?: Parameters[0]; - }; -}; - -export type MswHandlerFactory = SingleHandlerFactories & { - getAllMocks: (options?: GetAllMocksOptions) => Array; -}; - -export const createMswHandlerFactory = (config?: { - baseUrl?: string; -}): MswHandlerFactory => { - const baseUrl = config?.baseUrl ?? 'http://localhost:3000/base'; - const mocks: SingleHandlerFactories = { - serviceWithEmptyTagMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/no+tag'}`, typeof res === 'function' ? res : resolveToNull, options), - patchApiVbyApiVersionNoTagMock: (res, options) => http.patch(`${baseUrl}${'/api/v:apiVersion/no+tag'}`, typeof res === 'function' ? res : resolveToNull, options), - fooWowMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/no+tag'}`, typeof res === 'function' ? res : resolveToNull, options), - deleteCallWithoutParametersAndResponseMock: (res, options) => http.delete(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), - getCallWithoutParametersAndResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), - headCallWithoutParametersAndResponseMock: (res, options) => http.head(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), - optionsCallWithoutParametersAndResponseMock: (res, options) => http.options(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), - patchCallWithoutParametersAndResponseMock: (res, options) => http.patch(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), - postCallWithoutParametersAndResponseMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), - putCallWithoutParametersAndResponseMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), - callWithDescriptionsMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/descriptions/'}`, typeof res === 'function' ? res : resolveToNull, options), - callWithParametersMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/parameters/:parameterPath'}`, typeof res === 'function' ? res : resolveToNull, options), - callWithWeirdParameterNamesMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/parameters/:parameterPath1/:parameterPath2/:PARAMETERPATH3'}`, typeof res === 'function' ? res : resolveToNull, options), - callWithDefaultParametersMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/defaults'}`, typeof res === 'function' ? res : resolveToNull, options), - callWithDefaultOptionalParametersMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/defaults'}`, typeof res === 'function' ? res : resolveToNull, options), - callToTestOrderOfParamsMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/defaults'}`, typeof res === 'function' ? res : resolveToNull, options), - duplicateNameMock: (res, options) => http.delete(`${baseUrl}${'/api/v:apiVersion/duplicate'}`, typeof res === 'function' ? res : resolveToNull, options), - duplicateName2Mock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/duplicate'}`, typeof res === 'function' ? res : resolveToNull, options), - duplicateName3Mock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/duplicate'}`, typeof res === 'function' ? res : resolveToNull, options), - duplicateName4Mock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/duplicate'}`, typeof res === 'function' ? res : resolveToNull, options), - callWithNoContentResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/no-content'}`, typeof res === 'object' && res.result ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 204 }) : typeof res === 'function' ? res : resolveToNull, options), - callWithResponseAndNoContentResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/multiple-tags/response-and-no-content'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - dummyAMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/multiple-tags/a'}`, typeof res === 'object' && res.result ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 204 }) : typeof res === 'function' ? res : resolveToNull, options), - dummyBMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/multiple-tags/b'}`, typeof res === 'object' && res.result ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 204 }) : typeof res === 'function' ? res : resolveToNull, options), - callWithResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/response'}`, typeof res === 'function' ? res : resolveToNull, options), - callWithDuplicateResponsesMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/response'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 201 }) : typeof res === 'function' ? res : resolveToNull, options), - callWithResponsesMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/response'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - collectionFormatMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/collectionFormat'}`, typeof res === 'function' ? res : resolveToNull, options), - typesMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/types'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - complexTypesMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/complex'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - callWithResultFromHeaderMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/header'}`, typeof res === 'object' && res.result ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - testErrorCodeMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/error'}`, typeof res === 'object' && res.result ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - nonAsciiæøåÆøÅöôêÊ字符串Mock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/non-ascii-æøåÆØÅöôêÊ字符串'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - postApiVbyApiVersionBodyMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/body'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options) - }; - const getAllMocks = (options?: GetAllMocksOptions): Array => { - const onMissingMock = options?.onMissingMock ?? 'skip'; - const overrides = options?.overrides; - const handlers: Array = []; - const addRequiredHandler = (handler: (value: Value | (() => HttpResponse)) => HttpHandler, override: Value | undefined) => { - if (override != null) { - handlers.push(handler(override)); - } - else { - if (onMissingMock === 'error') { - handlers.push(handler(() => new HttpResponse('[heyapi-msw] The mock of this request is not implemented.', { status: 501 }))); - } - } - }; - handlers.push(mocks.callWithWeirdParameterNamesMock(overrides?.callWithWeirdParameterNamesMock)); - addRequiredHandler(mocks.callWithResponseAndNoContentResponseMock, overrides?.callWithResponseAndNoContentResponseMock); - handlers.push(mocks.dummyAMock(overrides?.dummyAMock)); - handlers.push(mocks.dummyBMock(overrides?.dummyBMock)); - handlers.push(mocks.callWithParametersMock(overrides?.callWithParametersMock)); - handlers.push(mocks.serviceWithEmptyTagMock(overrides?.serviceWithEmptyTagMock)); - handlers.push(mocks.patchApiVbyApiVersionNoTagMock(overrides?.patchApiVbyApiVersionNoTagMock)); - handlers.push(mocks.fooWowMock(overrides?.fooWowMock)); - handlers.push(mocks.deleteCallWithoutParametersAndResponseMock(overrides?.deleteCallWithoutParametersAndResponseMock)); - handlers.push(mocks.getCallWithoutParametersAndResponseMock(overrides?.getCallWithoutParametersAndResponseMock)); - handlers.push(mocks.headCallWithoutParametersAndResponseMock(overrides?.headCallWithoutParametersAndResponseMock)); - handlers.push(mocks.optionsCallWithoutParametersAndResponseMock(overrides?.optionsCallWithoutParametersAndResponseMock)); - handlers.push(mocks.patchCallWithoutParametersAndResponseMock(overrides?.patchCallWithoutParametersAndResponseMock)); - handlers.push(mocks.postCallWithoutParametersAndResponseMock(overrides?.postCallWithoutParametersAndResponseMock)); - handlers.push(mocks.putCallWithoutParametersAndResponseMock(overrides?.putCallWithoutParametersAndResponseMock)); - handlers.push(mocks.callWithDescriptionsMock(overrides?.callWithDescriptionsMock)); - handlers.push(mocks.callWithDefaultParametersMock(overrides?.callWithDefaultParametersMock)); - handlers.push(mocks.callWithDefaultOptionalParametersMock(overrides?.callWithDefaultOptionalParametersMock)); - handlers.push(mocks.callToTestOrderOfParamsMock(overrides?.callToTestOrderOfParamsMock)); - handlers.push(mocks.duplicateNameMock(overrides?.duplicateNameMock)); - handlers.push(mocks.duplicateName2Mock(overrides?.duplicateName2Mock)); - handlers.push(mocks.duplicateName3Mock(overrides?.duplicateName3Mock)); - handlers.push(mocks.duplicateName4Mock(overrides?.duplicateName4Mock)); - handlers.push(mocks.callWithNoContentResponseMock(overrides?.callWithNoContentResponseMock)); - handlers.push(mocks.callWithResponseMock(overrides?.callWithResponseMock)); - addRequiredHandler(mocks.callWithDuplicateResponsesMock, overrides?.callWithDuplicateResponsesMock); - addRequiredHandler(mocks.callWithResponsesMock, overrides?.callWithResponsesMock); - handlers.push(mocks.collectionFormatMock(overrides?.collectionFormatMock)); - addRequiredHandler(mocks.typesMock, overrides?.typesMock); - addRequiredHandler(mocks.complexTypesMock, overrides?.complexTypesMock); - handlers.push(mocks.callWithResultFromHeaderMock(overrides?.callWithResultFromHeaderMock)); - handlers.push(mocks.testErrorCodeMock(overrides?.testErrorCodeMock)); - addRequiredHandler(mocks.nonAsciiæøåÆøÅöôêÊ字符串Mock, overrides?.nonAsciiæøåÆøÅöôêÊ字符串Mock); - addRequiredHandler(mocks.postApiVbyApiVersionBodyMock, overrides?.postApiVbyApiVersionBodyMock); - return handlers; - }; - return { ...mocks, getAllMocks }; -}; - -const _defaults = createMswHandlerFactory({ baseUrl: '*' }); - -export const serviceWithEmptyTagMock = _defaults.serviceWithEmptyTagMock; - -export const patchApiVbyApiVersionNoTagMock = _defaults.patchApiVbyApiVersionNoTagMock; - -export const fooWowMock = _defaults.fooWowMock; - -export const deleteCallWithoutParametersAndResponseMock = _defaults.deleteCallWithoutParametersAndResponseMock; - -export const getCallWithoutParametersAndResponseMock = _defaults.getCallWithoutParametersAndResponseMock; - -export const headCallWithoutParametersAndResponseMock = _defaults.headCallWithoutParametersAndResponseMock; - -export const optionsCallWithoutParametersAndResponseMock = _defaults.optionsCallWithoutParametersAndResponseMock; - -export const patchCallWithoutParametersAndResponseMock = _defaults.patchCallWithoutParametersAndResponseMock; - -export const postCallWithoutParametersAndResponseMock = _defaults.postCallWithoutParametersAndResponseMock; - -export const putCallWithoutParametersAndResponseMock = _defaults.putCallWithoutParametersAndResponseMock; - -export const callWithDescriptionsMock = _defaults.callWithDescriptionsMock; - -export const callWithParametersMock = _defaults.callWithParametersMock; - -export const callWithWeirdParameterNamesMock = _defaults.callWithWeirdParameterNamesMock; - -export const callWithDefaultParametersMock = _defaults.callWithDefaultParametersMock; - -export const callWithDefaultOptionalParametersMock = _defaults.callWithDefaultOptionalParametersMock; - -export const callToTestOrderOfParamsMock = _defaults.callToTestOrderOfParamsMock; - -export const duplicateNameMock = _defaults.duplicateNameMock; - -export const duplicateName2Mock = _defaults.duplicateName2Mock; - -export const duplicateName3Mock = _defaults.duplicateName3Mock; - -export const duplicateName4Mock = _defaults.duplicateName4Mock; - -export const callWithNoContentResponseMock = _defaults.callWithNoContentResponseMock; - -export const callWithResponseAndNoContentResponseMock = _defaults.callWithResponseAndNoContentResponseMock; - -export const dummyAMock = _defaults.dummyAMock; - -export const dummyBMock = _defaults.dummyBMock; - -export const callWithResponseMock = _defaults.callWithResponseMock; - -export const callWithDuplicateResponsesMock = _defaults.callWithDuplicateResponsesMock; - -export const callWithResponsesMock = _defaults.callWithResponsesMock; - -export const collectionFormatMock = _defaults.collectionFormatMock; - -export const typesMock = _defaults.typesMock; - -export const complexTypesMock = _defaults.complexTypesMock; - -export const callWithResultFromHeaderMock = _defaults.callWithResultFromHeaderMock; - -export const testErrorCodeMock = _defaults.testErrorCodeMock; - -export const nonAsciiæøåÆøÅöôêÊ字符串Mock = _defaults.nonAsciiæøåÆøÅöôêÊ字符串Mock; - -export const postApiVbyApiVersionBodyMock = _defaults.postApiVbyApiVersionBodyMock; - -export const getAllMocks = _defaults.getAllMocks; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/types.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/types.gen.ts deleted file mode 100644 index d69b074040..0000000000 --- a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/default/types.gen.ts +++ /dev/null @@ -1,1190 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -export type ClientOptions = { - baseUrl: 'http://localhost:3000/base' | (string & {}); -}; - -export type ExternalRefA = ExternalSharedModel; - -export type ExternalRefB = ExternalSharedModel; - -/** - * Testing multiline comments in string: First line - * Second line - * - * Fourth line - */ -export type CommentWithBreaks = number; - -/** - * Testing backticks in string: `backticks` and ```multiple backticks``` should work - */ -export type CommentWithBackticks = number; - -/** - * Testing backticks and quotes in string: `backticks`, 'quotes', "double quotes" and ```multiple backticks``` should work - */ -export type CommentWithBackticksAndQuotes = number; - -/** - * Testing slashes in string: \backwards\\\ and /forwards/// should work - */ -export type CommentWithSlashes = number; - -/** - * Testing expression placeholders in string: ${expression} should work - */ -export type CommentWithExpressionPlaceholders = number; - -/** - * Testing quotes in string: 'single quote''' and "double quotes""" should work - */ -export type CommentWithQuotes = number; - -/** - * Testing reserved characters in string: * inline * and ** inline ** should work - */ -export type CommentWithReservedCharacters = number; - -/** - * This is a simple number - */ -export type SimpleInteger = number; - -/** - * This is a simple boolean - */ -export type SimpleBoolean = boolean; - -/** - * This is a simple string - */ -export type SimpleString = string; - -/** - * A string with non-ascii (unicode) characters valid in typescript identifiers (æøåÆØÅöÔèÈ字符串) - */ -export type NonAsciiStringæøåÆøÅöôêÊ字符串 = string; - -/** - * This is a simple file - */ -export type SimpleFile = Blob | File; - -export type SimpleReference = ModelWithString; - -/** - * This is a simple string - */ -export type SimpleStringWithPattern = string; - -/** - * This is a simple enum with strings - */ -export type EnumWithStrings = 'Success' | 'Warning' | 'Error' | '\'Single Quote\'' | '"Double Quotes"' | 'Non-ascii: øæåôöØÆÅÔÖ字符串'; - -/** - * This is a simple enum with numbers - */ -export type EnumWithNumbers = 1 | 2 | 3 | 1.1 | 1.2 | 1.3 | 100 | 200 | 300 | -100 | -200 | -300 | -1.1 | -1.2 | -1.3; - -/** - * Success=1,Warning=2,Error=3 - */ -export type EnumFromDescription = number; - -/** - * This is a simple enum with numbers - */ -export type EnumWithExtensions = 200 | 400 | 500; - -/** - * This is a simple array with numbers - */ -export type ArrayWithNumbers = Array; - -/** - * This is a simple array with booleans - */ -export type ArrayWithBooleans = Array; - -/** - * This is a simple array with strings - */ -export type ArrayWithStrings = Array; - -/** - * This is a simple array with references - */ -export type ArrayWithReferences = Array; - -/** - * This is a simple array containing an array - */ -export type ArrayWithArray = Array>; - -/** - * This is a simple array with properties - */ -export type ArrayWithProperties = Array<{ - foo?: string; - bar?: string; -}>; - -/** - * This is a string dictionary - */ -export type DictionaryWithString = { - [key: string]: string; -}; - -/** - * This is a string reference - */ -export type DictionaryWithReference = { - [key: string]: ModelWithString; -}; - -/** - * This is a complex dictionary - */ -export type DictionaryWithArray = { - [key: string]: Array; -}; - -/** - * This is a string dictionary - */ -export type DictionaryWithDictionary = { - [key: string]: { - [key: string]: string; - }; -}; - -/** - * This is a complex dictionary - */ -export type DictionaryWithProperties = { - [key: string]: { - foo?: string; - bar?: string; - }; -}; - -/** - * This is a type-only model that defines Date as a string - */ -export type Date = string; - -/** - * This is a model with one number property - */ -export type ModelWithInteger = { - /** - * This is a simple number property - */ - prop?: number; -}; - -/** - * This is a model with one boolean property - */ -export type ModelWithBoolean = { - /** - * This is a simple boolean property - */ - prop?: boolean; -}; - -/** - * This is a model with one string property - */ -export type ModelWithString = { - /** - * This is a simple string property - */ - prop?: string; -}; - -/** - * This is a model with one string property - */ -export type ModelWithStringError = { - /** - * This is a simple string property - */ - prop?: string; -}; - -/** - * This is a model with one string property - */ -export type ModelWithNullableString = { - /** - * This is a simple string property - */ - nullableProp?: string | null; - /** - * This is a simple string property - */ - nullableRequiredProp: string | null; -}; - -/** - * This is a model with one enum - */ -export type ModelWithEnum = { - /** - * This is a simple enum with strings - */ - test?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; - /** - * These are the HTTP error code enums - */ - statusCode?: '100' | '200 FOO' | '300 FOO_BAR' | '400 foo-bar' | '500 foo.bar' | '600 foo&bar'; - /** - * Simple boolean enum - */ - bool?: true; -}; - -/** - * This is a model with one enum - */ -export type ModelWithEnumFromDescription = { - /** - * Success=1,Warning=2,Error=3 - */ - test?: number; -}; - -/** - * This is a model with nested enums - */ -export type ModelWithNestedEnums = { - dictionaryWithEnum?: { - [key: string]: 'Success' | 'Warning' | 'Error'; - }; - dictionaryWithEnumFromDescription?: { - [key: string]: number; - }; - arrayWithEnum?: Array<'Success' | 'Warning' | 'Error'>; - arrayWithDescription?: Array; -}; - -/** - * This is a model with one property containing a reference - */ -export type ModelWithReference = { - prop?: ModelWithProperties; -}; - -/** - * This is a model with one property containing an array - */ -export type ModelWithArray = { - prop?: Array; - propWithFile?: Array; - propWithNumber?: Array; -}; - -/** - * This is a model with one property containing a dictionary - */ -export type ModelWithDictionary = { - prop?: { - [key: string]: string; - }; -}; - -/** - * This is a model with one property containing a circular reference - */ -export type ModelWithCircularReference = { - prop?: ModelWithCircularReference; -}; - -/** - * This is a model with one nested property - */ -export type ModelWithProperties = { - required: string; - readonly requiredAndReadOnly: string; - string?: string; - number?: number; - boolean?: boolean; - reference?: ModelWithString; - 'property with space'?: string; - default?: string; - try?: string; - readonly '@namespace.string'?: string; - readonly '@namespace.integer'?: number; -}; - -/** - * This is a model with one nested property - */ -export type ModelWithNestedProperties = { - readonly first: { - readonly second: { - readonly third: string; - }; - }; -}; - -/** - * This is a model with duplicated properties - */ -export type ModelWithDuplicateProperties = { - prop?: ModelWithString; -}; - -/** - * This is a model with ordered properties - */ -export type ModelWithOrderedProperties = { - zebra?: string; - apple?: string; - hawaii?: string; -}; - -/** - * This is a model with duplicated imports - */ -export type ModelWithDuplicateImports = { - propA?: ModelWithString; - propB?: ModelWithString; - propC?: ModelWithString; -}; - -/** - * This is a model that extends another model - */ -export type ModelThatExtends = ModelWithString & { - propExtendsA?: string; - propExtendsB?: ModelWithString; -}; - -/** - * This is a model that extends another model - */ -export type ModelThatExtendsExtends = ModelWithString & ModelThatExtends & { - propExtendsC?: string; - propExtendsD?: ModelWithString; -}; - -export type Default = { - name?: string; -}; - -/** - * This is a model that contains a some patterns - */ -export type ModelWithPattern = { - key: string; - name: string; - readonly enabled?: boolean; - readonly modified?: string; - id?: string; - text?: string; - patternWithSingleQuotes?: string; - patternWithNewline?: string; - patternWithBacktick?: string; - patternWithUnicode?: string; -}; - -export type ParameterActivityParams = { - description?: string; - graduate_id?: number; - organization_id?: number; - parent_activity?: number; - post_id?: number; -}; - -export type ResponsePostActivityResponse = { - description?: string; - graduate_id?: number; - organization_id?: number; - parent_activity_id?: number; - post_id?: number; -}; - -export type FailureFailure = { - error?: string; - message?: string; - reference_code?: string; -}; - -export type ExternalSharedModel = { - id: string; - name?: string; -}; - -/** - * This is a model with one property containing a reference - */ -export type ModelWithReferenceWritable = { - prop?: ModelWithPropertiesWritable; -}; - -/** - * This is a model with one nested property - */ -export type ModelWithPropertiesWritable = { - required: string; - string?: string; - number?: number; - boolean?: boolean; - reference?: ModelWithString; - 'property with space'?: string; - default?: string; - try?: string; -}; - -/** - * This is a model that contains a some patterns - */ -export type ModelWithPatternWritable = { - key: string; - name: string; - id?: string; - text?: string; - patternWithSingleQuotes?: string; - patternWithNewline?: string; - patternWithBacktick?: string; - patternWithUnicode?: string; -}; - -export type ServiceWithEmptyTagData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/no+tag'; -}; - -export type PatchApiVbyApiVersionNoTagData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/no+tag'; -}; - -export type PatchApiVbyApiVersionNoTagResponses = { - /** - * OK - */ - default: unknown; -}; - -export type FooWowData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/no+tag'; -}; - -export type FooWowResponses = { - /** - * OK - */ - default: unknown; -}; - -export type DeleteCallWithoutParametersAndResponseData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/simple'; -}; - -export type GetCallWithoutParametersAndResponseData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/simple'; -}; - -export type HeadCallWithoutParametersAndResponseData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/simple'; -}; - -export type OptionsCallWithoutParametersAndResponseData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/simple'; -}; - -export type PatchCallWithoutParametersAndResponseData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/simple'; -}; - -export type PostCallWithoutParametersAndResponseData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/simple'; -}; - -export type PutCallWithoutParametersAndResponseData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/simple'; -}; - -export type CallWithDescriptionsData = { - body?: never; - path?: never; - query?: { - /** - * Testing multiline comments in string: First line - * Second line - * - * Fourth line - */ - parameterWithBreaks?: string; - /** - * Testing backticks in string: `backticks` and ```multiple backticks``` should work - */ - parameterWithBackticks?: string; - /** - * Testing slashes in string: \backwards\\\ and /forwards/// should work - */ - parameterWithSlashes?: string; - /** - * Testing expression placeholders in string: ${expression} should work - */ - parameterWithExpressionPlaceholders?: string; - /** - * Testing quotes in string: 'single quote''' and "double quotes""" should work - */ - parameterWithQuotes?: string; - /** - * Testing reserved characters in string: * inline * and ** inline ** should work - */ - parameterWithReservedCharacters?: string; - }; - url: '/api/v{api-version}/descriptions/'; -}; - -export type CallWithParametersData = { - body?: never; - headers: { - /** - * This is the parameter that goes into the header - */ - parameterHeader: string; - }; - path: { - /** - * This is the parameter that goes into the path - */ - parameterPath: string; - /** - * api-version should be required in standalone clients - */ - 'api-version': string; - }; - query: { - /** - * This is the parameter that goes into the query params - */ - parameterQuery: string; - }; - url: '/api/v{api-version}/parameters/{parameterPath}'; -}; - -export type CallWithWeirdParameterNamesData = { - /** - * This is the parameter that is sent as request body - */ - body: string; - headers: { - /** - * This is the parameter that goes into the request header - */ - 'parameter.header': string; - }; - path: { - /** - * This is the parameter that goes into the path - */ - 'parameter.path.1'?: string; - /** - * This is the parameter that goes into the path - */ - 'parameter-path-2'?: string; - /** - * This is the parameter that goes into the path - */ - 'PARAMETER-PATH-3'?: string; - /** - * api-version should be required in standalone clients - */ - 'api-version': string; - }; - query: { - /** - * This is the parameter with a reserved keyword - */ - default?: string; - /** - * This is the parameter that goes into the request query params - */ - 'parameter-query': string; - }; - url: '/api/v{api-version}/parameters/{parameter.path.1}/{parameter-path-2}/{PARAMETER-PATH-3}'; -}; - -export type CallWithDefaultParametersData = { - body?: never; - path?: never; - query: { - /** - * This is a simple string with default value - */ - parameterString: string; - /** - * This is a simple number with default value - */ - parameterNumber: number; - /** - * This is a simple boolean with default value - */ - parameterBoolean: boolean; - /** - * This is a simple enum with default value - */ - parameterEnum: 'Success' | 'Warning' | 'Error'; - /** - * This is a model with one string property - */ - parameterModel: { - /** - * This is a simple string property - */ - prop?: string; - }; - }; - url: '/api/v{api-version}/defaults'; -}; - -export type CallWithDefaultOptionalParametersData = { - body?: never; - path?: never; - query?: { - /** - * This is a simple string that is optional with default value - */ - parameterString?: string; - /** - * This is a simple number that is optional with default value - */ - parameterNumber?: number; - /** - * This is a simple boolean that is optional with default value - */ - parameterBoolean?: boolean; - /** - * This is a simple enum that is optional with default value - */ - parameterEnum?: 'Success' | 'Warning' | 'Error'; - }; - url: '/api/v{api-version}/defaults'; -}; - -export type CallToTestOrderOfParamsData = { - body?: never; - path?: never; - query: { - /** - * This is a optional string with default - */ - parameterOptionalStringWithDefault?: string; - /** - * This is a optional string with empty default - */ - parameterOptionalStringWithEmptyDefault?: string; - /** - * This is a optional string with no default - */ - parameterOptionalStringWithNoDefault?: string; - /** - * This is a string with default - */ - parameterStringWithDefault: string; - /** - * This is a string with empty default - */ - parameterStringWithEmptyDefault: string; - /** - * This is a string with no default - */ - parameterStringWithNoDefault: string; - /** - * This is a string that can be null with no default - */ - parameterStringNullableWithNoDefault?: string | null; - /** - * This is a string that can be null with default - */ - parameterStringNullableWithDefault?: string | null; - }; - url: '/api/v{api-version}/defaults'; -}; - -export type DuplicateNameData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/duplicate'; -}; - -export type DuplicateName2Data = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/duplicate'; -}; - -export type DuplicateName3Data = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/duplicate'; -}; - -export type DuplicateName4Data = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/duplicate'; -}; - -export type CallWithNoContentResponseData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/no-content'; -}; - -export type CallWithNoContentResponseResponses = { - /** - * Success - */ - 204: unknown; -}; - -export type CallWithResponseAndNoContentResponseData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/multiple-tags/response-and-no-content'; -}; - -export type CallWithResponseAndNoContentResponseResponses = { - /** - * Response is a simple number - */ - 200: number; - /** - * Success - */ - 204: unknown; -}; - -export type CallWithResponseAndNoContentResponseResponse = CallWithResponseAndNoContentResponseResponses[keyof CallWithResponseAndNoContentResponseResponses]; - -export type DummyAData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/multiple-tags/a'; -}; - -export type DummyAResponses = { - /** - * Success - */ - 204: unknown; -}; - -export type DummyBData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/multiple-tags/b'; -}; - -export type DummyBResponses = { - /** - * Success - */ - 204: unknown; -}; - -export type CallWithResponseData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/response'; -}; - -export type CallWithResponseResponses = { - /** - * Message for default response - */ - default: ModelWithString; -}; - -export type CallWithResponseResponse = CallWithResponseResponses[keyof CallWithResponseResponses]; - -export type CallWithDuplicateResponsesData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/response'; -}; - -export type CallWithDuplicateResponsesErrors = { - /** - * Message for 500 error - */ - 500: ModelWithStringError; - /** - * Message for 501 error - */ - 501: ModelWithStringError; - /** - * Message for 502 error - */ - 502: ModelWithStringError; - /** - * Message for default response - */ - default: ModelWithString; -}; - -export type CallWithDuplicateResponsesError = CallWithDuplicateResponsesErrors[keyof CallWithDuplicateResponsesErrors]; - -export type CallWithDuplicateResponsesResponses = { - /** - * Message for 201 response - */ - 201: ModelWithString; - /** - * Message for 202 response - */ - 202: ModelWithString; -}; - -export type CallWithDuplicateResponsesResponse = CallWithDuplicateResponsesResponses[keyof CallWithDuplicateResponsesResponses]; - -export type CallWithResponsesData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/response'; -}; - -export type CallWithResponsesErrors = { - /** - * Message for 500 error - */ - 500: ModelWithStringError; - /** - * Message for 501 error - */ - 501: ModelWithStringError; - /** - * Message for 502 error - */ - 502: ModelWithStringError; - /** - * Message for default response - */ - default: ModelWithString; -}; - -export type CallWithResponsesError = CallWithResponsesErrors[keyof CallWithResponsesErrors]; - -export type CallWithResponsesResponses = { - /** - * Message for 200 response - */ - 200: { - readonly '@namespace.string'?: string; - readonly '@namespace.integer'?: number; - readonly value?: Array; - }; - /** - * Message for 201 response - */ - 201: ModelThatExtends; - /** - * Message for 202 response - */ - 202: ModelThatExtendsExtends; -}; - -export type CallWithResponsesResponse = CallWithResponsesResponses[keyof CallWithResponsesResponses]; - -export type CollectionFormatData = { - body?: never; - path?: never; - query: { - /** - * This is an array parameter that is sent as csv format (comma-separated values) - */ - parameterArrayCSV: Array; - /** - * This is an array parameter that is sent as ssv format (space-separated values) - */ - parameterArraySSV: Array; - /** - * This is an array parameter that is sent as tsv format (tab-separated values) - */ - parameterArrayTSV: Array; - /** - * This is an array parameter that is sent as pipes format (pipe-separated values) - */ - parameterArrayPipes: Array; - /** - * This is an array parameter that is sent as multi format (multiple parameter instances) - */ - parameterArrayMulti: Array; - }; - url: '/api/v{api-version}/collectionFormat'; -}; - -export type TypesData = { - body?: never; - path?: { - /** - * This is a number parameter - */ - id?: number; - }; - query: { - /** - * This is a number parameter - */ - parameterNumber: number; - /** - * This is a string parameter - */ - parameterString: string; - /** - * This is a boolean parameter - */ - parameterBoolean: boolean; - /** - * This is an array parameter - */ - parameterArray: Array; - /** - * This is a dictionary parameter - */ - parameterDictionary: { - [key: string]: unknown; - }; - /** - * This is an enum parameter - */ - parameterEnum: 'Success' | 'Warning' | 'Error'; - }; - url: '/api/v{api-version}/types'; -}; - -export type TypesResponses = { - /** - * Response is a simple number - */ - 200: number; - /** - * Response is a simple string - */ - 201: string; - /** - * Response is a simple boolean - */ - 202: boolean; - /** - * Response is a simple object - */ - 203: { - [key: string]: unknown; - }; -}; - -export type TypesResponse = TypesResponses[keyof TypesResponses]; - -export type ComplexTypesData = { - body?: never; - path?: never; - query: { - /** - * Parameter containing object - */ - parameterObject: { - first?: { - second?: { - third?: string; - }; - }; - }; - /** - * This is a model with one string property - */ - parameterReference: { - /** - * This is a simple string property - */ - prop?: string; - }; - }; - url: '/api/v{api-version}/complex'; -}; - -export type ComplexTypesErrors = { - /** - * 400 server error - */ - 400: unknown; - /** - * 500 server error - */ - 500: unknown; -}; - -export type ComplexTypesResponses = { - /** - * Successful response - */ - 200: Array; -}; - -export type ComplexTypesResponse = ComplexTypesResponses[keyof ComplexTypesResponses]; - -export type CallWithResultFromHeaderData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/header'; -}; - -export type CallWithResultFromHeaderErrors = { - /** - * 400 server error - */ - 400: unknown; - /** - * 500 server error - */ - 500: unknown; -}; - -export type CallWithResultFromHeaderResponses = { - /** - * Successful response - */ - 200: unknown; -}; - -export type TestErrorCodeData = { - body?: never; - path?: never; - query: { - /** - * Status code to return - */ - status: string; - }; - url: '/api/v{api-version}/error'; -}; - -export type TestErrorCodeErrors = { - /** - * Custom message: Internal Server Error - */ - 500: unknown; - /** - * Custom message: Not Implemented - */ - 501: unknown; - /** - * Custom message: Bad Gateway - */ - 502: unknown; - /** - * Custom message: Service Unavailable - */ - 503: unknown; -}; - -export type TestErrorCodeResponses = { - /** - * Custom message: Successful response - */ - 200: unknown; -}; - -export type NonAsciiæøåÆøÅöôêÊ字符串Data = { - body?: never; - path?: never; - query: { - /** - * Dummy input param - */ - nonAsciiParamæøåÆØÅöôêÊ: number; - }; - url: '/api/v{api-version}/non-ascii-æøåÆØÅöôêÊ字符串'; -}; - -export type NonAsciiæøåÆøÅöôêÊ字符串Responses = { - /** - * Successful response - */ - 200: NonAsciiStringæøåÆøÅöôêÊ字符串; -}; - -export type NonAsciiæøåÆøÅöôêÊ字符串Response = NonAsciiæøåÆøÅöôêÊ字符串Responses[keyof NonAsciiæøåÆøÅöôêÊ字符串Responses]; - -export type PostApiVbyApiVersionBodyData = { - /** - * Body should not be unknown - */ - body: ParameterActivityParams; - path?: never; - query?: never; - url: '/api/v{api-version}/body'; -}; - -export type PostApiVbyApiVersionBodyErrors = { - /** - * Bad Request - */ - 400: FailureFailure; - /** - * Internal Server Error - */ - 500: FailureFailure; -}; - -export type PostApiVbyApiVersionBodyError = PostApiVbyApiVersionBodyErrors[keyof PostApiVbyApiVersionBodyErrors]; - -export type PostApiVbyApiVersionBodyResponses = { - /** - * OK - */ - 200: ResponsePostActivityResponse; -}; - -export type PostApiVbyApiVersionBodyResponse = PostApiVbyApiVersionBodyResponses[keyof PostApiVbyApiVersionBodyResponses]; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example-disabled/types.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example-disabled/types.gen.ts deleted file mode 100644 index bf9849161c..0000000000 --- a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example-disabled/types.gen.ts +++ /dev/null @@ -1,50 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -export type ClientOptions = { - baseUrl: string; -}; - -export type Person = { - firstName?: string; - lastName?: string; - age?: number; -}; - -export type GetFooData = { - body?: never; - path?: never; - query?: never; - url: '/foo'; -}; - -export type GetFooResponses = { - /** - * OK - */ - 200: Person; -}; - -export type GetFooResponse = GetFooResponses[keyof GetFooResponses]; - -export type PostFooData = { - body: string; - path?: never; - query?: never; - url: '/foo'; -}; - -export type PostFooResponses = { - /** - * OK - */ - 200: { - fullName?: string; - age?: number; - }; - /** - * SUCCESSFUL - */ - 204: unknown; -}; - -export type PostFooResponse = PostFooResponses[keyof PostFooResponses]; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example/types.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example/types.gen.ts deleted file mode 100644 index bf9849161c..0000000000 --- a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example/types.gen.ts +++ /dev/null @@ -1,50 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -export type ClientOptions = { - baseUrl: string; -}; - -export type Person = { - firstName?: string; - lastName?: string; - age?: number; -}; - -export type GetFooData = { - body?: never; - path?: never; - query?: never; - url: '/foo'; -}; - -export type GetFooResponses = { - /** - * OK - */ - 200: Person; -}; - -export type GetFooResponse = GetFooResponses[keyof GetFooResponses]; - -export type PostFooData = { - body: string; - path?: never; - query?: never; - url: '/foo'; -}; - -export type PostFooResponses = { - /** - * OK - */ - 200: { - fullName?: string; - age?: number; - }; - /** - * SUCCESSFUL - */ - 204: unknown; -}; - -export type PostFooResponse = PostFooResponses[keyof PostFooResponses]; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/servers/types.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/servers/types.gen.ts deleted file mode 100644 index b54728320a..0000000000 --- a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/servers/types.gen.ts +++ /dev/null @@ -1,21 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -export type ClientOptions = { - baseUrl: 'https://foo.com/v1' | (string & {}); -}; - -export type GetFooData = { - body?: never; - path?: never; - query?: never; - url: '/foo'; -}; - -export type GetFooResponses = { - /** - * OK - */ - 200: string; -}; - -export type GetFooResponse = GetFooResponses[keyof GetFooResponses]; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/default/types.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/default/types.gen.ts deleted file mode 100644 index 3287ee8737..0000000000 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/default/types.gen.ts +++ /dev/null @@ -1,2081 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -export type ClientOptions = { - baseUrl: 'http://localhost:3000/base' | (string & {}); -}; - -/** - * Model with number-only name - */ -export type _400 = string; - -export type ExternalRefA = ExternalSharedModel; - -export type ExternalRefB = ExternalSharedModel; - -/** - * Testing multiline comments in string: First line - * Second line - * - * Fourth line - */ -export type CamelCaseCommentWithBreaks = number; - -/** - * Testing multiline comments in string: First line - * Second line - * - * Fourth line - */ -export type CommentWithBreaks = number; - -/** - * Testing backticks in string: `backticks` and ```multiple backticks``` should work - */ -export type CommentWithBackticks = number; - -/** - * Testing backticks and quotes in string: `backticks`, 'quotes', "double quotes" and ```multiple backticks``` should work - */ -export type CommentWithBackticksAndQuotes = number; - -/** - * Testing slashes in string: \backwards\\\ and /forwards/// should work - */ -export type CommentWithSlashes = number; - -/** - * Testing expression placeholders in string: ${expression} should work - */ -export type CommentWithExpressionPlaceholders = number; - -/** - * Testing quotes in string: 'single quote''' and "double quotes""" should work - */ -export type CommentWithQuotes = number; - -/** - * Testing reserved characters in string: * inline * and ** inline ** should work - */ -export type CommentWithReservedCharacters = number; - -/** - * This is a simple number - */ -export type SimpleInteger = number; - -/** - * This is a simple boolean - */ -export type SimpleBoolean = boolean; - -/** - * This is a simple string - */ -export type SimpleString = string; - -/** - * A string with non-ascii (unicode) characters valid in typescript identifiers (æøåÆØÅöÔèÈ字符串) - */ -export type NonAsciiStringæøåÆøÅöôêÊ字符串 = string; - -/** - * This is a simple file - */ -export type SimpleFile = Blob | File; - -/** - * This is a simple reference - */ -export type SimpleReference = ModelWithString; - -/** - * This is a simple string - */ -export type SimpleStringWithPattern = string | null; - -/** - * This is a simple enum with strings - */ -export type EnumWithStrings = 'Success' | 'Warning' | 'Error' | '\'Single Quote\'' | '"Double Quotes"' | 'Non-ascii: øæåôöØÆÅÔÖ字符串'; - -export type EnumWithReplacedCharacters = '\'Single Quote\'' | '"Double Quotes"' | 'øæåôöØÆÅÔÖ字符串' | 3.1 | ''; - -/** - * This is a simple enum with numbers - */ -export type EnumWithNumbers = 1 | 2 | 3 | 1.1 | 1.2 | 1.3 | 100 | 200 | 300 | -100 | -200 | -300 | -1.1 | -1.2 | -1.3; - -/** - * Success=1,Warning=2,Error=3 - */ -export type EnumFromDescription = number; - -/** - * This is a simple enum with numbers - */ -export type EnumWithExtensions = 200 | 400 | 500; - -export type EnumWithXEnumNames = 0 | 1 | 2; - -/** - * This is a simple array with numbers - */ -export type ArrayWithNumbers = Array; - -/** - * This is a simple array with booleans - */ -export type ArrayWithBooleans = Array; - -/** - * This is a simple array with strings - */ -export type ArrayWithStrings = Array; - -/** - * This is a simple array with references - */ -export type ArrayWithReferences = Array; - -/** - * This is a simple array containing an array - */ -export type ArrayWithArray = Array>; - -/** - * This is a simple array with properties - */ -export type ArrayWithProperties = Array<{ - '16x16'?: CamelCaseCommentWithBreaks; - bar?: string; -}>; - -/** - * This is a simple array with any of properties - */ -export type ArrayWithAnyOfProperties = Array<{ - foo?: string; -} | { - bar?: string; -}>; - -export type AnyOfAnyAndNull = { - data?: unknown; -}; - -/** - * This is a simple array with any of properties - */ -export type AnyOfArrays = { - results?: Array<{ - foo?: string; - } | { - bar?: string; - }>; -}; - -/** - * This is a string dictionary - */ -export type DictionaryWithString = { - [key: string]: string; -}; - -export type DictionaryWithPropertiesAndAdditionalProperties = { - foo?: number; - bar?: boolean; - [key: string]: string | number | boolean | undefined; -}; - -/** - * This is a string reference - */ -export type DictionaryWithReference = { - [key: string]: ModelWithString; -}; - -/** - * This is a complex dictionary - */ -export type DictionaryWithArray = { - [key: string]: Array; -}; - -/** - * This is a string dictionary - */ -export type DictionaryWithDictionary = { - [key: string]: { - [key: string]: string; - }; -}; - -/** - * This is a complex dictionary - */ -export type DictionaryWithProperties = { - [key: string]: { - foo?: string; - bar?: string; - }; -}; - -/** - * This is a model with one number property - */ -export type ModelWithInteger = { - /** - * This is a simple number property - */ - prop?: number; -}; - -/** - * This is a model with one boolean property - */ -export type ModelWithBoolean = { - /** - * This is a simple boolean property - */ - prop?: boolean; -}; - -/** - * This is a model with one string property - */ -export type ModelWithString = { - /** - * This is a simple string property - */ - prop?: string; -}; - -/** - * This is a model with one string property - */ -export type ModelWithStringError = { - /** - * This is a simple string property - */ - prop?: string; -}; - -/** - * `Comment` or `VoiceComment`. The JSON object for adding voice comments to tickets is different. See [Adding voice comments to tickets](/documentation/ticketing/managing-tickets/adding-voice-comments-to-tickets) - */ -export type ModelFromZendesk = string; - -/** - * This is a model with one string property - */ -export type ModelWithNullableString = { - /** - * This is a simple string property - */ - nullableProp1?: string | null; - /** - * This is a simple string property - */ - nullableRequiredProp1: string | null; - /** - * This is a simple string property - */ - nullableProp2?: string | null; - /** - * This is a simple string property - */ - nullableRequiredProp2: string | null; - /** - * This is a simple enum with strings - */ - 'foo_bar-enum'?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; -}; - -/** - * This is a model with one enum - */ -export type ModelWithEnum = { - /** - * This is a simple enum with strings - */ - 'foo_bar-enum'?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; - /** - * These are the HTTP error code enums - */ - statusCode?: '100' | '200 FOO' | '300 FOO_BAR' | '400 foo-bar' | '500 foo.bar' | '600 foo&bar'; - /** - * Simple boolean enum - */ - bool?: true; -}; - -/** - * This is a model with one enum with escaped name - */ -export type ModelWithEnumWithHyphen = { - /** - * Foo-Bar-Baz-Qux - */ - 'foo-bar-baz-qux'?: '3.0'; -}; - -/** - * This is a model with one enum - */ -export type ModelWithEnumFromDescription = { - /** - * Success=1,Warning=2,Error=3 - */ - test?: number; -}; - -/** - * This is a model with nested enums - */ -export type ModelWithNestedEnums = { - dictionaryWithEnum?: { - [key: string]: 'Success' | 'Warning' | 'Error'; - }; - dictionaryWithEnumFromDescription?: { - [key: string]: number; - }; - arrayWithEnum?: Array<'Success' | 'Warning' | 'Error'>; - arrayWithDescription?: Array; - /** - * This is a simple enum with strings - */ - 'foo_bar-enum'?: 'Success' | 'Warning' | 'Error' | 'ØÆÅ字符串'; -}; - -/** - * This is a model with one property containing a reference - */ -export type ModelWithReference = { - prop?: ModelWithProperties; -}; - -/** - * This is a model with one property containing an array - */ -export type ModelWithArrayReadOnlyAndWriteOnly = { - prop?: Array; - propWithFile?: Array; - propWithNumber?: Array; -}; - -/** - * This is a model with one property containing an array - */ -export type ModelWithArray = { - prop?: Array; - propWithFile?: Array; - propWithNumber?: Array; -}; - -/** - * This is a model with one property containing a dictionary - */ -export type ModelWithDictionary = { - prop?: { - [key: string]: string; - }; -}; - -/** - * This is a deprecated model with a deprecated property - * - * @deprecated - */ -export type DeprecatedModel = { - /** - * This is a deprecated property - * - * @deprecated - */ - prop?: string; -}; - -/** - * This is a model with one property containing a circular reference - */ -export type ModelWithCircularReference = { - prop?: ModelWithCircularReference; -}; - -/** - * This is a model with one property with a 'one of' relationship - */ -export type CompositionWithOneOf = { - propA?: ModelWithString | ModelWithEnum | ModelWithArray | ModelWithDictionary; -}; - -/** - * This is a model with one property with a 'one of' relationship where the options are not $ref - */ -export type CompositionWithOneOfAnonymous = { - propA?: { - propA?: string; - } | string | number; -}; - -/** - * Circle - */ -export type ModelCircle = { - kind: string; - radius?: number; -}; - -/** - * Square - */ -export type ModelSquare = { - kind: string; - sideLength?: number; -}; - -/** - * This is a model with one property with a 'one of' relationship where the options are not $ref - */ -export type CompositionWithOneOfDiscriminator = ({ - kind: 'circle'; -} & ModelCircle) | ({ - kind: 'square'; -} & ModelSquare); - -/** - * This is a model with one property with a 'any of' relationship - */ -export type CompositionWithAnyOf = { - propA?: ModelWithString | ModelWithEnum | ModelWithArray | ModelWithDictionary; -}; - -/** - * This is a model with one property with a 'any of' relationship where the options are not $ref - */ -export type CompositionWithAnyOfAnonymous = { - propA?: { - propA?: string; - } | string | number; -}; - -/** - * This is a model with nested 'any of' property with a type null - */ -export type CompositionWithNestedAnyAndTypeNull = { - propA?: Array | Array; -}; - -export type _3eNum1Период = 'Bird' | 'Dog'; - -export type ConstValue = 'ConstValue'; - -/** - * This is a model with one property with a 'any of' relationship where the options are not $ref - */ -export type CompositionWithNestedAnyOfAndNull = { - propA?: Array<_3eNum1Период | ConstValue> | null; -}; - -/** - * This is a model with one property with a 'one of' relationship - */ -export type CompositionWithOneOfAndNullable = { - propA?: { - boolean?: boolean; - } | ModelWithEnum | ModelWithArray | ModelWithDictionary | null; -}; - -/** - * This is a model that contains a simple dictionary within composition - */ -export type CompositionWithOneOfAndSimpleDictionary = { - propA?: boolean | { - [key: string]: number; - }; -}; - -/** - * This is a model that contains a dictionary of simple arrays within composition - */ -export type CompositionWithOneOfAndSimpleArrayDictionary = { - propA?: boolean | { - [key: string]: Array; - }; -}; - -/** - * This is a model that contains a dictionary of complex arrays (composited) within composition - */ -export type CompositionWithOneOfAndComplexArrayDictionary = { - propA?: boolean | { - [key: string]: Array; - }; -}; - -/** - * This is a model with one property with a 'all of' relationship - */ -export type CompositionWithAllOfAndNullable = { - propA?: ({ - boolean?: boolean; - } & ModelWithEnum & ModelWithArray & ModelWithDictionary) | null; -}; - -/** - * This is a model with one property with a 'any of' relationship - */ -export type CompositionWithAnyOfAndNullable = { - propA?: { - boolean?: boolean; - } | ModelWithEnum | ModelWithArray | ModelWithDictionary | null; -}; - -/** - * This is a base model with two simple optional properties - */ -export type CompositionBaseModel = { - firstName?: string; - lastname?: string; -}; - -/** - * This is a model that extends the base model - */ -export type CompositionExtendedModel = CompositionBaseModel & { - age: number; - firstName: string; - lastname: string; -}; - -/** - * This is a model with one nested property - */ -export type ModelWithProperties = { - required: string; - readonly requiredAndReadOnly: string; - requiredAndNullable: string | null; - string?: string; - number?: number; - boolean?: boolean; - reference?: ModelWithString; - 'property with space'?: string; - default?: string; - try?: string; - readonly '@namespace.string'?: string; - readonly '@namespace.integer'?: number; -}; - -/** - * This is a model with one nested property - */ -export type ModelWithNestedProperties = { - readonly first: { - readonly second: { - readonly third: string | null; - } | null; - } | null; -}; - -/** - * This is a model with duplicated properties - */ -export type ModelWithDuplicateProperties = { - prop?: ModelWithString; -}; - -/** - * This is a model with ordered properties - */ -export type ModelWithOrderedProperties = { - zebra?: string; - apple?: string; - hawaii?: string; -}; - -/** - * This is a model with duplicated imports - */ -export type ModelWithDuplicateImports = { - propA?: ModelWithString; - propB?: ModelWithString; - propC?: ModelWithString; -}; - -/** - * This is a model that extends another model - */ -export type ModelThatExtends = ModelWithString & { - propExtendsA?: string; - propExtendsB?: ModelWithString; -}; - -/** - * This is a model that extends another model - */ -export type ModelThatExtendsExtends = ModelWithString & ModelThatExtends & { - propExtendsC?: string; - propExtendsD?: ModelWithString; -}; - -/** - * This is a model that contains a some patterns - */ -export type ModelWithPattern = { - key: string; - name: string; - readonly enabled?: boolean; - readonly modified?: string; - id?: string; - text?: string; - patternWithSingleQuotes?: string; - patternWithNewline?: string; - patternWithBacktick?: string; - patternWithUnicode?: string; -}; - -export type File = { - /** - * Id - */ - readonly id?: string; - /** - * Updated at - */ - readonly updated_at?: string; - /** - * Created at - */ - readonly created_at?: string; - /** - * Mime - */ - mime: string; - /** - * File - */ - readonly file?: string; -}; - -export type Default = { - name?: string; -}; - -export type Pageable = { - page?: number; - size?: number; - sort?: Array; -}; - -/** - * This is a free-form object without additionalProperties. - */ -export type FreeFormObjectWithoutAdditionalProperties = { - [key: string]: unknown; -}; - -/** - * This is a free-form object with additionalProperties: true. - */ -export type FreeFormObjectWithAdditionalPropertiesEqTrue = { - [key: string]: unknown; -}; - -/** - * This is a free-form object with additionalProperties: {}. - */ -export type FreeFormObjectWithAdditionalPropertiesEqEmptyObject = { - [key: string]: unknown; -}; - -export type ModelWithConst = { - String?: 'String'; - number?: 0; - null?: unknown; - withType?: 'Some string'; -}; - -/** - * This is a model with one property and additionalProperties: true - */ -export type ModelWithAdditionalPropertiesEqTrue = { - /** - * This is a simple string property - */ - prop?: string; - [key: string]: unknown; -}; - -export type NestedAnyOfArraysNullable = { - nullableArray?: Array | null; -}; - -export type CompositionWithOneOfAndProperties = ({ - foo: SimpleParameter; -} | { - bar: NonAsciiStringæøåÆøÅöôêÊ字符串; -}) & { - baz: number | null; - qux: number; -}; - -/** - * An object that can be null - */ -export type NullableObject = { - foo?: string; -} | null; - -/** - * Some % character - */ -export type CharactersInDescription = string; - -export type ModelWithNullableObject = { - data?: NullableObject; -}; - -/** - * An object with additional properties that can be null - */ -export type ModelWithAdditionalPropertiesRef = { - [key: string]: NullableObject | null; -}; - -export type ModelWithOneOfEnum = { - foo: 'Bar'; -} | { - foo: 'Baz'; -} | { - foo: 'Qux'; -} | { - content: string; - foo: 'Quux'; -} | { - content: [ - string, - string - ]; - foo: 'Corge'; -}; - -export type ModelWithNestedArrayEnumsDataFoo = 'foo' | 'bar'; - -export type ModelWithNestedArrayEnumsDataBar = 'baz' | 'qux'; - -export type ModelWithNestedArrayEnumsData = { - foo?: Array; - bar?: Array; -}; - -export type ModelWithNestedArrayEnums = { - array_strings?: Array; - data?: ModelWithNestedArrayEnumsData; -}; - -export type ModelWithNestedCompositionEnums = { - foo?: ModelWithNestedArrayEnumsDataFoo; -}; - -export type ModelWithReadOnlyAndWriteOnly = { - foo: string; - readonly bar: string; -}; - -export type ModelWithConstantSizeArray = [ - number, - number -]; - -export type ModelWithAnyOfConstantSizeArray = [ - number | string, - number | string, - number | string -]; - -export type ModelWithPrefixItemsConstantSizeArray = Array; - -export type ModelWithAnyOfConstantSizeArrayNullable = [ - number | null | string, - number | null | string, - number | null | string -]; - -export type ModelWithAnyOfConstantSizeArrayWithNSizeAndOptions = [ - number | Import, - number | Import -]; - -export type ModelWithAnyOfConstantSizeArrayAndIntersect = [ - number & string, - number & string -]; - -export type ModelWithNumericEnumUnion = { - /** - * Период - */ - value?: -10 | -1 | 0 | 1 | 3 | 6 | 12; -}; - -/** - * Some description with `back ticks` - */ -export type ModelWithBackticksInDescription = { - /** - * The template `that` should be used for parsing and importing the contents of the CSV file. - * - *

There is one placeholder currently supported:

  • ${x} - refers to the n-th column in the CSV file, e.g. ${1}, ${2}, ...)

Example of a correct JSON template:

- *
-     * [
-     * {
-     * "resourceType": "Asset",
-     * "identifier": {
-     * "name": "${1}",
-     * "domain": {
-     * "name": "${2}",
-     * "community": {
-     * "name": "Some Community"
-     * }
-     * }
-     * },
-     * "attributes" : {
-     * "00000000-0000-0000-0000-000000003115" : [ {
-     * "value" : "${3}"
-     * } ],
-     * "00000000-0000-0000-0000-000000000222" : [ {
-     * "value" : "${4}"
-     * } ]
-     * }
-     * }
-     * ]
-     * 
- */ - template?: string; -}; - -export type ModelWithOneOfAndProperties = (SimpleParameter | NonAsciiStringæøåÆøÅöôêÊ字符串) & { - baz: number | null; - qux: number; -}; - -/** - * Model used to test deduplication strategy (unused) - */ -export type ParameterSimpleParameterUnused = string; - -/** - * Model used to test deduplication strategy - */ -export type PostServiceWithEmptyTagResponse = string; - -/** - * Model used to test deduplication strategy - */ -export type PostServiceWithEmptyTagResponse2 = string; - -/** - * Model used to test deduplication strategy - */ -export type DeleteFooData = string; - -/** - * Model used to test deduplication strategy - */ -export type DeleteFooData2 = string; - -/** - * Model with restricted keyword name - */ -export type Import = string; - -export type SchemaWithFormRestrictedKeys = { - description?: string; - 'x-enum-descriptions'?: string; - 'x-enum-varnames'?: string; - 'x-enumNames'?: string; - title?: string; - object?: { - description?: string; - 'x-enum-descriptions'?: string; - 'x-enum-varnames'?: string; - 'x-enumNames'?: string; - title?: string; - }; - array?: Array<{ - description?: string; - 'x-enum-descriptions'?: string; - 'x-enum-varnames'?: string; - 'x-enumNames'?: string; - title?: string; - }>; -}; - -/** - * This schema was giving PascalCase transformations a hard time - */ -export type IoK8sApimachineryPkgApisMetaV1DeleteOptions = { - /** - * Must be fulfilled before a deletion is carried out. If not possible, a 409 Conflict status will be returned. - */ - preconditions?: IoK8sApimachineryPkgApisMetaV1Preconditions; -}; - -/** - * This schema was giving PascalCase transformations a hard time - */ -export type IoK8sApimachineryPkgApisMetaV1Preconditions = { - /** - * Specifies the target ResourceVersion - */ - resourceVersion?: string; - /** - * Specifies the target UID. - */ - uid?: string; -}; - -export type AdditionalPropertiesUnknownIssue = { - [key: string]: string | number; -}; - -export type AdditionalPropertiesUnknownIssue2 = { - [key: string]: string | number; -}; - -export type AdditionalPropertiesUnknownIssue3 = string & { - entries: { - [key: string]: AdditionalPropertiesUnknownIssue; - }; -}; - -export type AdditionalPropertiesIntegerIssue = { - value: number; - [key: string]: number; -}; - -export type OneOfAllOfIssue = ((ConstValue | GenericSchemaDuplicateIssue1SystemBoolean) & _3eNum1Период) | GenericSchemaDuplicateIssue1SystemString; - -export type GenericSchemaDuplicateIssue1SystemBoolean = { - item?: boolean; - error?: string | null; - readonly hasError?: boolean; - data?: { - [key: string]: never; - }; -}; - -export type GenericSchemaDuplicateIssue1SystemString = { - item?: string | null; - error?: string | null; - readonly hasError?: boolean; -}; - -export type ExternalSharedModel = { - id: string; - name?: string; -}; - -/** - * This is a model with one property containing a reference - */ -export type ModelWithReferenceWritable = { - prop?: ModelWithPropertiesWritable; -}; - -/** - * This is a model with one property containing an array - */ -export type ModelWithArrayReadOnlyAndWriteOnlyWritable = { - prop?: Array; - propWithFile?: Array; - propWithNumber?: Array; -}; - -/** - * This is a model with one nested property - */ -export type ModelWithPropertiesWritable = { - required: string; - requiredAndNullable: string | null; - string?: string; - number?: number; - boolean?: boolean; - reference?: ModelWithString; - 'property with space'?: string; - default?: string; - try?: string; -}; - -/** - * This is a model that contains a some patterns - */ -export type ModelWithPatternWritable = { - key: string; - name: string; - id?: string; - text?: string; - patternWithSingleQuotes?: string; - patternWithNewline?: string; - patternWithBacktick?: string; - patternWithUnicode?: string; -}; - -export type FileWritable = { - /** - * Mime - */ - mime: string; -}; - -export type ModelWithReadOnlyAndWriteOnlyWritable = { - foo: string; - baz: string; -}; - -export type ModelWithAnyOfConstantSizeArrayWithNSizeAndOptionsWritable = [ - number | Import, - number | Import -]; - -export type AdditionalPropertiesUnknownIssueWritable = { - [key: string]: string | number; -}; - -export type OneOfAllOfIssueWritable = ((ConstValue | GenericSchemaDuplicateIssue1SystemBoolean) & _3eNum1Период) | GenericSchemaDuplicateIssue1SystemString; - -export type GenericSchemaDuplicateIssue1SystemBooleanWritable = { - item?: boolean; - error?: string | null; - data?: { - [key: string]: never; - }; -}; - -export type GenericSchemaDuplicateIssue1SystemStringWritable = { - item?: string | null; - error?: string | null; -}; - -/** - * This is a reusable parameter - */ -export type SimpleParameter = string; - -/** - * Parameter with illegal characters - */ -export type XFooBar = ModelWithString; - -export type SimpleRequestBody = ModelWithString; - -export type SimpleFormData = ModelWithString; - -export type ExportData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/no+tag'; -}; - -export type PatchApiVbyApiVersionNoTagData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/no+tag'; -}; - -export type PatchApiVbyApiVersionNoTagResponses = { - /** - * OK - */ - default: unknown; -}; - -export type ImportData = { - body: ModelWithReadOnlyAndWriteOnlyWritable | ModelWithArrayReadOnlyAndWriteOnlyWritable; - path?: never; - query?: never; - url: '/api/v{api-version}/no+tag'; -}; - -export type ImportResponses = { - /** - * Success - */ - 200: ModelFromZendesk; - /** - * Default success response - */ - default: ModelWithReadOnlyAndWriteOnly; -}; - -export type ImportResponse = ImportResponses[keyof ImportResponses]; - -export type FooWowData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/no+tag'; -}; - -export type FooWowResponses = { - /** - * OK - */ - default: unknown; -}; - -export type ApiVVersionODataControllerCountData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/simple/$count'; -}; - -export type ApiVVersionODataControllerCountResponses = { - /** - * Success - */ - 200: ModelFromZendesk; -}; - -export type ApiVVersionODataControllerCountResponse = ApiVVersionODataControllerCountResponses[keyof ApiVVersionODataControllerCountResponses]; - -export type GetApiVbyApiVersionSimpleOperationData = { - body?: never; - path: { - /** - * foo in method - */ - foo_param: string; - }; - query?: never; - url: '/api/v{api-version}/simple:operation'; -}; - -export type GetApiVbyApiVersionSimpleOperationErrors = { - /** - * Default error response - */ - default: ModelWithBoolean; -}; - -export type GetApiVbyApiVersionSimpleOperationError = GetApiVbyApiVersionSimpleOperationErrors[keyof GetApiVbyApiVersionSimpleOperationErrors]; - -export type GetApiVbyApiVersionSimpleOperationResponses = { - /** - * Response is a simple number - */ - 200: number; -}; - -export type GetApiVbyApiVersionSimpleOperationResponse = GetApiVbyApiVersionSimpleOperationResponses[keyof GetApiVbyApiVersionSimpleOperationResponses]; - -export type DeleteCallWithoutParametersAndResponseData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/simple'; -}; - -export type GetCallWithoutParametersAndResponseData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/simple'; -}; - -export type HeadCallWithoutParametersAndResponseData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/simple'; -}; - -export type OptionsCallWithoutParametersAndResponseData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/simple'; -}; - -export type PatchCallWithoutParametersAndResponseData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/simple'; -}; - -export type PostCallWithoutParametersAndResponseData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/simple'; -}; - -export type PutCallWithoutParametersAndResponseData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/simple'; -}; - -export type DeleteFooData3 = { - body?: never; - headers: { - /** - * Parameter with illegal characters - */ - 'x-Foo-Bar': ModelWithString; - }; - path: { - /** - * foo in method - */ - foo_param: string; - /** - * bar in method - */ - BarParam: string; - }; - query?: never; - url: '/api/v{api-version}/foo/{foo_param}/bar/{BarParam}'; -}; - -export type CallWithDescriptionsData = { - body?: never; - path?: never; - query?: { - /** - * Testing multiline comments in string: First line - * Second line - * - * Fourth line - */ - parameterWithBreaks?: string; - /** - * Testing backticks in string: `backticks` and ```multiple backticks``` should work - */ - parameterWithBackticks?: string; - /** - * Testing slashes in string: \backwards\\\ and /forwards/// should work - */ - parameterWithSlashes?: string; - /** - * Testing expression placeholders in string: ${expression} should work - */ - parameterWithExpressionPlaceholders?: string; - /** - * Testing quotes in string: 'single quote''' and "double quotes""" should work - */ - parameterWithQuotes?: string; - /** - * Testing reserved characters in string: * inline * and ** inline ** should work - */ - parameterWithReservedCharacters?: string; - }; - url: '/api/v{api-version}/descriptions'; -}; - -export type DeprecatedCallData = { - body?: never; - headers: { - /** - * This parameter is deprecated - * - * @deprecated - */ - parameter: DeprecatedModel | null; - }; - path?: never; - query?: never; - url: '/api/v{api-version}/parameters/deprecated'; -}; - -export type CallWithParametersData = { - /** - * This is the parameter that goes into the body - */ - body: { - [key: string]: unknown; - } | null; - headers: { - /** - * This is the parameter that goes into the header - */ - parameterHeader: string | null; - }; - path: { - /** - * This is the parameter that goes into the path - */ - parameterPath: string | null; - /** - * api-version should be required in standalone clients - */ - 'api-version': string | null; - }; - query: { - foo_ref_enum?: ModelWithNestedArrayEnumsDataFoo; - foo_all_of_enum: ModelWithNestedArrayEnumsDataFoo; - /** - * This is the parameter that goes into the query params - */ - cursor: string | null; - }; - url: '/api/v{api-version}/parameters/{parameterPath}'; -}; - -export type CallWithWeirdParameterNamesData = { - /** - * This is the parameter that goes into the body - */ - body: ModelWithString | null; - headers: { - /** - * This is the parameter that goes into the request header - */ - 'parameter.header': string | null; - }; - path: { - /** - * This is the parameter that goes into the path - */ - 'parameter.path.1'?: string; - /** - * This is the parameter that goes into the path - */ - 'parameter-path-2'?: string; - /** - * This is the parameter that goes into the path - */ - 'PARAMETER-PATH-3'?: string; - /** - * api-version should be required in standalone clients - */ - 'api-version': string | null; - }; - query: { - /** - * This is the parameter with a reserved keyword - */ - default?: string; - /** - * This is the parameter that goes into the request query params - */ - 'parameter-query': string | null; - }; - url: '/api/v{api-version}/parameters/{parameter.path.1}/{parameter-path-2}/{PARAMETER-PATH-3}'; -}; - -export type GetCallWithOptionalParamData = { - /** - * This is a required parameter - */ - body: ModelWithOneOfEnum; - path?: never; - query?: { - /** - * This is an optional parameter - */ - page?: number; - }; - url: '/api/v{api-version}/parameters'; -}; - -export type PostCallWithOptionalParamData = { - /** - * This is an optional parameter - */ - body?: { - offset?: number | null; - }; - path?: never; - query: { - /** - * This is a required parameter - */ - parameter: Pageable; - }; - url: '/api/v{api-version}/parameters'; -}; - -export type PostCallWithOptionalParamResponses = { - /** - * Response is a simple number - */ - 200: number; - /** - * Success - */ - 204: void; -}; - -export type PostCallWithOptionalParamResponse = PostCallWithOptionalParamResponses[keyof PostCallWithOptionalParamResponses]; - -export type PostApiVbyApiVersionRequestBodyData = { - /** - * A reusable request body - */ - body?: SimpleRequestBody; - path?: never; - query?: { - /** - * This is a reusable parameter - */ - parameter?: string; - }; - url: '/api/v{api-version}/requestBody'; -}; - -export type PostApiVbyApiVersionFormDataData = { - /** - * A reusable request body - */ - body?: SimpleFormData; - path?: never; - query?: { - /** - * This is a reusable parameter - */ - parameter?: string; - }; - url: '/api/v{api-version}/formData'; -}; - -export type CallWithDefaultParametersData = { - body?: never; - path?: never; - query?: { - /** - * This is a simple string with default value - */ - parameterString?: string | null; - /** - * This is a simple number with default value - */ - parameterNumber?: number | null; - /** - * This is a simple boolean with default value - */ - parameterBoolean?: boolean | null; - /** - * This is a simple enum with default value - */ - parameterEnum?: 'Success' | 'Warning' | 'Error'; - /** - * This is a simple model with default value - */ - parameterModel?: ModelWithString | null; - }; - url: '/api/v{api-version}/defaults'; -}; - -export type CallWithDefaultOptionalParametersData = { - body?: never; - path?: never; - query?: { - /** - * This is a simple string that is optional with default value - */ - parameterString?: string; - /** - * This is a simple number that is optional with default value - */ - parameterNumber?: number; - /** - * This is a simple boolean that is optional with default value - */ - parameterBoolean?: boolean; - /** - * This is a simple enum that is optional with default value - */ - parameterEnum?: 'Success' | 'Warning' | 'Error'; - /** - * This is a simple model that is optional with default value - */ - parameterModel?: ModelWithString; - }; - url: '/api/v{api-version}/defaults'; -}; - -export type CallToTestOrderOfParamsData = { - body?: never; - path?: never; - query: { - /** - * This is a optional string with default - */ - parameterOptionalStringWithDefault?: string; - /** - * This is a optional string with empty default - */ - parameterOptionalStringWithEmptyDefault?: string; - /** - * This is a optional string with no default - */ - parameterOptionalStringWithNoDefault?: string; - /** - * This is a string with default - */ - parameterStringWithDefault: string; - /** - * This is a string with empty default - */ - parameterStringWithEmptyDefault: string; - /** - * This is a string with no default - */ - parameterStringWithNoDefault: string; - /** - * This is a string that can be null with no default - */ - parameterStringNullableWithNoDefault?: string | null; - /** - * This is a string that can be null with default - */ - parameterStringNullableWithDefault?: string | null; - }; - url: '/api/v{api-version}/defaults'; -}; - -export type DuplicateNameData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/duplicate'; -}; - -export type DuplicateName2Data = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/duplicate'; -}; - -export type DuplicateName3Data = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/duplicate'; -}; - -export type DuplicateName4Data = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/duplicate'; -}; - -export type CallWithNoContentResponseData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/no-content'; -}; - -export type CallWithNoContentResponseResponses = { - /** - * Success - */ - 204: void; -}; - -export type CallWithNoContentResponseResponse = CallWithNoContentResponseResponses[keyof CallWithNoContentResponseResponses]; - -export type CallWithResponseAndNoContentResponseData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/multiple-tags/response-and-no-content'; -}; - -export type CallWithResponseAndNoContentResponseResponses = { - /** - * Response is a simple number - */ - 200: number; - /** - * Success - */ - 204: void; -}; - -export type CallWithResponseAndNoContentResponseResponse = CallWithResponseAndNoContentResponseResponses[keyof CallWithResponseAndNoContentResponseResponses]; - -export type DummyAData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/multiple-tags/a'; -}; - -export type DummyAResponses = { - 200: _400; -}; - -export type DummyAResponse = DummyAResponses[keyof DummyAResponses]; - -export type DummyBData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/multiple-tags/b'; -}; - -export type DummyBResponses = { - /** - * Success - */ - 204: void; -}; - -export type DummyBResponse = DummyBResponses[keyof DummyBResponses]; - -export type CallWithResponseData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/response'; -}; - -export type CallWithResponseResponses = { - default: Import; -}; - -export type CallWithResponseResponse = CallWithResponseResponses[keyof CallWithResponseResponses]; - -export type CallWithDuplicateResponsesData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/response'; -}; - -export type CallWithDuplicateResponsesErrors = { - /** - * Message for 500 error - */ - 500: ModelWithStringError; - /** - * Message for 501 error - */ - 501: ModelWithStringError; - /** - * Message for 502 error - */ - 502: ModelWithStringError; - /** - * Message for 4XX errors - */ - '4XX': DictionaryWithArray; - /** - * Default error response - */ - default: ModelWithBoolean; -}; - -export type CallWithDuplicateResponsesError = CallWithDuplicateResponsesErrors[keyof CallWithDuplicateResponsesErrors]; - -export type CallWithDuplicateResponsesResponses = { - /** - * Message for 200 response - */ - 200: ModelWithBoolean & ModelWithInteger; - /** - * Message for 201 response - */ - 201: ModelWithString; - /** - * Message for 202 response - */ - 202: ModelWithString; -}; - -export type CallWithDuplicateResponsesResponse = CallWithDuplicateResponsesResponses[keyof CallWithDuplicateResponsesResponses]; - -export type CallWithResponsesData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/response'; -}; - -export type CallWithResponsesErrors = { - /** - * Message for 500 error - */ - 500: ModelWithStringError; - /** - * Message for 501 error - */ - 501: ModelWithStringError; - /** - * Message for 502 error - */ - 502: ModelWithStringError; - /** - * Message for default response - */ - default: ModelWithStringError; -}; - -export type CallWithResponsesError = CallWithResponsesErrors[keyof CallWithResponsesErrors]; - -export type CallWithResponsesResponses = { - /** - * Message for 200 response - */ - 200: { - readonly '@namespace.string'?: string; - readonly '@namespace.integer'?: number; - readonly value?: Array; - }; - /** - * Message for 201 response - */ - 201: ModelThatExtends; - /** - * Message for 202 response - */ - 202: ModelThatExtendsExtends; -}; - -export type CallWithResponsesResponse = CallWithResponsesResponses[keyof CallWithResponsesResponses]; - -export type CollectionFormatData = { - body?: never; - path?: never; - query: { - /** - * This is an array parameter that is sent as csv format (comma-separated values) - */ - parameterArrayCSV: Array | null; - /** - * This is an array parameter that is sent as ssv format (space-separated values) - */ - parameterArraySSV: Array | null; - /** - * This is an array parameter that is sent as tsv format (tab-separated values) - */ - parameterArrayTSV: Array | null; - /** - * This is an array parameter that is sent as pipes format (pipe-separated values) - */ - parameterArrayPipes: Array | null; - /** - * This is an array parameter that is sent as multi format (multiple parameter instances) - */ - parameterArrayMulti: Array | null; - }; - url: '/api/v{api-version}/collectionFormat'; -}; - -export type TypesData = { - body?: never; - path?: { - /** - * This is a number parameter - */ - id?: number; - }; - query: { - /** - * This is a number parameter - */ - parameterNumber: number; - /** - * This is a string parameter - */ - parameterString: string | null; - /** - * This is a boolean parameter - */ - parameterBoolean: boolean | null; - /** - * This is an object parameter - */ - parameterObject: { - [key: string]: unknown; - } | null; - /** - * This is an array parameter - */ - parameterArray: Array | null; - /** - * This is a dictionary parameter - */ - parameterDictionary: { - [key: string]: unknown; - } | null; - /** - * This is an enum parameter - */ - parameterEnum: 'Success' | 'Warning' | 'Error'; - }; - url: '/api/v{api-version}/types'; -}; - -export type TypesResponses = { - /** - * Response is a simple number - */ - 200: number; - /** - * Response is a simple string - */ - 201: string; - /** - * Response is a simple boolean - */ - 202: boolean; - /** - * Response is a simple object - */ - 203: { - [key: string]: unknown; - }; -}; - -export type TypesResponse = TypesResponses[keyof TypesResponses]; - -export type UploadFileData = { - body: Blob | File; - path: { - /** - * api-version should be required in standalone clients - */ - 'api-version': string | null; - }; - query?: never; - url: '/api/v{api-version}/upload'; -}; - -export type UploadFileResponses = { - 200: boolean; -}; - -export type UploadFileResponse = UploadFileResponses[keyof UploadFileResponses]; - -export type FileResponseData = { - body?: never; - path: { - id: string; - /** - * api-version should be required in standalone clients - */ - 'api-version': string; - }; - query?: never; - url: '/api/v{api-version}/file/{id}'; -}; - -export type FileResponseResponses = { - /** - * Success - */ - 200: Blob | File; -}; - -export type FileResponseResponse = FileResponseResponses[keyof FileResponseResponses]; - -export type ComplexTypesData = { - body?: never; - path?: never; - query: { - /** - * Parameter containing object - */ - parameterObject: { - first?: { - second?: { - third?: string; - }; - }; - }; - /** - * Parameter containing reference - */ - parameterReference: ModelWithString; - }; - url: '/api/v{api-version}/complex'; -}; - -export type ComplexTypesErrors = { - /** - * 400 `server` error - */ - 400: unknown; - /** - * 500 server error - */ - 500: unknown; -}; - -export type ComplexTypesResponses = { - /** - * Successful response - */ - 200: Array; -}; - -export type ComplexTypesResponse = ComplexTypesResponses[keyof ComplexTypesResponses]; - -export type MultipartResponseData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/multipart'; -}; - -export type MultipartResponseResponses = { - /** - * OK - */ - 200: { - file?: Blob | File; - metadata?: { - foo?: string; - bar?: string; - }; - }; -}; - -export type MultipartResponseResponse = MultipartResponseResponses[keyof MultipartResponseResponses]; - -export type MultipartRequestData = { - body?: { - content?: Blob | File; - data?: ModelWithString | null; - }; - path?: never; - query?: never; - url: '/api/v{api-version}/multipart'; -}; - -export type ComplexParamsData = { - body?: { - readonly key: string | null; - name: string | null; - enabled?: boolean; - type: 'Monkey' | 'Horse' | 'Bird'; - listOfModels?: Array | null; - listOfStrings?: Array | null; - parameters: ModelWithString | ModelWithEnum | ModelWithArray | ModelWithDictionary; - readonly user?: { - readonly id?: number; - readonly name?: string | null; - }; - }; - path: { - id: number; - /** - * api-version should be required in standalone clients - */ - 'api-version': string; - }; - query?: never; - url: '/api/v{api-version}/complex/{id}'; -}; - -export type ComplexParamsResponses = { - /** - * Success - */ - 200: ModelWithString; -}; - -export type ComplexParamsResponse = ComplexParamsResponses[keyof ComplexParamsResponses]; - -export type CallWithResultFromHeaderData = { - body?: never; - path?: never; - query?: never; - url: '/api/v{api-version}/header'; -}; - -export type CallWithResultFromHeaderErrors = { - /** - * 400 server error - */ - 400: unknown; - /** - * 500 server error - */ - 500: unknown; -}; - -export type CallWithResultFromHeaderResponses = { - /** - * Successful response - */ - 200: unknown; -}; - -export type TestErrorCodeData = { - body?: never; - path?: never; - query: { - /** - * Status code to return - */ - status: number; - }; - url: '/api/v{api-version}/error'; -}; - -export type TestErrorCodeErrors = { - /** - * Custom message: Internal Server Error - */ - 500: unknown; - /** - * Custom message: Not Implemented - */ - 501: unknown; - /** - * Custom message: Bad Gateway - */ - 502: unknown; - /** - * Custom message: Service Unavailable - */ - 503: unknown; -}; - -export type TestErrorCodeResponses = { - /** - * Custom message: Successful response - */ - 200: unknown; -}; - -export type NonAsciiæøåÆøÅöôêÊ字符串Data = { - body?: never; - path?: never; - query: { - /** - * Dummy input param - */ - nonAsciiParamæøåÆØÅöôêÊ: number; - }; - url: '/api/v{api-version}/non-ascii-æøåÆØÅöôêÊ字符串'; -}; - -export type NonAsciiæøåÆøÅöôêÊ字符串Responses = { - /** - * Successful response - */ - 200: Array; -}; - -export type NonAsciiæøåÆøÅöôêÊ字符串Response = NonAsciiæøåÆøÅöôêÊ字符串Responses[keyof NonAsciiæøåÆøÅöôêÊ字符串Responses]; - -export type PutWithFormUrlEncodedData = { - body: ArrayWithStrings; - path?: never; - query?: never; - url: '/api/v{api-version}/non-ascii-æøåÆØÅöôêÊ字符串'; -}; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example-disabled/index.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example-disabled/index.ts deleted file mode 100644 index b545604fba..0000000000 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example-disabled/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -export type { ClientOptions, GetFooData, GetFooResponse, GetFooResponses, Person, PostFooData, PostFooResponse, PostFooResponses } from './types.gen'; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example-disabled/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example-disabled/msw.gen.ts deleted file mode 100644 index a2e510c260..0000000000 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example-disabled/msw.gen.ts +++ /dev/null @@ -1,75 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions } from 'msw'; - -import type { GetFooResponses, PostFooData, PostFooResponses } from './types.gen'; - -const resolveToNull = () => new HttpResponse(null); - -type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; - -type ToResponseUnion = { - [K in Extract]: { - status: K; - result: T[K]; - }; -}[Extract]; - -export type SingleHandlerFactories = { - getFooMock: HttpHandlerFactory<{ - result: GetFooResponses[200]; - status?: 200; - } | HttpResponseResolver>; - postFooMock: HttpHandlerFactory<{ - result: PostFooResponses[200]; - status?: 200; - } | ToResponseUnion | HttpResponseResolver>; -}; - -export type GetAllMocksOptions = { - onMissingMock?: 'error' | 'skip'; - overrides?: { - [K in keyof SingleHandlerFactories]?: Parameters[0]; - }; -}; - -export type MswHandlerFactory = SingleHandlerFactories & { - getAllMocks: (options?: GetAllMocksOptions) => Array; -}; - -export const createMswHandlerFactory = (config?: { - baseUrl?: string; -}): MswHandlerFactory => { - const baseUrl = config?.baseUrl ?? ''; - const mocks: SingleHandlerFactories = { - getFooMock: (res, options) => http.get(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - postFooMock: (res, options) => http.post(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options) - }; - const getAllMocks = (options?: GetAllMocksOptions): Array => { - const onMissingMock = options?.onMissingMock ?? 'skip'; - const overrides = options?.overrides; - const handlers: Array = []; - const addRequiredHandler = (handler: (value: Value | (() => HttpResponse)) => HttpHandler, override: Value | undefined) => { - if (override != null) { - handlers.push(handler(override)); - } - else { - if (onMissingMock === 'error') { - handlers.push(handler(() => new HttpResponse('[heyapi-msw] The mock of this request is not implemented.', { status: 501 }))); - } - } - }; - addRequiredHandler(mocks.getFooMock, overrides?.getFooMock); - addRequiredHandler(mocks.postFooMock, overrides?.postFooMock); - return handlers; - }; - return { ...mocks, getAllMocks }; -}; - -const _defaults = createMswHandlerFactory({ baseUrl: '*' }); - -export const getFooMock = _defaults.getFooMock; - -export const postFooMock = _defaults.postFooMock; - -export const getAllMocks = _defaults.getAllMocks; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example-disabled/types.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example-disabled/types.gen.ts deleted file mode 100644 index 9d0535a2e7..0000000000 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example-disabled/types.gen.ts +++ /dev/null @@ -1,50 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -export type ClientOptions = { - baseUrl: `${string}://${string}` | (string & {}); -}; - -export type Person = { - firstName?: string; - lastName?: string; - age?: number; -}; - -export type GetFooData = { - body?: never; - path?: never; - query?: never; - url: '/foo'; -}; - -export type GetFooResponses = { - /** - * OK - */ - 200: Person; -}; - -export type GetFooResponse = GetFooResponses[keyof GetFooResponses]; - -export type PostFooData = { - body: string; - path?: never; - query?: never; - url: '/foo'; -}; - -export type PostFooResponses = { - /** - * OK - */ - 200: { - fullName?: string; - age?: number; - }; - /** - * SUCCESSFUL - */ - 204: void; -}; - -export type PostFooResponse = PostFooResponses[keyof PostFooResponses]; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example/index.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example/index.ts deleted file mode 100644 index b545604fba..0000000000 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -export type { ClientOptions, GetFooData, GetFooResponse, GetFooResponses, Person, PostFooData, PostFooResponse, PostFooResponses } from './types.gen'; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example/msw.gen.ts deleted file mode 100644 index 90f967fa06..0000000000 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example/msw.gen.ts +++ /dev/null @@ -1,81 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions } from 'msw'; - -import type { GetFooResponses, PostFooData, PostFooResponses } from './types.gen'; - -const resolveToNull = () => new HttpResponse(null); - -type OptionalHttpHandlerFactory = (responseOrResolver?: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; - -type ToResponseUnion = { - [K in Extract]: { - status: K; - result: T[K]; - }; -}[Extract]; - -type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; - -export type SingleHandlerFactories = { - getFooMock: OptionalHttpHandlerFactory<{ - result: GetFooResponses[200]; - status?: 200; - } | HttpResponseResolver>; - postFooMock: HttpHandlerFactory<{ - result: PostFooResponses[200]; - status?: 200; - } | ToResponseUnion | HttpResponseResolver>; -}; - -export type GetAllMocksOptions = { - onMissingMock?: 'error' | 'skip'; - overrides?: { - [K in keyof SingleHandlerFactories]?: Parameters[0]; - }; -}; - -export type MswHandlerFactory = SingleHandlerFactories & { - getAllMocks: (options?: GetAllMocksOptions) => Array; -}; - -export const createMswHandlerFactory = (config?: { - baseUrl?: string; -}): MswHandlerFactory => { - const baseUrl = config?.baseUrl ?? ''; - const mocks: SingleHandlerFactories = { - getFooMock: (res = { result: { - firstName: 'Marry', - lastName: 'Jane', - age: 30 - }, status: 200 }, options) => http.get(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - postFooMock: (res, options) => http.post(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options) - }; - const getAllMocks = (options?: GetAllMocksOptions): Array => { - const onMissingMock = options?.onMissingMock ?? 'skip'; - const overrides = options?.overrides; - const handlers: Array = []; - const addRequiredHandler = (handler: (value: Value | (() => HttpResponse)) => HttpHandler, override: Value | undefined) => { - if (override != null) { - handlers.push(handler(override)); - } - else { - if (onMissingMock === 'error') { - handlers.push(handler(() => new HttpResponse('[heyapi-msw] The mock of this request is not implemented.', { status: 501 }))); - } - } - }; - handlers.push(mocks.getFooMock(overrides?.getFooMock)); - addRequiredHandler(mocks.postFooMock, overrides?.postFooMock); - return handlers; - }; - return { ...mocks, getAllMocks }; -}; - -const _defaults = createMswHandlerFactory({ baseUrl: '*' }); - -export const getFooMock = _defaults.getFooMock; - -export const postFooMock = _defaults.postFooMock; - -export const getAllMocks = _defaults.getAllMocks; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example/types.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example/types.gen.ts deleted file mode 100644 index 9d0535a2e7..0000000000 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-example/types.gen.ts +++ /dev/null @@ -1,50 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -export type ClientOptions = { - baseUrl: `${string}://${string}` | (string & {}); -}; - -export type Person = { - firstName?: string; - lastName?: string; - age?: number; -}; - -export type GetFooData = { - body?: never; - path?: never; - query?: never; - url: '/foo'; -}; - -export type GetFooResponses = { - /** - * OK - */ - 200: Person; -}; - -export type GetFooResponse = GetFooResponses[keyof GetFooResponses]; - -export type PostFooData = { - body: string; - path?: never; - query?: never; - url: '/foo'; -}; - -export type PostFooResponses = { - /** - * OK - */ - 200: { - fullName?: string; - age?: number; - }; - /** - * SUCCESSFUL - */ - 204: void; -}; - -export type PostFooResponse = PostFooResponses[keyof PostFooResponses]; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-types/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-types/msw.gen.ts deleted file mode 100644 index 0e95210e4c..0000000000 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-types/msw.gen.ts +++ /dev/null @@ -1,60 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions } from 'msw'; - -import type { GetFooResponses } from './types.gen'; - -const resolveToNull = () => new HttpResponse(null); - -type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; - -export type SingleHandlerFactories = { - getFooMock: HttpHandlerFactory<{ - result: GetFooResponses[200]; - status?: 200; - } | HttpResponseResolver>; -}; - -export type GetAllMocksOptions = { - onMissingMock?: 'error' | 'skip'; - overrides?: { - [K in keyof SingleHandlerFactories]?: Parameters[0]; - }; -}; - -export type MswHandlerFactory = SingleHandlerFactories & { - getAllMocks: (options?: GetAllMocksOptions) => Array; -}; - -export const createMswHandlerFactory = (config?: { - baseUrl?: string; -}): MswHandlerFactory => { - const baseUrl = config?.baseUrl ?? ''; - const mocks: SingleHandlerFactories = { - getFooMock: (res, options) => http.get(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options) - }; - const getAllMocks = (options?: GetAllMocksOptions): Array => { - const onMissingMock = options?.onMissingMock ?? 'skip'; - const overrides = options?.overrides; - const handlers: Array = []; - const addRequiredHandler = (handler: (value: Value | (() => HttpResponse)) => HttpHandler, override: Value | undefined) => { - if (override != null) { - handlers.push(handler(override)); - } - else { - if (onMissingMock === 'error') { - handlers.push(handler(() => new HttpResponse('[heyapi-msw] The mock of this request is not implemented.', { status: 501 }))); - } - } - }; - addRequiredHandler(mocks.getFooMock, overrides?.getFooMock); - return handlers; - }; - return { ...mocks, getAllMocks }; -}; - -const _defaults = createMswHandlerFactory({ baseUrl: '*' }); - -export const getFooMock = _defaults.getFooMock; - -export const getAllMocks = _defaults.getAllMocks; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/servers/index.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/servers/index.ts deleted file mode 100644 index f389f85547..0000000000 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/servers/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -export type { ClientOptions, GetFooData, GetFooResponse, GetFooResponses } from './types.gen'; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/servers/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/servers/msw.gen.ts deleted file mode 100644 index d365ef4f29..0000000000 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/servers/msw.gen.ts +++ /dev/null @@ -1,60 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions } from 'msw'; - -import type { GetFooResponses } from './types.gen'; - -const resolveToNull = () => new HttpResponse(null); - -type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; - -export type SingleHandlerFactories = { - getFooMock: HttpHandlerFactory<{ - result: GetFooResponses[200]; - status?: 200; - } | HttpResponseResolver>; -}; - -export type GetAllMocksOptions = { - onMissingMock?: 'error' | 'skip'; - overrides?: { - [K in keyof SingleHandlerFactories]?: Parameters[0]; - }; -}; - -export type MswHandlerFactory = SingleHandlerFactories & { - getAllMocks: (options?: GetAllMocksOptions) => Array; -}; - -export const createMswHandlerFactory = (config?: { - baseUrl?: string; -}): MswHandlerFactory => { - const baseUrl = config?.baseUrl ?? 'https://foo.com/v1'; - const mocks: SingleHandlerFactories = { - getFooMock: (res, options) => http.get(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options) - }; - const getAllMocks = (options?: GetAllMocksOptions): Array => { - const onMissingMock = options?.onMissingMock ?? 'skip'; - const overrides = options?.overrides; - const handlers: Array = []; - const addRequiredHandler = (handler: (value: Value | (() => HttpResponse)) => HttpHandler, override: Value | undefined) => { - if (override != null) { - handlers.push(handler(override)); - } - else { - if (onMissingMock === 'error') { - handlers.push(handler(() => new HttpResponse('[heyapi-msw] The mock of this request is not implemented.', { status: 501 }))); - } - } - }; - addRequiredHandler(mocks.getFooMock, overrides?.getFooMock); - return handlers; - }; - return { ...mocks, getAllMocks }; -}; - -const _defaults = createMswHandlerFactory({ baseUrl: '*' }); - -export const getFooMock = _defaults.getFooMock; - -export const getAllMocks = _defaults.getAllMocks; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/default/index.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/default/index.ts deleted file mode 100644 index 2ef59c1f0c..0000000000 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/default/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -export type { _3eNum1Период, _400, AdditionalPropertiesIntegerIssue, AdditionalPropertiesUnknownIssue, AdditionalPropertiesUnknownIssue2, AdditionalPropertiesUnknownIssue3, AdditionalPropertiesUnknownIssueWritable, AnyOfAnyAndNull, AnyOfArrays, ApiVVersionODataControllerCountData, ApiVVersionODataControllerCountResponse, ApiVVersionODataControllerCountResponses, ArrayWithAnyOfProperties, ArrayWithArray, ArrayWithBooleans, ArrayWithNumbers, ArrayWithProperties, ArrayWithReferences, ArrayWithStrings, CallToTestOrderOfParamsData, CallWithDefaultOptionalParametersData, CallWithDefaultParametersData, CallWithDescriptionsData, CallWithDuplicateResponsesData, CallWithDuplicateResponsesError, CallWithDuplicateResponsesErrors, CallWithDuplicateResponsesResponse, CallWithDuplicateResponsesResponses, CallWithNoContentResponseData, CallWithNoContentResponseResponse, CallWithNoContentResponseResponses, CallWithParametersData, CallWithResponseAndNoContentResponseData, CallWithResponseAndNoContentResponseResponse, CallWithResponseAndNoContentResponseResponses, CallWithResponseData, CallWithResponseResponse, CallWithResponseResponses, CallWithResponsesData, CallWithResponsesError, CallWithResponsesErrors, CallWithResponsesResponse, CallWithResponsesResponses, CallWithResultFromHeaderData, CallWithResultFromHeaderErrors, CallWithResultFromHeaderResponses, CallWithWeirdParameterNamesData, CamelCaseCommentWithBreaks, CharactersInDescription, ClientOptions, CollectionFormatData, CommentWithBackticks, CommentWithBackticksAndQuotes, CommentWithBreaks, CommentWithExpressionPlaceholders, CommentWithQuotes, CommentWithReservedCharacters, CommentWithSlashes, ComplexParamsData, ComplexParamsResponse, ComplexParamsResponses, ComplexTypesData, ComplexTypesErrors, ComplexTypesResponse, ComplexTypesResponses, CompositionBaseModel, CompositionExtendedModel, CompositionWithAllOfAndNullable, CompositionWithAnyOf, CompositionWithAnyOfAndNullable, CompositionWithAnyOfAnonymous, CompositionWithNestedAnyAndTypeNull, CompositionWithNestedAnyOfAndNull, CompositionWithOneOf, CompositionWithOneOfAndComplexArrayDictionary, CompositionWithOneOfAndNullable, CompositionWithOneOfAndProperties, CompositionWithOneOfAndSimpleArrayDictionary, CompositionWithOneOfAndSimpleDictionary, CompositionWithOneOfAnonymous, CompositionWithOneOfDiscriminator, ConstValue, Default, DeleteCallWithoutParametersAndResponseData, DeleteFooData, DeleteFooData2, DeleteFooData3, DeprecatedCallData, DeprecatedModel, DictionaryWithArray, DictionaryWithDictionary, DictionaryWithProperties, DictionaryWithPropertiesAndAdditionalProperties, DictionaryWithReference, DictionaryWithString, DummyAData, DummyAResponse, DummyAResponses, DummyBData, DummyBResponse, DummyBResponses, DuplicateName2Data, DuplicateName3Data, DuplicateName4Data, DuplicateNameData, EnumFromDescription, EnumWithExtensions, EnumWithNumbers, EnumWithReplacedCharacters, EnumWithStrings, EnumWithXEnumNames, ExportData, ExternalRefA, ExternalRefB, ExternalSharedModel, File, FileResponseData, FileResponseResponse, FileResponseResponses, FileWritable, FooWowData, FooWowResponses, FreeFormObjectWithAdditionalPropertiesEqEmptyObject, FreeFormObjectWithAdditionalPropertiesEqTrue, FreeFormObjectWithoutAdditionalProperties, GenericSchemaDuplicateIssue1SystemBoolean, GenericSchemaDuplicateIssue1SystemBooleanWritable, GenericSchemaDuplicateIssue1SystemString, GenericSchemaDuplicateIssue1SystemStringWritable, GetApiVbyApiVersionSimpleOperationData, GetApiVbyApiVersionSimpleOperationError, GetApiVbyApiVersionSimpleOperationErrors, GetApiVbyApiVersionSimpleOperationResponse, GetApiVbyApiVersionSimpleOperationResponses, GetCallWithOptionalParamData, GetCallWithoutParametersAndResponseData, HeadCallWithoutParametersAndResponseData, Import, ImportData, ImportResponse, ImportResponses, IoK8sApimachineryPkgApisMetaV1DeleteOptions, IoK8sApimachineryPkgApisMetaV1Preconditions, ModelCircle, ModelFromZendesk, ModelSquare, ModelThatExtends, ModelThatExtendsExtends, ModelWithAdditionalPropertiesEqTrue, ModelWithAdditionalPropertiesRef, ModelWithAnyOfConstantSizeArray, ModelWithAnyOfConstantSizeArrayAndIntersect, ModelWithAnyOfConstantSizeArrayNullable, ModelWithAnyOfConstantSizeArrayWithNSizeAndOptions, ModelWithAnyOfConstantSizeArrayWithNSizeAndOptionsWritable, ModelWithArray, ModelWithArrayReadOnlyAndWriteOnly, ModelWithArrayReadOnlyAndWriteOnlyWritable, ModelWithBackticksInDescription, ModelWithBoolean, ModelWithCircularReference, ModelWithConst, ModelWithConstantSizeArray, ModelWithDictionary, ModelWithDuplicateImports, ModelWithDuplicateProperties, ModelWithEnum, ModelWithEnumFromDescription, ModelWithEnumWithHyphen, ModelWithInteger, ModelWithNestedArrayEnums, ModelWithNestedArrayEnumsData, ModelWithNestedArrayEnumsDataBar, ModelWithNestedArrayEnumsDataFoo, ModelWithNestedCompositionEnums, ModelWithNestedEnums, ModelWithNestedProperties, ModelWithNullableObject, ModelWithNullableString, ModelWithNumericEnumUnion, ModelWithOneOfAndProperties, ModelWithOneOfEnum, ModelWithOrderedProperties, ModelWithPattern, ModelWithPatternWritable, ModelWithPrefixItemsConstantSizeArray, ModelWithProperties, ModelWithPropertiesWritable, ModelWithReadOnlyAndWriteOnly, ModelWithReadOnlyAndWriteOnlyWritable, ModelWithReference, ModelWithReferenceWritable, ModelWithString, ModelWithStringError, MultipartRequestData, MultipartResponseData, MultipartResponseResponse, MultipartResponseResponses, NestedAnyOfArraysNullable, NonAsciiæøåÆøÅöôêÊ字符串Data, NonAsciiæøåÆøÅöôêÊ字符串Response, NonAsciiæøåÆøÅöôêÊ字符串Responses, NonAsciiStringæøåÆøÅöôêÊ字符串, NullableObject, OneOfAllOfIssue, OneOfAllOfIssueWritable, OptionsCallWithoutParametersAndResponseData, Pageable, ParameterSimpleParameterUnused, PatchApiVbyApiVersionNoTagData, PatchApiVbyApiVersionNoTagResponses, PatchCallWithoutParametersAndResponseData, PostApiVbyApiVersionFormDataData, PostApiVbyApiVersionRequestBodyData, PostCallWithOptionalParamData, PostCallWithOptionalParamResponse, PostCallWithOptionalParamResponses, PostCallWithoutParametersAndResponseData, PostServiceWithEmptyTagResponse, PostServiceWithEmptyTagResponse2, PutCallWithoutParametersAndResponseData, PutWithFormUrlEncodedData, SchemaWithFormRestrictedKeys, SimpleBoolean, SimpleFile, SimpleFormData, SimpleInteger, SimpleParameter, SimpleReference, SimpleRequestBody, SimpleString, SimpleStringWithPattern, TestErrorCodeData, TestErrorCodeErrors, TestErrorCodeResponses, TypesData, TypesResponse, TypesResponses, UploadFileData, UploadFileResponse, UploadFileResponses, XFooBar } from './types.gen'; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/default/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/default/msw.gen.ts deleted file mode 100644 index 4f9fb98673..0000000000 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/default/msw.gen.ts +++ /dev/null @@ -1,382 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions } from 'msw'; - -import type { ApiVVersionODataControllerCountResponses, CallWithDuplicateResponsesResponses, CallWithNoContentResponseResponses, CallWithParametersData, CallWithResponseAndNoContentResponseResponses, CallWithResponsesResponses, CallWithResultFromHeaderResponses, CallWithWeirdParameterNamesData, ComplexParamsData, ComplexParamsResponses, ComplexTypesResponses, DummyAResponses, DummyBResponses, FileResponseResponses, GetApiVbyApiVersionSimpleOperationResponses, GetCallWithOptionalParamData, ImportData, ImportResponses, MultipartRequestData, MultipartResponseResponses, NonAsciiæøåÆøÅöôêÊ字符串Responses, PostApiVbyApiVersionFormDataData, PostApiVbyApiVersionRequestBodyData, PostCallWithOptionalParamData, PostCallWithOptionalParamResponses, PutWithFormUrlEncodedData, TestErrorCodeResponses, TypesResponses, UploadFileData, UploadFileResponses } from './types.gen'; - -const resolveToNull = () => new HttpResponse(null); - -type OptionalHttpHandlerFactory = (responseOrResolver?: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; - -type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; - -type ToResponseUnion = { - [K in Extract]: { - status: K; - result: T[K]; - }; -}[Extract]; - -export type SingleHandlerFactories = { - exportMock: OptionalHttpHandlerFactory; - patchApiVbyApiVersionNoTagMock: OptionalHttpHandlerFactory; - importMock: HttpHandlerFactory<{ - result: ImportResponses[200]; - status?: 200; - } | HttpResponseResolver>; - fooWowMock: OptionalHttpHandlerFactory; - apiVVersionODataControllerCountMock: HttpHandlerFactory<{ - result: ApiVVersionODataControllerCountResponses[200]; - status?: 200; - } | HttpResponseResolver>; - getApiVbyApiVersionSimpleOperationMock: HttpHandlerFactory<{ - result: GetApiVbyApiVersionSimpleOperationResponses[200]; - status?: 200; - } | HttpResponseResolver<{ - apiVersion: string; - }, never>>; - deleteCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; - getCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; - headCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; - optionsCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; - patchCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; - postCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; - putCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; - deleteFooMock: OptionalHttpHandlerFactory>; - callWithDescriptionsMock: OptionalHttpHandlerFactory; - deprecatedCallMock: OptionalHttpHandlerFactory; - callWithParametersMock: OptionalHttpHandlerFactory>; - callWithWeirdParameterNamesMock: OptionalHttpHandlerFactory>; - getCallWithOptionalParamMock: OptionalHttpHandlerFactory>; - postCallWithOptionalParamMock: HttpHandlerFactory<{ - result: PostCallWithOptionalParamResponses[200]; - status?: 200; - } | ToResponseUnion | HttpResponseResolver>; - postApiVbyApiVersionRequestBodyMock: OptionalHttpHandlerFactory>; - postApiVbyApiVersionFormDataMock: OptionalHttpHandlerFactory>; - callWithDefaultParametersMock: OptionalHttpHandlerFactory; - callWithDefaultOptionalParametersMock: OptionalHttpHandlerFactory; - callToTestOrderOfParamsMock: OptionalHttpHandlerFactory; - duplicateNameMock: OptionalHttpHandlerFactory; - duplicateName2Mock: OptionalHttpHandlerFactory; - duplicateName3Mock: OptionalHttpHandlerFactory; - duplicateName4Mock: OptionalHttpHandlerFactory; - callWithNoContentResponseMock: OptionalHttpHandlerFactory<{ - result: CallWithNoContentResponseResponses[204]; - status?: 204; - } | HttpResponseResolver>; - callWithResponseAndNoContentResponseMock: HttpHandlerFactory<{ - result: CallWithResponseAndNoContentResponseResponses[200]; - status?: 200; - } | ToResponseUnion | HttpResponseResolver>; - dummyAMock: HttpHandlerFactory<{ - result: DummyAResponses[200]; - status?: 200; - } | HttpResponseResolver>; - dummyBMock: OptionalHttpHandlerFactory<{ - result: DummyBResponses[204]; - status?: 204; - } | HttpResponseResolver>; - callWithResponseMock: OptionalHttpHandlerFactory; - callWithDuplicateResponsesMock: HttpHandlerFactory<{ - result: CallWithDuplicateResponsesResponses[200]; - status?: 200; - } | ToResponseUnion | HttpResponseResolver>; - callWithResponsesMock: HttpHandlerFactory<{ - result: CallWithResponsesResponses[200]; - status?: 200; - } | ToResponseUnion | HttpResponseResolver>; - collectionFormatMock: OptionalHttpHandlerFactory; - typesMock: HttpHandlerFactory<{ - result: TypesResponses[200]; - status?: 200; - } | ToResponseUnion | HttpResponseResolver<{ - apiVersion: string; - }, never>>; - uploadFileMock: HttpHandlerFactory<{ - result: UploadFileResponses[200]; - status?: 200; - } | HttpResponseResolver<{ - apiVersion: string; - }, UploadFileData['body']>>; - fileResponseMock: HttpHandlerFactory<{ - result: FileResponseResponses[200]; - status?: 200; - } | HttpResponseResolver<{ - apiVersion: string; - id: string; - }, never>>; - complexTypesMock: HttpHandlerFactory<{ - result: ComplexTypesResponses[200]; - status?: 200; - } | HttpResponseResolver>; - multipartResponseMock: HttpHandlerFactory<{ - result: MultipartResponseResponses[200]; - status?: 200; - } | HttpResponseResolver>; - multipartRequestMock: OptionalHttpHandlerFactory>; - complexParamsMock: HttpHandlerFactory<{ - result: ComplexParamsResponses[200]; - status?: 200; - } | HttpResponseResolver<{ - apiVersion: string; - id: string; - }, ComplexParamsData['body']>>; - callWithResultFromHeaderMock: OptionalHttpHandlerFactory<{ - result: CallWithResultFromHeaderResponses[200]; - status?: 200; - } | HttpResponseResolver>; - testErrorCodeMock: OptionalHttpHandlerFactory<{ - result: TestErrorCodeResponses[200]; - status?: 200; - } | HttpResponseResolver>; - nonAsciiæøåÆøÅöôêÊ字符串Mock: HttpHandlerFactory<{ - result: NonAsciiæøåÆøÅöôêÊ字符串Responses[200]; - status?: 200; - } | HttpResponseResolver>; - putWithFormUrlEncodedMock: OptionalHttpHandlerFactory>; -}; - -export type GetAllMocksOptions = { - onMissingMock?: 'error' | 'skip'; - overrides?: { - [K in keyof SingleHandlerFactories]?: Parameters[0]; - }; -}; - -export type MswHandlerFactory = SingleHandlerFactories & { - getAllMocks: (options?: GetAllMocksOptions) => Array; -}; - -export const createMswHandlerFactory = (config?: { - baseUrl?: string; -}): MswHandlerFactory => { - const baseUrl = config?.baseUrl ?? 'http://localhost:3000/base'; - const mocks: SingleHandlerFactories = { - exportMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/no+tag'}`, typeof res === 'function' ? res : resolveToNull, options), - patchApiVbyApiVersionNoTagMock: (res, options) => http.patch(`${baseUrl}${'/api/v:apiVersion/no+tag'}`, typeof res === 'function' ? res : resolveToNull, options), - importMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/no+tag'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - fooWowMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/no+tag'}`, typeof res === 'function' ? res : resolveToNull, options), - apiVVersionODataControllerCountMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/simple/$count'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - getApiVbyApiVersionSimpleOperationMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/simple\\:operation'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - deleteCallWithoutParametersAndResponseMock: (res, options) => http.delete(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), - getCallWithoutParametersAndResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), - headCallWithoutParametersAndResponseMock: (res, options) => http.head(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), - optionsCallWithoutParametersAndResponseMock: (res, options) => http.options(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), - patchCallWithoutParametersAndResponseMock: (res, options) => http.patch(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), - postCallWithoutParametersAndResponseMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), - putCallWithoutParametersAndResponseMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), - deleteFooMock: (res, options) => http.delete(`${baseUrl}${'/api/v:apiVersion/foo/:foo_param/bar/:BarParam'}`, typeof res === 'function' ? res : resolveToNull, options), - callWithDescriptionsMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/descriptions'}`, typeof res === 'function' ? res : resolveToNull, options), - deprecatedCallMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/parameters/deprecated'}`, typeof res === 'function' ? res : resolveToNull, options), - callWithParametersMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/parameters/:parameterPath'}`, typeof res === 'function' ? res : resolveToNull, options), - callWithWeirdParameterNamesMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/parameters/:parameterPath1/:parameterPath2/:PARAMETERPATH3'}`, typeof res === 'function' ? res : resolveToNull, options), - getCallWithOptionalParamMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/parameters'}`, typeof res === 'function' ? res : resolveToNull, options), - postCallWithOptionalParamMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/parameters'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - postApiVbyApiVersionRequestBodyMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/requestBody'}`, typeof res === 'function' ? res : resolveToNull, options), - postApiVbyApiVersionFormDataMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/formData'}`, typeof res === 'function' ? res : resolveToNull, options), - callWithDefaultParametersMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/defaults'}`, typeof res === 'function' ? res : resolveToNull, options), - callWithDefaultOptionalParametersMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/defaults'}`, typeof res === 'function' ? res : resolveToNull, options), - callToTestOrderOfParamsMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/defaults'}`, typeof res === 'function' ? res : resolveToNull, options), - duplicateNameMock: (res, options) => http.delete(`${baseUrl}${'/api/v:apiVersion/duplicate'}`, typeof res === 'function' ? res : resolveToNull, options), - duplicateName2Mock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/duplicate'}`, typeof res === 'function' ? res : resolveToNull, options), - duplicateName3Mock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/duplicate'}`, typeof res === 'function' ? res : resolveToNull, options), - duplicateName4Mock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/duplicate'}`, typeof res === 'function' ? res : resolveToNull, options), - callWithNoContentResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/no-content'}`, typeof res === 'object' && res.result ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 204 }) : typeof res === 'function' ? res : resolveToNull, options), - callWithResponseAndNoContentResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/multiple-tags/response-and-no-content'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - dummyAMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/multiple-tags/a'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - dummyBMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/multiple-tags/b'}`, typeof res === 'object' && res.result ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 204 }) : typeof res === 'function' ? res : resolveToNull, options), - callWithResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/response'}`, typeof res === 'function' ? res : resolveToNull, options), - callWithDuplicateResponsesMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/response'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - callWithResponsesMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/response'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - collectionFormatMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/collectionFormat'}`, typeof res === 'function' ? res : resolveToNull, options), - typesMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/types'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - uploadFileMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/upload'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - fileResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/file/:id'}`, typeof res === 'object' && res.result ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - complexTypesMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/complex'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - multipartResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/multipart'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - multipartRequestMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/multipart'}`, typeof res === 'function' ? res : resolveToNull, options), - complexParamsMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/complex/:id'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - callWithResultFromHeaderMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/header'}`, typeof res === 'object' && res.result ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - testErrorCodeMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/error'}`, typeof res === 'object' && res.result ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - nonAsciiæøåÆøÅöôêÊ字符串Mock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/non-ascii-æøåÆØÅöôêÊ字符串'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - putWithFormUrlEncodedMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/non-ascii-æøåÆØÅöôêÊ字符串'}`, typeof res === 'function' ? res : resolveToNull, options) - }; - const getAllMocks = (options?: GetAllMocksOptions): Array => { - const onMissingMock = options?.onMissingMock ?? 'skip'; - const overrides = options?.overrides; - const handlers: Array = []; - const addRequiredHandler = (handler: (value: Value | (() => HttpResponse)) => HttpHandler, override: Value | undefined) => { - if (override != null) { - handlers.push(handler(override)); - } - else { - if (onMissingMock === 'error') { - handlers.push(handler(() => new HttpResponse('[heyapi-msw] The mock of this request is not implemented.', { status: 501 }))); - } - } - }; - handlers.push(mocks.deleteFooMock(overrides?.deleteFooMock)); - handlers.push(mocks.callWithWeirdParameterNamesMock(overrides?.callWithWeirdParameterNamesMock)); - addRequiredHandler(mocks.apiVVersionODataControllerCountMock, overrides?.apiVVersionODataControllerCountMock); - handlers.push(mocks.deprecatedCallMock(overrides?.deprecatedCallMock)); - addRequiredHandler(mocks.callWithResponseAndNoContentResponseMock, overrides?.callWithResponseAndNoContentResponseMock); - addRequiredHandler(mocks.dummyAMock, overrides?.dummyAMock); - handlers.push(mocks.dummyBMock(overrides?.dummyBMock)); - handlers.push(mocks.callWithParametersMock(overrides?.callWithParametersMock)); - addRequiredHandler(mocks.fileResponseMock, overrides?.fileResponseMock); - addRequiredHandler(mocks.complexParamsMock, overrides?.complexParamsMock); - handlers.push(mocks.exportMock(overrides?.exportMock)); - handlers.push(mocks.patchApiVbyApiVersionNoTagMock(overrides?.patchApiVbyApiVersionNoTagMock)); - addRequiredHandler(mocks.importMock, overrides?.importMock); - handlers.push(mocks.fooWowMock(overrides?.fooWowMock)); - addRequiredHandler(mocks.getApiVbyApiVersionSimpleOperationMock, overrides?.getApiVbyApiVersionSimpleOperationMock); - handlers.push(mocks.deleteCallWithoutParametersAndResponseMock(overrides?.deleteCallWithoutParametersAndResponseMock)); - handlers.push(mocks.getCallWithoutParametersAndResponseMock(overrides?.getCallWithoutParametersAndResponseMock)); - handlers.push(mocks.headCallWithoutParametersAndResponseMock(overrides?.headCallWithoutParametersAndResponseMock)); - handlers.push(mocks.optionsCallWithoutParametersAndResponseMock(overrides?.optionsCallWithoutParametersAndResponseMock)); - handlers.push(mocks.patchCallWithoutParametersAndResponseMock(overrides?.patchCallWithoutParametersAndResponseMock)); - handlers.push(mocks.postCallWithoutParametersAndResponseMock(overrides?.postCallWithoutParametersAndResponseMock)); - handlers.push(mocks.putCallWithoutParametersAndResponseMock(overrides?.putCallWithoutParametersAndResponseMock)); - handlers.push(mocks.callWithDescriptionsMock(overrides?.callWithDescriptionsMock)); - handlers.push(mocks.getCallWithOptionalParamMock(overrides?.getCallWithOptionalParamMock)); - addRequiredHandler(mocks.postCallWithOptionalParamMock, overrides?.postCallWithOptionalParamMock); - handlers.push(mocks.postApiVbyApiVersionRequestBodyMock(overrides?.postApiVbyApiVersionRequestBodyMock)); - handlers.push(mocks.postApiVbyApiVersionFormDataMock(overrides?.postApiVbyApiVersionFormDataMock)); - handlers.push(mocks.callWithDefaultParametersMock(overrides?.callWithDefaultParametersMock)); - handlers.push(mocks.callWithDefaultOptionalParametersMock(overrides?.callWithDefaultOptionalParametersMock)); - handlers.push(mocks.callToTestOrderOfParamsMock(overrides?.callToTestOrderOfParamsMock)); - handlers.push(mocks.duplicateNameMock(overrides?.duplicateNameMock)); - handlers.push(mocks.duplicateName2Mock(overrides?.duplicateName2Mock)); - handlers.push(mocks.duplicateName3Mock(overrides?.duplicateName3Mock)); - handlers.push(mocks.duplicateName4Mock(overrides?.duplicateName4Mock)); - handlers.push(mocks.callWithNoContentResponseMock(overrides?.callWithNoContentResponseMock)); - handlers.push(mocks.callWithResponseMock(overrides?.callWithResponseMock)); - addRequiredHandler(mocks.callWithDuplicateResponsesMock, overrides?.callWithDuplicateResponsesMock); - addRequiredHandler(mocks.callWithResponsesMock, overrides?.callWithResponsesMock); - handlers.push(mocks.collectionFormatMock(overrides?.collectionFormatMock)); - addRequiredHandler(mocks.typesMock, overrides?.typesMock); - addRequiredHandler(mocks.uploadFileMock, overrides?.uploadFileMock); - addRequiredHandler(mocks.complexTypesMock, overrides?.complexTypesMock); - addRequiredHandler(mocks.multipartResponseMock, overrides?.multipartResponseMock); - handlers.push(mocks.multipartRequestMock(overrides?.multipartRequestMock)); - handlers.push(mocks.callWithResultFromHeaderMock(overrides?.callWithResultFromHeaderMock)); - handlers.push(mocks.testErrorCodeMock(overrides?.testErrorCodeMock)); - addRequiredHandler(mocks.nonAsciiæøåÆøÅöôêÊ字符串Mock, overrides?.nonAsciiæøåÆøÅöôêÊ字符串Mock); - handlers.push(mocks.putWithFormUrlEncodedMock(overrides?.putWithFormUrlEncodedMock)); - return handlers; - }; - return { ...mocks, getAllMocks }; -}; - -const _defaults = createMswHandlerFactory({ baseUrl: '*' }); - -export const exportMock = _defaults.exportMock; - -export const patchApiVbyApiVersionNoTagMock = _defaults.patchApiVbyApiVersionNoTagMock; - -export const importMock = _defaults.importMock; - -export const fooWowMock = _defaults.fooWowMock; - -export const apiVVersionODataControllerCountMock = _defaults.apiVVersionODataControllerCountMock; - -export const getApiVbyApiVersionSimpleOperationMock = _defaults.getApiVbyApiVersionSimpleOperationMock; - -export const deleteCallWithoutParametersAndResponseMock = _defaults.deleteCallWithoutParametersAndResponseMock; - -export const getCallWithoutParametersAndResponseMock = _defaults.getCallWithoutParametersAndResponseMock; - -export const headCallWithoutParametersAndResponseMock = _defaults.headCallWithoutParametersAndResponseMock; - -export const optionsCallWithoutParametersAndResponseMock = _defaults.optionsCallWithoutParametersAndResponseMock; - -export const patchCallWithoutParametersAndResponseMock = _defaults.patchCallWithoutParametersAndResponseMock; - -export const postCallWithoutParametersAndResponseMock = _defaults.postCallWithoutParametersAndResponseMock; - -export const putCallWithoutParametersAndResponseMock = _defaults.putCallWithoutParametersAndResponseMock; - -export const deleteFooMock = _defaults.deleteFooMock; - -export const callWithDescriptionsMock = _defaults.callWithDescriptionsMock; - -export const deprecatedCallMock = _defaults.deprecatedCallMock; - -export const callWithParametersMock = _defaults.callWithParametersMock; - -export const callWithWeirdParameterNamesMock = _defaults.callWithWeirdParameterNamesMock; - -export const getCallWithOptionalParamMock = _defaults.getCallWithOptionalParamMock; - -export const postCallWithOptionalParamMock = _defaults.postCallWithOptionalParamMock; - -export const postApiVbyApiVersionRequestBodyMock = _defaults.postApiVbyApiVersionRequestBodyMock; - -export const postApiVbyApiVersionFormDataMock = _defaults.postApiVbyApiVersionFormDataMock; - -export const callWithDefaultParametersMock = _defaults.callWithDefaultParametersMock; - -export const callWithDefaultOptionalParametersMock = _defaults.callWithDefaultOptionalParametersMock; - -export const callToTestOrderOfParamsMock = _defaults.callToTestOrderOfParamsMock; - -export const duplicateNameMock = _defaults.duplicateNameMock; - -export const duplicateName2Mock = _defaults.duplicateName2Mock; - -export const duplicateName3Mock = _defaults.duplicateName3Mock; - -export const duplicateName4Mock = _defaults.duplicateName4Mock; - -export const callWithNoContentResponseMock = _defaults.callWithNoContentResponseMock; - -export const callWithResponseAndNoContentResponseMock = _defaults.callWithResponseAndNoContentResponseMock; - -export const dummyAMock = _defaults.dummyAMock; - -export const dummyBMock = _defaults.dummyBMock; - -export const callWithResponseMock = _defaults.callWithResponseMock; - -export const callWithDuplicateResponsesMock = _defaults.callWithDuplicateResponsesMock; - -export const callWithResponsesMock = _defaults.callWithResponsesMock; - -export const collectionFormatMock = _defaults.collectionFormatMock; - -export const typesMock = _defaults.typesMock; - -export const uploadFileMock = _defaults.uploadFileMock; - -export const fileResponseMock = _defaults.fileResponseMock; - -export const complexTypesMock = _defaults.complexTypesMock; - -export const multipartResponseMock = _defaults.multipartResponseMock; - -export const multipartRequestMock = _defaults.multipartRequestMock; - -export const complexParamsMock = _defaults.complexParamsMock; - -export const callWithResultFromHeaderMock = _defaults.callWithResultFromHeaderMock; - -export const testErrorCodeMock = _defaults.testErrorCodeMock; - -export const nonAsciiæøåÆøÅöôêÊ字符串Mock = _defaults.nonAsciiæøåÆøÅöôêÊ字符串Mock; - -export const putWithFormUrlEncodedMock = _defaults.putWithFormUrlEncodedMock; - -export const getAllMocks = _defaults.getAllMocks; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example-disabled/index.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example-disabled/index.ts deleted file mode 100644 index b545604fba..0000000000 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example-disabled/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -export type { ClientOptions, GetFooData, GetFooResponse, GetFooResponses, Person, PostFooData, PostFooResponse, PostFooResponses } from './types.gen'; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example-disabled/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example-disabled/msw.gen.ts deleted file mode 100644 index a2e510c260..0000000000 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example-disabled/msw.gen.ts +++ /dev/null @@ -1,75 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions } from 'msw'; - -import type { GetFooResponses, PostFooData, PostFooResponses } from './types.gen'; - -const resolveToNull = () => new HttpResponse(null); - -type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; - -type ToResponseUnion = { - [K in Extract]: { - status: K; - result: T[K]; - }; -}[Extract]; - -export type SingleHandlerFactories = { - getFooMock: HttpHandlerFactory<{ - result: GetFooResponses[200]; - status?: 200; - } | HttpResponseResolver>; - postFooMock: HttpHandlerFactory<{ - result: PostFooResponses[200]; - status?: 200; - } | ToResponseUnion | HttpResponseResolver>; -}; - -export type GetAllMocksOptions = { - onMissingMock?: 'error' | 'skip'; - overrides?: { - [K in keyof SingleHandlerFactories]?: Parameters[0]; - }; -}; - -export type MswHandlerFactory = SingleHandlerFactories & { - getAllMocks: (options?: GetAllMocksOptions) => Array; -}; - -export const createMswHandlerFactory = (config?: { - baseUrl?: string; -}): MswHandlerFactory => { - const baseUrl = config?.baseUrl ?? ''; - const mocks: SingleHandlerFactories = { - getFooMock: (res, options) => http.get(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - postFooMock: (res, options) => http.post(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options) - }; - const getAllMocks = (options?: GetAllMocksOptions): Array => { - const onMissingMock = options?.onMissingMock ?? 'skip'; - const overrides = options?.overrides; - const handlers: Array = []; - const addRequiredHandler = (handler: (value: Value | (() => HttpResponse)) => HttpHandler, override: Value | undefined) => { - if (override != null) { - handlers.push(handler(override)); - } - else { - if (onMissingMock === 'error') { - handlers.push(handler(() => new HttpResponse('[heyapi-msw] The mock of this request is not implemented.', { status: 501 }))); - } - } - }; - addRequiredHandler(mocks.getFooMock, overrides?.getFooMock); - addRequiredHandler(mocks.postFooMock, overrides?.postFooMock); - return handlers; - }; - return { ...mocks, getAllMocks }; -}; - -const _defaults = createMswHandlerFactory({ baseUrl: '*' }); - -export const getFooMock = _defaults.getFooMock; - -export const postFooMock = _defaults.postFooMock; - -export const getAllMocks = _defaults.getAllMocks; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example/index.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example/index.ts deleted file mode 100644 index b545604fba..0000000000 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -export type { ClientOptions, GetFooData, GetFooResponse, GetFooResponses, Person, PostFooData, PostFooResponse, PostFooResponses } from './types.gen'; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example/msw.gen.ts deleted file mode 100644 index 0eac1db4bb..0000000000 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example/msw.gen.ts +++ /dev/null @@ -1,68 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions } from 'msw'; - -import type { GetFooResponses, PostFooData, PostFooResponses } from './types.gen'; - -const resolveToNull = () => new HttpResponse(null); - -type OptionalHttpHandlerFactory = (responseOrResolver?: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; - -type ToResponseUnion = { - [K in Extract]: { - status: K; - result: T[K]; - }; -}[Extract]; - -export type SingleHandlerFactories = { - getFooMock: OptionalHttpHandlerFactory<{ - result: GetFooResponses[200]; - status?: 200; - } | HttpResponseResolver>; - postFooMock: OptionalHttpHandlerFactory<{ - result: PostFooResponses[200]; - status?: 200; - } | ToResponseUnion | HttpResponseResolver>; -}; - -export type GetAllMocksOptions = { - onMissingMock?: 'error' | 'skip'; - overrides?: { - [K in keyof SingleHandlerFactories]?: Parameters[0]; - }; -}; - -export type MswHandlerFactory = SingleHandlerFactories & { - getAllMocks: (options?: GetAllMocksOptions) => Array; -}; - -export const createMswHandlerFactory = (config?: { - baseUrl?: string; -}): MswHandlerFactory => { - const baseUrl = config?.baseUrl ?? ''; - const mocks: SingleHandlerFactories = { - getFooMock: (res = { result: { - firstName: 'Marry', - lastName: 'Jane', - age: 30 - }, status: 200 }, options) => http.get(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - postFooMock: (res = { result: { fullName: 'John Doe', age: 34 }, status: 200 }, options) => http.post(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options) - }; - const getAllMocks = (options?: GetAllMocksOptions): Array => { - const overrides = options?.overrides; - const handlers: Array = []; - handlers.push(mocks.getFooMock(overrides?.getFooMock)); - handlers.push(mocks.postFooMock(overrides?.postFooMock)); - return handlers; - }; - return { ...mocks, getAllMocks }; -}; - -const _defaults = createMswHandlerFactory({ baseUrl: '*' }); - -export const getFooMock = _defaults.getFooMock; - -export const postFooMock = _defaults.postFooMock; - -export const getAllMocks = _defaults.getAllMocks; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-types/index.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-types/index.ts deleted file mode 100644 index f389f85547..0000000000 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-types/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -export type { ClientOptions, GetFooData, GetFooResponse, GetFooResponses } from './types.gen'; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-types/types.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-types/types.gen.ts deleted file mode 100644 index a0b37c70a4..0000000000 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-types/types.gen.ts +++ /dev/null @@ -1,23 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -export type ClientOptions = { - baseUrl: `${string}://${string}` | (string & {}); -}; - -export type GetFooData = { - body?: never; - path?: never; - query?: never; - url: '/foo'; -}; - -export type GetFooResponses = { - /** - * OK - */ - 200: { - name?: string; - }; -}; - -export type GetFooResponse = GetFooResponses[keyof GetFooResponses]; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/servers/index.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/servers/index.ts deleted file mode 100644 index f389f85547..0000000000 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/servers/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -export type { ClientOptions, GetFooData, GetFooResponse, GetFooResponses } from './types.gen'; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/servers/msw.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/servers/msw.gen.ts deleted file mode 100644 index d365ef4f29..0000000000 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/servers/msw.gen.ts +++ /dev/null @@ -1,60 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions } from 'msw'; - -import type { GetFooResponses } from './types.gen'; - -const resolveToNull = () => new HttpResponse(null); - -type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; - -export type SingleHandlerFactories = { - getFooMock: HttpHandlerFactory<{ - result: GetFooResponses[200]; - status?: 200; - } | HttpResponseResolver>; -}; - -export type GetAllMocksOptions = { - onMissingMock?: 'error' | 'skip'; - overrides?: { - [K in keyof SingleHandlerFactories]?: Parameters[0]; - }; -}; - -export type MswHandlerFactory = SingleHandlerFactories & { - getAllMocks: (options?: GetAllMocksOptions) => Array; -}; - -export const createMswHandlerFactory = (config?: { - baseUrl?: string; -}): MswHandlerFactory => { - const baseUrl = config?.baseUrl ?? 'https://foo.com/v1'; - const mocks: SingleHandlerFactories = { - getFooMock: (res, options) => http.get(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options) - }; - const getAllMocks = (options?: GetAllMocksOptions): Array => { - const onMissingMock = options?.onMissingMock ?? 'skip'; - const overrides = options?.overrides; - const handlers: Array = []; - const addRequiredHandler = (handler: (value: Value | (() => HttpResponse)) => HttpHandler, override: Value | undefined) => { - if (override != null) { - handlers.push(handler(override)); - } - else { - if (onMissingMock === 'error') { - handlers.push(handler(() => new HttpResponse('[heyapi-msw] The mock of this request is not implemented.', { status: 501 }))); - } - } - }; - addRequiredHandler(mocks.getFooMock, overrides?.getFooMock); - return handlers; - }; - return { ...mocks, getAllMocks }; -}; - -const _defaults = createMswHandlerFactory({ baseUrl: '*' }); - -export const getFooMock = _defaults.getFooMock; - -export const getAllMocks = _defaults.getAllMocks; diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/servers/types.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/servers/types.gen.ts deleted file mode 100644 index d7a0ac4610..0000000000 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/servers/types.gen.ts +++ /dev/null @@ -1,21 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -export type ClientOptions = { - baseUrl: 'https://foo.com/v1' | `${string}://${string}/v1` | (string & {}); -}; - -export type GetFooData = { - body?: never; - path?: never; - query?: never; - url: '/foo'; -}; - -export type GetFooResponses = { - /** - * OK - */ - 200: string; -}; - -export type GetFooResponse = GetFooResponses[keyof GetFooResponses]; diff --git a/packages/openapi-ts-tests/main/test/plugins.test.ts b/packages/openapi-ts-tests/main/test/plugins.test.ts index 4eab34e3bd..426e15a52e 100644 --- a/packages/openapi-ts-tests/main/test/plugins.test.ts +++ b/packages/openapi-ts-tests/main/test/plugins.test.ts @@ -9,7 +9,7 @@ import { getFilePaths, getSpecsPath } from '../../utils'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -const versions = ['2.0.x', '3.0.x', '3.1.x'] as const; +const versions = ['2.0.x', '3.0.x', '3.1.x']; for (const version of versions) { const namespace = 'plugins'; @@ -468,47 +468,6 @@ for (const version of versions) { }), description: 'generate Fastify types with Fastify plugin', }, - { - config: createConfig({ - output: 'default', - plugins: ['msw'], - }), - description: 'generate MSW mock handlers with MSW plugin', - }, - { - config: createConfig({ - input: 'response-example.yaml', - output: 'response-example', - plugins: ['msw'], - }), - description: 'generate MSW mock handlers from spec with example with MSW plugin', - }, - { - config: createConfig({ - input: 'response-example.yaml', - output: 'response-example-disabled', - plugins: [{ name: 'msw', valueSources: [] }], - }), - description: - 'generate MSW mock handlers from spec with example with MSW plugin but disabled', - }, - version !== '2.0.x' && { - config: createConfig({ - input: 'response-types.yaml', - output: 'response-types', - plugins: ['msw'], - }), - description: - 'generate MSW mock handlers from spec with multiple response types with MSW plugin', - }, - { - config: createConfig({ - input: 'servers.yaml', - output: 'servers', - plugins: ['msw'], - }), - description: 'generate MSW mock handlers from spec with servers field', - }, { config: createConfig({ input: 'transforms-read-write.yaml', @@ -621,7 +580,7 @@ for (const version of versions) { }), description: 'generate Angular requests and resources (class)', }, - ].filter((val) => typeof val === 'object'); + ]; it.each(scenarios)('$description', async ({ config }) => { await createClient(config); diff --git a/packages/openapi-ts-tests/msw/v2/.gitignore b/packages/openapi-ts-tests/msw/v2/.gitignore new file mode 100644 index 0000000000..d276aefe26 --- /dev/null +++ b/packages/openapi-ts-tests/msw/v2/.gitignore @@ -0,0 +1,5 @@ +.DS_Store +.idea +logs +node_modules +coverage diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/default/index.ts b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/default/index.ts similarity index 100% rename from packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/default/index.ts rename to packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/default/index.ts diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/default/msw.gen.ts b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/default/msw.gen.ts similarity index 100% rename from packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/default/msw.gen.ts rename to packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/default/msw.gen.ts diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/default/types.gen.ts b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/default/types.gen.ts similarity index 100% rename from packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/default/types.gen.ts rename to packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/default/types.gen.ts diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example-disabled/index.ts b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-example-disabled/index.ts similarity index 100% rename from packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example-disabled/index.ts rename to packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-example-disabled/index.ts diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example-disabled/msw.gen.ts b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-example-disabled/msw.gen.ts similarity index 100% rename from packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example-disabled/msw.gen.ts rename to packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-example-disabled/msw.gen.ts diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example-disabled/types.gen.ts b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-example-disabled/types.gen.ts similarity index 100% rename from packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example-disabled/types.gen.ts rename to packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-example-disabled/types.gen.ts diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example/index.ts b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-example/index.ts similarity index 100% rename from packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example/index.ts rename to packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-example/index.ts diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example/msw.gen.ts b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-example/msw.gen.ts similarity index 100% rename from packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/response-example/msw.gen.ts rename to packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-example/msw.gen.ts diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example/types.gen.ts b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-example/types.gen.ts similarity index 100% rename from packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-example/types.gen.ts rename to packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-example/types.gen.ts diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/servers/index.ts b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-types/index.ts similarity index 100% rename from packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/servers/index.ts rename to packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-types/index.ts diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-types/msw.gen.ts b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-types/msw.gen.ts similarity index 100% rename from packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/msw/response-types/msw.gen.ts rename to packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-types/msw.gen.ts diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-types/types.gen.ts b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-types/types.gen.ts similarity index 100% rename from packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-types/types.gen.ts rename to packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-types/types.gen.ts diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-types/index.ts b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/servers/index.ts similarity index 100% rename from packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/response-types/index.ts rename to packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/servers/index.ts diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/servers/msw.gen.ts b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/servers/msw.gen.ts similarity index 100% rename from packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/msw/servers/msw.gen.ts rename to packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/servers/msw.gen.ts diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/servers/types.gen.ts b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/servers/types.gen.ts similarity index 100% rename from packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/msw/servers/types.gen.ts rename to packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/servers/types.gen.ts diff --git a/packages/openapi-ts-tests/msw/v2/package.json b/packages/openapi-ts-tests/msw/v2/package.json new file mode 100644 index 0000000000..625739c84f --- /dev/null +++ b/packages/openapi-ts-tests/msw/v2/package.json @@ -0,0 +1,17 @@ +{ + "name": "@test/openapi-ts-msw-v2", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "typecheck": "tsgo --noEmit" + }, + "devDependencies": { + "@hey-api/openapi-ts": "workspace:*", + "msw": "2.12.14", + "typescript": "5.9.3" + }, + "engines": { + "node": ">=20.19.0" + } +} diff --git a/packages/openapi-ts-tests/msw/v2/test/3.1.x.test.ts b/packages/openapi-ts-tests/msw/v2/test/3.1.x.test.ts new file mode 100644 index 0000000000..9b4d100ec1 --- /dev/null +++ b/packages/openapi-ts-tests/msw/v2/test/3.1.x.test.ts @@ -0,0 +1,75 @@ +import fs from 'node:fs'; +import path from 'node:path'; + +import { createClient } from '@hey-api/openapi-ts'; + +import { getFilePaths } from '../../../utils'; +import { snapshotsDir, tmpDir } from './constants'; +import { createConfigFactory } from './utils'; + +const version = '3.1.x'; + +const outputDir = path.join(tmpDir, version); + +describe(`OpenAPI ${version}`, () => { + const createConfig = createConfigFactory({ openApiVersion: version, outputDir }); + + const scenarios = [ + { + config: createConfig({ + output: 'default', + }), + description: 'generates mock handlers', + }, + { + config: createConfig({ + input: 'response-example.yaml', + output: 'response-example', + }), + description: 'generates mock handlers with example', + }, + { + config: createConfig({ + input: 'response-example.yaml', + output: 'response-example-disabled', + plugins: [ + { + name: 'msw', + valueSources: [], + }, + ], + }), + description: 'generates mock handlers with example but disabled', + }, + { + config: createConfig({ + input: 'response-types.yaml', + output: 'response-types', + }), + description: 'generates mock handlers with multiple response types', + }, + { + config: createConfig({ + input: 'servers.yaml', + output: 'servers', + }), + description: 'generates mock handlers with servers field', + }, + ]; + + it.each(scenarios)('$description', async ({ config }) => { + await createClient(config); + + const outputString = config.output as string; + const filePaths = getFilePaths(outputString); + + await Promise.all( + filePaths.map(async (filePath) => { + const fileContent = fs.readFileSync(filePath, 'utf-8'); + await expect(fileContent).toMatchFileSnapshot( + path.join(snapshotsDir, version, filePath.slice(outputDir.length + 1)), + ); + }), + ); + }); +}); diff --git a/packages/openapi-ts-tests/msw/v2/test/constants.ts b/packages/openapi-ts-tests/msw/v2/test/constants.ts new file mode 100644 index 0000000000..e72988d8bb --- /dev/null +++ b/packages/openapi-ts-tests/msw/v2/test/constants.ts @@ -0,0 +1,4 @@ +import path from 'node:path'; + +export const snapshotsDir = path.join(__dirname, '..', '__snapshots__'); +export const tmpDir = path.join(__dirname, '..', '.tmp'); diff --git a/packages/openapi-ts-tests/msw/v2/test/globalTeardown.ts b/packages/openapi-ts-tests/msw/v2/test/globalTeardown.ts new file mode 100644 index 0000000000..7c8712f70f --- /dev/null +++ b/packages/openapi-ts-tests/msw/v2/test/globalTeardown.ts @@ -0,0 +1,7 @@ +import fs from 'node:fs'; + +import { tmpDir } from './constants'; + +export function teardown() { + fs.rmSync(tmpDir, { force: true, recursive: true }); +} diff --git a/packages/openapi-ts-tests/msw/v2/test/utils.ts b/packages/openapi-ts-tests/msw/v2/test/utils.ts new file mode 100644 index 0000000000..5623d1c084 --- /dev/null +++ b/packages/openapi-ts-tests/msw/v2/test/utils.ts @@ -0,0 +1,33 @@ +import path from 'node:path'; + +import type { UserConfig } from '@hey-api/openapi-ts'; + +import { getSpecsPath } from '../../../utils'; + +export function createConfigFactory({ + openApiVersion, + outputDir, +}: { + openApiVersion: string; + outputDir: string; +}) { + return ( + userConfig: Omit & Partial>, + ): UserConfig => { + const input = userConfig.input instanceof Array ? userConfig.input[0]! : userConfig.input; + const inputPath = path.join( + getSpecsPath(), + openApiVersion, + typeof input === 'string' ? input : 'full.yaml', + ); + const output = userConfig.output instanceof Array ? userConfig.output[0]! : userConfig.output; + const outputPath = typeof output === 'string' ? output : (output?.path ?? ''); + return { + plugins: ['msw'], + ...userConfig, + input: inputPath, + logs: { level: 'silent', path: './logs' }, + output: path.join(outputDir, outputPath), + }; + }; +} diff --git a/packages/openapi-ts-tests/msw/v2/tsconfig.json b/packages/openapi-ts-tests/msw/v2/tsconfig.json new file mode 100644 index 0000000000..e7572df83d --- /dev/null +++ b/packages/openapi-ts-tests/msw/v2/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["test/**/*", "__snapshots__/**/*"], + "references": [{ "path": "../../../openapi-ts" }] +} diff --git a/packages/openapi-ts-tests/msw/v2/turbo.json b/packages/openapi-ts-tests/msw/v2/turbo.json new file mode 100644 index 0000000000..f25a4152d3 --- /dev/null +++ b/packages/openapi-ts-tests/msw/v2/turbo.json @@ -0,0 +1,10 @@ +{ + "$schema": "../../../../node_modules/turbo/schema.json", + "extends": ["//"], + "tasks": { + "build": { + "dependsOn": [], + "outputs": ["dist/**"] + } + } +} diff --git a/packages/openapi-ts-tests/msw/v2/vitest.setup.ts b/packages/openapi-ts-tests/msw/v2/vitest.setup.ts new file mode 100644 index 0000000000..c6178ba405 --- /dev/null +++ b/packages/openapi-ts-tests/msw/v2/vitest.setup.ts @@ -0,0 +1,7 @@ +import { fileURLToPath } from 'node:url'; + +import { beforeAll } from 'vitest'; + +beforeAll(() => { + process.chdir(fileURLToPath(new URL('.', import.meta.url))); +}); diff --git a/packages/openapi-ts-tests/orpc/v1/.gitignore b/packages/openapi-ts-tests/orpc/v1/.gitignore index c8ad94d76a..d276aefe26 100644 --- a/packages/openapi-ts-tests/orpc/v1/.gitignore +++ b/packages/openapi-ts-tests/orpc/v1/.gitignore @@ -1,9 +1,5 @@ .DS_Store .idea -.tmp logs node_modules - -.env coverage -dist diff --git a/packages/openapi-ts-tests/orpc/v1/test/3.0.x.test.ts b/packages/openapi-ts-tests/orpc/v1/test/3.0.x.test.ts index 0e9454e287..5e2314b34a 100644 --- a/packages/openapi-ts-tests/orpc/v1/test/3.0.x.test.ts +++ b/packages/openapi-ts-tests/orpc/v1/test/3.0.x.test.ts @@ -5,14 +5,14 @@ import { createClient } from '@hey-api/openapi-ts'; import { getFilePaths } from '../../../utils'; import { snapshotsDir, tmpDir } from './constants'; -import { createOrpcConfig } from './utils'; +import { createConfigFactory } from './utils'; const version = '3.0.x'; const outputDir = path.join(tmpDir, version); describe(`OpenAPI ${version}`, () => { - const createConfig = createOrpcConfig({ openApiVersion: version, outputDir }); + const createConfig = createConfigFactory({ openApiVersion: version, outputDir }); const scenarios = [ { diff --git a/packages/openapi-ts-tests/orpc/v1/test/3.1.x.test.ts b/packages/openapi-ts-tests/orpc/v1/test/3.1.x.test.ts index 7c75b015e7..15c14eb532 100644 --- a/packages/openapi-ts-tests/orpc/v1/test/3.1.x.test.ts +++ b/packages/openapi-ts-tests/orpc/v1/test/3.1.x.test.ts @@ -5,14 +5,14 @@ import { createClient } from '@hey-api/openapi-ts'; import { getFilePaths } from '../../../utils'; import { snapshotsDir, tmpDir } from './constants'; -import { createOrpcConfig } from './utils'; +import { createConfigFactory } from './utils'; const version = '3.1.x'; const outputDir = path.join(tmpDir, version); describe(`OpenAPI ${version}`, () => { - const createConfig = createOrpcConfig({ openApiVersion: version, outputDir }); + const createConfig = createConfigFactory({ openApiVersion: version, outputDir }); const scenarios = [ { diff --git a/packages/openapi-ts-tests/orpc/v1/test/utils.ts b/packages/openapi-ts-tests/orpc/v1/test/utils.ts index 9e2fd69490..e6af8fa652 100644 --- a/packages/openapi-ts-tests/orpc/v1/test/utils.ts +++ b/packages/openapi-ts-tests/orpc/v1/test/utils.ts @@ -4,9 +4,14 @@ import type { UserConfig } from '@hey-api/openapi-ts'; import { getSpecsPath } from '../../../utils'; -export const createOrpcConfig = - ({ openApiVersion, outputDir }: { openApiVersion: string; outputDir: string }) => - (userConfig: UserConfig) => { +export function createConfigFactory({ + openApiVersion, + outputDir, +}: { + openApiVersion: string; + outputDir: string; +}) { + return (userConfig: UserConfig) => { const input = userConfig.input instanceof Array ? userConfig.input[0]! : userConfig.input; const inputPath = path.join( getSpecsPath(), @@ -29,3 +34,4 @@ export const createOrpcConfig = output: path.join(outputDir, outputPath), } as UserConfig; }; +} diff --git a/packages/openapi-ts-tests/sdks/test/method-class-conflict.test.ts b/packages/openapi-ts-tests/sdks/test/method-class-conflict.test.ts index c11aa833ba..2f2dd878ed 100644 --- a/packages/openapi-ts-tests/sdks/test/method-class-conflict.test.ts +++ b/packages/openapi-ts-tests/sdks/test/method-class-conflict.test.ts @@ -4,7 +4,7 @@ import path from 'node:path'; import { createClient } from '@hey-api/openapi-ts'; import { getFilePaths, getSpecsPath } from '../../utils'; -import { createSdkConfig, getSnapshotsPath, getTempSnapshotsPath } from './utils'; +import { createConfigFactory, getSnapshotsPath, getTempSnapshotsPath } from './utils'; const namespace = 'method-class-conflict'; @@ -14,9 +14,7 @@ const snapshotsDir = path.join(getSnapshotsPath(), namespace); const specPath = path.join(getSpecsPath(), '3.0.x', 'sdk-method-class-conflict.yaml'); describe(`SDK: ${namespace}`, () => { - const createConfig = createSdkConfig({ - outputDir, - }); + const createConfig = createConfigFactory({ outputDir }); const scenarios = [ { diff --git a/packages/openapi-ts-tests/sdks/test/opencode.test.ts b/packages/openapi-ts-tests/sdks/test/opencode.test.ts index 8d9b04cb8f..199448a493 100644 --- a/packages/openapi-ts-tests/sdks/test/opencode.test.ts +++ b/packages/openapi-ts-tests/sdks/test/opencode.test.ts @@ -4,7 +4,7 @@ import path from 'node:path'; import { createClient } from '@hey-api/openapi-ts'; import { getFilePaths, getSpecsPath } from '../../utils'; -import { createSdkConfig, getSnapshotsPath, getTempSnapshotsPath } from './utils'; +import { createConfigFactory, getSnapshotsPath, getTempSnapshotsPath } from './utils'; const namespace = 'opencode'; @@ -14,9 +14,7 @@ const snapshotsDir = path.join(getSnapshotsPath(), namespace); const specPath = path.join(getSpecsPath(), '3.1.x', 'opencode.yaml'); describe(`SDK: ${namespace}`, () => { - const createConfig = createSdkConfig({ - outputDir, - }); + const createConfig = createConfigFactory({ outputDir }); const scenarios = [ { diff --git a/packages/openapi-ts-tests/sdks/test/utils.ts b/packages/openapi-ts-tests/sdks/test/utils.ts index 983cb282ef..5db3ad206e 100644 --- a/packages/openapi-ts-tests/sdks/test/utils.ts +++ b/packages/openapi-ts-tests/sdks/test/utils.ts @@ -6,9 +6,8 @@ import { type UserConfig } from '@hey-api/openapi-ts'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -export const createSdkConfig = - ({ outputDir }: { outputDir: string }) => - (userConfig: UserConfig) => +export function createConfigFactory({ outputDir }: { outputDir: string }) { + return (userConfig: UserConfig) => ({ ...userConfig, logs: { @@ -26,6 +25,7 @@ export const createSdkConfig = ), }, }) as const satisfies UserConfig; +} export const getSnapshotsPath = (): string => path.join(__dirname, '..', '__snapshots__'); diff --git a/packages/openapi-ts-tests/valibot/v1/.gitignore b/packages/openapi-ts-tests/valibot/v1/.gitignore index e0a0cbb0f4..d276aefe26 100644 --- a/packages/openapi-ts-tests/valibot/v1/.gitignore +++ b/packages/openapi-ts-tests/valibot/v1/.gitignore @@ -1,14 +1,5 @@ .DS_Store .idea -.tmp -.tsdown logs node_modules -temp - -.env coverage -dist - -# test files -.gen diff --git a/packages/openapi-ts-tests/valibot/v1/test/3.0.x.test.ts b/packages/openapi-ts-tests/valibot/v1/test/3.0.x.test.ts index c5b0e4962f..9eb6caff4e 100644 --- a/packages/openapi-ts-tests/valibot/v1/test/3.0.x.test.ts +++ b/packages/openapi-ts-tests/valibot/v1/test/3.0.x.test.ts @@ -4,15 +4,15 @@ import path from 'node:path'; import { createClient } from '@hey-api/openapi-ts'; import { getFilePaths } from '../../../utils'; -import { createValibotConfig, getSnapshotsPath, getTempSnapshotsPath } from './utils'; +import { snapshotsDir, tmpDir } from './constants'; +import { createConfigFactory } from './utils'; const version = '3.0.x'; -const outputDir = path.join(getTempSnapshotsPath(), version); -const snapshotsDir = path.join(getSnapshotsPath(), version); +const outputDir = path.join(tmpDir, version); describe(`OpenAPI ${version}`, () => { - const createConfig = createValibotConfig({ openApiVersion: version, outputDir }); + const createConfig = createConfigFactory({ openApiVersion: version, outputDir }); const scenarios = [ { @@ -48,7 +48,7 @@ describe(`OpenAPI ${version}`, () => { filePaths.map(async (filePath) => { const fileContent = fs.readFileSync(filePath, 'utf-8'); await expect(fileContent).toMatchFileSnapshot( - path.join(snapshotsDir, filePath.slice(outputDir.length + 1)), + path.join(snapshotsDir, version, filePath.slice(outputDir.length + 1)), ); }), ); diff --git a/packages/openapi-ts-tests/valibot/v1/test/3.1.x.test.ts b/packages/openapi-ts-tests/valibot/v1/test/3.1.x.test.ts index 53c1f8959e..5d913d351d 100644 --- a/packages/openapi-ts-tests/valibot/v1/test/3.1.x.test.ts +++ b/packages/openapi-ts-tests/valibot/v1/test/3.1.x.test.ts @@ -4,15 +4,15 @@ import path from 'node:path'; import { createClient } from '@hey-api/openapi-ts'; import { getFilePaths } from '../../../utils'; -import { createValibotConfig, getSnapshotsPath, getTempSnapshotsPath } from './utils'; +import { snapshotsDir, tmpDir } from './constants'; +import { createConfigFactory } from './utils'; const version = '3.1.x'; -const outputDir = path.join(getTempSnapshotsPath(), version); -const snapshotsDir = path.join(getSnapshotsPath(), version); +const outputDir = path.join(tmpDir, version); describe(`OpenAPI ${version}`, () => { - const createConfig = createValibotConfig({ openApiVersion: version, outputDir }); + const createConfig = createConfigFactory({ openApiVersion: version, outputDir }); const scenarios = [ { @@ -166,7 +166,7 @@ describe(`OpenAPI ${version}`, () => { filePaths.map(async (filePath) => { const fileContent = fs.readFileSync(filePath, 'utf-8'); await expect(fileContent).toMatchFileSnapshot( - path.join(snapshotsDir, filePath.slice(outputDir.length + 1)), + path.join(snapshotsDir, version, filePath.slice(outputDir.length + 1)), ); }), ); diff --git a/packages/openapi-ts-tests/valibot/v1/test/constants.ts b/packages/openapi-ts-tests/valibot/v1/test/constants.ts new file mode 100644 index 0000000000..e72988d8bb --- /dev/null +++ b/packages/openapi-ts-tests/valibot/v1/test/constants.ts @@ -0,0 +1,4 @@ +import path from 'node:path'; + +export const snapshotsDir = path.join(__dirname, '..', '__snapshots__'); +export const tmpDir = path.join(__dirname, '..', '.tmp'); diff --git a/packages/openapi-ts-tests/valibot/v1/test/globalTeardown.ts b/packages/openapi-ts-tests/valibot/v1/test/globalTeardown.ts new file mode 100644 index 0000000000..7c8712f70f --- /dev/null +++ b/packages/openapi-ts-tests/valibot/v1/test/globalTeardown.ts @@ -0,0 +1,7 @@ +import fs from 'node:fs'; + +import { tmpDir } from './constants'; + +export function teardown() { + fs.rmSync(tmpDir, { force: true, recursive: true }); +} diff --git a/packages/openapi-ts-tests/valibot/v1/test/utils.ts b/packages/openapi-ts-tests/valibot/v1/test/utils.ts index 2b4586f238..31917d2ced 100644 --- a/packages/openapi-ts-tests/valibot/v1/test/utils.ts +++ b/packages/openapi-ts-tests/valibot/v1/test/utils.ts @@ -1,22 +1,20 @@ import fs from 'node:fs'; import path from 'node:path'; -import { fileURLToPath } from 'node:url'; import { createClient, type UserConfig } from '@hey-api/openapi-ts'; import * as v from 'valibot'; import { getSpecsPath } from '../../../utils'; +import { tmpDir } from './constants'; -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -export const getSnapshotsPath = (): string => path.join(__dirname, '..', '__snapshots__'); - -export const getTempSnapshotsPath = (): string => path.join(__dirname, '..', '.gen', 'snapshots'); - -export const createValibotConfig = - ({ openApiVersion, outputDir }: { openApiVersion: string; outputDir: string }) => - (userConfig: UserConfig) => { +export function createConfigFactory({ + openApiVersion, + outputDir, +}: { + openApiVersion: string; + outputDir: string; +}) { + return (userConfig: UserConfig) => { const input = userConfig.input instanceof Array ? userConfig.input[0]! : userConfig.input; const inputPath = path.join( getSpecsPath(), @@ -39,6 +37,7 @@ export const createValibotConfig = output: path.join(outputDir, outputPath), } as UserConfig; }; +} function loadGeneratedSchemas(generatedPath: string): any { if (!fs.existsSync(generatedPath)) { @@ -79,7 +78,7 @@ export async function setupValibotTest( version = '3.1.x', ): Promise { const inputPath = path.join(getSpecsPath(), version, input); - const outputPath = path.join(__dirname, '.gen', version, output); + const outputPath = path.join(tmpDir, '.integration', version, output); fs.mkdirSync(outputPath, { recursive: true }); diff --git a/packages/openapi-ts-tests/valibot/v1/tsconfig.json b/packages/openapi-ts-tests/valibot/v1/tsconfig.json index b406106e5a..e7572df83d 100644 --- a/packages/openapi-ts-tests/valibot/v1/tsconfig.json +++ b/packages/openapi-ts-tests/valibot/v1/tsconfig.json @@ -1,6 +1,5 @@ { "extends": "../../tsconfig.base.json", "include": ["test/**/*", "__snapshots__/**/*"], - "exclude": [".gen/**/*"], "references": [{ "path": "../../../openapi-ts" }] } diff --git a/packages/openapi-ts-tests/zod/v3/test/3.0.x.test.ts b/packages/openapi-ts-tests/zod/v3/test/3.0.x.test.ts index b9c080a5f2..d441759618 100644 --- a/packages/openapi-ts-tests/zod/v3/test/3.0.x.test.ts +++ b/packages/openapi-ts-tests/zod/v3/test/3.0.x.test.ts @@ -4,7 +4,7 @@ import path from 'node:path'; import { createClient } from '@hey-api/openapi-ts'; import { getFilePaths } from '../../../utils'; -import { createZodConfig, getSnapshotsPath, getTempSnapshotsPath, zodVersions } from './utils'; +import { createConfigFactory, getSnapshotsPath, getTempSnapshotsPath, zodVersions } from './utils'; const version = '3.0.x'; @@ -13,7 +13,7 @@ for (const zodVersion of zodVersions) { const snapshotsDir = path.join(getSnapshotsPath(), version, zodVersion.folder); describe(`OpenAPI ${version}`, () => { - const createConfig = createZodConfig({ + const createConfig = createConfigFactory({ openApiVersion: version, outputDir, zodVersion, diff --git a/packages/openapi-ts-tests/zod/v3/test/3.1.x.test.ts b/packages/openapi-ts-tests/zod/v3/test/3.1.x.test.ts index ca5a271525..a538ccfaff 100644 --- a/packages/openapi-ts-tests/zod/v3/test/3.1.x.test.ts +++ b/packages/openapi-ts-tests/zod/v3/test/3.1.x.test.ts @@ -4,7 +4,7 @@ import path from 'node:path'; import { createClient } from '@hey-api/openapi-ts'; import { getFilePaths } from '../../../utils'; -import { createZodConfig, getSnapshotsPath, getTempSnapshotsPath, zodVersions } from './utils'; +import { createConfigFactory, getSnapshotsPath, getTempSnapshotsPath, zodVersions } from './utils'; const version = '3.1.x'; @@ -13,7 +13,7 @@ for (const zodVersion of zodVersions) { const snapshotsDir = path.join(getSnapshotsPath(), version, zodVersion.folder); describe(`OpenAPI ${version}`, () => { - const createConfig = createZodConfig({ + const createConfig = createConfigFactory({ openApiVersion: version, outputDir, zodVersion, diff --git a/packages/openapi-ts-tests/zod/v3/test/openapi.test.ts b/packages/openapi-ts-tests/zod/v3/test/openapi.test.ts index 145a7415b4..8f3c4375e3 100644 --- a/packages/openapi-ts-tests/zod/v3/test/openapi.test.ts +++ b/packages/openapi-ts-tests/zod/v3/test/openapi.test.ts @@ -4,7 +4,7 @@ import path from 'node:path'; import { createClient } from '@hey-api/openapi-ts'; import { getFilePaths } from '../../../utils'; -import { createZodConfig, getSnapshotsPath, getTempSnapshotsPath, zodVersions } from './utils'; +import { createConfigFactory, getSnapshotsPath, getTempSnapshotsPath, zodVersions } from './utils'; const versions = ['2.0.x', '3.0.x', '3.1.x']; @@ -14,7 +14,7 @@ for (const version of versions) { const snapshotsDir = path.join(getSnapshotsPath(), version, zodVersion.folder); describe(`OpenAPI ${version}`, () => { - const createConfig = createZodConfig({ + const createConfig = createConfigFactory({ openApiVersion: version, outputDir, zodVersion, diff --git a/packages/openapi-ts-tests/zod/v3/test/utils.ts b/packages/openapi-ts-tests/zod/v3/test/utils.ts index ae0b7897dc..7451b309a9 100644 --- a/packages/openapi-ts-tests/zod/v3/test/utils.ts +++ b/packages/openapi-ts-tests/zod/v3/test/utils.ts @@ -8,17 +8,16 @@ import { getSpecsPath } from '../../../utils'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -export const createZodConfig = - ({ - openApiVersion, - outputDir, - zodVersion, - }: { - openApiVersion: string; - outputDir: string; - zodVersion: (typeof zodVersions)[number]; - }) => - (userConfig: UserConfig) => { +export function createConfigFactory({ + openApiVersion, + outputDir, + zodVersion, +}: { + openApiVersion: string; + outputDir: string; + zodVersion: (typeof zodVersions)[number]; +}) { + return (userConfig: UserConfig) => { const input = userConfig.input instanceof Array ? userConfig.input[0]! : userConfig.input; const inputPath = path.join( getSpecsPath(), @@ -47,6 +46,7 @@ export const createZodConfig = output: path.join(outputDir, typeof userConfig.output === 'string' ? userConfig.output : ''), } as const satisfies UserConfig; }; +} export const getSnapshotsPath = (): string => path.join(__dirname, '..', '__snapshots__'); diff --git a/packages/openapi-ts-tests/zod/v4/test/3.0.x.test.ts b/packages/openapi-ts-tests/zod/v4/test/3.0.x.test.ts index b9c080a5f2..d441759618 100644 --- a/packages/openapi-ts-tests/zod/v4/test/3.0.x.test.ts +++ b/packages/openapi-ts-tests/zod/v4/test/3.0.x.test.ts @@ -4,7 +4,7 @@ import path from 'node:path'; import { createClient } from '@hey-api/openapi-ts'; import { getFilePaths } from '../../../utils'; -import { createZodConfig, getSnapshotsPath, getTempSnapshotsPath, zodVersions } from './utils'; +import { createConfigFactory, getSnapshotsPath, getTempSnapshotsPath, zodVersions } from './utils'; const version = '3.0.x'; @@ -13,7 +13,7 @@ for (const zodVersion of zodVersions) { const snapshotsDir = path.join(getSnapshotsPath(), version, zodVersion.folder); describe(`OpenAPI ${version}`, () => { - const createConfig = createZodConfig({ + const createConfig = createConfigFactory({ openApiVersion: version, outputDir, zodVersion, diff --git a/packages/openapi-ts-tests/zod/v4/test/3.1.x.test.ts b/packages/openapi-ts-tests/zod/v4/test/3.1.x.test.ts index c0e72e37f2..2d5aaaa02d 100644 --- a/packages/openapi-ts-tests/zod/v4/test/3.1.x.test.ts +++ b/packages/openapi-ts-tests/zod/v4/test/3.1.x.test.ts @@ -4,7 +4,7 @@ import path from 'node:path'; import { createClient } from '@hey-api/openapi-ts'; import { getFilePaths } from '../../../utils'; -import { createZodConfig, getSnapshotsPath, getTempSnapshotsPath, zodVersions } from './utils'; +import { createConfigFactory, getSnapshotsPath, getTempSnapshotsPath, zodVersions } from './utils'; const version = '3.1.x'; @@ -13,7 +13,7 @@ for (const zodVersion of zodVersions) { const snapshotsDir = path.join(getSnapshotsPath(), version, zodVersion.folder); describe(`OpenAPI ${version}`, () => { - const createConfig = createZodConfig({ + const createConfig = createConfigFactory({ openApiVersion: version, outputDir, zodVersion, diff --git a/packages/openapi-ts-tests/zod/v4/test/formats.test.ts b/packages/openapi-ts-tests/zod/v4/test/formats.test.ts index a0c50793e3..fb571f318e 100644 --- a/packages/openapi-ts-tests/zod/v4/test/formats.test.ts +++ b/packages/openapi-ts-tests/zod/v4/test/formats.test.ts @@ -4,7 +4,7 @@ import path from 'node:path'; import { createClient } from '@hey-api/openapi-ts'; import { getFilePaths } from '../../../utils'; -import { createZodConfig, getSnapshotsPath, getTempSnapshotsPath, zodVersions } from './utils'; +import { createConfigFactory, getSnapshotsPath, getTempSnapshotsPath, zodVersions } from './utils'; const version = '3.1.x'; @@ -13,7 +13,7 @@ for (const zodVersion of zodVersions) { const snapshotsDir = path.join(getSnapshotsPath(), version, zodVersion.folder); describe(`OpenAPI ${version} Zod formats`, () => { - const createConfig = createZodConfig({ + const createConfig = createConfigFactory({ openApiVersion: version, outputDir, zodVersion, diff --git a/packages/openapi-ts-tests/zod/v4/test/openapi.test.ts b/packages/openapi-ts-tests/zod/v4/test/openapi.test.ts index 82e2e249e6..1f8b290f93 100644 --- a/packages/openapi-ts-tests/zod/v4/test/openapi.test.ts +++ b/packages/openapi-ts-tests/zod/v4/test/openapi.test.ts @@ -4,7 +4,7 @@ import path from 'node:path'; import { createClient } from '@hey-api/openapi-ts'; import { getFilePaths } from '../../../utils'; -import { createZodConfig, getSnapshotsPath, getTempSnapshotsPath, zodVersions } from './utils'; +import { createConfigFactory, getSnapshotsPath, getTempSnapshotsPath, zodVersions } from './utils'; const versions = ['2.0.x', '3.0.x', '3.1.x']; @@ -14,7 +14,7 @@ for (const version of versions) { const snapshotsDir = path.join(getSnapshotsPath(), version, zodVersion.folder); describe(`OpenAPI ${version}`, () => { - const createConfig = createZodConfig({ + const createConfig = createConfigFactory({ openApiVersion: version, outputDir, zodVersion, diff --git a/packages/openapi-ts-tests/zod/v4/test/utils.ts b/packages/openapi-ts-tests/zod/v4/test/utils.ts index ae0b7897dc..7451b309a9 100644 --- a/packages/openapi-ts-tests/zod/v4/test/utils.ts +++ b/packages/openapi-ts-tests/zod/v4/test/utils.ts @@ -8,17 +8,16 @@ import { getSpecsPath } from '../../../utils'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -export const createZodConfig = - ({ - openApiVersion, - outputDir, - zodVersion, - }: { - openApiVersion: string; - outputDir: string; - zodVersion: (typeof zodVersions)[number]; - }) => - (userConfig: UserConfig) => { +export function createConfigFactory({ + openApiVersion, + outputDir, + zodVersion, +}: { + openApiVersion: string; + outputDir: string; + zodVersion: (typeof zodVersions)[number]; +}) { + return (userConfig: UserConfig) => { const input = userConfig.input instanceof Array ? userConfig.input[0]! : userConfig.input; const inputPath = path.join( getSpecsPath(), @@ -47,6 +46,7 @@ export const createZodConfig = output: path.join(outputDir, typeof userConfig.output === 'string' ? userConfig.output : ''), } as const satisfies UserConfig; }; +} export const getSnapshotsPath = (): string => path.join(__dirname, '..', '__snapshots__'); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2d1036df8b..b781770e0a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -48,7 +48,7 @@ importers: version: 7.0.0-dev.20260321.1 '@vitest/coverage-v8': specifier: 4.1.0 - version: 4.1.0(vitest@4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))) + version: 4.1.0(vitest@4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.12.14(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))) eslint: specifier: 9.39.2 version: 9.39.2(jiti@2.6.1) @@ -96,7 +96,7 @@ importers: version: 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) vitest: specifier: 4.1.0 - version: 4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.12.14(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) dev: devDependencies: @@ -146,8 +146,8 @@ importers: specifier: 2.2.0 version: 2.2.0 msw: - specifier: 2.10.2 - version: 2.10.2(@types/node@25.2.1)(typescript@5.9.3) + specifier: 2.12.14 + version: 2.12.14(@types/node@25.2.1)(typescript@5.9.3) nuxt: specifier: 3.21.0 version: 3.21.0(@netlify/blobs@9.1.2)(@parcel/watcher@2.5.1)(@types/node@25.2.1)(@vue/compiler-sfc@3.5.27)(cac@6.7.14)(db0@0.3.4)(encoding@0.1.13)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.9.2)(less@4.4.2)(magicast@0.5.2)(optionator@0.9.4)(rolldown@1.0.0-rc.9)(rollup@4.56.0)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue-tsc@3.2.4(typescript@5.9.3))(yaml@2.8.2) @@ -236,7 +236,7 @@ importers: devDependencies: '@angular-devkit/build-angular': specifier: 21.1.2 - version: 21.1.2(f1f0187b9a28baac9b02f8c93bfba118) + version: 21.1.2(e7b38691dcceec66c29b1e19d8dba0f4) '@angular/cli': specifier: 21.1.2 version: 21.1.2(@types/node@24.10.10)(chokidar@5.0.0)(hono@4.11.8) @@ -330,7 +330,7 @@ importers: devDependencies: '@angular-devkit/build-angular': specifier: 21.1.2 - version: 21.1.2(a3942970943f268369c4c88439aad5ea) + version: 21.1.2(b0adb2eb4671a686a9409000aca50fdf) '@angular/cli': specifier: 21.1.2 version: 21.1.2(@types/node@24.10.10)(chokidar@5.0.0)(hono@4.11.8) @@ -473,7 +473,7 @@ importers: version: 7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) vitest: specifier: 4.1.0 - version: 4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.12.14(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) examples/openapi-ts-fetch: dependencies: @@ -524,8 +524,8 @@ importers: specifier: 0.4.7 version: 0.4.7(eslint@9.39.2(jiti@2.6.1)) msw: - specifier: 2.10.2 - version: 2.10.2(@types/node@25.2.1)(typescript@5.9.3) + specifier: 2.12.14 + version: 2.12.14(@types/node@25.2.1)(typescript@5.9.3) oxfmt: specifier: 0.41.0 version: 0.41.0 @@ -543,7 +543,7 @@ importers: version: 7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) vitest: specifier: 4.1.0 - version: 4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.12.14(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) examples/openapi-ts-ky: dependencies: @@ -615,19 +615,19 @@ importers: examples/openapi-ts-nestjs: dependencies: '@nestjs/common': - specifier: ^11.0.1 - version: 11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2) + specifier: 11.0.1 + version: 11.0.1(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/core': - specifier: ^11.0.1 - version: 11.1.16(@nestjs/common@11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.16)(reflect-metadata@0.2.2)(rxjs@7.8.2) + specifier: 11.0.1 + version: 11.0.1(@nestjs/common@11.0.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.0.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/platform-express': - specifier: ^11.0.1 - version: 11.1.16(@nestjs/common@11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16) + specifier: 11.0.1 + version: 11.0.1(@nestjs/common@11.0.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.0.1) reflect-metadata: - specifier: ^0.2.2 + specifier: 0.2.2 version: 0.2.2 rxjs: - specifier: ^7.8.1 + specifier: 7.8.2 version: 7.8.2 devDependencies: '@hey-api/openapi-ts': @@ -635,7 +635,7 @@ importers: version: link:../../packages/openapi-ts '@nestjs/testing': specifier: 11.0.1 - version: 11.0.1(@nestjs/common@11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16)(@nestjs/platform-express@11.1.16) + version: 11.0.1(@nestjs/common@11.0.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.0.1)(@nestjs/platform-express@11.0.1) '@swc-node/register': specifier: 1.10.10 version: 1.10.10(@swc/core@1.11.29)(@swc/types@0.1.25)(typescript@5.9.3) @@ -659,7 +659,7 @@ importers: version: 7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) vitest: specifier: 4.1.0 - version: 4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.12.14(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) examples/openapi-ts-next: dependencies: @@ -797,7 +797,7 @@ importers: version: 8.0.2(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.13(typescript@5.9.3)) vitest: specifier: 4.1.0 - version: 4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.12.14(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) vue-tsc: specifier: 3.2.4 version: 3.2.4(typescript@5.9.3) @@ -952,7 +952,7 @@ importers: version: 8.0.2(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.13(typescript@5.9.3)) vitest: specifier: 4.1.0 - version: 4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.12.14(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) vue-tsc: specifier: 3.2.4 version: 3.2.4(typescript@5.9.3) @@ -1004,7 +1004,7 @@ importers: devDependencies: '@angular-devkit/build-angular': specifier: 21.1.2 - version: 21.1.2(d1d14c4ec45bbc59bdd6f28c4606c248) + version: 21.1.2(bce736dd892461a752d981a601516c23) '@angular/cli': specifier: 21.1.2 version: 21.1.2(@types/node@25.2.1)(chokidar@5.0.0)(hono@4.11.8) @@ -1165,7 +1165,7 @@ importers: version: 7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) vitest: specifier: 4.1.0 - version: 4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.12.14(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) examples/openapi-ts-tanstack-vue-query: dependencies: @@ -1250,7 +1250,7 @@ importers: version: 8.0.2(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vue@3.5.13(typescript@5.9.3)) vitest: specifier: 4.1.0 - version: 4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.12.14(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) vue-tsc: specifier: 3.2.4 version: 3.2.4(typescript@5.9.3) @@ -1337,7 +1337,7 @@ importers: version: 3.16.2 '@nuxt/test-utils': specifier: 4.0.0 - version: 4.0.0(@vue/test-utils@2.4.6)(jsdom@28.0.0)(magicast@0.3.5)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))) + version: 4.0.0(@vue/test-utils@2.4.6)(jsdom@28.0.0)(magicast@0.3.5)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.12.14(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))) vite: specifier: 7.3.1 version: 7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) @@ -1483,7 +1483,7 @@ importers: devDependencies: '@angular-devkit/build-angular': specifier: 21.1.2 - version: 21.1.2(d1d14c4ec45bbc59bdd6f28c4606c248) + version: 21.1.2(bce736dd892461a752d981a601516c23) '@angular/animations': specifier: 21.1.2 version: 21.1.2(@angular/core@21.1.2(@angular/compiler@21.1.2)(rxjs@7.8.2)(zone.js@0.16.0)) @@ -1568,9 +1568,6 @@ importers: ky: specifier: 1.14.3 version: 1.14.3 - msw: - specifier: 2.10.2 - version: 2.10.2(@types/node@25.2.1)(typescript@5.9.3) node-fetch: specifier: 3.3.2 version: 3.3.2 @@ -1596,6 +1593,18 @@ importers: specifier: 4.3.6 version: 4.3.6 + packages/openapi-ts-tests/msw/v2: + devDependencies: + '@hey-api/openapi-ts': + specifier: workspace:* + version: link:../../../openapi-ts + msw: + specifier: 2.12.14 + version: 2.12.14(@types/node@25.2.1)(typescript@5.9.3) + typescript: + specifier: 5.9.3 + version: 5.9.3 + packages/openapi-ts-tests/nestjs/v11: devDependencies: '@hey-api/openapi-ts': @@ -2775,21 +2784,9 @@ packages: commander: optional: true - '@borewit/text-codec@0.2.2': - resolution: {integrity: sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==} - '@braidai/lang@1.1.2': resolution: {integrity: sha512-qBcknbBufNHlui137Hft8xauQMTZDKdophmLFv05r2eNmdIv/MlPuP4TdUknHG68UdWLgVZwgxVe735HzJNIwA==} - '@bundled-es-modules/cookie@2.0.1': - resolution: {integrity: sha512-8o+5fRPLNbjbdGRRmJj3h6Hh1AQJf2dk3qQ/5ZFb+PXkRNiSoMGGUKlsgLfrxneb72axVJyIYji64E2+nNfYyw==} - - '@bundled-es-modules/statuses@1.0.1': - resolution: {integrity: sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==} - - '@bundled-es-modules/tough-cookie@0.1.6': - resolution: {integrity: sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==} - '@changesets/apply-release-plan@7.1.0': resolution: {integrity: sha512-yq8ML3YS7koKQ/9bk1PqO0HMzApIFNwjlwCnwFEXMzNe8NpzeeYYKCmnhWJGkN8g7E51MnWaSbqRcTcdIxUgnQ==} @@ -4676,8 +4673,8 @@ packages: cpu: [x64] os: [win32] - '@mswjs/interceptors@0.39.8': - resolution: {integrity: sha512-2+BzZbjRO7Ct61k8fMNHEtoKjeWI9pIlHFTqBwZ5icHpqszIgEZbjb1MW5Z0+bITTCTl3gk4PDBxs9tA/csXvA==} + '@mswjs/interceptors@0.41.3': + resolution: {integrity: sha512-cXu86tF4VQVfwz8W1SPbhoRyHJkti6mjH/XJIxp40jhO4j2k1m4KYrEykxqWPkFF3vrK4rgQppBh//AwyGSXPA==} engines: {node: '>=18'} '@napi-rs/nice-android-arm-eabi@1.1.1': @@ -4802,11 +4799,11 @@ packages: '@neoconfetti/svelte@2.0.0': resolution: {integrity: sha512-n/Uu7/XmHc8w0uBci0QWBjgbRzLhfWsH8yPJ5pMaseIvzSwabXvB30nb3JjzEYNBp9uGt4eCeY7LUmxAjnJV8A==} - '@nestjs/common@11.1.16': - resolution: {integrity: sha512-JSIeW+USuMJkkcNbiOdcPkVCeI3TSnXstIVEPpp3HiaKnPRuSbUUKm9TY9o/XpIcPHWUOQItAtC5BiAwFdVITQ==} + '@nestjs/common@11.0.1': + resolution: {integrity: sha512-GbPKvDz/sYjhR86ebZu+0F5jAvYDZDXY5WcHek9gkEkMI9eIo3xeH/F/tNIPhdyeWp3eG+kNWqR9VPtC18G+TA==} peerDependencies: - class-transformer: '>=0.4.1' - class-validator: '>=0.13.2' + class-transformer: '*' + class-validator: '*' reflect-metadata: ^0.1.12 || ^0.2.0 rxjs: ^7.1.0 peerDependenciesMeta: @@ -4815,8 +4812,8 @@ packages: class-validator: optional: true - '@nestjs/core@11.1.16': - resolution: {integrity: sha512-tXWXyCiqWthelJjrE0KLFjf0O98VEt+WPVx5CrqCf+059kIxJ8y1Vw7Cy7N4fwQafWNrmFL2AfN87DDMbVAY0w==} + '@nestjs/core@11.0.1': + resolution: {integrity: sha512-Yn7X2aInjmX7yxpH8TjJmgC0JPvs+tcreETkquSRmKbuK5J28dZDi8loiaw3eRTLLvzzUovv5mlqFxmVhDESOw==} engines: {node: '>= 20'} peerDependencies: '@nestjs/common': ^11.0.0 @@ -4833,8 +4830,8 @@ packages: '@nestjs/websockets': optional: true - '@nestjs/platform-express@11.1.16': - resolution: {integrity: sha512-IOegr5+ZfUiMKgk+garsSU4MOkPRhm46e6w8Bp1GcO4vCdl9Piz6FlWAzKVfa/U3Hn/DdzSVJOW3TWcQQFdBDw==} + '@nestjs/platform-express@11.0.1': + resolution: {integrity: sha512-vkAcm4Lm/aAvvpYtRcRKuwzsliy4SqoSp0saHOIx6VdphIb1k7ziRkjDbLFDczDZmkiyX1pJ9kI5SHjoQzVDPw==} peerDependencies: '@nestjs/common': ^11.0.0 '@nestjs/core': ^11.0.0 @@ -7554,13 +7551,6 @@ packages: '@vue/composition-api': optional: true - '@tokenizer/inflate@0.4.1': - resolution: {integrity: sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==} - engines: {node: '>=18'} - - '@tokenizer/token@0.3.0': - resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} - '@tsconfig/node10@1.0.11': resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} @@ -9344,9 +9334,9 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - concat-stream@2.0.0: - resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==} - engines: {'0': node >= 6.0} + concat-stream@1.6.2: + resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} + engines: {'0': node >= 0.8} confbox@0.1.8: resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} @@ -9674,6 +9664,15 @@ packages: supports-color: optional: true + debug@4.3.6: + resolution: {integrity: sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + debug@4.3.7: resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} engines: {node: '>=6.0'} @@ -10421,6 +10420,10 @@ packages: resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} engines: {node: '>= 0.10.0'} + express@5.0.1: + resolution: {integrity: sha512-ORF7g6qGnD+YtUG9yx4DFoqCShNMmUKiXuT5oWMHiOvt/4WFbHC6yCwQMTSBMno7AqntNCAzzcnnjowRkTL9eQ==} + engines: {node: '>= 18'} + express@5.2.1: resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} engines: {node: '>= 18'} @@ -10542,10 +10545,6 @@ packages: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} - file-type@21.3.0: - resolution: {integrity: sha512-8kPJMIGz1Yt/aPEwOsrR97ZyZaD1Iqm8PClb1nYFclUCkBi0Ma5IsYNQzvSFS9ib51lWyIw5mIT9rWzI/xjpzA==} - engines: {node: '>=20'} - file-uri-to-path@1.0.0: resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} @@ -11764,10 +11763,6 @@ packages: resolution: {integrity: sha512-+Y2DqovevLkb6DrSQ6SXTYLEd6kvlRbhsxzgJrk7BUfOVA/mt21ak6pFDZDKxiAczHMWxrb02kXBTSTIA0O94A==} hasBin: true - load-esm@1.0.3: - resolution: {integrity: sha512-v5xlu8eHD1+6r8EHTg6hfmO97LN8ugKtiXcy5e6oN72iD2r6u0RPfLl6fxM+7Wnh2ZRq15o0russMst44WauPA==} - engines: {node: '>=13.2.0'} - load-tsconfig@0.2.5: resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -12270,6 +12265,9 @@ packages: ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -12280,8 +12278,8 @@ packages: msgpackr@1.11.5: resolution: {integrity: sha512-UjkUHN0yqp9RWKy0Lplhh+wlpdt9oQBYgULZOiFhV3VclSF1JnSQWZ5r9gORQlNYaUKQoR8itv7g7z1xDDuACA==} - msw@2.10.2: - resolution: {integrity: sha512-RCKM6IZseZQCWcSWlutdf590M8nVfRHG1ImwzOtwz8IYxgT4zhUO0rfTcTvDGiaFE0Rhcc+h43lcF3Jc9gFtwQ==} + msw@2.12.14: + resolution: {integrity: sha512-4KXa4nVBIBjbDbd7vfQNuQ25eFxug0aropCQFoI0JdOBuJWamkT1yLVIWReFI8SiTRc+H1hKzaNk+cLk2N9rtQ==} engines: {node: '>=18'} hasBin: true peerDependencies: @@ -12293,9 +12291,10 @@ packages: muggle-string@0.4.1: resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} - multer@2.1.1: - resolution: {integrity: sha512-mo+QTzKlx8R7E5ylSXxWzGoXoZbOsRMpyitcht8By2KHvMbf3tjwosZ/Mu/XYU6UuJ3VZnODIrak5ZrPiPyB6A==} - engines: {node: '>= 10.16.0'} + multer@1.4.5-lts.1: + resolution: {integrity: sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==} + engines: {node: '>= 6.0.0'} + deprecated: Multer 1.x is impacted by a number of vulnerabilities, which have been patched in 2.x. You should upgrade to the latest 2.x version. multicast-dns@7.2.5: resolution: {integrity: sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==} @@ -12946,6 +12945,10 @@ packages: path-to-regexp@6.3.0: resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} + path-to-regexp@8.2.0: + resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==} + engines: {node: '>=16'} + path-to-regexp@8.3.0: resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} @@ -13447,9 +13450,6 @@ packages: prr@1.0.1: resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} - psl@1.15.0: - resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} - pump@3.0.3: resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} @@ -13482,9 +13482,6 @@ packages: quansync@1.0.0: resolution: {integrity: sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA==} - querystringify@2.2.0: - resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} - queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -13751,6 +13748,9 @@ packages: resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} engines: {node: '>= 4'} + rettime@0.10.1: + resolution: {integrity: sha512-uyDrIlUEH37cinabq0AX4QbgV4HbFZ/gqoiunWQ1UqBtRvTTytwhNYjE++pO/MjPTZL5KQCf2bEoJ/BJNVQ5Kw==} + reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -14388,10 +14388,6 @@ packages: strip-literal@3.1.0: resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} - strtok3@10.3.4: - resolution: {integrity: sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg==} - engines: {node: '>=18'} - structured-clone-es@1.0.0: resolution: {integrity: sha512-FL8EeKFFyNQv5cMnXI31CIMCsFarSVI2bF0U0ImeNE3g/F1IvJQyqzOXxPBRXiwQfyBTlbNe88jh1jFW0O/jiQ==} @@ -14642,10 +14638,6 @@ packages: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} - token-types@6.1.2: - resolution: {integrity: sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==} - engines: {node: '>=14.16'} - tokenx@1.3.0: resolution: {integrity: sha512-NLdXTEZkKiO0gZuLtMoZKjCXTREXeZZt8nnnNeyoXtNZAfG/GKGSbQtLU5STspc0rMSwcA+UJfWZkbNU01iKmQ==} @@ -14656,10 +14648,6 @@ packages: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} - tough-cookie@4.1.4: - resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==} - engines: {node: '>=6'} - tough-cookie@6.0.0: resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==} engines: {node: '>=16'} @@ -14890,10 +14878,6 @@ packages: resolution: {integrity: sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==} engines: {node: '>=8'} - uint8array-extras@1.5.0: - resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} - engines: {node: '>=18'} - ultrahtml@1.6.0: resolution: {integrity: sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==} @@ -15024,10 +15008,6 @@ packages: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} - universalify@0.2.0: - resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} - engines: {node: '>= 4.0.0'} - universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} @@ -15229,6 +15209,9 @@ packages: uploadthing: optional: true + until-async@3.0.2: + resolution: {integrity: sha512-IiSk4HlzAMqTUseHHe3VhIGyuFmN90zMTpD3Z3y8jeQbzLIq500MVM7Jq2vUAnTKAFPJrqwkzr6PoTcPhGcOiw==} + untun@0.1.3: resolution: {integrity: sha512-4luGP9LMYszMRZwsvyUd9MrxgEGZdZuZgpVQHEEX0lCYFESasVRvZd0EYpCkOIbJKHMuv0LskpXc/8Un+MJzEQ==} hasBin: true @@ -15265,9 +15248,6 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - url-parse@1.5.10: - resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} - urlpattern-polyfill@10.1.0: resolution: {integrity: sha512-IGjKp/o0NL3Bso1PymYURCJxMPNAf/ILOpendP9f5B6e1rTJgdgiOvgfoT8VxCAdY+Wisb9uhGaJJf3yZ2V9nw==} @@ -16002,6 +15982,10 @@ packages: xmlchars@2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -16219,13 +16203,13 @@ snapshots: transitivePeerDependencies: - chokidar - '@angular-devkit/build-angular@21.1.2(a3942970943f268369c4c88439aad5ea)': + '@angular-devkit/build-angular@21.1.2(b0adb2eb4671a686a9409000aca50fdf)': dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.2101.2(chokidar@5.0.0) '@angular-devkit/build-webpack': 0.2101.2(chokidar@5.0.0)(webpack-dev-server@5.2.2(tslib@2.8.1)(webpack@5.104.1(@swc/core@1.15.18)(esbuild@0.27.2)))(webpack@5.104.1(@swc/core@1.15.18)(esbuild@0.27.2)) '@angular-devkit/core': 21.1.2(chokidar@5.0.0) - '@angular/build': 21.1.2(fa3d27d2bfba2058220c00fd3fb69db1) + '@angular/build': 21.1.2(c61f5a4471c856746a2fa4de08e90517) '@angular/compiler-cli': 21.1.2(@angular/compiler@21.1.2)(typescript@5.9.3) '@babel/core': 7.28.5 '@babel/generator': 7.28.5 @@ -16308,13 +16292,13 @@ snapshots: - webpack-cli - yaml - '@angular-devkit/build-angular@21.1.2(d1d14c4ec45bbc59bdd6f28c4606c248)': + '@angular-devkit/build-angular@21.1.2(bce736dd892461a752d981a601516c23)': dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.2101.2(chokidar@5.0.0) '@angular-devkit/build-webpack': 0.2101.2(chokidar@5.0.0)(webpack-dev-server@5.2.2(tslib@2.8.1)(webpack@5.104.1(@swc/core@1.15.18)(esbuild@0.27.2)))(webpack@5.104.1(@swc/core@1.15.18)(esbuild@0.27.2)) '@angular-devkit/core': 21.1.2(chokidar@5.0.0) - '@angular/build': 21.1.2(ca7d45c5c89e8f8891af69ebb1866aaf) + '@angular/build': 21.1.2(ab55d5d3e10a09025eb4fe22599bb5be) '@angular/compiler-cli': 21.1.2(@angular/compiler@21.1.2)(typescript@5.9.3) '@babel/core': 7.28.5 '@babel/generator': 7.28.5 @@ -16397,13 +16381,13 @@ snapshots: - webpack-cli - yaml - '@angular-devkit/build-angular@21.1.2(f1f0187b9a28baac9b02f8c93bfba118)': + '@angular-devkit/build-angular@21.1.2(e7b38691dcceec66c29b1e19d8dba0f4)': dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.2101.2(chokidar@5.0.0) '@angular-devkit/build-webpack': 0.2101.2(chokidar@5.0.0)(webpack-dev-server@5.2.2(tslib@2.8.1)(webpack@5.104.1(@swc/core@1.15.18)(esbuild@0.27.2)))(webpack@5.104.1(@swc/core@1.15.18)(esbuild@0.27.2)) '@angular-devkit/core': 21.1.2(chokidar@5.0.0) - '@angular/build': 21.1.2(59f40ca61b5d02419ec13dbea9cd06eb) + '@angular/build': 21.1.2(cf7fde1dea0a268731df571b0c811188) '@angular/compiler-cli': 21.1.2(@angular/compiler@21.1.2)(typescript@5.9.3) '@babel/core': 7.28.5 '@babel/generator': 7.28.5 @@ -16521,7 +16505,7 @@ snapshots: '@angular/core': 21.1.2(@angular/compiler@21.1.2)(rxjs@7.8.2)(zone.js@0.16.0) tslib: 2.8.1 - '@angular/build@21.1.2(59f40ca61b5d02419ec13dbea9cd06eb)': + '@angular/build@21.1.2(ab55d5d3e10a09025eb4fe22599bb5be)': dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.2101.2(chokidar@5.0.0) @@ -16530,8 +16514,8 @@ snapshots: '@babel/core': 7.28.5 '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-split-export-declaration': 7.24.7 - '@inquirer/confirm': 5.1.21(@types/node@24.10.10) - '@vitejs/plugin-basic-ssl': 2.1.0(vite@7.3.0(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + '@inquirer/confirm': 5.1.21(@types/node@25.2.1) + '@vitejs/plugin-basic-ssl': 2.1.0(vite@7.3.0(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) beasties: 0.3.5 browserslist: 4.28.1 esbuild: 0.27.2 @@ -16552,7 +16536,7 @@ snapshots: tslib: 2.8.1 typescript: 5.9.3 undici: 7.18.2 - vite: 7.3.0(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.0(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) watchpack: 2.5.0 optionalDependencies: '@angular/core': 21.1.2(@angular/compiler@21.1.2)(rxjs@7.8.2)(zone.js@0.16.0) @@ -16563,8 +16547,8 @@ snapshots: less: 4.4.2 lmdb: 3.4.4 postcss: 8.5.6 - tailwindcss: 3.4.14(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@24.10.10)(typescript@5.9.3)) - vitest: 4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.0(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + tailwindcss: 3.4.14(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.2.1)(typescript@5.9.3)) + vitest: 4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.12.14(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) transitivePeerDependencies: - '@types/node' - chokidar @@ -16578,7 +16562,7 @@ snapshots: - tsx - yaml - '@angular/build@21.1.2(ca7d45c5c89e8f8891af69ebb1866aaf)': + '@angular/build@21.1.2(c61f5a4471c856746a2fa4de08e90517)': dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.2101.2(chokidar@5.0.0) @@ -16587,8 +16571,8 @@ snapshots: '@babel/core': 7.28.5 '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-split-export-declaration': 7.24.7 - '@inquirer/confirm': 5.1.21(@types/node@25.2.1) - '@vitejs/plugin-basic-ssl': 2.1.0(vite@7.3.0(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + '@inquirer/confirm': 5.1.21(@types/node@24.10.10) + '@vitejs/plugin-basic-ssl': 2.1.0(vite@7.3.0(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) beasties: 0.3.5 browserslist: 4.28.1 esbuild: 0.27.2 @@ -16609,7 +16593,7 @@ snapshots: tslib: 2.8.1 typescript: 5.9.3 undici: 7.18.2 - vite: 7.3.0(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) + vite: 7.3.0(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) watchpack: 2.5.0 optionalDependencies: '@angular/core': 21.1.2(@angular/compiler@21.1.2)(rxjs@7.8.2)(zone.js@0.16.0) @@ -16620,8 +16604,8 @@ snapshots: less: 4.4.2 lmdb: 3.4.4 postcss: 8.5.6 - tailwindcss: 3.4.14(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@25.2.1)(typescript@5.9.3)) - vitest: 4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + tailwindcss: 3.4.14(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@24.10.10)(typescript@5.9.3)) + vitest: 4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.12.14(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) transitivePeerDependencies: - '@types/node' - chokidar @@ -16635,7 +16619,7 @@ snapshots: - tsx - yaml - '@angular/build@21.1.2(fa3d27d2bfba2058220c00fd3fb69db1)': + '@angular/build@21.1.2(cf7fde1dea0a268731df571b0c811188)': dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.2101.2(chokidar@5.0.0) @@ -16678,7 +16662,7 @@ snapshots: lmdb: 3.4.4 postcss: 8.5.6 tailwindcss: 3.4.14(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@24.10.10)(typescript@5.9.3)) - vitest: 4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + vitest: 4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.12.14(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.0(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) transitivePeerDependencies: - '@types/node' - chokidar @@ -17883,23 +17867,8 @@ snapshots: cac: 6.7.14 citty: 0.1.6 - '@borewit/text-codec@0.2.2': {} - '@braidai/lang@1.1.2': {} - '@bundled-es-modules/cookie@2.0.1': - dependencies: - cookie: 0.7.2 - - '@bundled-es-modules/statuses@1.0.1': - dependencies: - statuses: 2.0.2 - - '@bundled-es-modules/tough-cookie@0.1.6': - dependencies: - '@types/tough-cookie': 4.0.5 - tough-cookie: 4.1.4 - '@changesets/apply-release-plan@7.1.0': dependencies: '@changesets/config': 3.1.3 @@ -19485,7 +19454,7 @@ snapshots: '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3': optional: true - '@mswjs/interceptors@0.39.8': + '@mswjs/interceptors@0.41.3': dependencies: '@open-draft/deferred-promise': 2.2.0 '@open-draft/logger': 0.3.0 @@ -19582,51 +19551,47 @@ snapshots: '@neoconfetti/svelte@2.0.0': {} - '@nestjs/common@11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2)': + '@nestjs/common@11.0.1(reflect-metadata@0.2.2)(rxjs@7.8.2)': dependencies: - file-type: 21.3.0 iterare: 1.2.1 - load-esm: 1.0.3 reflect-metadata: 0.2.2 rxjs: 7.8.2 tslib: 2.8.1 uid: 2.0.2 - transitivePeerDependencies: - - supports-color - '@nestjs/core@11.1.16(@nestjs/common@11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.16)(reflect-metadata@0.2.2)(rxjs@7.8.2)': + '@nestjs/core@11.0.1(@nestjs/common@11.0.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.0.1)(reflect-metadata@0.2.2)(rxjs@7.8.2)': dependencies: - '@nestjs/common': 11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.0.1(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nuxt/opencollective': 0.4.1 fast-safe-stringify: 2.1.1 iterare: 1.2.1 - path-to-regexp: 8.3.0 + path-to-regexp: 8.2.0 reflect-metadata: 0.2.2 rxjs: 7.8.2 tslib: 2.8.1 uid: 2.0.2 optionalDependencies: - '@nestjs/platform-express': 11.1.16(@nestjs/common@11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16) + '@nestjs/platform-express': 11.0.1(@nestjs/common@11.0.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.0.1) - '@nestjs/platform-express@11.1.16(@nestjs/common@11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16)': + '@nestjs/platform-express@11.0.1(@nestjs/common@11.0.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.0.1)': dependencies: - '@nestjs/common': 11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.16(@nestjs/common@11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.16)(reflect-metadata@0.2.2)(rxjs@7.8.2) - cors: 2.8.6 - express: 5.2.1 - multer: 2.1.1 - path-to-regexp: 8.3.0 + '@nestjs/common': 11.0.1(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.0.1(@nestjs/common@11.0.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.0.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) + body-parser: 1.20.3 + cors: 2.8.5 + express: 5.0.1 + multer: 1.4.5-lts.1 tslib: 2.8.1 transitivePeerDependencies: - supports-color - '@nestjs/testing@11.0.1(@nestjs/common@11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16)(@nestjs/platform-express@11.1.16)': + '@nestjs/testing@11.0.1(@nestjs/common@11.0.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.0.1)(@nestjs/platform-express@11.0.1)': dependencies: - '@nestjs/common': 11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.16(@nestjs/common@11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.16)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.0.1(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.0.1(@nestjs/common@11.0.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.0.1)(reflect-metadata@0.2.2)(rxjs@7.8.2) tslib: 2.8.1 optionalDependencies: - '@nestjs/platform-express': 11.1.16(@nestjs/common@11.1.16(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.16) + '@nestjs/platform-express': 11.0.1(@nestjs/common@11.0.1(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.0.1) '@netlify/binary-info@1.0.0': {} @@ -20377,7 +20342,7 @@ snapshots: transitivePeerDependencies: - magicast - '@nuxt/test-utils@4.0.0(@vue/test-utils@2.4.6)(jsdom@28.0.0)(magicast@0.3.5)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))': + '@nuxt/test-utils@4.0.0(@vue/test-utils@2.4.6)(jsdom@28.0.0)(magicast@0.3.5)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.12.14(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))': dependencies: '@clack/prompts': 1.0.0 '@nuxt/devtools-kit': 2.7.0(magicast@0.3.5)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) @@ -20406,12 +20371,12 @@ snapshots: tinyexec: 1.0.2 ufo: 1.6.3 unplugin: 3.0.0 - vitest-environment-nuxt: 1.0.1(@vue/test-utils@2.4.6)(jsdom@28.0.0)(magicast@0.3.5)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))) + vitest-environment-nuxt: 1.0.1(@vue/test-utils@2.4.6)(jsdom@28.0.0)(magicast@0.3.5)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.12.14(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))) vue: 3.5.27(typescript@5.9.3) optionalDependencies: '@vue/test-utils': 2.4.6 jsdom: 28.0.0 - vitest: 4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + vitest: 4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.12.14(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) transitivePeerDependencies: - crossws - magicast @@ -22538,15 +22503,6 @@ snapshots: vue: 3.5.25(typescript@5.9.3) vue-demi: 0.14.10(vue@3.5.25(typescript@5.9.3)) - '@tokenizer/inflate@0.4.1': - dependencies: - debug: 4.4.3 - token-types: 6.1.2 - transitivePeerDependencies: - - supports-color - - '@tokenizer/token@0.3.0': {} - '@tsconfig/node10@1.0.11': optional: true @@ -23292,7 +23248,7 @@ snapshots: vite: 7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) vue: 3.5.27(typescript@5.9.3) - '@vitest/coverage-v8@4.1.0(vitest@4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))': + '@vitest/coverage-v8@4.1.0(vitest@4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.12.14(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))': dependencies: '@bcoe/v8-coverage': 1.0.2 '@vitest/utils': 4.1.0 @@ -23304,7 +23260,7 @@ snapshots: obug: 2.1.1 std-env: 4.0.0 tinyrainbow: 3.0.3 - vitest: 4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + vitest: 4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.12.14(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) '@vitest/expect@4.1.0': dependencies: @@ -23315,32 +23271,32 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.0.3 - '@vitest/mocker@4.1.0(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.0(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/mocker@4.1.0(msw@2.12.14(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.0(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@vitest/spy': 4.1.0 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - msw: 2.10.2(@types/node@24.10.10)(typescript@5.9.3) + msw: 2.12.14(@types/node@24.10.10)(typescript@5.9.3) vite: 7.3.0(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) optional: true - '@vitest/mocker@4.1.0(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/mocker@4.1.0(msw@2.12.14(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@vitest/spy': 4.1.0 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - msw: 2.10.2(@types/node@24.10.10)(typescript@5.9.3) + msw: 2.12.14(@types/node@24.10.10)(typescript@5.9.3) vite: 7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) - '@vitest/mocker@4.1.0(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/mocker@4.1.0(msw@2.12.14(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@vitest/spy': 4.1.0 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - msw: 2.10.2(@types/node@25.2.1)(typescript@5.9.3) + msw: 2.12.14(@types/node@25.2.1)(typescript@5.9.3) vite: 7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2) '@vitest/pretty-format@4.1.0': @@ -24825,11 +24781,11 @@ snapshots: concat-map@0.0.1: {} - concat-stream@2.0.0: + concat-stream@1.6.2: dependencies: buffer-from: 1.1.2 inherits: 2.0.4 - readable-stream: 3.6.2 + readable-stream: 2.3.8 typedarray: 0.0.6 confbox@0.1.8: {} @@ -25156,6 +25112,10 @@ snapshots: dependencies: ms: 2.1.3 + debug@4.3.6: + dependencies: + ms: 2.1.2 + debug@4.3.7: dependencies: ms: 2.1.3 @@ -25428,7 +25388,7 @@ snapshots: accepts: 1.3.8 base64id: 2.0.0 cookie: 0.7.2 - cors: 2.8.5 + cors: 2.8.6 debug: 4.3.7 engine.io-parser: 5.2.3 ws: 8.17.1 @@ -26227,6 +26187,43 @@ snapshots: transitivePeerDependencies: - supports-color + express@5.0.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.2.2 + content-disposition: 1.0.1 + content-type: 1.0.5 + cookie: 0.7.1 + cookie-signature: 1.2.2 + debug: 4.3.6 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.1 + fresh: 2.0.0 + http-errors: 2.0.0 + merge-descriptors: 2.0.0 + methods: 1.1.2 + mime-types: 3.0.1 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.13.0 + range-parser: 1.2.1 + router: 2.2.0 + safe-buffer: 5.2.1 + send: 1.2.0 + serve-static: 2.2.1 + setprototypeof: 1.2.0 + statuses: 2.0.1 + type-is: 2.0.1 + utils-merge: 1.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + express@5.2.1: dependencies: accepts: 2.0.0 @@ -26400,15 +26397,6 @@ snapshots: dependencies: flat-cache: 4.0.1 - file-type@21.3.0: - dependencies: - '@tokenizer/inflate': 0.4.1 - strtok3: 10.3.4 - token-types: 6.1.2 - uint8array-extras: 1.5.0 - transitivePeerDependencies: - - supports-color - file-uri-to-path@1.0.0: {} fill-range@7.1.1: @@ -27754,8 +27742,6 @@ snapshots: '@lmdb/lmdb-win32-x64': 3.4.4 optional: true - load-esm@1.0.3: {} - load-tsconfig@0.2.5: {} loader-runner@4.3.1: {} @@ -28378,6 +28364,8 @@ snapshots: ms@2.0.0: {} + ms@2.1.2: {} + ms@2.1.3: {} msgpackr-extract@3.0.3: @@ -28397,25 +28385,25 @@ snapshots: msgpackr-extract: 3.0.3 optional: true - msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3): + msw@2.12.14(@types/node@24.10.10)(typescript@5.9.3): dependencies: - '@bundled-es-modules/cookie': 2.0.1 - '@bundled-es-modules/statuses': 1.0.1 - '@bundled-es-modules/tough-cookie': 0.1.6 '@inquirer/confirm': 5.1.21(@types/node@24.10.10) - '@mswjs/interceptors': 0.39.8 + '@mswjs/interceptors': 0.41.3 '@open-draft/deferred-promise': 2.2.0 - '@open-draft/until': 2.1.0 - '@types/cookie': 0.6.0 '@types/statuses': 2.0.6 + cookie: 1.0.2 graphql: 16.13.1 headers-polyfill: 4.0.3 is-node-process: 1.2.0 outvariant: 1.4.3 path-to-regexp: 6.3.0 picocolors: 1.1.1 + rettime: 0.10.1 + statuses: 2.0.2 strict-event-emitter: 0.5.1 - type-fest: 4.41.0 + tough-cookie: 6.0.0 + type-fest: 5.5.0 + until-async: 3.0.2 yargs: 17.7.2 optionalDependencies: typescript: 5.9.3 @@ -28423,25 +28411,25 @@ snapshots: - '@types/node' optional: true - msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3): + msw@2.12.14(@types/node@25.2.1)(typescript@5.9.3): dependencies: - '@bundled-es-modules/cookie': 2.0.1 - '@bundled-es-modules/statuses': 1.0.1 - '@bundled-es-modules/tough-cookie': 0.1.6 '@inquirer/confirm': 5.1.21(@types/node@25.2.1) - '@mswjs/interceptors': 0.39.8 + '@mswjs/interceptors': 0.41.3 '@open-draft/deferred-promise': 2.2.0 - '@open-draft/until': 2.1.0 - '@types/cookie': 0.6.0 '@types/statuses': 2.0.6 + cookie: 1.0.2 graphql: 16.13.1 headers-polyfill: 4.0.3 is-node-process: 1.2.0 outvariant: 1.4.3 path-to-regexp: 6.3.0 picocolors: 1.1.1 + rettime: 0.10.1 + statuses: 2.0.2 strict-event-emitter: 0.5.1 - type-fest: 4.41.0 + tough-cookie: 6.0.0 + type-fest: 5.5.0 + until-async: 3.0.2 yargs: 17.7.2 optionalDependencies: typescript: 5.9.3 @@ -28450,12 +28438,15 @@ snapshots: muggle-string@0.4.1: {} - multer@2.1.1: + multer@1.4.5-lts.1: dependencies: append-field: 1.0.0 busboy: 1.6.0 - concat-stream: 2.0.0 + concat-stream: 1.6.2 + mkdirp: 0.5.6 + object-assign: 4.1.1 type-is: 1.6.18 + xtend: 4.0.2 multicast-dns@7.2.5: dependencies: @@ -29778,6 +29769,8 @@ snapshots: path-to-regexp@6.3.0: {} + path-to-regexp@8.2.0: {} + path-to-regexp@8.3.0: {} path-type@4.0.0: {} @@ -30262,10 +30255,6 @@ snapshots: prr@1.0.1: optional: true - psl@1.15.0: - dependencies: - punycode: 2.3.1 - pump@3.0.3: dependencies: end-of-stream: 1.4.5 @@ -30291,8 +30280,6 @@ snapshots: quansync@1.0.0: {} - querystringify@2.2.0: {} - queue-microtask@1.2.3: {} quick-format-unescaped@4.0.4: {} @@ -30592,6 +30579,8 @@ snapshots: retry@0.13.1: {} + rettime@0.10.1: {} + reusify@1.1.0: {} rfdc@1.4.1: {} @@ -31461,10 +31450,6 @@ snapshots: dependencies: js-tokens: 9.0.1 - strtok3@10.3.4: - dependencies: - '@tokenizer/token': 0.3.0 - structured-clone-es@1.0.0: {} styled-jsx@5.1.6(react@19.0.0): @@ -31819,25 +31804,12 @@ snapshots: toidentifier@1.0.1: {} - token-types@6.1.2: - dependencies: - '@borewit/text-codec': 0.2.2 - '@tokenizer/token': 0.3.0 - ieee754: 1.2.1 - tokenx@1.3.0: {} toml@3.0.0: {} totalist@3.0.1: {} - tough-cookie@4.1.4: - dependencies: - psl: 1.15.0 - punycode: 2.3.1 - universalify: 0.2.0 - url-parse: 1.5.10 - tough-cookie@6.0.0: dependencies: tldts: 7.0.22 @@ -32093,8 +32065,6 @@ snapshots: dependencies: '@lukeed/csprng': 1.1.0 - uint8array-extras@1.5.0: {} - ultrahtml@1.6.0: {} unbox-primitive@1.1.0: @@ -32335,8 +32305,6 @@ snapshots: universalify@0.1.2: {} - universalify@0.2.0: {} - universalify@2.0.1: {} unixify@1.0.0: @@ -32536,6 +32504,8 @@ snapshots: db0: 0.3.4 ioredis: 5.9.2 + until-async@3.0.2: {} + untun@0.1.3: dependencies: citty: 0.1.6 @@ -32599,11 +32569,6 @@ snapshots: dependencies: punycode: 2.3.1 - url-parse@1.5.10: - dependencies: - querystringify: 2.2.0 - requires-port: 1.0.0 - urlpattern-polyfill@10.1.0: {} urlpattern-polyfill@8.0.2: {} @@ -33048,9 +33013,9 @@ snapshots: - universal-cookie - yaml - vitest-environment-nuxt@1.0.1(@vue/test-utils@2.4.6)(jsdom@28.0.0)(magicast@0.3.5)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))): + vitest-environment-nuxt@1.0.1(@vue/test-utils@2.4.6)(jsdom@28.0.0)(magicast@0.3.5)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.12.14(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))): dependencies: - '@nuxt/test-utils': 4.0.0(@vue/test-utils@2.4.6)(jsdom@28.0.0)(magicast@0.3.5)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))) + '@nuxt/test-utils': 4.0.0(@vue/test-utils@2.4.6)(jsdom@28.0.0)(magicast@0.3.5)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.12.14(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2))) transitivePeerDependencies: - '@cucumber/cucumber' - '@jest/globals' @@ -33067,10 +33032,10 @@ snapshots: - vite - vitest - vitest@4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.0(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)): + vitest@4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.12.14(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.0(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)): dependencies: '@vitest/expect': 4.1.0 - '@vitest/mocker': 4.1.0(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.0(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + '@vitest/mocker': 4.1.0(msw@2.12.14(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.0(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) '@vitest/pretty-format': 4.1.0 '@vitest/runner': 4.1.0 '@vitest/snapshot': 4.1.0 @@ -33096,10 +33061,10 @@ snapshots: - msw optional: true - vitest@4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)): + vitest@4.1.0(@types/node@24.10.10)(jsdom@28.0.0)(msw@2.12.14(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)): dependencies: '@vitest/expect': 4.1.0 - '@vitest/mocker': 4.1.0(msw@2.10.2(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + '@vitest/mocker': 4.1.0(msw@2.12.14(@types/node@24.10.10)(typescript@5.9.3))(vite@7.3.1(@types/node@24.10.10)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) '@vitest/pretty-format': 4.1.0 '@vitest/runner': 4.1.0 '@vitest/snapshot': 4.1.0 @@ -33124,10 +33089,10 @@ snapshots: transitivePeerDependencies: - msw - vitest@4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)): + vitest@4.1.0(@types/node@25.2.1)(jsdom@28.0.0)(msw@2.12.14(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)): dependencies: '@vitest/expect': 4.1.0 - '@vitest/mocker': 4.1.0(msw@2.10.2(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) + '@vitest/mocker': 4.1.0(msw@2.12.14(@types/node@25.2.1)(typescript@5.9.3))(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) '@vitest/pretty-format': 4.1.0 '@vitest/runner': 4.1.0 '@vitest/snapshot': 4.1.0 @@ -33573,6 +33538,8 @@ snapshots: xmlchars@2.2.0: {} + xtend@4.0.2: {} + y18n@5.0.8: {} yallist@3.1.1: {} diff --git a/specs/2.0.x/response-example.yaml b/specs/2.0.x/response-example.yaml deleted file mode 100644 index 542075891c..0000000000 --- a/specs/2.0.x/response-example.yaml +++ /dev/null @@ -1,54 +0,0 @@ -swagger: 2.0 -info: - title: OpenAPI 2.0 body response application/json inline example - version: 1 -paths: - /foo: - post: - consumes: - - text/plain - produces: - - application/json - parameters: - - name: body - in: body - required: true - schema: - type: string - responses: - '200': - description: OK - schema: - type: object - properties: - fullName: - type: string - age: - type: number - example: - fullName: 'John Doe' - age: 34 - '204': - description: SUCCESSFUL - get: - produces: - - application/json - responses: - '200': - description: OK - schema: - $ref: '#/definitions/Person' -definitions: - Person: - type: object - properties: - firstName: - type: string - lastName: - type: string - age: - type: number - example: - firstName: 'Marry' - lastName: 'Jane' - age: 30 diff --git a/specs/3.0.x/response-example.yaml b/specs/3.0.x/response-example.yaml deleted file mode 100644 index 2fd4275202..0000000000 --- a/specs/3.0.x/response-example.yaml +++ /dev/null @@ -1,53 +0,0 @@ -openapi: 3.0.4 -info: - title: OpenAPI 3.0.4 body response application/json inline example - version: 1 -paths: - /foo: - post: - requestBody: - content: - 'text/plain': - schema: - type: string - required: true - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - fullName: - type: string - age: - type: number - example: - fullName: 'John Doe' - age: 34 - '204': - description: SUCCESSFUL - get: - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/Person' -components: - schemas: - Person: - type: object - properties: - firstName: - type: string - lastName: - type: string - age: - type: number - example: - firstName: 'Marry' - lastName: 'Jane' - age: 30 diff --git a/specs/3.0.x/response-types.yaml b/specs/3.0.x/response-types.yaml deleted file mode 100644 index 7d21afd1fd..0000000000 --- a/specs/3.0.x/response-types.yaml +++ /dev/null @@ -1,26 +0,0 @@ -openapi: 3.0.4 -info: - title: OpenAPI 3.0.4 response types - version: '1' -paths: - /foo: - get: - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - name: - type: string - example: - name: 'Alice' - text/plain: - schema: - type: string - application/octet-stream: - schema: - type: string - format: binary diff --git a/vitest.config.ts b/vitest.config.ts index 83bfff04b3..803997d5c3 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -59,6 +59,15 @@ export default defineConfig({ setupFiles: ['./vitest.setup.ts'], }, }, + { + extends: true, + test: { + globalSetup: ['./test/globalTeardown.ts'], + name: '@test/openapi-ts-msw-v2', + root: 'packages/openapi-ts-tests/msw/v2', + setupFiles: ['./vitest.setup.ts'], + }, + }, { extends: true, test: { @@ -87,6 +96,7 @@ export default defineConfig({ { extends: true, test: { + globalSetup: ['./test/globalTeardown.ts'], name: '@test/openapi-ts-valibot-v1', root: 'packages/openapi-ts-tests/valibot/v1', setupFiles: ['./vitest.setup.ts'], From cfefe18e1749095b687909d103beb11b092b59e4 Mon Sep 17 00:00:00 2001 From: Lubos Date: Thu, 26 Mar 2026 03:28:07 +0100 Subject: [PATCH 06/16] refactor: organize msw plugin files --- dev/playground.ts | 21 +- packages/openapi-ts/src/plugins/msw/plugin.ts | 321 +----------------- .../{ => shared}/computeDominantResponse.ts | 5 +- .../msw/{ => shared}/handlerCreator.ts | 169 ++++----- .../{ => shared}/sortHandlersBySpecificity.ts | 0 .../openapi-ts/src/plugins/msw/v2/plugin.ts | 267 +++++++++++++++ 6 files changed, 365 insertions(+), 418 deletions(-) rename packages/openapi-ts/src/plugins/msw/{ => shared}/computeDominantResponse.ts (96%) rename packages/openapi-ts/src/plugins/msw/{ => shared}/handlerCreator.ts (72%) rename packages/openapi-ts/src/plugins/msw/{ => shared}/sortHandlersBySpecificity.ts (100%) create mode 100644 packages/openapi-ts/src/plugins/msw/v2/plugin.ts diff --git a/dev/playground.ts b/dev/playground.ts index 893e9bcd14..a226a21adf 100644 --- a/dev/playground.ts +++ b/dev/playground.ts @@ -1,7 +1,11 @@ +/* eslint-disable */ import type { DefinePlugin, IR } from '@hey-api/openapi-ts'; +import { http, HttpResponse } from 'msw'; +import { setupServer } from 'msw/node'; -// import { createOpencode } from '@opencode-ai/sdk'; import { client } from './gen/typescript/client.gen'; +// import { createOpencode } from '@opencode-ai/sdk'; +import { createMswHandlerFactory, getAllMocks } from './gen/typescript/msw.gen'; import { OpenCode } from './gen/typescript/sdk.gen'; type MyPluginConfig = { readonly name: 'myplugin' }; @@ -17,6 +21,21 @@ export const handler: MyPlugin['Handler'] = ({ plugin }) => { }); }; +const server = setupServer( + // ...getAllMocks({ + // overrides: { + // // ... + // }, + // }), + createMswHandlerFactory({ baseUrl: '*' }).tuiPublishMock(), + // http.post('*/tui/publish', () => HttpResponse.json({ + // firstName: 'John', + // id: 'abc-123', + // lastName: 'Maverick', + // })), +); +server.listen(); + async function run() { // const { client, server } = await createOpencode(); // console.log(client, server); diff --git a/packages/openapi-ts/src/plugins/msw/plugin.ts b/packages/openapi-ts/src/plugins/msw/plugin.ts index aafb71e9e8..5efd5d1258 100644 --- a/packages/openapi-ts/src/plugins/msw/plugin.ts +++ b/packages/openapi-ts/src/plugins/msw/plugin.ts @@ -1,321 +1,4 @@ -import { parseUrl } from '@hey-api/shared'; - -import { $ } from '../../ts-dsl'; -import { operationToHandlerCreator } from './handlerCreator'; -import { sortHandlersBySpecificity } from './sortHandlersBySpecificity'; import type { MswPlugin } from './types'; +import { handlerV2 } from './v2/plugin'; -export const handler: MswPlugin['Handler'] = ({ plugin }) => { - // Register external MSW symbols - plugin.symbol('http', { - external: 'msw', - meta: { - category: 'external', - resource: 'msw.http', - tool: 'msw', - }, - }); - - const symbolHttpHandler = plugin.symbol('HttpHandler', { - external: 'msw', - kind: 'type', - meta: { - category: 'external', - resource: 'msw.HttpHandler', - tool: 'msw', - }, - }); - - const symbolHttpResponse = plugin.symbol('HttpResponse', { - external: 'msw', - meta: { - category: 'external', - resource: 'msw.HttpResponse', - tool: 'msw', - }, - }); - - plugin.symbol('HttpResponseResolver', { - external: 'msw', - kind: 'type', - meta: { - category: 'external', - resource: 'msw.HttpResponseResolver', - tool: 'msw', - }, - }); - - plugin.symbol('RequestHandlerOptions', { - external: 'msw', - kind: 'type', - meta: { - category: 'external', - resource: 'msw.RequestHandlerOptions', - tool: 'msw', - }, - }); - - // Generate resolveToNull helper - // const resolveToNull = () => new HttpResponse(null) - const symbolResolveToNull = plugin.symbol('resolveToNull', { - meta: { - category: 'function', - resource: 'resolve-to-null', - }, - }); - const resolveToNullFn = $.const(symbolResolveToNull).assign( - $.func((f) => f.do($.new(symbolHttpResponse, $.literal(null)).return())), - ); - plugin.node(resolveToNullFn); - - // Resolve default baseUrl from spec servers - let defaultBaseUrl = ''; - const { servers } = plugin.context.ir; - const firstServer = servers?.[0]; - if (firstServer) { - const serverUrl = firstServer.url; - const url = parseUrl(serverUrl); - if (url.protocol && url.host && !serverUrl.includes('{')) { - defaultBaseUrl = serverUrl; - } else if (serverUrl !== '/' && serverUrl.startsWith('/')) { - defaultBaseUrl = serverUrl.endsWith('/') ? serverUrl.slice(0, -1) : serverUrl; - } - } - - // Generate createMswHandlerFactory - const symbolFactory = plugin.symbol('createMswHandlerFactory'); - const ofObject = $.object().pretty(); - const singleHandlerFactoriesType = $.type.object(); - const handlerMeta: Array<{ isOptional: boolean; name: string; path: string }> = []; - - plugin.forEach( - 'operation', - ({ operation }) => { - const handlerCreator = operationToHandlerCreator({ - examples: plugin.config.valueSources?.includes('example') ?? true, - operation, - plugin, - }); - if (handlerCreator) { - ofObject.prop(handlerCreator.name, handlerCreator.value); - singleHandlerFactoriesType.prop(handlerCreator.name, (p) => p.type(handlerCreator.type)); - handlerMeta.push({ - isOptional: handlerCreator.isOptional, - name: handlerCreator.name, - path: operation.path, - }); - } - }, - { - order: 'declarations', - }, - ); - - // Emit SingleHandlerFactories type - const symbolSingleHandlerFactories = plugin.symbol('SingleHandlerFactories'); - plugin.node($.type.alias(symbolSingleHandlerFactories).export().type(singleHandlerFactoriesType)); - - // Emit GetAllMocksOptions type - const symbolGetAllMocksOptions = plugin.symbol('GetAllMocksOptions'); - plugin.node( - $.type - .alias(symbolGetAllMocksOptions) - .export() - .type( - $.type - .object() - .prop('onMissingMock', (p) => - p.required(false).type($.type.or($.type.literal('error'), $.type.literal('skip'))), - ) - .prop('overrides', (p) => - p.required(false).type( - $.type - .mapped('K') - .key($.type.operator().keyof($.type(symbolSingleHandlerFactories))) - .optional() - .type( - $.type.idx( - $.type('Parameters', (t) => - t.generic($.type.idx($.type(symbolSingleHandlerFactories), $.type('K'))), - ), - $.type.literal(0), - ), - ), - ), - ), - ), - ); - - // Emit MswHandlerFactory type - const symbolMswHandlerFactory = plugin.symbol('MswHandlerFactory'); - plugin.node( - $.type - .alias(symbolMswHandlerFactory) - .export() - .type( - $.type.and( - $.type(symbolSingleHandlerFactories), - $.type.object().prop('getAllMocks', (p) => - p.type( - $.type - .func() - .param('options', (pp) => pp.type($.type(symbolGetAllMocksOptions)).optional()) - .returns($.type('Array', (t) => t.generic($.type(symbolHttpHandler)))), - ), - ), - ), - ), - ); - - // Build getAllMocks function body - const getAllMocksBodyStmts: Array = []; - const hasRequiredHandlers = handlerMeta.some((h) => !h.isOptional); - - if (hasRequiredHandlers) { - getAllMocksBodyStmts.push( - $.const('onMissingMock').assign( - $.binary($.attr($('options'), 'onMissingMock').optional(), '??', $.literal('skip')), - ), - ); - } - - getAllMocksBodyStmts.push( - $.const('overrides').assign($.attr($('options'), 'overrides').optional()), - ); - - getAllMocksBodyStmts.push( - $.const('handlers') - .type($.type('Array', (t) => t.generic($.type(symbolHttpHandler)))) - .assign($.array()), - ); - - // Generate addRequiredHandler helper when there are required handlers - if (hasRequiredHandlers) { - const errorResolver = $.func((ef) => - ef.do( - $.new( - symbolHttpResponse, - $.literal('[heyapi-msw] The mock of this request is not implemented.'), - $.object().prop('status', $.literal(501)), - ).return(), - ), - ); - - // handler: (value: Value | (() => HttpResponse)) => HttpHandler - const handlerParamType = $.type - .func() - .param('value', (pp) => - pp.type( - $.type.or( - 'Value', - $.type.func().returns($.type(symbolHttpResponse, (t) => t.generic('any'))), - ), - ), - ) - .returns($.type(symbolHttpHandler)); - - getAllMocksBodyStmts.push( - $.const('addRequiredHandler').assign( - $.func((f) => - f - .generic('Value') - .param('handler', (p) => p.type(handlerParamType)) - .param('override', (p) => p.type($.type.or('Value', 'undefined'))) - .do( - $.if($.binary($('override'), '!=', $.literal(null))) - .do( - $.stmt( - $('handlers') - .attr('push') - .call($('handler').call($('override'))), - ), - ) - .otherwise( - $.if($.binary($('onMissingMock'), '===', $.literal('error'))).do( - $.stmt($('handlers').attr('push').call($('handler').call(errorResolver))), - ), - ), - ), - ), - ), - ); - } - - for (const handler of sortHandlersBySpecificity(handlerMeta)) { - if (handler.isOptional) { - getAllMocksBodyStmts.push( - $.stmt( - $('handlers') - .attr('push') - .call( - $('mocks') - .attr(handler.name) - .call($.attr($('overrides'), handler.name).optional()), - ), - ), - ); - } else { - getAllMocksBodyStmts.push( - $.stmt( - $('addRequiredHandler').call( - $('mocks').attr(handler.name), - $.attr($('overrides'), handler.name).optional(), - ), - ), - ); - } - } - - getAllMocksBodyStmts.push($.return($('handlers'))); - - const getAllMocksFn = $.func((f) => { - f.param('options', (p) => p.required(false).type($.type(symbolGetAllMocksOptions))); - f.returns($.type('Array', (t) => t.generic($.type(symbolHttpHandler)))); - f.do(...getAllMocksBodyStmts); - }); - - const factoryFn = $.const(symbolFactory) - .export() - .assign( - $.func((f) => - f - .param('config', (p) => - p - .required(false) - .type($.type.object().prop('baseUrl', (p) => p.required(false).type('string'))), - ) - .returns($.type(symbolMswHandlerFactory)) - .do( - $.const('baseUrl').assign( - $.binary($.attr($('config'), 'baseUrl').optional(), '??', $.literal(defaultBaseUrl)), - ), - $.const('mocks').type('SingleHandlerFactories').assign(ofObject), - $.const('getAllMocks').assign(getAllMocksFn), - $.return($.object().spread('mocks').prop('getAllMocks', 'getAllMocks')), - ), - ), - ); - plugin.node(factoryFn); - - // Export individual handlers with wildcard baseUrl for convenient direct imports - const symbolDefaults = plugin.symbol('_defaults'); - plugin.node( - $.const(symbolDefaults).assign( - $(symbolFactory).call($.object().prop('baseUrl', $.literal('*'))), - ), - ); - for (const handler of handlerMeta) { - const sym = plugin.symbol(handler.name); - plugin.node( - $.const(sym) - .export() - .assign($.attr($(symbolDefaults), handler.name)), - ); - } - const symbolGetAllMocksExport = plugin.symbol('getAllMocks'); - plugin.node( - $.const(symbolGetAllMocksExport) - .export() - .assign($.attr($(symbolDefaults), 'getAllMocks')), - ); -}; +export const handler: MswPlugin['Handler'] = (args) => handlerV2(args); diff --git a/packages/openapi-ts/src/plugins/msw/computeDominantResponse.ts b/packages/openapi-ts/src/plugins/msw/shared/computeDominantResponse.ts similarity index 96% rename from packages/openapi-ts/src/plugins/msw/computeDominantResponse.ts rename to packages/openapi-ts/src/plugins/msw/shared/computeDominantResponse.ts index 0afce179f2..5bd01d8692 100644 --- a/packages/openapi-ts/src/plugins/msw/computeDominantResponse.ts +++ b/packages/openapi-ts/src/plugins/msw/shared/computeDominantResponse.ts @@ -1,6 +1,7 @@ -import { type IR, statusCodeToGroup } from '@hey-api/shared'; +import type { IR } from '@hey-api/shared'; +import { statusCodeToGroup } from '@hey-api/shared'; -import type { MswPlugin } from './types'; +import type { MswPlugin } from '../types'; export type ResponseKind = 'binary' | 'json' | 'text' | 'void'; diff --git a/packages/openapi-ts/src/plugins/msw/handlerCreator.ts b/packages/openapi-ts/src/plugins/msw/shared/handlerCreator.ts similarity index 72% rename from packages/openapi-ts/src/plugins/msw/handlerCreator.ts rename to packages/openapi-ts/src/plugins/msw/shared/handlerCreator.ts index 90e7d4f4b0..ab28470a97 100644 --- a/packages/openapi-ts/src/plugins/msw/handlerCreator.ts +++ b/packages/openapi-ts/src/plugins/msw/shared/handlerCreator.ts @@ -1,8 +1,9 @@ +import type { Symbol } from '@hey-api/codegen-core'; import type { IR } from '@hey-api/shared'; -import { $ } from '../../ts-dsl'; +import { $ } from '../../../ts-dsl'; +import type { MswPlugin } from '../types'; import { computeDominantResponse, type DominantResponse } from './computeDominantResponse'; -import type { MswPlugin } from './types'; const emitToResponseUnion = (plugin: MswPlugin['Instance']) => { const symbol = plugin.symbol('ToResponseUnion', { @@ -11,9 +12,9 @@ const emitToResponseUnion = (plugin: MswPlugin['Instance']) => { resource: 'to-response-union', }, }); - const extractKeyofTNumber = $.type('Extract', (t) => - t.generic($.type('keyof T')).generic($.type('number')), - ); + const extractKeyofTNumber = $.type('Extract') + .generic($.type('keyof T')) + .generic($.type('number')); const toResponseUnionType = $.type .alias(symbol) .generic('T') @@ -26,9 +27,9 @@ const emitToResponseUnion = (plugin: MswPlugin['Instance']) => { $.type .object() .prop('status', (p) => p.type('K')) - .prop('result', (p) => p.type($.type.idx($.type('T'), $.type('K')))), + .prop('result', (p) => p.type($.type('T').idx($.type('K')))), ), - $.type('Extract', (t) => t.generic($.type('keyof T')).generic($.type('number'))), + $.type('Extract').generic($.type('keyof T')).generic($.type('number')), ), ); plugin.node(toResponseUnionType); @@ -114,74 +115,54 @@ const httpMethodMap: Record = { * When `res` is an object with a `result` property, it uses * `res.result` as the value and `res.status` as the status code. */ -const buildResponseOverrideExpr = ({ +function buildResponseOverrideExpr({ dominantResponse: { kind: responseKind, statusCode: responseStatusCode }, responseOrFnName, symbolHttpResponse, }: { dominantResponse: DominantResponse; responseOrFnName: string; - symbolHttpResponse: ReturnType; -}) => { + symbolHttpResponse: Symbol; +}) { const statusOption = $.object().prop( 'status', responseStatusCode - ? $.binary($.attr(responseOrFnName, 'status'), '??', $.literal(responseStatusCode)) - : $.attr(responseOrFnName, 'status'), + ? $(responseOrFnName).attr('status').coalesce($.literal(responseStatusCode)) + : $(responseOrFnName).attr('status'), ); - const resultExpr = $.attr(responseOrFnName, 'result'); + const resultExpr = $(responseOrFnName).attr('result'); switch (responseKind) { - case 'void': { - return $.func((f) => - f.do( - $.new( - symbolHttpResponse, - $.binary(resultExpr, '??', $.literal(null)), - statusOption, - ).return(), - ), + case 'void': + return $.func().do( + $.new(symbolHttpResponse, resultExpr.coalesce($.literal(null)), statusOption).return(), ); - } - case 'json': { - return $.func((f) => - f.do( - $(symbolHttpResponse) - .attr('json') - .call($.binary(resultExpr, '??', $.literal(null)), statusOption) - .return(), - ), + case 'json': + return $.func().do( + $(symbolHttpResponse) + .attr('json') + .call(resultExpr.coalesce($.literal(null)), statusOption) + .return(), ); - } - case 'text': { - return $.func((f) => - f.do( - $(symbolHttpResponse) - .attr('text') - .call($.binary(resultExpr, '??', $.literal(null)), statusOption) - .return(), - ), + case 'text': + return $.func().do( + $(symbolHttpResponse) + .attr('text') + .call(resultExpr.coalesce($.literal(null)), statusOption) + .return(), ); - } - case 'binary': { - return $.func((f) => - f.do( - $.new( - symbolHttpResponse, - $.binary(resultExpr, '??', $.literal(null)), - statusOption, - ).return(), - ), + case 'binary': + return $.func().do( + $.new(symbolHttpResponse, resultExpr.coalesce($.literal(null)), statusOption).return(), ); - } } -}; +} /** * Builds an arrow function that creates an MSW handler for a single operation. * The response method and status code are inferred from the operation's responses. */ -const createHandlerCreatorFn = ({ +function createHandlerCreatorFn({ dominantResponse, hasResponseOverride, method, @@ -194,25 +175,21 @@ const createHandlerCreatorFn = ({ hasResponseOverride: boolean; method: string; operation: IR.OperationObject; - symbolHttp: ReturnType; - symbolHttpResponse: ReturnType; - symbolResolveToNull: ReturnType; -}) => { + symbolHttp: Symbol; + symbolHttpResponse: Symbol; + symbolResolveToNull: Symbol; +}) { const responseOrFnName = 'res'; const optionsName = 'options'; - const fallbackTernary = $.ternary( - $.binary($.typeofExpr(responseOrFnName), '===', $.literal('function')), - ) + const fallbackTernary = $.ternary($.typeofExpr(responseOrFnName).eq($.literal('function'))) .do(responseOrFnName) .otherwise($(symbolResolveToNull)); const resolverArg = hasResponseOverride ? $.ternary( - $.binary( - $.binary($.typeofExpr(responseOrFnName), '===', $.literal('object')), - '&&', - $.attr(responseOrFnName, 'result'), + $($.typeofExpr(responseOrFnName).eq($.literal('object'))).and( + $(responseOrFnName).attr('result'), ), ) .do( @@ -233,20 +210,25 @@ const createHandlerCreatorFn = ({ optionsName, ); - return $.func((f) => { - if (dominantResponse.example != null && dominantResponse.statusCode != null) { - const status = dominantResponse.statusCode; - const example = dominantResponse.example; - f.param(responseOrFnName, (p) => p.assign($.fromValue({ result: example, status }))); - } else { - f.param(responseOrFnName); - } - f.param(optionsName); - f.do(httpCall.return()); - }); -}; + return $.func() + .$if( + dominantResponse.example != null && dominantResponse.statusCode != null, + (f) => + f.param(responseOrFnName, (p) => + p.assign( + $.fromValue({ + result: dominantResponse.example, + status: dominantResponse.statusCode, + }), + ), + ), + (f) => f.param(responseOrFnName), + ) + .param(optionsName) + .do(httpCall.return()); +} -export const operationToHandlerCreator = ({ +export function operationToHandlerCreator({ examples, operation, plugin, @@ -254,11 +236,9 @@ export const operationToHandlerCreator = ({ examples: boolean; operation: IR.OperationObject; plugin: MswPlugin['Instance']; -}) => { +}) { const method = httpMethodMap[operation.method]; - if (!method) { - return; - } + if (!method) return; const dominantResponse = computeDominantResponse({ operation, plugin }); @@ -295,7 +275,7 @@ export const operationToHandlerCreator = ({ if (!plugin.getSymbol({ category: 'type', resource: 'to-response-union' })) { emitToResponseUnion(plugin); } - responsesOverrideType = $.type(symbolToResponseUnion, (t) => t.generic(symbolResponsesType)); + responsesOverrideType = $.type(symbolToResponseUnion).generic(symbolResponsesType); } // Query data type for parameters @@ -312,7 +292,7 @@ export const operationToHandlerCreator = ({ operation.parameters?.path && Object.keys(operation.parameters.path).length > 0; const hasBody = !!operation.body; - let pathParamsType: ReturnType | ReturnType | undefined; + let pathParamsType: ReturnType | undefined; if (hasPathParams) { // Generate inline object type with sanitized param names derived from the // path string (not the IR keys, which are lowercased and may diverge from @@ -327,17 +307,18 @@ export const operationToHandlerCreator = ({ pathParamsType = objType; } - let bodyType: ReturnType | ReturnType | undefined; + let bodyType: ReturnType | undefined; if (hasBody && symbolDataType) { - bodyType = $.type.idx($.type(symbolDataType), $.type.literal('body')); + bodyType = $.type(symbolDataType).idx($.type.literal('body')); } // Build the resolver type: HttpResponseResolver // Omit response type generic to avoid MSW's DefaultBodyType constraint issues const hasResolverGenerics = pathParamsType || bodyType; const resolverType = hasResolverGenerics - ? $.type(symbolHttpResponseResolver, (t) => - t.generics(pathParamsType ?? $.type('never'), bodyType ?? $.type('never')), + ? $.type(symbolHttpResponseResolver).generics( + pathParamsType ?? $.type('never'), + bodyType ?? $.type('never'), ) : $.type(symbolHttpResponseResolver); @@ -365,14 +346,12 @@ export const operationToHandlerCreator = ({ dominantResponse.example != null || dominantResponse.kind === 'void'; - let responseOrResolverType: ReturnType | ReturnType; + let responseOrResolverType: ReturnType; if (dominantResponse.statusCode != null && symbolResponsesType) { const dominantResponseType = $.type .object() .prop('result', (p) => - p.type( - $.type.idx($.type(symbolResponsesType), $.type.literal(dominantResponse.statusCode!)), - ), + p.type($.type(symbolResponsesType).idx($.type.literal(dominantResponse.statusCode!))), ) .prop('status', (p) => p.optional().type($.type.literal(dominantResponse.statusCode!))); responseOrResolverType = $.type.or( @@ -388,14 +367,12 @@ export const operationToHandlerCreator = ({ if (!plugin.getSymbol({ category: 'type', resource: 'optional-http-handler-factory' })) { emitOptionalParamHandlerFactory(plugin); } - handlerType = $.type(symbolOptionalHttpHandlerFactory, (t) => - t.generic(responseOrResolverType), - ); + handlerType = $.type(symbolOptionalHttpHandlerFactory).generic(responseOrResolverType); } else { if (!plugin.getSymbol({ category: 'type', resource: 'http-handler-factory' })) { emitHandlerFactory(plugin); } - handlerType = $.type(symbolHttpHandlerFactory, (t) => t.generic(responseOrResolverType)); + handlerType = $.type(symbolHttpHandlerFactory).generic(responseOrResolverType); } return { @@ -404,4 +381,4 @@ export const operationToHandlerCreator = ({ type: handlerType, value: handlerCreator, }; -}; +} diff --git a/packages/openapi-ts/src/plugins/msw/sortHandlersBySpecificity.ts b/packages/openapi-ts/src/plugins/msw/shared/sortHandlersBySpecificity.ts similarity index 100% rename from packages/openapi-ts/src/plugins/msw/sortHandlersBySpecificity.ts rename to packages/openapi-ts/src/plugins/msw/shared/sortHandlersBySpecificity.ts diff --git a/packages/openapi-ts/src/plugins/msw/v2/plugin.ts b/packages/openapi-ts/src/plugins/msw/v2/plugin.ts new file mode 100644 index 0000000000..26c755c40f --- /dev/null +++ b/packages/openapi-ts/src/plugins/msw/v2/plugin.ts @@ -0,0 +1,267 @@ +import { parseUrl } from '@hey-api/shared'; + +import { $ } from '../../../ts-dsl'; +import { operationToHandlerCreator } from '../shared/handlerCreator'; +import { sortHandlersBySpecificity } from '../shared/sortHandlersBySpecificity'; +import type { MswPlugin } from '../types'; + +export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { + plugin.symbol('http', { + external: 'msw', + }); + const symbolHttpHandler = plugin.symbol('HttpHandler', { + external: 'msw', + kind: 'type', + }); + const symbolHttpResponse = plugin.symbol('HttpResponse', { + external: 'msw', + }); + plugin.symbol('HttpResponseResolver', { + external: 'msw', + kind: 'type', + }); + plugin.symbol('RequestHandlerOptions', { + external: 'msw', + kind: 'type', + }); + + // Generate resolveToNull helper + // const resolveToNull = () => new HttpResponse(null) + const symbolResolveToNull = plugin.symbol('resolveToNull', { + meta: { + category: 'function', + resource: 'resolve-to-null', + }, + }); + const resolveToNullFn = $.const(symbolResolveToNull).assign( + $.func().do($.new(symbolHttpResponse, $.literal(null)).return()), + ); + plugin.node(resolveToNullFn); + + // Resolve default baseUrl from spec servers + let defaultBaseUrl = ''; + const { servers } = plugin.context.ir; + const firstServer = servers?.[0]; + if (firstServer) { + const serverUrl = firstServer.url; + const url = parseUrl(serverUrl); + if (url.protocol && url.host && !serverUrl.includes('{')) { + defaultBaseUrl = serverUrl; + } else if (serverUrl !== '/' && serverUrl.startsWith('/')) { + defaultBaseUrl = serverUrl.endsWith('/') ? serverUrl.slice(0, -1) : serverUrl; + } + } + + // Generate createMswHandlerFactory + const symbolFactory = plugin.symbol('createMswHandlerFactory'); + const ofObject = $.object().pretty(); + const singleHandlerFactoriesType = $.type.object(); + const handlerMeta: Array<{ isOptional: boolean; name: string; path: string }> = []; + + plugin.forEach( + 'operation', + ({ operation }) => { + const handlerCreator = operationToHandlerCreator({ + examples: plugin.config.valueSources?.includes('example') ?? true, + operation, + plugin, + }); + if (handlerCreator) { + ofObject.prop(handlerCreator.name, handlerCreator.value); + singleHandlerFactoriesType.prop(handlerCreator.name, (p) => p.type(handlerCreator.type)); + handlerMeta.push({ + isOptional: handlerCreator.isOptional, + name: handlerCreator.name, + path: operation.path, + }); + } + }, + { + order: 'declarations', + }, + ); + + // Emit SingleHandlerFactories type + const symbolSingleHandlerFactories = plugin.symbol('SingleHandlerFactories'); + plugin.node($.type.alias(symbolSingleHandlerFactories).export().type(singleHandlerFactoriesType)); + + // Emit GetAllMocksOptions type + const symbolGetAllMocksOptions = plugin.symbol('GetAllMocksOptions'); + plugin.node( + $.type + .alias(symbolGetAllMocksOptions) + .export() + .type( + $.type + .object() + .prop('onMissingMock', (p) => + p.optional().type($.type.or($.type.literal('error'), $.type.literal('skip'))), + ) + .prop('overrides', (p) => + p.optional().type( + $.type + .mapped('K') + .key($.type.operator().keyof($.type(symbolSingleHandlerFactories))) + .optional() + .type( + $.type.idx( + $.type('Parameters').generic( + $.type(symbolSingleHandlerFactories).idx($.type('K')), + ), + $.type.literal(0), + ), + ), + ), + ), + ), + ); + + // Emit MswHandlerFactory type + const symbolMswHandlerFactory = plugin.symbol('MswHandlerFactory'); + plugin.node( + $.type + .alias(symbolMswHandlerFactory) + .export() + .type( + $.type.and( + $.type(symbolSingleHandlerFactories), + $.type.object().prop('getAllMocks', (p) => + p.type( + $.type + .func() + .param('options', (pp) => pp.type($.type(symbolGetAllMocksOptions)).optional()) + .returns($.type('Array').generic($.type(symbolHttpHandler))), + ), + ), + ), + ), + ); + + // Build getAllMocks function body + const getAllMocksBodyStmts: Array = []; + const hasRequiredHandlers = handlerMeta.some((h) => !h.isOptional); + + if (hasRequiredHandlers) { + getAllMocksBodyStmts.push( + $.const('onMissingMock').assign( + $('options').attr('onMissingMock').optional().coalesce($.literal('skip')), + ), + ); + } + + getAllMocksBodyStmts.push($.const('overrides').assign($('options').attr('overrides').optional())); + + getAllMocksBodyStmts.push( + $.const('handlers') + .type($.type('Array').generic($.type(symbolHttpHandler))) + .assign($.array()), + ); + + // Generate addRequiredHandler helper when there are required handlers + if (hasRequiredHandlers) { + const errorResolver = $.func().do( + $.new( + symbolHttpResponse, + $.literal('[heyapi-msw] The mock of this request is not implemented.'), + $.object().prop('status', $.literal(501)), + ).return(), + ); + + // handler: (value: Value | (() => HttpResponse)) => HttpHandler + const handlerParamType = $.type + .func() + .param('value', (pp) => + pp.type( + $.type.or('Value', $.type.func().returns($.type(symbolHttpResponse).generic('any'))), + ), + ) + .returns($.type(symbolHttpHandler)); + + getAllMocksBodyStmts.push( + $.const('addRequiredHandler').assign( + $.func() + .generic('Value') + .param('handler', (p) => p.type(handlerParamType)) + .param('override', (p) => p.type($.type.or('Value', 'undefined'))) + .do( + $.if($('override').looseNeq($.literal(null))) + .do( + $.stmt( + $('handlers') + .attr('push') + .call($('handler').call($('override'))), + ), + ) + .otherwise( + $.if($('onMissingMock').eq($.literal('error'))).do( + $.stmt($('handlers').attr('push').call($('handler').call(errorResolver))), + ), + ), + ), + ), + ); + } + + for (const handler of sortHandlersBySpecificity(handlerMeta)) { + if (handler.isOptional) { + getAllMocksBodyStmts.push( + $.stmt( + $('handlers') + .attr('push') + .call($('mocks').attr(handler.name).call($('overrides').attr(handler.name).optional())), + ), + ); + } else { + getAllMocksBodyStmts.push( + $.stmt( + $('addRequiredHandler').call( + $('mocks').attr(handler.name), + $('overrides').attr(handler.name).optional(), + ), + ), + ); + } + } + + getAllMocksBodyStmts.push($.return($('handlers'))); + + const getAllMocksFn = $.func() + .param('options', (p) => p.optional().type($.type(symbolGetAllMocksOptions))) + .returns($.type('Array').generic($.type(symbolHttpHandler))) + .do(...getAllMocksBodyStmts); + + const factoryFn = $.const(symbolFactory) + .export() + .assign( + $.func() + .param('config', (p) => + p.optional().type($.type.object().prop('baseUrl', (p) => p.optional().type('string'))), + ) + .returns($.type(symbolMswHandlerFactory)) + .do( + $.const('baseUrl').assign( + $('config').attr('baseUrl').optional().coalesce($.literal(defaultBaseUrl)), + ), + $.const('mocks').type('SingleHandlerFactories').assign(ofObject), + $.const('getAllMocks').assign(getAllMocksFn), + $.return($.object().spread('mocks').prop('getAllMocks', 'getAllMocks')), + ), + ); + plugin.node(factoryFn); + + // Export individual handlers with wildcard baseUrl for convenient direct imports + const symbolDefaults = plugin.symbol('_defaults'); + plugin.node( + $.const(symbolDefaults).assign( + $(symbolFactory).call($.object().prop('baseUrl', $.literal('*'))), + ), + ); + for (const handler of handlerMeta) { + const sym = plugin.symbol(handler.name); + plugin.node($.const(sym).export().assign($(symbolDefaults).attr(handler.name))); + } + const symbolGetAllMocksExport = plugin.symbol('getAllMocks'); + plugin.node( + $.const(symbolGetAllMocksExport).export().assign($(symbolDefaults).attr('getAllMocks')), + ); +}; From 711b7a0bb7a0382214f2f88a8cc8ed0fb193541c Mon Sep 17 00:00:00 2001 From: Lubos Date: Thu, 26 Mar 2026 14:53:27 +0100 Subject: [PATCH 07/16] feat: add baseUrl option to msw plugin --- .changeset/nasty-planes-cry.md | 5 + dev/openapi-python.config.ts | 2 +- dev/openapi-ts.config.ts | 2 +- dev/playground.ts | 11 +- dev/typescript/presets.ts | 4 +- .../2.0.x/schema-unknown/client.gen.ts | 2 +- .../2.0.x/servers-host/client.gen.ts | 2 +- .../v2/__snapshots__/3.1.x/default/msw.gen.ts | 102 +----------------- .../response-example-disabled/msw.gen.ts | 10 +- .../3.1.x/response-example/msw.gen.ts | 10 +- .../3.1.x/response-types/msw.gen.ts | 8 +- .../v2/__snapshots__/3.1.x/servers/msw.gen.ts | 8 +- .../plugins/@hey-api/client-core/client.ts | 47 ++------ packages/openapi-ts/src/plugins/msw/config.ts | 1 + packages/openapi-ts/src/plugins/msw/types.ts | 15 +++ .../openapi-ts/src/plugins/msw/v2/plugin.ts | 48 ++------- packages/shared/src/index.ts | 2 +- packages/shared/src/utils/url.ts | 32 ++++++ 18 files changed, 86 insertions(+), 225 deletions(-) create mode 100644 .changeset/nasty-planes-cry.md diff --git a/.changeset/nasty-planes-cry.md b/.changeset/nasty-planes-cry.md new file mode 100644 index 0000000000..f31edf98c7 --- /dev/null +++ b/.changeset/nasty-planes-cry.md @@ -0,0 +1,5 @@ +--- +"@hey-api/shared": patch +--- + +**utils**: export `getBaseUrl()` function diff --git a/dev/openapi-python.config.ts b/dev/openapi-python.config.ts index 804ad7590c..50158636cc 100644 --- a/dev/openapi-python.config.ts +++ b/dev/openapi-python.config.ts @@ -21,6 +21,6 @@ export default defineConfig(() => [ output: { path: path.resolve(__dirname, 'gen', 'python'), }, - plugins: getPreset(), + plugins: [...getPreset()], }, ]); diff --git a/dev/openapi-ts.config.ts b/dev/openapi-ts.config.ts index 675ac64366..1de9a3d04e 100644 --- a/dev/openapi-ts.config.ts +++ b/dev/openapi-ts.config.ts @@ -21,6 +21,6 @@ export default defineConfig(() => [ output: { path: path.resolve(__dirname, 'gen', 'typescript'), }, - plugins: getPreset(), + plugins: [...getPreset()], }, ]); diff --git a/dev/playground.ts b/dev/playground.ts index a226a21adf..f6b0951253 100644 --- a/dev/playground.ts +++ b/dev/playground.ts @@ -5,7 +5,7 @@ import { setupServer } from 'msw/node'; import { client } from './gen/typescript/client.gen'; // import { createOpencode } from '@opencode-ai/sdk'; -import { createMswHandlerFactory, getAllMocks } from './gen/typescript/msw.gen'; +import { createMswHandlerFactory } from './gen/typescript/msw.gen'; import { OpenCode } from './gen/typescript/sdk.gen'; type MyPluginConfig = { readonly name: 'myplugin' }; @@ -22,12 +22,9 @@ export const handler: MyPlugin['Handler'] = ({ plugin }) => { }; const server = setupServer( - // ...getAllMocks({ - // overrides: { - // // ... - // }, - // }), - createMswHandlerFactory({ baseUrl: '*' }).tuiPublishMock(), + createMswHandlerFactory({ + baseUrl: 'https://api.example.com', + }).tuiPublishMock(), // http.post('*/tui/publish', () => HttpResponse.json({ // firstName: 'John', // id: 'abc-123', diff --git a/dev/typescript/presets.ts b/dev/typescript/presets.ts index 67ba36a279..3acd462a5b 100644 --- a/dev/typescript/presets.ts +++ b/dev/typescript/presets.ts @@ -44,7 +44,9 @@ export const presets = { }, paramsStructure: 'flat', }, - 'msw', + { + name: 'msw', + }, ], rpc: () => [ /** RPC-style SDK with Zod validation */ diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/schema-unknown/client.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/schema-unknown/client.gen.ts index cab3c70195..52dac25543 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/schema-unknown/client.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/schema-unknown/client.gen.ts @@ -13,4 +13,4 @@ import type { ClientOptions as ClientOptions2 } from './types.gen'; */ export type CreateClientConfig = (override?: Config) => Config & T>; -export const client = createClient(createConfig()); +export const client = createClient(createConfig({ baseUrl: 'api.postmarkapp.com/' })); diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/servers-host/client.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/servers-host/client.gen.ts index cab3c70195..684843b24b 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/servers-host/client.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/servers-host/client.gen.ts @@ -13,4 +13,4 @@ import type { ClientOptions as ClientOptions2 } from './types.gen'; */ export type CreateClientConfig = (override?: Config) => Config & T>; -export const client = createClient(createConfig()); +export const client = createClient(createConfig({ baseUrl: 'foo.com' })); diff --git a/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/default/msw.gen.ts b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/default/msw.gen.ts index 4f9fb98673..af22e4629f 100644 --- a/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/default/msw.gen.ts +++ b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/default/msw.gen.ts @@ -163,7 +163,7 @@ export type MswHandlerFactory = SingleHandlerFactories & { export const createMswHandlerFactory = (config?: { baseUrl?: string; }): MswHandlerFactory => { - const baseUrl = config?.baseUrl ?? 'http://localhost:3000/base'; + const baseUrl = config?.baseUrl ?? '*'; const mocks: SingleHandlerFactories = { exportMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/no+tag'}`, typeof res === 'function' ? res : resolveToNull, options), patchApiVbyApiVersionNoTagMock: (res, options) => http.patch(`${baseUrl}${'/api/v:apiVersion/no+tag'}`, typeof res === 'function' ? res : resolveToNull, options), @@ -280,103 +280,3 @@ export const createMswHandlerFactory = (config?: { }; return { ...mocks, getAllMocks }; }; - -const _defaults = createMswHandlerFactory({ baseUrl: '*' }); - -export const exportMock = _defaults.exportMock; - -export const patchApiVbyApiVersionNoTagMock = _defaults.patchApiVbyApiVersionNoTagMock; - -export const importMock = _defaults.importMock; - -export const fooWowMock = _defaults.fooWowMock; - -export const apiVVersionODataControllerCountMock = _defaults.apiVVersionODataControllerCountMock; - -export const getApiVbyApiVersionSimpleOperationMock = _defaults.getApiVbyApiVersionSimpleOperationMock; - -export const deleteCallWithoutParametersAndResponseMock = _defaults.deleteCallWithoutParametersAndResponseMock; - -export const getCallWithoutParametersAndResponseMock = _defaults.getCallWithoutParametersAndResponseMock; - -export const headCallWithoutParametersAndResponseMock = _defaults.headCallWithoutParametersAndResponseMock; - -export const optionsCallWithoutParametersAndResponseMock = _defaults.optionsCallWithoutParametersAndResponseMock; - -export const patchCallWithoutParametersAndResponseMock = _defaults.patchCallWithoutParametersAndResponseMock; - -export const postCallWithoutParametersAndResponseMock = _defaults.postCallWithoutParametersAndResponseMock; - -export const putCallWithoutParametersAndResponseMock = _defaults.putCallWithoutParametersAndResponseMock; - -export const deleteFooMock = _defaults.deleteFooMock; - -export const callWithDescriptionsMock = _defaults.callWithDescriptionsMock; - -export const deprecatedCallMock = _defaults.deprecatedCallMock; - -export const callWithParametersMock = _defaults.callWithParametersMock; - -export const callWithWeirdParameterNamesMock = _defaults.callWithWeirdParameterNamesMock; - -export const getCallWithOptionalParamMock = _defaults.getCallWithOptionalParamMock; - -export const postCallWithOptionalParamMock = _defaults.postCallWithOptionalParamMock; - -export const postApiVbyApiVersionRequestBodyMock = _defaults.postApiVbyApiVersionRequestBodyMock; - -export const postApiVbyApiVersionFormDataMock = _defaults.postApiVbyApiVersionFormDataMock; - -export const callWithDefaultParametersMock = _defaults.callWithDefaultParametersMock; - -export const callWithDefaultOptionalParametersMock = _defaults.callWithDefaultOptionalParametersMock; - -export const callToTestOrderOfParamsMock = _defaults.callToTestOrderOfParamsMock; - -export const duplicateNameMock = _defaults.duplicateNameMock; - -export const duplicateName2Mock = _defaults.duplicateName2Mock; - -export const duplicateName3Mock = _defaults.duplicateName3Mock; - -export const duplicateName4Mock = _defaults.duplicateName4Mock; - -export const callWithNoContentResponseMock = _defaults.callWithNoContentResponseMock; - -export const callWithResponseAndNoContentResponseMock = _defaults.callWithResponseAndNoContentResponseMock; - -export const dummyAMock = _defaults.dummyAMock; - -export const dummyBMock = _defaults.dummyBMock; - -export const callWithResponseMock = _defaults.callWithResponseMock; - -export const callWithDuplicateResponsesMock = _defaults.callWithDuplicateResponsesMock; - -export const callWithResponsesMock = _defaults.callWithResponsesMock; - -export const collectionFormatMock = _defaults.collectionFormatMock; - -export const typesMock = _defaults.typesMock; - -export const uploadFileMock = _defaults.uploadFileMock; - -export const fileResponseMock = _defaults.fileResponseMock; - -export const complexTypesMock = _defaults.complexTypesMock; - -export const multipartResponseMock = _defaults.multipartResponseMock; - -export const multipartRequestMock = _defaults.multipartRequestMock; - -export const complexParamsMock = _defaults.complexParamsMock; - -export const callWithResultFromHeaderMock = _defaults.callWithResultFromHeaderMock; - -export const testErrorCodeMock = _defaults.testErrorCodeMock; - -export const nonAsciiæøåÆøÅöôêÊ字符串Mock = _defaults.nonAsciiæøåÆøÅöôêÊ字符串Mock; - -export const putWithFormUrlEncodedMock = _defaults.putWithFormUrlEncodedMock; - -export const getAllMocks = _defaults.getAllMocks; diff --git a/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-example-disabled/msw.gen.ts b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-example-disabled/msw.gen.ts index a2e510c260..dfa6f9a911 100644 --- a/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-example-disabled/msw.gen.ts +++ b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-example-disabled/msw.gen.ts @@ -40,7 +40,7 @@ export type MswHandlerFactory = SingleHandlerFactories & { export const createMswHandlerFactory = (config?: { baseUrl?: string; }): MswHandlerFactory => { - const baseUrl = config?.baseUrl ?? ''; + const baseUrl = config?.baseUrl ?? '*'; const mocks: SingleHandlerFactories = { getFooMock: (res, options) => http.get(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), postFooMock: (res, options) => http.post(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options) @@ -65,11 +65,3 @@ export const createMswHandlerFactory = (config?: { }; return { ...mocks, getAllMocks }; }; - -const _defaults = createMswHandlerFactory({ baseUrl: '*' }); - -export const getFooMock = _defaults.getFooMock; - -export const postFooMock = _defaults.postFooMock; - -export const getAllMocks = _defaults.getAllMocks; diff --git a/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-example/msw.gen.ts b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-example/msw.gen.ts index 0eac1db4bb..2b59b7b873 100644 --- a/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-example/msw.gen.ts +++ b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-example/msw.gen.ts @@ -40,7 +40,7 @@ export type MswHandlerFactory = SingleHandlerFactories & { export const createMswHandlerFactory = (config?: { baseUrl?: string; }): MswHandlerFactory => { - const baseUrl = config?.baseUrl ?? ''; + const baseUrl = config?.baseUrl ?? '*'; const mocks: SingleHandlerFactories = { getFooMock: (res = { result: { firstName: 'Marry', @@ -58,11 +58,3 @@ export const createMswHandlerFactory = (config?: { }; return { ...mocks, getAllMocks }; }; - -const _defaults = createMswHandlerFactory({ baseUrl: '*' }); - -export const getFooMock = _defaults.getFooMock; - -export const postFooMock = _defaults.postFooMock; - -export const getAllMocks = _defaults.getAllMocks; diff --git a/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-types/msw.gen.ts b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-types/msw.gen.ts index f557bc4708..3be5d7128f 100644 --- a/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-types/msw.gen.ts +++ b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-types/msw.gen.ts @@ -29,7 +29,7 @@ export type MswHandlerFactory = SingleHandlerFactories & { export const createMswHandlerFactory = (config?: { baseUrl?: string; }): MswHandlerFactory => { - const baseUrl = config?.baseUrl ?? ''; + const baseUrl = config?.baseUrl ?? '*'; const mocks: SingleHandlerFactories = { getFooMock: (res = { result: { name: 'Alice' }, status: 200 }, options) => http.get(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options) }; @@ -41,9 +41,3 @@ export const createMswHandlerFactory = (config?: { }; return { ...mocks, getAllMocks }; }; - -const _defaults = createMswHandlerFactory({ baseUrl: '*' }); - -export const getFooMock = _defaults.getFooMock; - -export const getAllMocks = _defaults.getAllMocks; diff --git a/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/servers/msw.gen.ts b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/servers/msw.gen.ts index d365ef4f29..3ac93d847f 100644 --- a/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/servers/msw.gen.ts +++ b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/servers/msw.gen.ts @@ -29,7 +29,7 @@ export type MswHandlerFactory = SingleHandlerFactories & { export const createMswHandlerFactory = (config?: { baseUrl?: string; }): MswHandlerFactory => { - const baseUrl = config?.baseUrl ?? 'https://foo.com/v1'; + const baseUrl = config?.baseUrl ?? '*'; const mocks: SingleHandlerFactories = { getFooMock: (res, options) => http.get(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options) }; @@ -52,9 +52,3 @@ export const createMswHandlerFactory = (config?: { }; return { ...mocks, getAllMocks }; }; - -const _defaults = createMswHandlerFactory({ baseUrl: '*' }); - -export const getFooMock = _defaults.getFooMock; - -export const getAllMocks = _defaults.getAllMocks; diff --git a/packages/openapi-ts/src/plugins/@hey-api/client-core/client.ts b/packages/openapi-ts/src/plugins/@hey-api/client-core/client.ts index c2578ab3a3..725f57c10f 100644 --- a/packages/openapi-ts/src/plugins/@hey-api/client-core/client.ts +++ b/packages/openapi-ts/src/plugins/@hey-api/client-core/client.ts @@ -1,4 +1,4 @@ -import { parseUrl } from '@hey-api/shared'; +import { getBaseUrl } from '@hey-api/shared'; import { getTypedConfig } from '../../../config/utils'; import { clientFolderAbsolutePath } from '../../../generate/client'; @@ -6,26 +6,6 @@ import { $ } from '../../../ts-dsl'; import type { PluginHandler } from './types'; import { getClientBaseUrlKey } from './utils'; -const resolveBaseUrlString = ({ plugin }: Parameters[0]): string | undefined => { - const { baseUrl } = plugin.config; - - if (baseUrl === false) { - return; - } - - if (typeof baseUrl === 'string') { - return baseUrl; - } - - const { servers } = plugin.context.ir; - - if (!servers) { - return; - } - - return servers[typeof baseUrl === 'number' ? baseUrl : 0]?.url; -}; - export const createClient: PluginHandler = ({ plugin }) => { const clientModule = clientFolderAbsolutePath(getTypedConfig(plugin)); const symbolCreateClient = plugin.symbol('createClient', { @@ -47,26 +27,13 @@ export const createClient: PluginHandler = ({ plugin }) => { }) : undefined; - const defaultVals = $.object(); + const baseUrl = getBaseUrl(plugin.config.baseUrl ?? true, plugin.context.ir); - const resolvedBaseUrl = resolveBaseUrlString({ - plugin: plugin as any, - }); - if (resolvedBaseUrl) { - const url = parseUrl(resolvedBaseUrl); - if (url.protocol && url.host && !resolvedBaseUrl.includes('{')) { - defaultVals.prop(getClientBaseUrlKey(getTypedConfig(plugin)), $.literal(resolvedBaseUrl)); - } else if (resolvedBaseUrl !== '/' && resolvedBaseUrl.startsWith('/')) { - const baseUrl = resolvedBaseUrl.endsWith('/') - ? resolvedBaseUrl.slice(0, -1) - : resolvedBaseUrl; - defaultVals.prop(getClientBaseUrlKey(getTypedConfig(plugin)), $.literal(baseUrl)); - } - } - - if ('throwOnError' in plugin.config && plugin.config.throwOnError) { - defaultVals.prop('throwOnError', $.literal(true)); - } + const defaultVals = $.object() + .$if(baseUrl, (o, v) => o.prop(getClientBaseUrlKey(getTypedConfig(plugin)), $.literal(v))) + .$if('throwOnError' in plugin.config && plugin.config.throwOnError, (o) => + o.prop('throwOnError', $.literal(true)), + ); const createConfigParameters = [ $(symbolCreateConfig) diff --git a/packages/openapi-ts/src/plugins/msw/config.ts b/packages/openapi-ts/src/plugins/msw/config.ts index fe00493720..82264203d4 100644 --- a/packages/openapi-ts/src/plugins/msw/config.ts +++ b/packages/openapi-ts/src/plugins/msw/config.ts @@ -5,6 +5,7 @@ import type { MswPlugin } from './types'; export const defaultConfig: MswPlugin['Config'] = { config: { + baseUrl: '*', includeInEntry: false, valueSources: ['example'], }, diff --git a/packages/openapi-ts/src/plugins/msw/types.ts b/packages/openapi-ts/src/plugins/msw/types.ts index 323738064c..480cd06562 100644 --- a/packages/openapi-ts/src/plugins/msw/types.ts +++ b/packages/openapi-ts/src/plugins/msw/types.ts @@ -3,6 +3,19 @@ import type { DefinePlugin, Plugin } from '@hey-api/shared'; export type UserConfig = Plugin.Name<'msw'> & Plugin.Hooks & Plugin.UserExports & { + /** + * Set a default base URL when creating the handlers? You can set `baseUrl` + * to a string which will be used as the base URL. If your input defines + * server(s), you can set `baseUrl` to a number to pick a specific server + * to use as the base URL. You can disable setting the base URL by setting + * `baseUrl` to `false`. By default, `baseUrl` is `'*'`, which matches all + * URLs. + * + * If the matched URL contains template literals, it will be ignored. + * + * @default '*' + */ + baseUrl?: string | number | boolean; /** * Sources for default parameter values in handler factories. Order determines * priority (earlier entries take precedence). @@ -17,6 +30,8 @@ export type UserConfig = Plugin.Name<'msw'> & export type Config = Plugin.Name<'msw'> & Plugin.Hooks & Plugin.Exports & { + /** Set a default base URL when creating the handlers. */ + baseUrl: string | number | boolean; /** Sources for default parameter values in handler factories. */ valueSources: ReadonlyArray<'example'>; }; diff --git a/packages/openapi-ts/src/plugins/msw/v2/plugin.ts b/packages/openapi-ts/src/plugins/msw/v2/plugin.ts index 26c755c40f..71ab5c6e8e 100644 --- a/packages/openapi-ts/src/plugins/msw/v2/plugin.ts +++ b/packages/openapi-ts/src/plugins/msw/v2/plugin.ts @@ -1,4 +1,4 @@ -import { parseUrl } from '@hey-api/shared'; +import { getBaseUrl } from '@hey-api/shared'; import { $ } from '../../../ts-dsl'; import { operationToHandlerCreator } from '../shared/handlerCreator'; @@ -38,21 +38,6 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { ); plugin.node(resolveToNullFn); - // Resolve default baseUrl from spec servers - let defaultBaseUrl = ''; - const { servers } = plugin.context.ir; - const firstServer = servers?.[0]; - if (firstServer) { - const serverUrl = firstServer.url; - const url = parseUrl(serverUrl); - if (url.protocol && url.host && !serverUrl.includes('{')) { - defaultBaseUrl = serverUrl; - } else if (serverUrl !== '/' && serverUrl.startsWith('/')) { - defaultBaseUrl = serverUrl.endsWith('/') ? serverUrl.slice(0, -1) : serverUrl; - } - } - - // Generate createMswHandlerFactory const symbolFactory = plugin.symbol('createMswHandlerFactory'); const ofObject = $.object().pretty(); const singleHandlerFactoriesType = $.type.object(); @@ -104,12 +89,9 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { .key($.type.operator().keyof($.type(symbolSingleHandlerFactories))) .optional() .type( - $.type.idx( - $.type('Parameters').generic( - $.type(symbolSingleHandlerFactories).idx($.type('K')), - ), - $.type.literal(0), - ), + $.type('Parameters') + .generic($.type(symbolSingleHandlerFactories).idx($.type('K'))) + .idx($.type.literal(0)), ), ), ), @@ -230,6 +212,7 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { .returns($.type('Array').generic($.type(symbolHttpHandler))) .do(...getAllMocksBodyStmts); + const baseUrl = getBaseUrl(plugin.config.baseUrl, plugin.context.ir); const factoryFn = $.const(symbolFactory) .export() .assign( @@ -240,7 +223,10 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { .returns($.type(symbolMswHandlerFactory)) .do( $.const('baseUrl').assign( - $('config').attr('baseUrl').optional().coalesce($.literal(defaultBaseUrl)), + $('config') + .attr('baseUrl') + .optional() + .$if(baseUrl !== undefined, (b) => b.coalesce($.literal(baseUrl!))), ), $.const('mocks').type('SingleHandlerFactories').assign(ofObject), $.const('getAllMocks').assign(getAllMocksFn), @@ -248,20 +234,4 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { ), ); plugin.node(factoryFn); - - // Export individual handlers with wildcard baseUrl for convenient direct imports - const symbolDefaults = plugin.symbol('_defaults'); - plugin.node( - $.const(symbolDefaults).assign( - $(symbolFactory).call($.object().prop('baseUrl', $.literal('*'))), - ), - ); - for (const handler of handlerMeta) { - const sym = plugin.symbol(handler.name); - plugin.node($.const(sym).export().assign($(symbolDefaults).attr(handler.name))); - } - const symbolGetAllMocksExport = plugin.symbol('getAllMocks'); - plugin.node( - $.const(symbolGetAllMocksExport).export().assign($(symbolDefaults).attr('getAllMocks')), - ); }; diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 4cf329cf67..1972e2d0e3 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -131,4 +131,4 @@ export { refToName, resolveRef, } from './utils/ref'; -export { parseUrl } from './utils/url'; +export { getBaseUrl, parseUrl } from './utils/url'; diff --git a/packages/shared/src/utils/url.ts b/packages/shared/src/utils/url.ts index 6eb335b799..e3bab22d0c 100644 --- a/packages/shared/src/utils/url.ts +++ b/packages/shared/src/utils/url.ts @@ -1,3 +1,5 @@ +import type { IR } from '../ir/types'; + const parseUrlRegExp = /^(([^:/?#]+):)?((\/\/)?([^:/?#]*)(:?([^/?#]*)))?([^?#]*)(\?([^#]*))?(#(.*))?/; @@ -8,6 +10,36 @@ interface Url { protocol: string; } +/** + * Resolve the base URL value based on the plugin configuration. + * + * The `baseUrl` config option can be: + * - `false` to disable using the base URL + * - a string to use as the base URL + * - a number to pick a server from the IR `servers` array + */ +function resolveBaseUrl(baseUrl: string | number | boolean, ir: IR.Model): string | undefined { + if (baseUrl === false) return; + if (typeof baseUrl === 'string') return baseUrl; + const servers = ir.servers ?? []; + return servers[typeof baseUrl === 'number' ? baseUrl : 0]?.url; +} + +/** + * Resolve the base URL string if it's a valid URL or path. + */ +export function getBaseUrl(config: string | number | boolean, ir: IR.Model): string | undefined { + const baseUrl = resolveBaseUrl(config, ir); + if (baseUrl === undefined) return; + if (baseUrl.includes('{')) return; + const url = parseUrl(baseUrl); + if (url.protocol && url.host) return baseUrl; + if (baseUrl !== '/' && baseUrl.startsWith('/')) { + return baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl; + } + return baseUrl; +} + export function parseUrl(value: string): Url { const errorResponse: Url = { host: '', From 7704644e9fc5afe4f8818c5fc896917b2889ee86 Mon Sep 17 00:00:00 2001 From: Lubos Date: Thu, 26 Mar 2026 16:44:39 +0100 Subject: [PATCH 08/16] chore: rename msw nodes --- .changeset/early-knives-kneel.md | 5 + dev/playground.ts | 15 ++- .../src/plugins/msw/shared/handlerCreator.ts | 36 ++----- .../openapi-ts/src/plugins/msw/v2/plugin.ts | 102 +++++++++--------- packages/openapi-ts/src/ts-dsl/decl/func.ts | 13 ++- packages/openapi-ts/src/ts-dsl/decl/param.ts | 4 +- packages/openapi-ts/src/ts-dsl/index.ts | 7 +- packages/openapi-ts/src/ts-dsl/stmt/var.ts | 4 +- 8 files changed, 90 insertions(+), 96 deletions(-) create mode 100644 .changeset/early-knives-kneel.md diff --git a/.changeset/early-knives-kneel.md b/.changeset/early-knives-kneel.md new file mode 100644 index 0000000000..2d1f4a57ea --- /dev/null +++ b/.changeset/early-knives-kneel.md @@ -0,0 +1,5 @@ +--- +"@hey-api/openapi-ts": patch +--- + +**client**: use `getBaseUrl()` function to determine default value diff --git a/dev/playground.ts b/dev/playground.ts index f6b0951253..de4f12cf18 100644 --- a/dev/playground.ts +++ b/dev/playground.ts @@ -5,7 +5,7 @@ import { setupServer } from 'msw/node'; import { client } from './gen/typescript/client.gen'; // import { createOpencode } from '@opencode-ai/sdk'; -import { createMswHandlerFactory } from './gen/typescript/msw.gen'; +import { createMswHandlers } from './gen/typescript/msw.gen'; import { OpenCode } from './gen/typescript/sdk.gen'; type MyPluginConfig = { readonly name: 'myplugin' }; @@ -22,9 +22,15 @@ export const handler: MyPlugin['Handler'] = ({ plugin }) => { }; const server = setupServer( - createMswHandlerFactory({ + // ...createMswHandlers({ + // baseUrl: 'https://api.example.com', + // }).getAllHandlers(), + createMswHandlers({ baseUrl: 'https://api.example.com', - }).tuiPublishMock(), + }).tuiPublishMock({ + result: false, + // status: 200, + }), // http.post('*/tui/publish', () => HttpResponse.json({ // firstName: 'John', // id: 'abc-123', @@ -40,7 +46,7 @@ async function run() { baseUrl: 'https://api.example.com', }); const sdk = new OpenCode({ client }); - sdk.tui.publish({ + const published = await sdk.tui.publish({ body: { properties: { message: 'Hello from Hey API OpenAPI TypeScript Playground!', @@ -50,6 +56,7 @@ async function run() { }, directory: 'main', }); + console.log('Published:', published.data, published.error); } run(); diff --git a/packages/openapi-ts/src/plugins/msw/shared/handlerCreator.ts b/packages/openapi-ts/src/plugins/msw/shared/handlerCreator.ts index ab28470a97..9879cb94c2 100644 --- a/packages/openapi-ts/src/plugins/msw/shared/handlerCreator.ts +++ b/packages/openapi-ts/src/plugins/msw/shared/handlerCreator.ts @@ -99,17 +99,6 @@ const toMswPath = (path: string) => .replace(/:/g, String.raw`\:`) .replace(/\0/g, ':'); -const httpMethodMap: Record = { - delete: 'delete', - get: 'get', - head: 'head', - options: 'options', - patch: 'patch', - post: 'post', - put: 'put', - trace: 'trace', -}; - /** * Builds the response override expression for the `res` parameter. * When `res` is an object with a `result` property, it uses @@ -162,7 +151,7 @@ function buildResponseOverrideExpr({ * Builds an arrow function that creates an MSW handler for a single operation. * The response method and status code are inferred from the operation's responses. */ -function createHandlerCreatorFn({ +function createHandlerFuncNode({ dominantResponse, hasResponseOverride, method, @@ -237,9 +226,6 @@ export function operationToHandlerCreator({ operation: IR.OperationObject; plugin: MswPlugin['Instance']; }) { - const method = httpMethodMap[operation.method]; - if (!method) return; - const dominantResponse = computeDominantResponse({ operation, plugin }); const symbolHttp = plugin.external('msw.http'); @@ -327,16 +313,6 @@ export function operationToHandlerCreator({ dominantResponse.example = undefined; } - const handlerCreator = createHandlerCreatorFn({ - dominantResponse, - hasResponseOverride: dominantResponse.statusCode != null, - method, - operation, - symbolHttp, - symbolHttpResponse, - symbolResolveToNull, - }); - const isOptional = // if there is no dominantResponse, it means there is no status code definition // so we can set the default response as null @@ -376,9 +352,17 @@ export function operationToHandlerCreator({ } return { + funcNode: createHandlerFuncNode({ + dominantResponse, + hasResponseOverride: dominantResponse.statusCode != null, + method: operation.method, + operation, + symbolHttp, + symbolHttpResponse, + symbolResolveToNull, + }), isOptional, name: `${operation.id}Mock`, type: handlerType, - value: handlerCreator, }; } diff --git a/packages/openapi-ts/src/plugins/msw/v2/plugin.ts b/packages/openapi-ts/src/plugins/msw/v2/plugin.ts index 71ab5c6e8e..64189069f9 100644 --- a/packages/openapi-ts/src/plugins/msw/v2/plugin.ts +++ b/packages/openapi-ts/src/plugins/msw/v2/plugin.ts @@ -38,8 +38,8 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { ); plugin.node(resolveToNullFn); - const symbolFactory = plugin.symbol('createMswHandlerFactory'); - const ofObject = $.object().pretty(); + const symbolFactory = plugin.symbol('createMswHandlers'); + const handlersObject = $.object().pretty(); const singleHandlerFactoriesType = $.type.object(); const handlerMeta: Array<{ isOptional: boolean; name: string; path: string }> = []; @@ -52,7 +52,7 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { plugin, }); if (handlerCreator) { - ofObject.prop(handlerCreator.name, handlerCreator.value); + handlersObject.prop(handlerCreator.name, handlerCreator.funcNode); singleHandlerFactoriesType.prop(handlerCreator.name, (p) => p.type(handlerCreator.type)); handlerMeta.push({ isOptional: handlerCreator.isOptional, @@ -66,31 +66,29 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { }, ); - // Emit SingleHandlerFactories type - const symbolSingleHandlerFactories = plugin.symbol('SingleHandlerFactories'); - plugin.node($.type.alias(symbolSingleHandlerFactories).export().type(singleHandlerFactoriesType)); + const symbolMswHandlerCreators = plugin.symbol('MswHandlerCreators'); + plugin.node($.type.alias(symbolMswHandlerCreators).export().type(singleHandlerFactoriesType)); - // Emit GetAllMocksOptions type - const symbolGetAllMocksOptions = plugin.symbol('GetAllMocksOptions'); + const symbolGetAllHandlersOptions = plugin.symbol('GetAllHandlersOptions'); plugin.node( $.type - .alias(symbolGetAllMocksOptions) + .alias(symbolGetAllHandlersOptions) .export() .type( $.type .object() - .prop('onMissingMock', (p) => + .prop('onMissingHandler', (p) => p.optional().type($.type.or($.type.literal('error'), $.type.literal('skip'))), ) .prop('overrides', (p) => p.optional().type( $.type .mapped('K') - .key($.type.operator().keyof($.type(symbolSingleHandlerFactories))) + .key($.type.operator().keyof($.type(symbolMswHandlerCreators))) .optional() .type( $.type('Parameters') - .generic($.type(symbolSingleHandlerFactories).idx($.type('K'))) + .generic($.type(symbolMswHandlerCreators).idx($.type('K'))) .idx($.type.literal(0)), ), ), @@ -98,42 +96,40 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { ), ); - // Emit MswHandlerFactory type - const symbolMswHandlerFactory = plugin.symbol('MswHandlerFactory'); + const symbolMswHandlers = plugin.symbol('MswHandlers'); plugin.node( $.type - .alias(symbolMswHandlerFactory) + .alias(symbolMswHandlers) .export() .type( $.type.and( - $.type(symbolSingleHandlerFactories), - $.type.object().prop('getAllMocks', (p) => + $.type(symbolMswHandlerCreators), + $.type.object().prop('getAllHandlers', (p) => p.type( $.type .func() - .param('options', (pp) => pp.type($.type(symbolGetAllMocksOptions)).optional()) - .returns($.type('Array').generic($.type(symbolHttpHandler))), + .param('options', (pp) => pp.type(symbolGetAllHandlersOptions).optional()) + .returns($.type('Array').generic(symbolHttpHandler)), ), ), ), ), ); - // Build getAllMocks function body - const getAllMocksBodyStmts: Array = []; + const getAllHandlersDo: Array> = []; const hasRequiredHandlers = handlerMeta.some((h) => !h.isOptional); if (hasRequiredHandlers) { - getAllMocksBodyStmts.push( - $.const('onMissingMock').assign( - $('options').attr('onMissingMock').optional().coalesce($.literal('skip')), + getAllHandlersDo.push( + $.const('onMissingHandler').assign( + $('options').attr('onMissingHandler').coalesce($.literal('skip')), ), ); } - getAllMocksBodyStmts.push($.const('overrides').assign($('options').attr('overrides').optional())); + getAllHandlersDo.push($.const('overrides').assign($('options').attr('overrides'))); - getAllMocksBodyStmts.push( + getAllHandlersDo.push( $.const('handlers') .type($.type('Array').generic($.type(symbolHttpHandler))) .assign($.array()), @@ -159,7 +155,7 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { ) .returns($.type(symbolHttpHandler)); - getAllMocksBodyStmts.push( + getAllHandlersDo.push( $.const('addRequiredHandler').assign( $.func() .generic('Value') @@ -175,7 +171,7 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { ), ) .otherwise( - $.if($('onMissingMock').eq($.literal('error'))).do( + $.if($('onMissingHandler').eq($.literal('error'))).do( $.stmt($('handlers').attr('push').call($('handler').call(errorResolver))), ), ), @@ -186,7 +182,7 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { for (const handler of sortHandlersBySpecificity(handlerMeta)) { if (handler.isOptional) { - getAllMocksBodyStmts.push( + getAllHandlersDo.push( $.stmt( $('handlers') .attr('push') @@ -194,7 +190,7 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { ), ); } else { - getAllMocksBodyStmts.push( + getAllHandlersDo.push( $.stmt( $('addRequiredHandler').call( $('mocks').attr(handler.name), @@ -205,33 +201,31 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { } } - getAllMocksBodyStmts.push($.return($('handlers'))); - - const getAllMocksFn = $.func() - .param('options', (p) => p.optional().type($.type(symbolGetAllMocksOptions))) - .returns($.type('Array').generic($.type(symbolHttpHandler))) - .do(...getAllMocksBodyStmts); + getAllHandlersDo.push($('handlers').return()); const baseUrl = getBaseUrl(plugin.config.baseUrl, plugin.context.ir); - const factoryFn = $.const(symbolFactory) + const factoryFn = $.func(symbolFactory) .export() - .assign( - $.func() - .param('config', (p) => - p.optional().type($.type.object().prop('baseUrl', (p) => p.optional().type('string'))), - ) - .returns($.type(symbolMswHandlerFactory)) - .do( - $.const('baseUrl').assign( - $('config') - .attr('baseUrl') - .optional() - .$if(baseUrl !== undefined, (b) => b.coalesce($.literal(baseUrl!))), - ), - $.const('mocks').type('SingleHandlerFactories').assign(ofObject), - $.const('getAllMocks').assign(getAllMocksFn), - $.return($.object().spread('mocks').prop('getAllMocks', 'getAllMocks')), - ), + .param('config', (p) => + p + .type($.type.object().prop('baseUrl', (p) => p.optional().type('string'))) + .assign($.object()), + ) + .returns(symbolMswHandlers) + .do( + $.const('baseUrl').assign( + $('config') + .attr('baseUrl') + .$if(baseUrl !== undefined, (b) => b.coalesce($.literal(baseUrl!))), + ), + $.const('mocks').type(symbolMswHandlerCreators).assign(handlersObject), + $.const('getAllHandlers').assign( + $.func() + .param('options', (p) => p.type(symbolGetAllHandlersOptions).assign($.object())) + .returns($.type('Array').generic(symbolHttpHandler)) + .do(...getAllHandlersDo), + ), + $.return($.object().spread('mocks').prop('getAllHandlers', 'getAllHandlers')), ); plugin.node(factoryFn); }; diff --git a/packages/openapi-ts/src/ts-dsl/decl/func.ts b/packages/openapi-ts/src/ts-dsl/decl/func.ts index 06f18e4bd9..903a584623 100644 --- a/packages/openapi-ts/src/ts-dsl/decl/func.ts +++ b/packages/openapi-ts/src/ts-dsl/decl/func.ts @@ -10,6 +10,7 @@ import { DocMixin } from '../mixins/doc'; import { AbstractMixin, AsyncMixin, + ExportMixin, PrivateMixin, ProtectedMixin, PublicMixin, @@ -29,11 +30,13 @@ const Mixed = AbstractMixin( DecoratorMixin( DoMixin( DocMixin( - ParamMixin( - PrivateMixin( - ProtectedMixin( - PublicMixin( - StaticMixin(TypeParamsMixin(TypeReturnsMixin(TsDsl))), + ExportMixin( + ParamMixin( + PrivateMixin( + ProtectedMixin( + PublicMixin( + StaticMixin(TypeParamsMixin(TypeReturnsMixin(TsDsl))), + ), ), ), ), diff --git a/packages/openapi-ts/src/ts-dsl/decl/param.ts b/packages/openapi-ts/src/ts-dsl/decl/param.ts index e451ddea80..fc3cc9390f 100644 --- a/packages/openapi-ts/src/ts-dsl/decl/param.ts +++ b/packages/openapi-ts/src/ts-dsl/decl/param.ts @@ -45,8 +45,8 @@ export class ParamTsDsl extends Mixed { } /** Sets the parameter type. */ - type(type: string | TypeTsDsl): this { - this._type = type instanceof TypeTsDsl ? type : new TypeExprTsDsl(type); + type(node: NodeName | TypeTsDsl): this { + this._type = node instanceof TypeTsDsl ? node : new TypeExprTsDsl(node); return this; } diff --git a/packages/openapi-ts/src/ts-dsl/index.ts b/packages/openapi-ts/src/ts-dsl/index.ts index 2540953187..e8b14a4eb1 100644 --- a/packages/openapi-ts/src/ts-dsl/index.ts +++ b/packages/openapi-ts/src/ts-dsl/index.ts @@ -1,3 +1,4 @@ +import type { NodeName } from '@hey-api/codegen-core'; import type ts from 'typescript'; import { ClassTsDsl } from './decl/class'; @@ -135,9 +136,9 @@ const tsDsl = { }) as { (): FuncTsDsl<'arrow'>; (fn: (f: FuncTsDsl<'arrow'>) => void): FuncTsDsl<'arrow'>; - (name: string): FuncTsDsl<'decl'>; - (name: string, fn: (f: FuncTsDsl<'decl'>) => void): FuncTsDsl<'decl'>; - (name?: string, fn?: (f: FuncTsDsl<'decl'>) => void): FuncTsDsl<'arrow'> | FuncTsDsl<'decl'>; + (name: NodeName): FuncTsDsl<'decl'>; + (name: NodeName, fn: (f: FuncTsDsl<'decl'>) => void): FuncTsDsl<'decl'>; + (name?: NodeName, fn?: (f: FuncTsDsl<'decl'>) => void): FuncTsDsl<'arrow'> | FuncTsDsl<'decl'>; }, /** Creates a getter method declaration. */ diff --git a/packages/openapi-ts/src/ts-dsl/stmt/var.ts b/packages/openapi-ts/src/ts-dsl/stmt/var.ts index 766036fc1a..f39a8df993 100644 --- a/packages/openapi-ts/src/ts-dsl/stmt/var.ts +++ b/packages/openapi-ts/src/ts-dsl/stmt/var.ts @@ -52,8 +52,8 @@ export class VarTsDsl extends Mixed { } /** Sets the variable type. */ - type(type: string | TypeTsDsl): this { - this._type = type instanceof TypeTsDsl ? type : new TypeExprTsDsl(type); + type(node: NodeName | TypeTsDsl): this { + this._type = node instanceof TypeTsDsl ? node : new TypeExprTsDsl(node); return this; } From 8b3a168b1e7c41bc3508729ce6de7e8c67cba00c Mon Sep 17 00:00:00 2001 From: Lubos Date: Thu, 26 Mar 2026 22:25:27 +0100 Subject: [PATCH 09/16] chore: add method prop to object --- dev/playground.ts | 24 +++++++-- dev/typescript/presets.ts | 1 - docs/openapi-ts/migrating.md | 2 +- packages/openapi-ts/CHANGELOG.md | 2 +- .../src/plugins/msw/shared/handlerCreator.ts | 18 +++---- .../openapi-ts/src/plugins/msw/v2/plugin.ts | 16 +++--- packages/openapi-ts/src/ts-dsl/decl/method.ts | 5 ++ packages/openapi-ts/src/ts-dsl/expr/object.ts | 35 +++++++++---- packages/openapi-ts/src/ts-dsl/expr/prop.ts | 50 ++++++++++--------- .../openapi-ts/src/ts-dsl/utils/factories.ts | 4 ++ .../shared/src/openApi/3.0.x/parser/schema.ts | 4 +- .../shared/src/openApi/3.1.x/parser/schema.ts | 4 +- .../src/openApi/shared/transforms/enums.ts | 2 +- 13 files changed, 102 insertions(+), 65 deletions(-) diff --git a/dev/playground.ts b/dev/playground.ts index de4f12cf18..c455a335e9 100644 --- a/dev/playground.ts +++ b/dev/playground.ts @@ -31,11 +31,25 @@ const server = setupServer( result: false, // status: 200, }), - // http.post('*/tui/publish', () => HttpResponse.json({ - // firstName: 'John', - // id: 'abc-123', - // lastName: 'Maverick', - // })), + http.post( + '*/tui/publish', + (info) => + HttpResponse.json( + { + firstName: 'John', + id: 'abc-123', + lastName: 'Maverick', + }, + { + // status: 200, + // statusText: 'OK', + // type: 'default', + }, + ), + { + // once: true, + }, + ), ); server.listen(); diff --git a/dev/typescript/presets.ts b/dev/typescript/presets.ts index 3acd462a5b..50315abcb8 100644 --- a/dev/typescript/presets.ts +++ b/dev/typescript/presets.ts @@ -35,7 +35,6 @@ export const presets = { ], msw: () => [ /** SDK + MSW handlers */ - // '@hey-api/sdk', { name: '@hey-api/sdk', operations: { diff --git a/docs/openapi-ts/migrating.md b/docs/openapi-ts/migrating.md index 1ada00c980..cab0480f95 100644 --- a/docs/openapi-ts/migrating.md +++ b/docs/openapi-ts/migrating.md @@ -155,7 +155,7 @@ useQuery(() => ({ ...getPetByIdQuery({ path: { petId: petId.value as number }, }), - enabled: () => petId.value != null, + enabled: () => petId.value !== null, })); ``` diff --git a/packages/openapi-ts/CHANGELOG.md b/packages/openapi-ts/CHANGELOG.md index cc07ed8b39..c2c0738efa 100644 --- a/packages/openapi-ts/CHANGELOG.md +++ b/packages/openapi-ts/CHANGELOG.md @@ -884,7 +884,7 @@ useQuery(() => ({ ...getPetByIdQuery({ path: { petId: petId.value as number }, }), - enabled: () => petId.value != null, + enabled: () => petId.value !== null, })); ``` diff --git a/packages/openapi-ts/src/plugins/msw/shared/handlerCreator.ts b/packages/openapi-ts/src/plugins/msw/shared/handlerCreator.ts index 9879cb94c2..9e5f570c60 100644 --- a/packages/openapi-ts/src/plugins/msw/shared/handlerCreator.ts +++ b/packages/openapi-ts/src/plugins/msw/shared/handlerCreator.ts @@ -199,22 +199,20 @@ function createHandlerFuncNode({ optionsName, ); - return $.func() - .$if( - dominantResponse.example != null && dominantResponse.statusCode != null, - (f) => - f.param(responseOrFnName, (p) => - p.assign( + return (m: ReturnType) => + m + .param(responseOrFnName, (p) => + p.$if(dominantResponse.example != null && dominantResponse.statusCode != null, (pp) => + pp.assign( $.fromValue({ result: dominantResponse.example, status: dominantResponse.statusCode, }), ), ), - (f) => f.param(responseOrFnName), - ) - .param(optionsName) - .do(httpCall.return()); + ) + .param(optionsName) + .do(httpCall.return()); } export function operationToHandlerCreator({ diff --git a/packages/openapi-ts/src/plugins/msw/v2/plugin.ts b/packages/openapi-ts/src/plugins/msw/v2/plugin.ts index 64189069f9..b4020ee500 100644 --- a/packages/openapi-ts/src/plugins/msw/v2/plugin.ts +++ b/packages/openapi-ts/src/plugins/msw/v2/plugin.ts @@ -51,15 +51,13 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { operation, plugin, }); - if (handlerCreator) { - handlersObject.prop(handlerCreator.name, handlerCreator.funcNode); - singleHandlerFactoriesType.prop(handlerCreator.name, (p) => p.type(handlerCreator.type)); - handlerMeta.push({ - isOptional: handlerCreator.isOptional, - name: handlerCreator.name, - path: operation.path, - }); - } + handlersObject.method(handlerCreator.name, handlerCreator.funcNode); + singleHandlerFactoriesType.prop(handlerCreator.name, (p) => p.type(handlerCreator.type)); + handlerMeta.push({ + isOptional: handlerCreator.isOptional, + name: handlerCreator.name, + path: operation.path, + }); }, { order: 'declarations', diff --git a/packages/openapi-ts/src/ts-dsl/decl/method.ts b/packages/openapi-ts/src/ts-dsl/decl/method.ts index 0aa44c9b64..d52d20e6ac 100644 --- a/packages/openapi-ts/src/ts-dsl/decl/method.ts +++ b/packages/openapi-ts/src/ts-dsl/decl/method.ts @@ -19,8 +19,11 @@ import { TypeParamsMixin } from '../mixins/type-params'; import { TypeReturnsMixin } from '../mixins/type-returns'; import { BlockTsDsl } from '../stmt/block'; import { TokenTsDsl } from '../token'; +import { f } from '../utils/factories'; import { safeAccessorName } from '../utils/name'; +export type MethodCtor = (name: NodeName, fn?: (m: MethodTsDsl) => void) => MethodTsDsl; + const Mixed = AbstractMixin( AsyncMixin( DecoratorMixin( @@ -78,3 +81,5 @@ export class MethodTsDsl extends Mixed { return this.$docs(node); } } + +f.method.set((...args) => new MethodTsDsl(...args)); diff --git a/packages/openapi-ts/src/ts-dsl/expr/object.ts b/packages/openapi-ts/src/ts-dsl/expr/object.ts index caa7d11b16..34bb28fd7c 100644 --- a/packages/openapi-ts/src/ts-dsl/expr/object.ts +++ b/packages/openapi-ts/src/ts-dsl/expr/object.ts @@ -3,16 +3,16 @@ import ts from 'typescript'; import type { MaybeTsDsl } from '../base'; import { TsDsl } from '../base'; +import type { MethodTsDsl } from '../decl/method'; import { AsMixin } from '../mixins/as'; import { ExprMixin } from '../mixins/expr'; import { HintMixin } from '../mixins/hint'; import { LayoutMixin } from '../mixins/layout'; +import { f } from '../utils/factories'; import { ObjectPropTsDsl } from './prop'; type Expr = NodeName | MaybeTsDsl; type Stmt = NodeName | MaybeTsDsl; -type ExprFn = Expr | ((p: ObjectPropTsDsl) => void); -type StmtFn = Stmt | ((p: ObjectPropTsDsl) => void); const Mixed = AsMixin(ExprMixin(HintMixin(LayoutMixin(TsDsl)))); @@ -22,9 +22,13 @@ export class ObjectTsDsl extends Mixed { protected _props = new Map(); protected _spreadCounter = 0; - constructor(...props: Array) { + constructor(...props: Array | [(o: ObjectTsDsl) => void]) { super(); - this.props(...props); + if (props.length === 1 && typeof props[0] === 'function') { + props[0](this); + } else { + this.props(...(props as Array)); + } } override analyze(ctx: AnalysisContext): void { @@ -43,7 +47,7 @@ export class ObjectTsDsl extends Mixed { } /** Adds a computed property (e.g., `{ [expr]: value }`), or removes if null. */ - computed(name: string, expr: ExprFn | null): this { + computed(name: string, expr: Expr | null): this { if (expr === null) { this._props.delete(`computed:${name}`); } else { @@ -56,7 +60,7 @@ export class ObjectTsDsl extends Mixed { } /** Adds a getter property (e.g., `{ get foo() { ... } }`), or removes if null. */ - getter(name: string, stmt: StmtFn | null): this { + getter(name: string, stmt: Stmt | null): this { if (stmt === null) { this._props.delete(`getter:${name}`); } else { @@ -75,8 +79,21 @@ export class ObjectTsDsl extends Mixed { return this._props.size === 0; } + /** Adds a method property (e.g., `{ foo() { ... } }`), or removes if null. */ + method(name: string, fn: ((m: MethodTsDsl) => void) | null): this { + if (fn === null) { + this._props.delete(`method:${name}`); + } else { + this._props.set( + `method:${name}`, + new ObjectPropTsDsl({ kind: 'method', name }).value(f.method(name, fn)), + ); + } + return this; + } + /** Adds a property assignment, or removes if null. */ - prop(name: string, expr: ExprFn | null): this { + prop(name: string, expr: Expr | null): this { if (expr === null) { this._props.delete(`prop:${name}`); } else { @@ -94,7 +111,7 @@ export class ObjectTsDsl extends Mixed { } /** Adds a setter property (e.g., `{ set foo(v) { ... } }`), or removes if null. */ - setter(name: string, stmt: StmtFn | null): this { + setter(name: string, stmt: Stmt | null): this { if (stmt === null) { this._props.delete(`setter:${name}`); } else { @@ -104,7 +121,7 @@ export class ObjectTsDsl extends Mixed { } /** Adds a spread property (e.g., `{ ...options }`). */ - spread(expr: ExprFn): this { + spread(expr: Expr): this { const key = `spread:${this._spreadCounter++}`; this._props.set(key, new ObjectPropTsDsl({ kind: 'spread' }).value(expr)); return this; diff --git a/packages/openapi-ts/src/ts-dsl/expr/prop.ts b/packages/openapi-ts/src/ts-dsl/expr/prop.ts index 308ba82a0e..76d1ac3766 100644 --- a/packages/openapi-ts/src/ts-dsl/expr/prop.ts +++ b/packages/openapi-ts/src/ts-dsl/expr/prop.ts @@ -7,17 +7,20 @@ import { TsDsl } from '../base'; import { GetterTsDsl } from '../decl/getter'; import { SetterTsDsl } from '../decl/setter'; import { DocMixin } from '../mixins/doc'; +import type { f } from '../utils/factories'; import { safePropName } from '../utils/name'; import { IdTsDsl } from './id'; -type Expr = NodeName | MaybeTsDsl; -type Stmt = NodeName | MaybeTsDsl; - -export type ObjectPropKind = 'computed' | 'getter' | 'prop' | 'setter' | 'spread'; +export type ObjectPropKind = 'computed' | 'getter' | 'method' | 'prop' | 'setter' | 'spread'; +export type ObjectPropValue = + | NodeName + | MaybeTsDsl + | ReturnType; type Meta = | { kind: 'computed'; name: string } | { kind: 'getter'; name: string } + | { kind: 'method'; name: string } | { kind: 'prop'; name: string } | { kind: 'setter'; name: string } | { kind: 'spread'; name?: undefined }; @@ -27,7 +30,7 @@ const Mixed = DocMixin(TsDsl); export class ObjectPropTsDsl extends Mixed { readonly '~dsl' = 'ObjectPropTsDsl'; - protected _value?: Ref; + protected _value?: Ref; protected _meta: Meta; constructor(meta: Meta) { @@ -35,14 +38,6 @@ export class ObjectPropTsDsl extends Mixed { this._meta = meta; } - get kind(): ObjectPropKind { - return this._meta.kind; - } - - get propName(): string | undefined { - return this._meta.name; - } - override analyze(ctx: AnalysisContext): void { super.analyze(ctx); ctx.analyze(this._value); @@ -52,12 +47,16 @@ export class ObjectPropTsDsl extends Mixed { return !this.missingRequiredCalls().length; } - value(value: Expr | Stmt | ((p: ObjectPropTsDsl) => void)) { - if (typeof value === 'function') { - value(this); - } else { - this._value = ref(value); - } + get kind(): ObjectPropKind { + return this._meta.kind; + } + + get propName(): string | undefined { + return this._meta.name; + } + + value(value: ObjectPropValue): this { + this._value = ref(value); return this; } @@ -68,19 +67,22 @@ export class ObjectPropTsDsl extends Mixed { if (ts.isStatement(node)) { throw new Error('Invalid spread: object spread must be an expression, not a statement.'); } - const result = ts.factory.createSpreadAssignment(node); + const result = ts.factory.createSpreadAssignment(node as ts.Expression); return this.$docs(result); } if (this._meta.kind === 'getter') { - const getter = new GetterTsDsl(this._meta.name).do(node); + const getter = new GetterTsDsl(this._meta.name).do(node as ts.Statement); const result = this.$node(getter); return this.$docs(result); } if (this._meta.kind === 'setter') { - const setter = new SetterTsDsl(this._meta.name).do(node); + const setter = new SetterTsDsl(this._meta.name).do(node as ts.Statement); const result = this.$node(setter); return this.$docs(result); } + if (this._meta.kind === 'method') { + return this.$docs(node as ts.MethodDeclaration); + } if (ts.isIdentifier(node) && node.text === this._meta.name) { const result = ts.factory.createShorthandPropertyAssignment(this._meta.name); return this.$docs(result); @@ -94,13 +96,13 @@ export class ObjectPropTsDsl extends Mixed { this._meta.kind === 'computed' ? ts.factory.createComputedPropertyName(this.$node(new IdTsDsl(this._meta.name))) : this.$node(safePropName(this._meta.name)), - node, + node as ts.Expression, ); return this.$docs(result); } $validate(): asserts this is this & { - _value: Expr | Stmt; + _value: ObjectPropValue; kind: ObjectPropKind; } { const missing = this.missingRequiredCalls(); diff --git a/packages/openapi-ts/src/ts-dsl/utils/factories.ts b/packages/openapi-ts/src/ts-dsl/utils/factories.ts index 58d8071ce6..c6defabf7f 100644 --- a/packages/openapi-ts/src/ts-dsl/utils/factories.ts +++ b/packages/openapi-ts/src/ts-dsl/utils/factories.ts @@ -1,3 +1,4 @@ +import type { MethodCtor } from '../decl/method'; import type { AsCtor } from '../expr/as'; import type { AttrCtor } from '../expr/attr'; import type { AwaitCtor } from '../expr/await'; @@ -46,6 +47,9 @@ export const f = { /** Factory for creating function or method call expressions (e.g., `fn(arg)`). */ call: createFactory('call'), + /** Factory for creating method declarations (e.g., `{ foo() { ... } }`). */ + method: createFactory('method'), + /** Factory for creating new expressions (e.g., `new ClassName()`). */ new: createFactory('new'), diff --git a/packages/shared/src/openApi/3.0.x/parser/schema.ts b/packages/shared/src/openApi/3.0.x/parser/schema.ts index cc363caee8..9361776716 100644 --- a/packages/shared/src/openApi/3.0.x/parser/schema.ts +++ b/packages/shared/src/openApi/3.0.x/parser/schema.ts @@ -792,7 +792,7 @@ const parseAnyOf = ({ }); // `$ref` should be defined with discriminators - if (schema.discriminator && irCompositionSchema.$ref != null) { + if (schema.discriminator && irCompositionSchema.$ref) { const values = discriminatorValues(irCompositionSchema.$ref, schema.discriminator.mapping); const valueSchemas: ReadonlyArray = values.map((value) => @@ -960,7 +960,7 @@ const parseOneOf = ({ }); // `$ref` should be defined with discriminators - if (schema.discriminator && irCompositionSchema.$ref != null) { + if (schema.discriminator && irCompositionSchema.$ref) { const values = discriminatorValues(irCompositionSchema.$ref, schema.discriminator.mapping); const valueSchemas: ReadonlyArray = values.map((value) => diff --git a/packages/shared/src/openApi/3.1.x/parser/schema.ts b/packages/shared/src/openApi/3.1.x/parser/schema.ts index 16e605eb03..ec595d4ebe 100644 --- a/packages/shared/src/openApi/3.1.x/parser/schema.ts +++ b/packages/shared/src/openApi/3.1.x/parser/schema.ts @@ -876,7 +876,7 @@ const parseAnyOf = ({ }); // `$ref` should be defined with discriminators - if (schema.discriminator && irCompositionSchema.$ref != null) { + if (schema.discriminator && irCompositionSchema.$ref) { const values = discriminatorValues(irCompositionSchema.$ref, schema.discriminator.mapping); const valueSchemas: ReadonlyArray = values.map((value) => @@ -1035,7 +1035,7 @@ const parseOneOf = ({ }); // `$ref` should be defined with discriminators - if (schema.discriminator && irCompositionSchema.$ref != null) { + if (schema.discriminator && irCompositionSchema.$ref) { const values = discriminatorValues(irCompositionSchema.$ref, schema.discriminator.mapping); const valueSchemas: ReadonlyArray = values.map((value) => diff --git a/packages/shared/src/openApi/shared/transforms/enums.ts b/packages/shared/src/openApi/shared/transforms/enums.ts index f90030dcaa..26180408d7 100644 --- a/packages/shared/src/openApi/shared/transforms/enums.ts +++ b/packages/shared/src/openApi/shared/transforms/enums.ts @@ -238,7 +238,7 @@ const rootMode = ({ config, spec }: { config: EnumsConfig; spec: unknown }) => { const schemasPointerNamespace = specToSchemasPointerNamespace(spec); for (const { key, parent, signature } of inlineEnums) { const name = signatureToName[signature]; - if (name && key != null && parent && typeof parent === 'object') { + if (name && key !== null && parent && typeof parent === 'object') { (parent as Record)[key] = { $ref: `${schemasPointerNamespace}${name}`, }; From 06cd3dbff4e444026beec0c0c174ae8ada43ae06 Mon Sep 17 00:00:00 2001 From: Lubos Date: Fri, 27 Mar 2026 01:51:51 +0100 Subject: [PATCH 10/16] chore: move handlers to separate functions --- dev/playground.ts | 59 ++-- eslint.config.js | 2 +- .../shared/{handlerCreator.ts => handler.ts} | 280 ++++++++++-------- .../openapi-ts/src/plugins/msw/shared/path.ts | 24 ++ .../src/plugins/msw/shared/types.ts | 22 ++ .../openapi-ts/src/plugins/msw/v2/plugin.ts | 76 ++--- packages/openapi-ts/src/ts-dsl/expr/typeof.ts | 4 +- 7 files changed, 262 insertions(+), 205 deletions(-) rename packages/openapi-ts/src/plugins/msw/shared/{handlerCreator.ts => handler.ts} (58%) create mode 100644 packages/openapi-ts/src/plugins/msw/shared/path.ts create mode 100644 packages/openapi-ts/src/plugins/msw/shared/types.ts diff --git a/dev/playground.ts b/dev/playground.ts index c455a335e9..cda7044a7c 100644 --- a/dev/playground.ts +++ b/dev/playground.ts @@ -5,7 +5,7 @@ import { setupServer } from 'msw/node'; import { client } from './gen/typescript/client.gen'; // import { createOpencode } from '@opencode-ai/sdk'; -import { createMswHandlers } from './gen/typescript/msw.gen'; +import { createMswHandlers, handleTuiPublish } from './gen/typescript/msw.gen'; import { OpenCode } from './gen/typescript/sdk.gen'; type MyPluginConfig = { readonly name: 'myplugin' }; @@ -22,34 +22,37 @@ export const handler: MyPlugin['Handler'] = ({ plugin }) => { }; const server = setupServer( - // ...createMswHandlers({ - // baseUrl: 'https://api.example.com', - // }).getAllHandlers(), - createMswHandlers({ + ...createMswHandlers({ baseUrl: 'https://api.example.com', - }).tuiPublishMock({ - result: false, - // status: 200, - }), - http.post( - '*/tui/publish', - (info) => - HttpResponse.json( - { - firstName: 'John', - id: 'abc-123', - lastName: 'Maverick', - }, - { - // status: 200, - // statusText: 'OK', - // type: 'default', - }, - ), - { - // once: true, - }, - ), + }).getAllHandlers(), + // handleTuiPublish({ + // result: false + // }), + // createMswHandlers({ + // baseUrl: 'https://api.example.com', + // }).tuiPublish({ + // result: false, + // // status: 200, + // }), + // http.post( + // '*/tui/publish', + // (info) => + // HttpResponse.json( + // { + // firstName: 'John', + // id: 'abc-123', + // lastName: 'Maverick', + // }, + // { + // // status: 200, + // // statusText: 'OK', + // // type: 'default', + // }, + // ), + // { + // // once: true, + // }, + // ), ); server.listen(); diff --git a/eslint.config.js b/eslint.config.js index b227062824..d3f598eeea 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -58,7 +58,7 @@ export default tseslint.config( '**/dist/', '**/node_modules/', 'temp/', - 'dev/.gen/', + 'dev/gen/', 'examples/openapi-ts-nestjs/src/client/**/*.ts', 'examples/openapi-ts-openai/src/client/**/*.ts', '**/test/generated/', diff --git a/packages/openapi-ts/src/plugins/msw/shared/handlerCreator.ts b/packages/openapi-ts/src/plugins/msw/shared/handler.ts similarity index 58% rename from packages/openapi-ts/src/plugins/msw/shared/handlerCreator.ts rename to packages/openapi-ts/src/plugins/msw/shared/handler.ts index 9e5f570c60..0bc3afac5a 100644 --- a/packages/openapi-ts/src/plugins/msw/shared/handlerCreator.ts +++ b/packages/openapi-ts/src/plugins/msw/shared/handler.ts @@ -1,9 +1,11 @@ import type { Symbol } from '@hey-api/codegen-core'; import type { IR } from '@hey-api/shared'; +import { applyNaming } from '@hey-api/shared'; import { $ } from '../../../ts-dsl'; import type { MswPlugin } from '../types'; import { computeDominantResponse, type DominantResponse } from './computeDominantResponse'; +import { sanitizeParamName, sanitizePath } from './path'; const emitToResponseUnion = (plugin: MswPlugin['Instance']) => { const symbol = plugin.symbol('ToResponseUnion', { @@ -42,8 +44,6 @@ const emitHandlerFactory = (plugin: MswPlugin['Instance']) => { resource: 'http-handler-factory', }, }); - const symbolHttpHandler = plugin.external('msw.HttpHandler'); - const symbolRequestHandlerOptions = plugin.external('msw.RequestHandlerOptions'); const handlerFactoryType = $.type .alias(symbol) .generic('ResponseOrResolver') @@ -51,8 +51,8 @@ const emitHandlerFactory = (plugin: MswPlugin['Instance']) => { $.type .func() .param('responseOrResolver', (p) => p.type('ResponseOrResolver')) - .param('options', (p) => p.type($.type(symbolRequestHandlerOptions)).optional()) - .returns($.type(symbolHttpHandler)), + .param('options', (p) => p.type(plugin.external('msw.RequestHandlerOptions')).optional()) + .returns(plugin.external('msw.HttpHandler')), ); plugin.node(handlerFactoryType); }; @@ -64,8 +64,6 @@ const emitOptionalParamHandlerFactory = (plugin: MswPlugin['Instance']) => { resource: 'optional-http-handler-factory', }, }); - const symbolHttpHandler = plugin.external('msw.HttpHandler'); - const symbolRequestHandlerOptions = plugin.external('msw.RequestHandlerOptions'); const optionalHandlerFactoryType = $.type .alias(symbol) .generic('ResponseOrResolver') @@ -73,18 +71,12 @@ const emitOptionalParamHandlerFactory = (plugin: MswPlugin['Instance']) => { $.type .func() .param('responseOrResolver', (p) => p.type('ResponseOrResolver').optional()) - .param('options', (p) => p.type($.type(symbolRequestHandlerOptions)).optional()) - .returns($.type(symbolHttpHandler)), + .param('options', (p) => p.type(plugin.external('msw.RequestHandlerOptions')).optional()) + .returns(plugin.external('msw.HttpHandler')), ); plugin.node(optionalHandlerFactoryType); }; -// path-to-regexp v6 (used by MSW) only allows word characters in param names. -// So transform what's necessary: replace non-word chars with camelCase transitions, -// preserving the original casing to stay consistent with the TypeScript plugin's types. -const sanitizeParamName = (name: string) => - name.replace(/\W+(.)?/g, (_, char?: string) => (char ? char.toUpperCase() : '')); - const extractPathParamNames = (path: string) => { const names: Array = []; for (const match of path.matchAll(/\{([^}]+)\}/g)) { @@ -93,12 +85,6 @@ const extractPathParamNames = (path: string) => { return names; }; -const toMswPath = (path: string) => - path - .replace(/\{([^}]+)\}/g, (_, name: string) => `\0${sanitizeParamName(name)}`) - .replace(/:/g, String.raw`\:`) - .replace(/\0/g, ':'); - /** * Builds the response override expression for the `res` parameter. * When `res` is an object with a `result` property, it uses @@ -106,44 +92,36 @@ const toMswPath = (path: string) => */ function buildResponseOverrideExpr({ dominantResponse: { kind: responseKind, statusCode: responseStatusCode }, - responseOrFnName, symbolHttpResponse, + symbolResolver, }: { dominantResponse: DominantResponse; - responseOrFnName: string; symbolHttpResponse: Symbol; + symbolResolver: Symbol; }) { const statusOption = $.object().prop( 'status', responseStatusCode - ? $(responseOrFnName).attr('status').coalesce($.literal(responseStatusCode)) - : $(responseOrFnName).attr('status'), + ? $(symbolResolver).attr('status').coalesce($.literal(responseStatusCode)) + : $(symbolResolver).attr('status'), ); - const resultExpr = $(responseOrFnName).attr('result'); + const resultExpr = $(symbolResolver).attr('result'); switch (responseKind) { - case 'void': - return $.func().do( - $.new(symbolHttpResponse, resultExpr.coalesce($.literal(null)), statusOption).return(), - ); + case 'binary': + return $.new(symbolHttpResponse, resultExpr.coalesce($.literal(null)), statusOption).return(); case 'json': - return $.func().do( - $(symbolHttpResponse) - .attr('json') - .call(resultExpr.coalesce($.literal(null)), statusOption) - .return(), - ); + return $(symbolHttpResponse) + .attr('json') + .call(resultExpr.coalesce($.literal(null)), statusOption) + .return(); case 'text': - return $.func().do( - $(symbolHttpResponse) - .attr('text') - .call(resultExpr.coalesce($.literal(null)), statusOption) - .return(), - ); - case 'binary': - return $.func().do( - $.new(symbolHttpResponse, resultExpr.coalesce($.literal(null)), statusOption).return(), - ); + return $(symbolHttpResponse) + .attr('text') + .call(resultExpr.coalesce($.literal(null)), statusOption) + .return(); + case 'void': + return $.new(symbolHttpResponse, resultExpr.coalesce($.literal(null)), statusOption).return(); } } @@ -151,58 +129,42 @@ function buildResponseOverrideExpr({ * Builds an arrow function that creates an MSW handler for a single operation. * The response method and status code are inferred from the operation's responses. */ -function createHandlerFuncNode({ +function createHandlerFunc({ + baseUrl, + bodyType, dominantResponse, hasResponseOverride, method, operation, + paramsType, + plugin, + responseOrResolverType, + symbol, symbolHttp, symbolHttpResponse, - symbolResolveToNull, }: { + baseUrl: string | undefined; + bodyType: ReturnType; dominantResponse: DominantResponse; hasResponseOverride: boolean; method: string; operation: IR.OperationObject; + paramsType: ReturnType; + plugin: MswPlugin['Instance']; + responseOrResolverType: ReturnType; + symbol: Symbol; symbolHttp: Symbol; symbolHttpResponse: Symbol; - symbolResolveToNull: Symbol; }) { - const responseOrFnName = 'res'; - const optionsName = 'options'; - - const fallbackTernary = $.ternary($.typeofExpr(responseOrFnName).eq($.literal('function'))) - .do(responseOrFnName) - .otherwise($(symbolResolveToNull)); + const symbolResolver = plugin.symbol('resolver'); + const symbolOptions = plugin.symbol('options'); - const resolverArg = hasResponseOverride - ? $.ternary( - $($.typeofExpr(responseOrFnName).eq($.literal('object'))).and( - $(responseOrFnName).attr('result'), - ), - ) - .do( - buildResponseOverrideExpr({ - dominantResponse, - responseOrFnName, - symbolHttpResponse, - }), - ) - .otherwise(fallbackTernary) - : fallbackTernary; - - const httpCall = $(symbolHttp) - .attr(method) - .call( - $.template($('baseUrl')).add($.literal(toMswPath(operation.path))), - resolverArg, - optionsName, - ); - - return (m: ReturnType) => - m - .param(responseOrFnName, (p) => - p.$if(dominantResponse.example != null && dominantResponse.statusCode != null, (pp) => + return $.func(symbol) + .export() + .param(symbolResolver, (p) => + p + .type(responseOrResolverType) + .$if(dominantResponse.example != null && dominantResponse.statusCode != null, (pp) => pp.assign( $.fromValue({ result: dominantResponse.example, @@ -210,16 +172,71 @@ function createHandlerFuncNode({ }), ), ), - ) - .param(optionsName) - .do(httpCall.return()); + ) + .param(symbolOptions, (p) => + p.optional().type( + plugin.referenceSymbol({ + category: 'type', + resource: 'request-handler-options', + tool: 'msw', + }), + ), + ) + .returns(plugin.external('msw.HttpHandler')) + .do( + $(symbolHttp) + .attr(method) + .call( + $.template( + $(symbolOptions) + .attr('baseUrl') + .optional() + .coalesce($.literal(baseUrl ?? '')), + ).add(sanitizePath(operation.path)), + $.func() + .param('info') + .$if( + hasResponseOverride, + (f) => + f.do( + $.if( + $($.typeofExpr(symbolResolver).eq($.literal('object'))).and( + $(symbolResolver).attr('result'), + ), + ).do( + buildResponseOverrideExpr({ + dominantResponse, + symbolHttpResponse, + symbolResolver, + }), + ), + $.if($.typeofExpr(symbolResolver).eq($.literal('function'))).do( + $(symbolResolver).call('info').return(), + ), + $.new(symbolHttpResponse, $.literal(null)).return(), + ), + (f) => + f.do( + $.if($.typeofExpr(symbolResolver).eq($.literal('function'))).do( + $(symbolResolver).call('info').return(), + ), + $.new(symbolHttpResponse, $.literal(null)).return(), + ), + ), + symbolOptions, + ) + .generics(paramsType, bodyType) + .return(), + ); } -export function operationToHandlerCreator({ +export function getHandler({ + baseUrl, examples, operation, plugin, }: { + baseUrl: string | undefined; examples: boolean; operation: IR.OperationObject; plugin: MswPlugin['Instance']; @@ -228,23 +245,6 @@ export function operationToHandlerCreator({ const symbolHttp = plugin.external('msw.http'); const symbolHttpResponse = plugin.external('msw.HttpResponse'); - const symbolHttpResponseResolver = plugin.external('msw.HttpResponseResolver'); - const symbolHttpHandlerFactory = plugin.referenceSymbol({ - category: 'type', - resource: 'http-handler-factory', - }); - const symbolOptionalHttpHandlerFactory = plugin.referenceSymbol({ - category: 'type', - resource: 'optional-http-handler-factory', - }); - const symbolToResponseUnion = plugin.referenceSymbol({ - category: 'type', - resource: 'to-response-union', - }); - const symbolResolveToNull = plugin.referenceSymbol({ - category: 'function', - resource: 'resolve-to-null', - }); // Query response type from @hey-api/typescript const symbolResponsesType = plugin.querySymbol({ @@ -259,7 +259,12 @@ export function operationToHandlerCreator({ if (!plugin.getSymbol({ category: 'type', resource: 'to-response-union' })) { emitToResponseUnion(plugin); } - responsesOverrideType = $.type(symbolToResponseUnion).generic(symbolResponsesType); + responsesOverrideType = $.type( + plugin.referenceSymbol({ + category: 'type', + resource: 'to-response-union', + }), + ).generic(symbolResponsesType); } // Query data type for parameters @@ -271,13 +276,8 @@ export function operationToHandlerCreator({ tool: 'typescript', }); - // Build HttpResponseResolver generics - const hasPathParams = - operation.parameters?.path && Object.keys(operation.parameters.path).length > 0; - const hasBody = !!operation.body; - - let pathParamsType: ReturnType | undefined; - if (hasPathParams) { + let paramsType: ReturnType; + if (operation.parameters?.path && Object.keys(operation.parameters.path).length) { // Generate inline object type with sanitized param names derived from the // path string (not the IR keys, which are lowercased and may diverge from // the original spec names that the TypeScript plugin preserves). @@ -288,23 +288,23 @@ export function operationToHandlerCreator({ // for OpenAPI 4.0 — revisit this if/when that lands. objType.prop(sanitizeParamName(name), (p) => p.type('string')); } - pathParamsType = objType; + paramsType = objType; + } else { + paramsType = $.type('never'); } - let bodyType: ReturnType | undefined; - if (hasBody && symbolDataType) { + let bodyType: ReturnType; + if (operation.body && symbolDataType) { bodyType = $.type(symbolDataType).idx($.type.literal('body')); + } else { + bodyType = $.type('never'); } - // Build the resolver type: HttpResponseResolver // Omit response type generic to avoid MSW's DefaultBodyType constraint issues - const hasResolverGenerics = pathParamsType || bodyType; - const resolverType = hasResolverGenerics - ? $.type(symbolHttpResponseResolver).generics( - pathParamsType ?? $.type('never'), - bodyType ?? $.type('never'), - ) - : $.type(symbolHttpResponseResolver); + const resolverType = $.type(plugin.external('msw.HttpResponseResolver')).generics( + paramsType, + bodyType, + ); // When examples are disabled, strip the example from the dominant response if (!examples) { @@ -336,31 +336,51 @@ export function operationToHandlerCreator({ responseOrResolverType = resolverType; } - let handlerType: ReturnType; + let type: ReturnType; if (isOptional) { if (!plugin.getSymbol({ category: 'type', resource: 'optional-http-handler-factory' })) { emitOptionalParamHandlerFactory(plugin); } - handlerType = $.type(symbolOptionalHttpHandlerFactory).generic(responseOrResolverType); + type = $.type( + plugin.referenceSymbol({ + category: 'type', + resource: 'optional-http-handler-factory', + }), + ).generic(responseOrResolverType); } else { if (!plugin.getSymbol({ category: 'type', resource: 'http-handler-factory' })) { emitHandlerFactory(plugin); } - handlerType = $.type(symbolHttpHandlerFactory).generic(responseOrResolverType); + type = $.type( + plugin.referenceSymbol({ + category: 'type', + resource: 'http-handler-factory', + }), + ).generic(responseOrResolverType); } + const symbol = plugin.symbol( + applyNaming(`handle-${operation.id}`, { + casing: 'camelCase', // TODO: expose as a config option + }), + ); return { - funcNode: createHandlerFuncNode({ + isOptional, + node: createHandlerFunc({ + baseUrl, + bodyType, dominantResponse, hasResponseOverride: dominantResponse.statusCode != null, method: operation.method, operation, + paramsType, + plugin, + responseOrResolverType, + symbol, symbolHttp, symbolHttpResponse, - symbolResolveToNull, }), - isOptional, - name: `${operation.id}Mock`, - type: handlerType, + symbol, + type, }; } diff --git a/packages/openapi-ts/src/plugins/msw/shared/path.ts b/packages/openapi-ts/src/plugins/msw/shared/path.ts new file mode 100644 index 0000000000..20b1ec207e --- /dev/null +++ b/packages/openapi-ts/src/plugins/msw/shared/path.ts @@ -0,0 +1,24 @@ +/** + * path-to-regexp v6 (used by MSW) only allows word characters in param names. + * So transform what's necessary: replace non-word chars with camelCase transitions, + * preserving the original casing to stay consistent with the TypeScript plugin's types. + */ +export function sanitizeParamName(name: string): string { + return name.replace(/\W+(.)?/g, (_, char?: string) => (char ? char.toUpperCase() : '')); +} + +/** + * Transforms an OpenAPI path template (e.g. `/users/{userId}/posts/{postId}`) + * into an MSW path template (e.g. `/users/:userId/posts/:postId`), sanitizing + * param names as needed to conform to path-to-regexp v6 requirements. + * + * Note: MSW's path-to-regexp v6 does not allow regex patterns in the path + * (e.g. `{id:\d+}`), so this function assumes simple param names without + * patterns. + */ +export function sanitizePath(path: string): string { + return path + .replace(/\{([^}]+)\}/g, (_, name: string) => `\0${sanitizeParamName(name)}`) + .replace(/:/g, String.raw`\:`) + .replace(/\0/g, ':'); +} diff --git a/packages/openapi-ts/src/plugins/msw/shared/types.ts b/packages/openapi-ts/src/plugins/msw/shared/types.ts new file mode 100644 index 0000000000..67ce081630 --- /dev/null +++ b/packages/openapi-ts/src/plugins/msw/shared/types.ts @@ -0,0 +1,22 @@ +import { $ } from '../../../ts-dsl'; +import type { MswPlugin } from '../types'; + +export function createRequestHandlerOptions(plugin: MswPlugin['Instance']) { + const symbol = plugin.symbol('RequestHandlerOptions', { + meta: { + category: 'type', + resource: 'request-handler-options', + tool: 'msw', + }, + }); + const node = $.type + .alias(symbol) + .export() + .type( + $.type.and( + $.type(plugin.external('msw.RequestHandlerOptions')), + $.type.object().prop('baseUrl', (p) => p.type('string').optional()), + ), + ); + plugin.node(node); +} diff --git a/packages/openapi-ts/src/plugins/msw/v2/plugin.ts b/packages/openapi-ts/src/plugins/msw/v2/plugin.ts index b4020ee500..739d8b458a 100644 --- a/packages/openapi-ts/src/plugins/msw/v2/plugin.ts +++ b/packages/openapi-ts/src/plugins/msw/v2/plugin.ts @@ -1,8 +1,9 @@ import { getBaseUrl } from '@hey-api/shared'; import { $ } from '../../../ts-dsl'; -import { operationToHandlerCreator } from '../shared/handlerCreator'; +import { getHandler } from '../shared/handler'; import { sortHandlersBySpecificity } from '../shared/sortHandlersBySpecificity'; +import { createRequestHandlerOptions } from '../shared/types'; import type { MswPlugin } from '../types'; export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { @@ -25,18 +26,9 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { kind: 'type', }); - // Generate resolveToNull helper - // const resolveToNull = () => new HttpResponse(null) - const symbolResolveToNull = plugin.symbol('resolveToNull', { - meta: { - category: 'function', - resource: 'resolve-to-null', - }, - }); - const resolveToNullFn = $.const(symbolResolveToNull).assign( - $.func().do($.new(symbolHttpResponse, $.literal(null)).return()), - ); - plugin.node(resolveToNullFn); + const baseUrl = getBaseUrl(plugin.config.baseUrl, plugin.context.ir); + + createRequestHandlerOptions(plugin); const symbolFactory = plugin.symbol('createMswHandlers'); const handlersObject = $.object().pretty(); @@ -46,16 +38,36 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { plugin.forEach( 'operation', ({ operation }) => { - const handlerCreator = operationToHandlerCreator({ + const handler = getHandler({ + baseUrl, examples: plugin.config.valueSources?.includes('example') ?? true, operation, plugin, }); - handlersObject.method(handlerCreator.name, handlerCreator.funcNode); - singleHandlerFactoriesType.prop(handlerCreator.name, (p) => p.type(handlerCreator.type)); + plugin.node(handler.node); + const symbolResponse = plugin.symbol('resolver'); + const symbolOptions = plugin.symbol('options'); + handlersObject.method(operation.id, (m) => + m + .param(symbolResponse) + // , (p) => + // p.$if(dominantResponse.example != null && dominantResponse.statusCode != null, (pp) => + // pp.assign( + // $.fromValue({ + // result: dominantResponse.example, + // status: dominantResponse.statusCode, + // }), + // ), + // ), + // ) + .param(symbolOptions) + .do($(handler.symbol).call(symbolResponse, symbolOptions).return()), + ); + // handlersObject.prop(operation.id, handler.symbol); + singleHandlerFactoriesType.prop(operation.id, (p) => p.type(handler.type)); handlerMeta.push({ - isOptional: handlerCreator.isOptional, - name: handlerCreator.name, + isOptional: handler.isOptional, + name: operation.id, path: operation.path, }); }, @@ -94,26 +106,6 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { ), ); - const symbolMswHandlers = plugin.symbol('MswHandlers'); - plugin.node( - $.type - .alias(symbolMswHandlers) - .export() - .type( - $.type.and( - $.type(symbolMswHandlerCreators), - $.type.object().prop('getAllHandlers', (p) => - p.type( - $.type - .func() - .param('options', (pp) => pp.type(symbolGetAllHandlersOptions).optional()) - .returns($.type('Array').generic(symbolHttpHandler)), - ), - ), - ), - ), - ); - const getAllHandlersDo: Array> = []; const hasRequiredHandlers = handlerMeta.some((h) => !h.isOptional); @@ -128,9 +120,7 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { getAllHandlersDo.push($.const('overrides').assign($('options').attr('overrides'))); getAllHandlersDo.push( - $.const('handlers') - .type($.type('Array').generic($.type(symbolHttpHandler))) - .assign($.array()), + $.const('handlers').type($.type('Array').generic(symbolHttpHandler)).assign($.array()), ); // Generate addRequiredHandler helper when there are required handlers @@ -151,7 +141,7 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { $.type.or('Value', $.type.func().returns($.type(symbolHttpResponse).generic('any'))), ), ) - .returns($.type(symbolHttpHandler)); + .returns(symbolHttpHandler); getAllHandlersDo.push( $.const('addRequiredHandler').assign( @@ -201,7 +191,6 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { getAllHandlersDo.push($('handlers').return()); - const baseUrl = getBaseUrl(plugin.config.baseUrl, plugin.context.ir); const factoryFn = $.func(symbolFactory) .export() .param('config', (p) => @@ -209,7 +198,6 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { .type($.type.object().prop('baseUrl', (p) => p.optional().type('string'))) .assign($.object()), ) - .returns(symbolMswHandlers) .do( $.const('baseUrl').assign( $('config') diff --git a/packages/openapi-ts/src/ts-dsl/expr/typeof.ts b/packages/openapi-ts/src/ts-dsl/expr/typeof.ts index 99dae0cdc1..6230901321 100644 --- a/packages/openapi-ts/src/ts-dsl/expr/typeof.ts +++ b/packages/openapi-ts/src/ts-dsl/expr/typeof.ts @@ -1,4 +1,4 @@ -import type { AnalysisContext } from '@hey-api/codegen-core'; +import type { AnalysisContext, NodeName } from '@hey-api/codegen-core'; import ts from 'typescript'; import type { MaybeTsDsl } from '../base'; @@ -6,7 +6,7 @@ import { TsDsl } from '../base'; import { OperatorMixin } from '../mixins/operator'; import { f } from '../utils/factories'; -export type TypeOfExpr = string | MaybeTsDsl; +export type TypeOfExpr = NodeName | MaybeTsDsl; export type TypeOfExprCtor = (expr: TypeOfExpr) => TypeOfExprTsDsl; const Mixed = OperatorMixin(TsDsl); From e1640f41294029f38c1eefd7ecdf046e28e1cee6 Mon Sep 17 00:00:00 2001 From: Lubos Date: Fri, 27 Mar 2026 21:10:15 +0100 Subject: [PATCH 11/16] chore: clean up msw output --- dev/playground.ts | 41 ++-- eslint.config.js | 1 + .../src/plugins/msw/shared/handler.ts | 120 ++--------- .../openapi-ts/src/plugins/msw/shared/sort.ts | 49 +++++ .../msw/shared/sortHandlersBySpecificity.ts | 56 ----- .../openapi-ts/src/plugins/msw/v2/plugin.ts | 201 +++++------------- 6 files changed, 136 insertions(+), 332 deletions(-) create mode 100644 packages/openapi-ts/src/plugins/msw/shared/sort.ts delete mode 100644 packages/openapi-ts/src/plugins/msw/shared/sortHandlersBySpecificity.ts diff --git a/dev/playground.ts b/dev/playground.ts index cda7044a7c..642a9ba80f 100644 --- a/dev/playground.ts +++ b/dev/playground.ts @@ -1,6 +1,4 @@ -/* eslint-disable */ import type { DefinePlugin, IR } from '@hey-api/openapi-ts'; -import { http, HttpResponse } from 'msw'; import { setupServer } from 'msw/node'; import { client } from './gen/typescript/client.gen'; @@ -21,38 +19,27 @@ export const handler: MyPlugin['Handler'] = ({ plugin }) => { }); }; +const handlers = createMswHandlers({ + baseUrl: 'https://api.example.com', +}); + const server = setupServer( - ...createMswHandlers({ - baseUrl: 'https://api.example.com', - }).getAllHandlers(), + ...handlers.all({ + // overrides: { + // tuiPublish: { + // result: true, + // }, + // }, + }), // handleTuiPublish({ // result: false // }), - // createMswHandlers({ - // baseUrl: 'https://api.example.com', - // }).tuiPublish({ + // handlers.one.tuiPublish({ // result: false, // // status: 200, + // }, { + // // ... // }), - // http.post( - // '*/tui/publish', - // (info) => - // HttpResponse.json( - // { - // firstName: 'John', - // id: 'abc-123', - // lastName: 'Maverick', - // }, - // { - // // status: 200, - // // statusText: 'OK', - // // type: 'default', - // }, - // ), - // { - // // once: true, - // }, - // ), ); server.listen(); diff --git a/eslint.config.js b/eslint.config.js index d3f598eeea..be1860d746 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -59,6 +59,7 @@ export default tseslint.config( '**/node_modules/', 'temp/', 'dev/gen/', + 'dev/playground.ts', 'examples/openapi-ts-nestjs/src/client/**/*.ts', 'examples/openapi-ts-openai/src/client/**/*.ts', '**/test/generated/', diff --git a/packages/openapi-ts/src/plugins/msw/shared/handler.ts b/packages/openapi-ts/src/plugins/msw/shared/handler.ts index 0bc3afac5a..08e71592f8 100644 --- a/packages/openapi-ts/src/plugins/msw/shared/handler.ts +++ b/packages/openapi-ts/src/plugins/msw/shared/handler.ts @@ -37,46 +37,6 @@ const emitToResponseUnion = (plugin: MswPlugin['Instance']) => { plugin.node(toResponseUnionType); }; -const emitHandlerFactory = (plugin: MswPlugin['Instance']) => { - const symbol = plugin.symbol('HttpHandlerFactory', { - meta: { - category: 'type', - resource: 'http-handler-factory', - }, - }); - const handlerFactoryType = $.type - .alias(symbol) - .generic('ResponseOrResolver') - .type( - $.type - .func() - .param('responseOrResolver', (p) => p.type('ResponseOrResolver')) - .param('options', (p) => p.type(plugin.external('msw.RequestHandlerOptions')).optional()) - .returns(plugin.external('msw.HttpHandler')), - ); - plugin.node(handlerFactoryType); -}; - -const emitOptionalParamHandlerFactory = (plugin: MswPlugin['Instance']) => { - const symbol = plugin.symbol('OptionalHttpHandlerFactory', { - meta: { - category: 'type', - resource: 'optional-http-handler-factory', - }, - }); - const optionalHandlerFactoryType = $.type - .alias(symbol) - .generic('ResponseOrResolver') - .type( - $.type - .func() - .param('responseOrResolver', (p) => p.type('ResponseOrResolver').optional()) - .param('options', (p) => p.type(plugin.external('msw.RequestHandlerOptions')).optional()) - .returns(plugin.external('msw.HttpHandler')), - ); - plugin.node(optionalHandlerFactoryType); -}; - const extractPathParamNames = (path: string) => { const names: Array = []; for (const match of path.matchAll(/\{([^}]+)\}/g)) { @@ -163,6 +123,7 @@ function createHandlerFunc({ .export() .param(symbolResolver, (p) => p + .optional() .type(responseOrResolverType) .$if(dominantResponse.example != null && dominantResponse.statusCode != null, (pp) => pp.assign( @@ -195,34 +156,27 @@ function createHandlerFunc({ ).add(sanitizePath(operation.path)), $.func() .param('info') - .$if( - hasResponseOverride, - (f) => - f.do( - $.if( - $($.typeofExpr(symbolResolver).eq($.literal('object'))).and( - $(symbolResolver).attr('result'), - ), - ).do( - buildResponseOverrideExpr({ - dominantResponse, - symbolHttpResponse, - symbolResolver, - }), - ), - $.if($.typeofExpr(symbolResolver).eq($.literal('function'))).do( - $(symbolResolver).call('info').return(), - ), - $.new(symbolHttpResponse, $.literal(null)).return(), - ), - (f) => - f.do( - $.if($.typeofExpr(symbolResolver).eq($.literal('function'))).do( - $(symbolResolver).call('info').return(), + .do( + $.if($.typeofExpr(symbolResolver).eq($.literal('function'))).do( + $(symbolResolver).call('info').return(), + ), + ) + .$if(hasResponseOverride, (f) => + f.do( + $.if( + $($.typeofExpr(symbolResolver).eq($.literal('object'))).and( + $(symbolResolver).attr('result'), ), - $.new(symbolHttpResponse, $.literal(null)).return(), + ).do( + buildResponseOverrideExpr({ + dominantResponse, + symbolHttpResponse, + symbolResolver, + }), ), - ), + ), + ) + .do($.new(symbolHttpResponse, $.literal(null)).return()), symbolOptions, ) .generics(paramsType, bodyType) @@ -311,15 +265,6 @@ export function getHandler({ dominantResponse.example = undefined; } - const isOptional = - // if there is no dominantResponse, it means there is no status code definition - // so we can set the default response as null - !(dominantResponse.statusCode != null) || - // if there is example, the param is optional because example can be used - // if it's void, the param is optional because we can define the default (`null`) - dominantResponse.example != null || - dominantResponse.kind === 'void'; - let responseOrResolverType: ReturnType; if (dominantResponse.statusCode != null && symbolResponsesType) { const dominantResponseType = $.type @@ -336,36 +281,12 @@ export function getHandler({ responseOrResolverType = resolverType; } - let type: ReturnType; - if (isOptional) { - if (!plugin.getSymbol({ category: 'type', resource: 'optional-http-handler-factory' })) { - emitOptionalParamHandlerFactory(plugin); - } - type = $.type( - plugin.referenceSymbol({ - category: 'type', - resource: 'optional-http-handler-factory', - }), - ).generic(responseOrResolverType); - } else { - if (!plugin.getSymbol({ category: 'type', resource: 'http-handler-factory' })) { - emitHandlerFactory(plugin); - } - type = $.type( - plugin.referenceSymbol({ - category: 'type', - resource: 'http-handler-factory', - }), - ).generic(responseOrResolverType); - } - const symbol = plugin.symbol( applyNaming(`handle-${operation.id}`, { casing: 'camelCase', // TODO: expose as a config option }), ); return { - isOptional, node: createHandlerFunc({ baseUrl, bodyType, @@ -381,6 +302,5 @@ export function getHandler({ symbolHttpResponse, }), symbol, - type, }; } diff --git a/packages/openapi-ts/src/plugins/msw/shared/sort.ts b/packages/openapi-ts/src/plugins/msw/shared/sort.ts new file mode 100644 index 0000000000..5d408d9c69 --- /dev/null +++ b/packages/openapi-ts/src/plugins/msw/shared/sort.ts @@ -0,0 +1,49 @@ +export interface HandlerInfo { + name: string; + path: string; +} + +/** + * Returns 1 for a static segment, 0 for a parameterized segment. + * + * Works only with OpenAPI `{param}` format. + */ +function segmentScore(segment: string): number { + return /\{[^}]+\}/.test(segment) ? 0 : 1; +} + +/** + * Sorts handlers by route specificity. + * + * Without this, routes like `/foo/:bar` could appear before `/foo/baz`. + * + * Inspired by: + * @see https://reactrouter.com/6.28.0/start/concepts#ranking-routes + * @see https://github.com/lukeed/route-sort + */ +export function sortHandlers(handlers: ReadonlyArray): ReadonlyArray { + return handlers + .map((info, index) => ({ index, info })) + .sort((a, b) => { + const segmentsA = a.info.path.split('/').filter(Boolean); + const segmentsB = b.info.path.split('/').filter(Boolean); + + // deeper routes are more specific + if (segmentsA.length !== segmentsB.length) { + return segmentsB.length - segmentsA.length; + } + + // static segments beat dynamic ones + for (let i = 0; i < segmentsA.length; i++) { + const scoreA = segmentScore(segmentsA[i]!); + const scoreB = segmentScore(segmentsB[i]!); + if (scoreA !== scoreB) { + return scoreB - scoreA; + } + } + + // preserve declaration order + return a.index - b.index; + }) + .map((entry) => entry.info); +} diff --git a/packages/openapi-ts/src/plugins/msw/shared/sortHandlersBySpecificity.ts b/packages/openapi-ts/src/plugins/msw/shared/sortHandlersBySpecificity.ts deleted file mode 100644 index 7d68b51d3f..0000000000 --- a/packages/openapi-ts/src/plugins/msw/shared/sortHandlersBySpecificity.ts +++ /dev/null @@ -1,56 +0,0 @@ -interface HandlerMeta { - name: string; - path: string; -} - -/** - * Returns 1 for a static segment, 0 for a parameterized segment. - * Works with OpenAPI `{param}` format. - */ -const segmentScore = (segment: string): number => (/\{[^}]+\}/.test(segment) ? 0 : 1); - -/** - * Sorts handler metadata by route specificity so that more specific routes - * appear before less specific ones in the generated `getAllMocks` handler array. - * - * MSW matches handlers top-to-bottom, so without sorting a dynamic route like - * `/api/permissions/:userId` would shadow `/api/permissions/all`. - * - * Algorithm inspired by React Router v6 and route-sort: - * @see https://reactrouter.com/explanation/route-matching - * @see https://github.com/lukeed/route-sort - * - * Rules, applied in priority order: - * 1. More path segments (deeper routes) come first. - * 2. At equal depth, static segments beat dynamic ones (left-to-right). - * 3. At equal specificity, preserve original declaration order (stable sort). - */ -export const sortHandlersBySpecificity = ( - handlers: ReadonlyArray, -): Array => { - const indexed = handlers.map((handler, index) => ({ handler, index })); - - indexed.sort((a, b) => { - const segmentsA = a.handler.path.split('/').filter(Boolean); - const segmentsB = b.handler.path.split('/').filter(Boolean); - - // Rule 1: deeper routes are more specific - if (segmentsA.length !== segmentsB.length) { - return segmentsB.length - segmentsA.length; - } - - // Rule 2: at equal depth, static segments beat dynamic ones (left-to-right) - for (let i = 0; i < segmentsA.length; i++) { - const scoreA = segmentScore(segmentsA[i]!); - const scoreB = segmentScore(segmentsB[i]!); - if (scoreA !== scoreB) { - return scoreB - scoreA; - } - } - - // Rule 3: preserve declaration order - return a.index - b.index; - }); - - return indexed.map((entry) => entry.handler); -}; diff --git a/packages/openapi-ts/src/plugins/msw/v2/plugin.ts b/packages/openapi-ts/src/plugins/msw/v2/plugin.ts index 739d8b458a..5997d6af2c 100644 --- a/packages/openapi-ts/src/plugins/msw/v2/plugin.ts +++ b/packages/openapi-ts/src/plugins/msw/v2/plugin.ts @@ -2,7 +2,7 @@ import { getBaseUrl } from '@hey-api/shared'; import { $ } from '../../../ts-dsl'; import { getHandler } from '../shared/handler'; -import { sortHandlersBySpecificity } from '../shared/sortHandlersBySpecificity'; +import { type HandlerInfo, sortHandlers } from '../shared/sort'; import { createRequestHandlerOptions } from '../shared/types'; import type { MswPlugin } from '../types'; @@ -14,7 +14,7 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { external: 'msw', kind: 'type', }); - const symbolHttpResponse = plugin.symbol('HttpResponse', { + plugin.symbol('HttpResponse', { external: 'msw', }); plugin.symbol('HttpResponseResolver', { @@ -30,10 +30,13 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { createRequestHandlerOptions(plugin); + const symbolAll = plugin.symbol('all'); + const symbolBaseUrl = plugin.symbol('baseUrl'); const symbolFactory = plugin.symbol('createMswHandlers'); - const handlersObject = $.object().pretty(); - const singleHandlerFactoriesType = $.type.object(); - const handlerMeta: Array<{ isOptional: boolean; name: string; path: string }> = []; + const symbolOne = plugin.symbol('one'); + const oneObject = $.object().pretty(); + const oneType = $.type.object(); + const handlerInfo: Array = []; plugin.forEach( 'operation', @@ -45,152 +48,29 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { plugin, }); plugin.node(handler.node); + const symbolResponse = plugin.symbol('resolver'); const symbolOptions = plugin.symbol('options'); - handlersObject.method(operation.id, (m) => - m + const name = operation.id; + oneType.prop(name, (p) => p.type($(handler.symbol).typeofType())); + oneObject.prop( + name, + $.func() .param(symbolResponse) - // , (p) => - // p.$if(dominantResponse.example != null && dominantResponse.statusCode != null, (pp) => - // pp.assign( - // $.fromValue({ - // result: dominantResponse.example, - // status: dominantResponse.statusCode, - // }), - // ), - // ), - // ) .param(symbolOptions) - .do($(handler.symbol).call(symbolResponse, symbolOptions).return()), + .do( + $(handler.symbol) + .call(symbolResponse, $.object().spread(symbolOptions).prop('baseUrl', symbolBaseUrl)) + .return(), + ), ); - // handlersObject.prop(operation.id, handler.symbol); - singleHandlerFactoriesType.prop(operation.id, (p) => p.type(handler.type)); - handlerMeta.push({ - isOptional: handler.isOptional, - name: operation.id, - path: operation.path, - }); + handlerInfo.push({ name, path: operation.path }); }, { order: 'declarations', }, ); - const symbolMswHandlerCreators = plugin.symbol('MswHandlerCreators'); - plugin.node($.type.alias(symbolMswHandlerCreators).export().type(singleHandlerFactoriesType)); - - const symbolGetAllHandlersOptions = plugin.symbol('GetAllHandlersOptions'); - plugin.node( - $.type - .alias(symbolGetAllHandlersOptions) - .export() - .type( - $.type - .object() - .prop('onMissingHandler', (p) => - p.optional().type($.type.or($.type.literal('error'), $.type.literal('skip'))), - ) - .prop('overrides', (p) => - p.optional().type( - $.type - .mapped('K') - .key($.type.operator().keyof($.type(symbolMswHandlerCreators))) - .optional() - .type( - $.type('Parameters') - .generic($.type(symbolMswHandlerCreators).idx($.type('K'))) - .idx($.type.literal(0)), - ), - ), - ), - ), - ); - - const getAllHandlersDo: Array> = []; - const hasRequiredHandlers = handlerMeta.some((h) => !h.isOptional); - - if (hasRequiredHandlers) { - getAllHandlersDo.push( - $.const('onMissingHandler').assign( - $('options').attr('onMissingHandler').coalesce($.literal('skip')), - ), - ); - } - - getAllHandlersDo.push($.const('overrides').assign($('options').attr('overrides'))); - - getAllHandlersDo.push( - $.const('handlers').type($.type('Array').generic(symbolHttpHandler)).assign($.array()), - ); - - // Generate addRequiredHandler helper when there are required handlers - if (hasRequiredHandlers) { - const errorResolver = $.func().do( - $.new( - symbolHttpResponse, - $.literal('[heyapi-msw] The mock of this request is not implemented.'), - $.object().prop('status', $.literal(501)), - ).return(), - ); - - // handler: (value: Value | (() => HttpResponse)) => HttpHandler - const handlerParamType = $.type - .func() - .param('value', (pp) => - pp.type( - $.type.or('Value', $.type.func().returns($.type(symbolHttpResponse).generic('any'))), - ), - ) - .returns(symbolHttpHandler); - - getAllHandlersDo.push( - $.const('addRequiredHandler').assign( - $.func() - .generic('Value') - .param('handler', (p) => p.type(handlerParamType)) - .param('override', (p) => p.type($.type.or('Value', 'undefined'))) - .do( - $.if($('override').looseNeq($.literal(null))) - .do( - $.stmt( - $('handlers') - .attr('push') - .call($('handler').call($('override'))), - ), - ) - .otherwise( - $.if($('onMissingHandler').eq($.literal('error'))).do( - $.stmt($('handlers').attr('push').call($('handler').call(errorResolver))), - ), - ), - ), - ), - ); - } - - for (const handler of sortHandlersBySpecificity(handlerMeta)) { - if (handler.isOptional) { - getAllHandlersDo.push( - $.stmt( - $('handlers') - .attr('push') - .call($('mocks').attr(handler.name).call($('overrides').attr(handler.name).optional())), - ), - ); - } else { - getAllHandlersDo.push( - $.stmt( - $('addRequiredHandler').call( - $('mocks').attr(handler.name), - $('overrides').attr(handler.name).optional(), - ), - ), - ); - } - } - - getAllHandlersDo.push($('handlers').return()); - const factoryFn = $.func(symbolFactory) .export() .param('config', (p) => @@ -199,19 +79,42 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { .assign($.object()), ) .do( - $.const('baseUrl').assign( + $.const(symbolBaseUrl).assign( $('config') .attr('baseUrl') .$if(baseUrl !== undefined, (b) => b.coalesce($.literal(baseUrl!))), ), - $.const('mocks').type(symbolMswHandlerCreators).assign(handlersObject), - $.const('getAllHandlers').assign( - $.func() - .param('options', (p) => p.type(symbolGetAllHandlersOptions).assign($.object())) - .returns($.type('Array').generic(symbolHttpHandler)) - .do(...getAllHandlersDo), - ), - $.return($.object().spread('mocks').prop('getAllHandlers', 'getAllHandlers')), + $.const(symbolOne).type(oneType).assign(oneObject), + $.func(symbolAll) + .param('options', (p) => + p + .type( + $.type.object().prop('overrides', (p) => + p.optional().type( + $.type + .mapped('K') + .key($.type.operator().keyof($(symbolOne).typeofType())) + .optional() + .type( + $.type('Parameters') + .generic($(symbolOne).typeofType().idx('K')) + .idx($.type.literal(0)), + ), + ), + ), + ) + .assign($.object()), + ) + .returns($.type('ReadonlyArray').generic(symbolHttpHandler)) + .do( + $.const('overrides').assign($('options').attr('overrides').coalesce($.object())), + $.array( + ...sortHandlers(handlerInfo).map((info) => + $(symbolOne).attr(info.name).call($('overrides').attr(info.name)), + ), + ).return(), + ), + $.object().prop('all', symbolAll).prop('one', symbolOne).return(), ); plugin.node(factoryFn); }; From dec30c933878cc6b56086061ea11fe55990d332a Mon Sep 17 00:00:00 2001 From: Lubos Date: Fri, 27 Mar 2026 23:50:01 +0100 Subject: [PATCH 12/16] chore: add comments --- dev/playground.ts | 33 ++--- packages/openapi-ts/src/plugins/msw/config.ts | 1 + .../src/plugins/msw/shared/handler.ts | 115 +++++++----------- .../src/plugins/msw/shared/operation.ts | 5 + .../src/plugins/msw/shared/types.ts | 5 +- packages/openapi-ts/src/plugins/msw/types.ts | 2 + .../openapi-ts/src/plugins/msw/v2/plugin.ts | 112 ++++++++++------- packages/openapi-ts/src/ts-dsl/stmt/if.ts | 4 +- 8 files changed, 142 insertions(+), 135 deletions(-) create mode 100644 packages/openapi-ts/src/plugins/msw/shared/operation.ts diff --git a/dev/playground.ts b/dev/playground.ts index 642a9ba80f..20a61adf64 100644 --- a/dev/playground.ts +++ b/dev/playground.ts @@ -24,22 +24,25 @@ const handlers = createMswHandlers({ }); const server = setupServer( - ...handlers.all({ - // overrides: { - // tuiPublish: { - // result: true, - // }, - // }, - }), - // handleTuiPublish({ - // result: false - // }), - // handlers.one.tuiPublish({ - // result: false, - // // status: 200, - // }, { - // // ... + // ...handlers.all({ + // // overrides: { + // // tuiPublish: { + // // result: true, + // // }, + // // }, // }), + handleTuiPublish({ + result: false, + }), + handlers.one.tuiPublish( + { + result: false, + // status: 200, + }, + { + // ... + }, + ), ); server.listen(); diff --git a/packages/openapi-ts/src/plugins/msw/config.ts b/packages/openapi-ts/src/plugins/msw/config.ts index 82264203d4..86e2c1e375 100644 --- a/packages/openapi-ts/src/plugins/msw/config.ts +++ b/packages/openapi-ts/src/plugins/msw/config.ts @@ -6,6 +6,7 @@ import type { MswPlugin } from './types'; export const defaultConfig: MswPlugin['Config'] = { config: { baseUrl: '*', + comments: true, includeInEntry: false, valueSources: ['example'], }, diff --git a/packages/openapi-ts/src/plugins/msw/shared/handler.ts b/packages/openapi-ts/src/plugins/msw/shared/handler.ts index 08e71592f8..e86cd6907b 100644 --- a/packages/openapi-ts/src/plugins/msw/shared/handler.ts +++ b/packages/openapi-ts/src/plugins/msw/shared/handler.ts @@ -5,6 +5,7 @@ import { applyNaming } from '@hey-api/shared'; import { $ } from '../../../ts-dsl'; import type { MswPlugin } from '../types'; import { computeDominantResponse, type DominantResponse } from './computeDominantResponse'; +import { getOperationComment } from './operation'; import { sanitizeParamName, sanitizePath } from './path'; const emitToResponseUnion = (plugin: MswPlugin['Instance']) => { @@ -37,28 +38,20 @@ const emitToResponseUnion = (plugin: MswPlugin['Instance']) => { plugin.node(toResponseUnionType); }; -const extractPathParamNames = (path: string) => { - const names: Array = []; - for (const match of path.matchAll(/\{([^}]+)\}/g)) { - names.push(match[1]!); - } - return names; -}; - /** * Builds the response override expression for the `res` parameter. - * When `res` is an object with a `result` property, it uses - * `res.result` as the value and `res.status` as the status code. */ function buildResponseOverrideExpr({ dominantResponse: { kind: responseKind, statusCode: responseStatusCode }, - symbolHttpResponse, + plugin, symbolResolver, }: { dominantResponse: DominantResponse; - symbolHttpResponse: Symbol; + plugin: MswPlugin['Instance']; symbolResolver: Symbol; }) { + const symbolHttpResponse = plugin.external('msw.HttpResponse'); + const statusOption = $.object().prop( 'status', responseStatusCode @@ -85,42 +78,39 @@ function buildResponseOverrideExpr({ } } -/** - * Builds an arrow function that creates an MSW handler for a single operation. - * The response method and status code are inferred from the operation's responses. - */ function createHandlerFunc({ baseUrl, bodyType, dominantResponse, - hasResponseOverride, method, operation, paramsType, plugin, responseOrResolverType, - symbol, - symbolHttp, - symbolHttpResponse, }: { baseUrl: string | undefined; bodyType: ReturnType; dominantResponse: DominantResponse; - hasResponseOverride: boolean; method: string; operation: IR.OperationObject; paramsType: ReturnType; plugin: MswPlugin['Instance']; responseOrResolverType: ReturnType; - symbol: Symbol; - symbolHttp: Symbol; - symbolHttpResponse: Symbol; -}) { +}): Symbol { + const symbolHttp = plugin.external('msw.http'); + const symbolHttpResponse = plugin.external('msw.HttpResponse'); const symbolResolver = plugin.symbol('resolver'); const symbolOptions = plugin.symbol('options'); - return $.func(symbol) + const symbol = plugin.symbol( + applyNaming(`handle-${operation.id}`, { + casing: 'camelCase', // TODO: expose as a config option + }), + ); + + const handlerFunc = $.func(symbol) .export() + .$if(plugin.config.comments && getOperationComment(operation), (f, v) => f.doc(v)) .param(symbolResolver, (p) => p .optional() @@ -161,16 +151,12 @@ function createHandlerFunc({ $(symbolResolver).call('info').return(), ), ) - .$if(hasResponseOverride, (f) => + .$if(dominantResponse.statusCode != null, (f) => f.do( - $.if( - $($.typeofExpr(symbolResolver).eq($.literal('object'))).and( - $(symbolResolver).attr('result'), - ), - ).do( + $.if(symbolResolver).do( buildResponseOverrideExpr({ dominantResponse, - symbolHttpResponse, + plugin, symbolResolver, }), ), @@ -182,6 +168,8 @@ function createHandlerFunc({ .generics(paramsType, bodyType) .return(), ); + plugin.node(handlerFunc); + return symbol; } export function getHandler({ @@ -194,13 +182,9 @@ export function getHandler({ examples: boolean; operation: IR.OperationObject; plugin: MswPlugin['Instance']; -}) { +}): Symbol { const dominantResponse = computeDominantResponse({ operation, plugin }); - const symbolHttp = plugin.external('msw.http'); - const symbolHttpResponse = plugin.external('msw.HttpResponse'); - - // Query response type from @hey-api/typescript const symbolResponsesType = plugin.querySymbol({ category: 'type', resource: 'operation', @@ -209,7 +193,6 @@ export function getHandler({ }); let responsesOverrideType: ReturnType | undefined; if (symbolResponsesType && dominantResponse.allCandidates.length > 1) { - // We only neeed to add ToResponseUnion if there are multiple responses if (!plugin.getSymbol({ category: 'type', resource: 'to-response-union' })) { emitToResponseUnion(plugin); } @@ -221,43 +204,41 @@ export function getHandler({ ).generic(symbolResponsesType); } - // Query data type for parameters const symbolDataType = plugin.querySymbol({ category: 'type', resource: 'operation', resourceId: operation.id, role: 'data', - tool: 'typescript', }); + let bodyType: ReturnType; + if (operation.body && symbolDataType) { + bodyType = $.type(symbolDataType).idx($.type.literal('body')); + } else { + bodyType = $.type('never'); + } + let paramsType: ReturnType; if (operation.parameters?.path && Object.keys(operation.parameters.path).length) { // Generate inline object type with sanitized param names derived from the // path string (not the IR keys, which are lowercased and may diverge from // the original spec names that the TypeScript plugin preserves). const objType = $.type.object(); - for (const name of extractPathParamNames(operation.path)) { + for (const parameter of Object.values(operation.parameters.path ?? {})) { // OpenAPI 3.x path params are always single-segment, so MSW (path-to-regexp v6) // will always provide a single string. Multi-segment params ({path+}) are proposed // for OpenAPI 4.0 — revisit this if/when that lands. - objType.prop(sanitizeParamName(name), (p) => p.type('string')); + objType.prop(sanitizeParamName(parameter.name), (p) => p.type('string')); } paramsType = objType; } else { paramsType = $.type('never'); } - let bodyType: ReturnType; - if (operation.body && symbolDataType) { - bodyType = $.type(symbolDataType).idx($.type.literal('body')); - } else { - bodyType = $.type('never'); - } - - // Omit response type generic to avoid MSW's DefaultBodyType constraint issues const resolverType = $.type(plugin.external('msw.HttpResponseResolver')).generics( paramsType, bodyType, + // omit response type to avoid DefaultBodyType constraint issues ); // When examples are disabled, strip the example from the dominant response @@ -281,26 +262,14 @@ export function getHandler({ responseOrResolverType = resolverType; } - const symbol = plugin.symbol( - applyNaming(`handle-${operation.id}`, { - casing: 'camelCase', // TODO: expose as a config option - }), - ); - return { - node: createHandlerFunc({ - baseUrl, - bodyType, - dominantResponse, - hasResponseOverride: dominantResponse.statusCode != null, - method: operation.method, - operation, - paramsType, - plugin, - responseOrResolverType, - symbol, - symbolHttp, - symbolHttpResponse, - }), - symbol, - }; + return createHandlerFunc({ + baseUrl, + bodyType, + dominantResponse, + method: operation.method, + operation, + paramsType, + plugin, + responseOrResolverType, + }); } diff --git a/packages/openapi-ts/src/plugins/msw/shared/operation.ts b/packages/openapi-ts/src/plugins/msw/shared/operation.ts new file mode 100644 index 0000000000..7a161d8115 --- /dev/null +++ b/packages/openapi-ts/src/plugins/msw/shared/operation.ts @@ -0,0 +1,5 @@ +import type { IR } from '@hey-api/shared'; + +export function getOperationComment(operation: IR.OperationObject): string { + return `Handler for the \`${operation.method.toUpperCase()} ${operation.path}\` operation.`; +} diff --git a/packages/openapi-ts/src/plugins/msw/shared/types.ts b/packages/openapi-ts/src/plugins/msw/shared/types.ts index 67ce081630..2296499ab6 100644 --- a/packages/openapi-ts/src/plugins/msw/shared/types.ts +++ b/packages/openapi-ts/src/plugins/msw/shared/types.ts @@ -1,7 +1,9 @@ +import type { Symbol } from '@hey-api/codegen-core'; + import { $ } from '../../../ts-dsl'; import type { MswPlugin } from '../types'; -export function createRequestHandlerOptions(plugin: MswPlugin['Instance']) { +export function createRequestHandlerOptions(plugin: MswPlugin['Instance']): Symbol { const symbol = plugin.symbol('RequestHandlerOptions', { meta: { category: 'type', @@ -19,4 +21,5 @@ export function createRequestHandlerOptions(plugin: MswPlugin['Instance']) { ), ); plugin.node(node); + return symbol; } diff --git a/packages/openapi-ts/src/plugins/msw/types.ts b/packages/openapi-ts/src/plugins/msw/types.ts index 480cd06562..331d57038f 100644 --- a/packages/openapi-ts/src/plugins/msw/types.ts +++ b/packages/openapi-ts/src/plugins/msw/types.ts @@ -2,6 +2,7 @@ import type { DefinePlugin, Plugin } from '@hey-api/shared'; export type UserConfig = Plugin.Name<'msw'> & Plugin.Hooks & + Plugin.UserComments & Plugin.UserExports & { /** * Set a default base URL when creating the handlers? You can set `baseUrl` @@ -29,6 +30,7 @@ export type UserConfig = Plugin.Name<'msw'> & export type Config = Plugin.Name<'msw'> & Plugin.Hooks & + Plugin.Comments & Plugin.Exports & { /** Set a default base URL when creating the handlers. */ baseUrl: string | number | boolean; diff --git a/packages/openapi-ts/src/plugins/msw/v2/plugin.ts b/packages/openapi-ts/src/plugins/msw/v2/plugin.ts index 5997d6af2c..839bfd0edf 100644 --- a/packages/openapi-ts/src/plugins/msw/v2/plugin.ts +++ b/packages/openapi-ts/src/plugins/msw/v2/plugin.ts @@ -2,6 +2,7 @@ import { getBaseUrl } from '@hey-api/shared'; import { $ } from '../../../ts-dsl'; import { getHandler } from '../shared/handler'; +import { getOperationComment } from '../shared/operation'; import { type HandlerInfo, sortHandlers } from '../shared/sort'; import { createRequestHandlerOptions } from '../shared/types'; import type { MswPlugin } from '../types'; @@ -28,10 +29,9 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { const baseUrl = getBaseUrl(plugin.config.baseUrl, plugin.context.ir); - createRequestHandlerOptions(plugin); + const symbolRequestHandlerOptions = createRequestHandlerOptions(plugin); const symbolAll = plugin.symbol('all'); - const symbolBaseUrl = plugin.symbol('baseUrl'); const symbolFactory = plugin.symbol('createMswHandlers'); const symbolOne = plugin.symbol('one'); const oneObject = $.object().pretty(); @@ -41,26 +41,29 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { plugin.forEach( 'operation', ({ operation }) => { - const handler = getHandler({ + const symbolHandler = getHandler({ baseUrl, examples: plugin.config.valueSources?.includes('example') ?? true, operation, plugin, }); - plugin.node(handler.node); const symbolResponse = plugin.symbol('resolver'); const symbolOptions = plugin.symbol('options'); const name = operation.id; - oneType.prop(name, (p) => p.type($(handler.symbol).typeofType())); + oneType.prop(name, (p) => + p + .type($(symbolHandler).typeofType()) + .$if(plugin.config.comments && getOperationComment(operation), (f, v) => f.doc(v)), + ); oneObject.prop( name, $.func() .param(symbolResponse) .param(symbolOptions) .do( - $(handler.symbol) - .call(symbolResponse, $.object().spread(symbolOptions).prop('baseUrl', symbolBaseUrl)) + $(symbolHandler) + .call(symbolResponse, $.object().spread('config').spread(symbolOptions)) .return(), ), ); @@ -71,50 +74,71 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { }, ); - const factoryFn = $.func(symbolFactory) + const symbolHandlerFactoriesType = plugin.symbol('MswHandlerFactories'); + const handlerFactoriesType = $.type.alias(symbolHandlerFactoriesType).export().type(oneType); + plugin.node(handlerFactoriesType); + + const factoryResultAll = 'all'; + const factoryResultOne = 'one'; + + const symbolFactoryReturnType = plugin.symbol('CreateMswHandlersResult'); + const factoryReturnType = $.type + .alias(symbolFactoryReturnType) .export() - .param('config', (p) => - p - .type($.type.object().prop('baseUrl', (p) => p.optional().type('string'))) - .assign($.object()), - ) - .do( - $.const(symbolBaseUrl).assign( - $('config') - .attr('baseUrl') - .$if(baseUrl !== undefined, (b) => b.coalesce($.literal(baseUrl!))), - ), - $.const(symbolOne).type(oneType).assign(oneObject), - $.func(symbolAll) - .param('options', (p) => - p - .type( - $.type.object().prop('overrides', (p) => + .type( + $.type + .object() + .prop(factoryResultAll, (p) => + p.type( + $.type + .func() + .param('options', (p) => p.optional().type( - $.type - .mapped('K') - .key($.type.operator().keyof($(symbolOne).typeofType())) - .optional() - .type( - $.type('Parameters') - .generic($(symbolOne).typeofType().idx('K')) - .idx($.type.literal(0)), + $.type.object().prop('overrides', (p) => + p.optional().type( + $.type + .mapped('K') + .key($.type.operator().keyof($.type(symbolHandlerFactoriesType))) + .optional() + .type( + $.type('Parameters') + .generic($.type(symbolHandlerFactoriesType).idx('K')) + .idx($.type.literal(0)), + ), ), + ), ), - ), - ) - .assign($.object()), + ) + .returns($.type('ReadonlyArray').generic(symbolHttpHandler)), + ), ) - .returns($.type('ReadonlyArray').generic(symbolHttpHandler)) - .do( - $.const('overrides').assign($('options').attr('overrides').coalesce($.object())), - $.array( - ...sortHandlers(handlerInfo).map((info) => - $(symbolOne).attr(info.name).call($('overrides').attr(info.name)), + .prop(factoryResultOne, (p) => p.type(symbolHandlerFactoriesType)), + ); + plugin.node(factoryReturnType); + + const factoryFn = $.func(symbolFactory) + .export() + .param('config', (p) => p.type(symbolRequestHandlerOptions).assign($.object())) + .returns(symbolFactoryReturnType) + .do( + $.const(symbolOne) + .type($.type(symbolFactoryReturnType).idx($.type.literal(factoryResultOne))) + .assign(oneObject), + $.const(symbolAll) + .type($.type(symbolFactoryReturnType).idx($.type.literal(factoryResultAll))) + .assign( + $.func() + .param('options', (p) => p.assign($.object())) + .do( + $.const('overrides').assign($('options').attr('overrides').coalesce($.object())), + $.array( + ...sortHandlers(handlerInfo).map((info) => + $(symbolOne).attr(info.name).call($('overrides').attr(info.name)), + ), + ).return(), ), - ).return(), ), - $.object().prop('all', symbolAll).prop('one', symbolOne).return(), + $.object().prop(factoryResultAll, symbolAll).prop(factoryResultOne, symbolOne).return(), ); plugin.node(factoryFn); }; diff --git a/packages/openapi-ts/src/ts-dsl/stmt/if.ts b/packages/openapi-ts/src/ts-dsl/stmt/if.ts index 8d7a1b8f18..c75077c98e 100644 --- a/packages/openapi-ts/src/ts-dsl/stmt/if.ts +++ b/packages/openapi-ts/src/ts-dsl/stmt/if.ts @@ -1,4 +1,4 @@ -import type { AnalysisContext } from '@hey-api/codegen-core'; +import type { AnalysisContext, NodeName } from '@hey-api/codegen-core'; import ts from 'typescript'; import type { MaybeTsDsl } from '../base'; @@ -7,7 +7,7 @@ import type { DoExpr } from '../mixins/do'; import { DoMixin } from '../mixins/do'; import { BlockTsDsl } from './block'; -export type IfCondition = string | MaybeTsDsl; +export type IfCondition = NodeName | MaybeTsDsl; const Mixed = DoMixin(TsDsl); From 161340b001876bde6a1d277a97419b28e423efa4 Mon Sep 17 00:00:00 2001 From: Lubos Date: Sun, 29 Mar 2026 23:04:25 +0200 Subject: [PATCH 13/16] chore: support overriding all arguments --- dev/opencode.json | 9806 +++++++++++++++++ dev/package.json | 1 + dev/playground.ts | 103 +- .../openapi-ts/src/plugins/msw/v2/plugin.ts | 91 +- packages/openapi-ts/src/ts-dsl/expr/array.ts | 33 +- packages/openapi-ts/src/ts-dsl/expr/attr.ts | 5 +- packages/openapi-ts/src/ts-dsl/expr/call.ts | 3 +- packages/openapi-ts/src/ts-dsl/expr/expr.ts | 3 +- packages/openapi-ts/src/ts-dsl/expr/new.ts | 3 +- packages/openapi-ts/src/ts-dsl/expr/spread.ts | 34 + packages/openapi-ts/src/ts-dsl/index.ts | 9 + packages/openapi-ts/src/ts-dsl/mixins/args.ts | 8 +- .../openapi-ts/src/ts-dsl/mixins/spread.ts | 24 + .../src/ts-dsl/type/tuple-member.ts | 64 + packages/openapi-ts/src/ts-dsl/type/tuple.ts | 8 +- .../openapi-ts/src/ts-dsl/utils/factories.ts | 8 + pnpm-lock.yaml | 125 + 17 files changed, 10248 insertions(+), 80 deletions(-) create mode 100644 dev/opencode.json create mode 100644 packages/openapi-ts/src/ts-dsl/expr/spread.ts create mode 100644 packages/openapi-ts/src/ts-dsl/mixins/spread.ts create mode 100644 packages/openapi-ts/src/ts-dsl/type/tuple-member.ts diff --git a/dev/opencode.json b/dev/opencode.json new file mode 100644 index 0000000000..a36f14d816 --- /dev/null +++ b/dev/opencode.json @@ -0,0 +1,9806 @@ +{ + "openapi": "3.1.1", + "info": { + "title": "opencode", + "description": "opencode api", + "version": "1.0.0" + }, + "paths": { + "/global/health": { + "get": { + "operationId": "global.health", + "summary": "Get health", + "description": "Get health information about the OpenCode server.", + "responses": { + "200": { + "description": "Health information", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "healthy": { + "type": "boolean", + "const": true + }, + "version": { + "type": "string" + } + }, + "required": ["healthy", "version"] + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.global.health({\n ...\n})" + } + ] + } + }, + "/global/event": { + "get": { + "operationId": "global.event", + "summary": "Get global events", + "description": "Subscribe to global events from the OpenCode system using server-sent events.", + "responses": { + "200": { + "description": "Event stream", + "content": { + "text/event-stream": { + "schema": { + "$ref": "#/components/schemas/GlobalEvent" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.global.event({\n ...\n})" + } + ] + } + }, + "/global/dispose": { + "post": { + "operationId": "global.dispose", + "summary": "Dispose instance", + "description": "Clean up and dispose all OpenCode instances, releasing all resources.", + "responses": { + "200": { + "description": "Global disposed", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.global.dispose({\n ...\n})" + } + ] + } + }, + "/project": { + "get": { + "operationId": "project.list", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "List all projects", + "description": "Get a list of projects that have been opened with OpenCode.", + "responses": { + "200": { + "description": "List of projects", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Project" + } + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.project.list({\n ...\n})" + } + ] + } + }, + "/project/current": { + "get": { + "operationId": "project.current", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "Get current project", + "description": "Retrieve the currently active project that OpenCode is working with.", + "responses": { + "200": { + "description": "Current project information", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Project" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.project.current({\n ...\n})" + } + ] + } + }, + "/project/{projectID}": { + "patch": { + "operationId": "project.update", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "projectID", + "schema": { + "type": "string" + }, + "required": true + } + ], + "summary": "Update project", + "description": "Update project properties such as name, icon and color.", + "responses": { + "200": { + "description": "Updated project information", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Project" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "icon": { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "color": { + "type": "string" + } + } + } + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.project.update({\n ...\n})" + } + ] + } + }, + "/pty": { + "get": { + "operationId": "pty.list", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "List PTY sessions", + "description": "Get a list of all active pseudo-terminal (PTY) sessions managed by OpenCode.", + "responses": { + "200": { + "description": "List of sessions", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Pty" + } + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.pty.list({\n ...\n})" + } + ] + }, + "post": { + "operationId": "pty.create", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "Create PTY session", + "description": "Create a new pseudo-terminal (PTY) session for running shell commands and processes.", + "responses": { + "200": { + "description": "Created session", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pty" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "command": { + "type": "string" + }, + "args": { + "type": "array", + "items": { + "type": "string" + } + }, + "cwd": { + "type": "string" + }, + "title": { + "type": "string" + }, + "env": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "string" + } + } + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.pty.create({\n ...\n})" + } + ] + } + }, + "/pty/{ptyID}": { + "get": { + "operationId": "pty.get", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "ptyID", + "schema": { + "type": "string" + }, + "required": true + } + ], + "summary": "Get PTY session", + "description": "Retrieve detailed information about a specific pseudo-terminal (PTY) session.", + "responses": { + "200": { + "description": "Session info", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pty" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.pty.get({\n ...\n})" + } + ] + }, + "put": { + "operationId": "pty.update", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "ptyID", + "schema": { + "type": "string" + }, + "required": true + } + ], + "summary": "Update PTY session", + "description": "Update properties of an existing pseudo-terminal (PTY) session.", + "responses": { + "200": { + "description": "Updated session", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Pty" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "size": { + "type": "object", + "properties": { + "rows": { + "type": "number" + }, + "cols": { + "type": "number" + } + }, + "required": ["rows", "cols"] + } + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.pty.update({\n ...\n})" + } + ] + }, + "delete": { + "operationId": "pty.remove", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "ptyID", + "schema": { + "type": "string" + }, + "required": true + } + ], + "summary": "Remove PTY session", + "description": "Remove and terminate a specific pseudo-terminal (PTY) session.", + "responses": { + "200": { + "description": "Session removed", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.pty.remove({\n ...\n})" + } + ] + } + }, + "/pty/{ptyID}/connect": { + "get": { + "operationId": "pty.connect", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "ptyID", + "schema": { + "type": "string" + }, + "required": true + } + ], + "summary": "Connect to PTY session", + "description": "Establish a WebSocket connection to interact with a pseudo-terminal (PTY) session in real-time.", + "responses": { + "200": { + "description": "Connected session", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.pty.connect({\n ...\n})" + } + ] + } + }, + "/config": { + "get": { + "operationId": "config.get", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "Get configuration", + "description": "Retrieve the current OpenCode configuration settings and preferences.", + "responses": { + "200": { + "description": "Get config info", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Config" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.config.get({\n ...\n})" + } + ] + }, + "patch": { + "operationId": "config.update", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "Update configuration", + "description": "Update OpenCode configuration settings and preferences.", + "responses": { + "200": { + "description": "Successfully updated config", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Config" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Config" + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.config.update({\n ...\n})" + } + ] + } + }, + "/experimental/tool/ids": { + "get": { + "operationId": "tool.ids", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "List tool IDs", + "description": "Get a list of all available tool IDs, including both built-in tools and dynamically registered tools.", + "responses": { + "200": { + "description": "Tool IDs", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ToolIDs" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.tool.ids({\n ...\n})" + } + ] + } + }, + "/experimental/tool": { + "get": { + "operationId": "tool.list", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "provider", + "schema": { + "type": "string" + }, + "required": true + }, + { + "in": "query", + "name": "model", + "schema": { + "type": "string" + }, + "required": true + } + ], + "summary": "List tools", + "description": "Get a list of available tools with their JSON schema parameters for a specific provider and model combination.", + "responses": { + "200": { + "description": "Tools", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ToolList" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.tool.list({\n ...\n})" + } + ] + } + }, + "/instance/dispose": { + "post": { + "operationId": "instance.dispose", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "Dispose instance", + "description": "Clean up and dispose the current OpenCode instance, releasing all resources.", + "responses": { + "200": { + "description": "Instance disposed", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.instance.dispose({\n ...\n})" + } + ] + } + }, + "/path": { + "get": { + "operationId": "path.get", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "Get paths", + "description": "Retrieve the current working directory and related path information for the OpenCode instance.", + "responses": { + "200": { + "description": "Path", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Path" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.path.get({\n ...\n})" + } + ] + } + }, + "/vcs": { + "get": { + "operationId": "vcs.get", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "Get VCS info", + "description": "Retrieve version control system (VCS) information for the current project, such as git branch.", + "responses": { + "200": { + "description": "VCS info", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VcsInfo" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.vcs.get({\n ...\n})" + } + ] + } + }, + "/session": { + "get": { + "operationId": "session.list", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "List sessions", + "description": "Get a list of all OpenCode sessions, sorted by most recently updated.", + "responses": { + "200": { + "description": "List of sessions", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Session" + } + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.session.list({\n ...\n})" + } + ] + }, + "post": { + "operationId": "session.create", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "Create session", + "description": "Create a new OpenCode session for interacting with AI assistants and managing conversations.", + "responses": { + "200": { + "description": "Successfully created session", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Session" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "parentID": { + "type": "string", + "pattern": "^ses.*" + }, + "title": { + "type": "string" + }, + "permission": { + "$ref": "#/components/schemas/PermissionRuleset" + } + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.session.create({\n ...\n})" + } + ] + } + }, + "/session/status": { + "get": { + "operationId": "session.status", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "Get session status", + "description": "Retrieve the current status of all sessions, including active, idle, and completed states.", + "responses": { + "200": { + "description": "Get session status", + "content": { + "application/json": { + "schema": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "$ref": "#/components/schemas/SessionStatus" + } + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.session.status({\n ...\n})" + } + ] + } + }, + "/session/{sessionID}": { + "get": { + "operationId": "session.get", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "sessionID", + "schema": { + "type": "string", + "pattern": "^ses.*" + }, + "required": true + } + ], + "summary": "Get session", + "description": "Retrieve detailed information about a specific OpenCode session.", + "tags": ["Session"], + "responses": { + "200": { + "description": "Get session", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Session" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.session.get({\n ...\n})" + } + ] + }, + "delete": { + "operationId": "session.delete", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "sessionID", + "schema": { + "type": "string", + "pattern": "^ses.*" + }, + "required": true + } + ], + "summary": "Delete session", + "description": "Delete a session and permanently remove all associated data, including messages and history.", + "responses": { + "200": { + "description": "Successfully deleted session", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.session.delete({\n ...\n})" + } + ] + }, + "patch": { + "operationId": "session.update", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "sessionID", + "schema": { + "type": "string" + }, + "required": true + } + ], + "summary": "Update session", + "description": "Update properties of an existing session, such as title or other metadata.", + "responses": { + "200": { + "description": "Successfully updated session", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Session" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "time": { + "type": "object", + "properties": { + "archived": { + "type": "number" + } + } + } + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.session.update({\n ...\n})" + } + ] + } + }, + "/session/{sessionID}/children": { + "get": { + "operationId": "session.children", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "sessionID", + "schema": { + "type": "string", + "pattern": "^ses.*" + }, + "required": true + } + ], + "summary": "Get session children", + "tags": ["Session"], + "description": "Retrieve all child sessions that were forked from the specified parent session.", + "responses": { + "200": { + "description": "List of children", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Session" + } + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.session.children({\n ...\n})" + } + ] + } + }, + "/session/{sessionID}/todo": { + "get": { + "operationId": "session.todo", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "sessionID", + "schema": { + "type": "string" + }, + "required": true, + "description": "Session ID" + } + ], + "summary": "Get session todos", + "description": "Retrieve the todo list associated with a specific session, showing tasks and action items.", + "responses": { + "200": { + "description": "Todo list", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Todo" + } + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.session.todo({\n ...\n})" + } + ] + } + }, + "/session/{sessionID}/init": { + "post": { + "operationId": "session.init", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "sessionID", + "schema": { + "type": "string" + }, + "required": true, + "description": "Session ID" + } + ], + "summary": "Initialize session", + "description": "Analyze the current application and create an AGENTS.md file with project-specific agent configurations.", + "responses": { + "200": { + "description": "200", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "modelID": { + "type": "string" + }, + "providerID": { + "type": "string" + }, + "messageID": { + "type": "string", + "pattern": "^msg.*" + } + }, + "required": ["modelID", "providerID", "messageID"] + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.session.init({\n ...\n})" + } + ] + } + }, + "/session/{sessionID}/fork": { + "post": { + "operationId": "session.fork", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "sessionID", + "schema": { + "type": "string", + "pattern": "^ses.*" + }, + "required": true + } + ], + "summary": "Fork session", + "description": "Create a new session by forking an existing session at a specific message point.", + "responses": { + "200": { + "description": "200", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Session" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "messageID": { + "type": "string", + "pattern": "^msg.*" + } + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.session.fork({\n ...\n})" + } + ] + } + }, + "/session/{sessionID}/abort": { + "post": { + "operationId": "session.abort", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "sessionID", + "schema": { + "type": "string" + }, + "required": true + } + ], + "summary": "Abort session", + "description": "Abort an active session and stop any ongoing AI processing or command execution.", + "responses": { + "200": { + "description": "Aborted session", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.session.abort({\n ...\n})" + } + ] + } + }, + "/session/{sessionID}/share": { + "post": { + "operationId": "session.share", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "sessionID", + "schema": { + "type": "string" + }, + "required": true + } + ], + "summary": "Share session", + "description": "Create a shareable link for a session, allowing others to view the conversation.", + "responses": { + "200": { + "description": "Successfully shared session", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Session" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.session.share({\n ...\n})" + } + ] + }, + "delete": { + "operationId": "session.unshare", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "sessionID", + "schema": { + "type": "string", + "pattern": "^ses.*" + }, + "required": true + } + ], + "summary": "Unshare session", + "description": "Remove the shareable link for a session, making it private again.", + "responses": { + "200": { + "description": "Successfully unshared session", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Session" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.session.unshare({\n ...\n})" + } + ] + } + }, + "/session/{sessionID}/diff": { + "get": { + "operationId": "session.diff", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "sessionID", + "schema": { + "type": "string" + }, + "required": true, + "description": "Session ID" + }, + { + "in": "query", + "name": "messageID", + "schema": { + "type": "string", + "pattern": "^msg.*" + } + } + ], + "summary": "Get session diff", + "description": "Get all file changes (diffs) made during this session.", + "responses": { + "200": { + "description": "List of diffs", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileDiff" + } + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.session.diff({\n ...\n})" + } + ] + } + }, + "/session/{sessionID}/summarize": { + "post": { + "operationId": "session.summarize", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "sessionID", + "schema": { + "type": "string" + }, + "required": true, + "description": "Session ID" + } + ], + "summary": "Summarize session", + "description": "Generate a concise summary of the session using AI compaction to preserve key information.", + "responses": { + "200": { + "description": "Summarized session", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "providerID": { + "type": "string" + }, + "modelID": { + "type": "string" + }, + "auto": { + "default": false, + "type": "boolean" + } + }, + "required": ["providerID", "modelID"] + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.session.summarize({\n ...\n})" + } + ] + } + }, + "/session/{sessionID}/message": { + "get": { + "operationId": "session.messages", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "sessionID", + "schema": { + "type": "string" + }, + "required": true, + "description": "Session ID" + }, + { + "in": "query", + "name": "limit", + "schema": { + "type": "number" + } + } + ], + "summary": "Get session messages", + "description": "Retrieve all messages in a session, including user prompts and AI responses.", + "responses": { + "200": { + "description": "List of messages", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "info": { + "$ref": "#/components/schemas/Message" + }, + "parts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Part" + } + } + }, + "required": ["info", "parts"] + } + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.session.messages({\n ...\n})" + } + ] + }, + "post": { + "operationId": "session.prompt", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "sessionID", + "schema": { + "type": "string" + }, + "required": true, + "description": "Session ID" + } + ], + "summary": "Send message", + "description": "Create and send a new message to a session, streaming the AI response.", + "responses": { + "200": { + "description": "Created message", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "info": { + "$ref": "#/components/schemas/AssistantMessage" + }, + "parts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Part" + } + } + }, + "required": ["info", "parts"] + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "messageID": { + "type": "string", + "pattern": "^msg.*" + }, + "model": { + "type": "object", + "properties": { + "providerID": { + "type": "string" + }, + "modelID": { + "type": "string" + } + }, + "required": ["providerID", "modelID"] + }, + "agent": { + "type": "string" + }, + "noReply": { + "type": "boolean" + }, + "tools": { + "description": "@deprecated tools and permissions have been merged, you can set permissions on the session itself now", + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "boolean" + } + }, + "system": { + "type": "string" + }, + "variant": { + "type": "string" + }, + "parts": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/TextPartInput" + }, + { + "$ref": "#/components/schemas/FilePartInput" + }, + { + "$ref": "#/components/schemas/AgentPartInput" + }, + { + "$ref": "#/components/schemas/SubtaskPartInput" + } + ] + } + } + }, + "required": ["parts"] + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.session.prompt({\n ...\n})" + } + ] + } + }, + "/session/{sessionID}/message/{messageID}": { + "get": { + "operationId": "session.message", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "sessionID", + "schema": { + "type": "string" + }, + "required": true, + "description": "Session ID" + }, + { + "in": "path", + "name": "messageID", + "schema": { + "type": "string" + }, + "required": true, + "description": "Message ID" + } + ], + "summary": "Get message", + "description": "Retrieve a specific message from a session by its message ID.", + "responses": { + "200": { + "description": "Message", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "info": { + "$ref": "#/components/schemas/Message" + }, + "parts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Part" + } + } + }, + "required": ["info", "parts"] + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.session.message({\n ...\n})" + } + ] + } + }, + "/session/{sessionID}/message/{messageID}/part/{partID}": { + "delete": { + "operationId": "part.delete", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "sessionID", + "schema": { + "type": "string" + }, + "required": true, + "description": "Session ID" + }, + { + "in": "path", + "name": "messageID", + "schema": { + "type": "string" + }, + "required": true, + "description": "Message ID" + }, + { + "in": "path", + "name": "partID", + "schema": { + "type": "string" + }, + "required": true, + "description": "Part ID" + } + ], + "description": "Delete a part from a message", + "responses": { + "200": { + "description": "Successfully deleted part", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.part.delete({\n ...\n})" + } + ] + }, + "patch": { + "operationId": "part.update", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "sessionID", + "schema": { + "type": "string" + }, + "required": true, + "description": "Session ID" + }, + { + "in": "path", + "name": "messageID", + "schema": { + "type": "string" + }, + "required": true, + "description": "Message ID" + }, + { + "in": "path", + "name": "partID", + "schema": { + "type": "string" + }, + "required": true, + "description": "Part ID" + } + ], + "description": "Update a part in a message", + "responses": { + "200": { + "description": "Successfully updated part", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Part" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Part" + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.part.update({\n ...\n})" + } + ] + } + }, + "/session/{sessionID}/prompt_async": { + "post": { + "operationId": "session.prompt_async", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "sessionID", + "schema": { + "type": "string" + }, + "required": true, + "description": "Session ID" + } + ], + "summary": "Send async message", + "description": "Create and send a new message to a session asynchronously, starting the session if needed and returning immediately.", + "responses": { + "204": { + "description": "Prompt accepted" + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "messageID": { + "type": "string", + "pattern": "^msg.*" + }, + "model": { + "type": "object", + "properties": { + "providerID": { + "type": "string" + }, + "modelID": { + "type": "string" + } + }, + "required": ["providerID", "modelID"] + }, + "agent": { + "type": "string" + }, + "noReply": { + "type": "boolean" + }, + "tools": { + "description": "@deprecated tools and permissions have been merged, you can set permissions on the session itself now", + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "boolean" + } + }, + "system": { + "type": "string" + }, + "variant": { + "type": "string" + }, + "parts": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/TextPartInput" + }, + { + "$ref": "#/components/schemas/FilePartInput" + }, + { + "$ref": "#/components/schemas/AgentPartInput" + }, + { + "$ref": "#/components/schemas/SubtaskPartInput" + } + ] + } + } + }, + "required": ["parts"] + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.session.prompt_async({\n ...\n})" + } + ] + } + }, + "/session/{sessionID}/command": { + "post": { + "operationId": "session.command", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "sessionID", + "schema": { + "type": "string" + }, + "required": true, + "description": "Session ID" + } + ], + "summary": "Send command", + "description": "Send a new command to a session for execution by the AI assistant.", + "responses": { + "200": { + "description": "Created message", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "info": { + "$ref": "#/components/schemas/AssistantMessage" + }, + "parts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Part" + } + } + }, + "required": ["info", "parts"] + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "messageID": { + "type": "string", + "pattern": "^msg.*" + }, + "agent": { + "type": "string" + }, + "model": { + "type": "string" + }, + "arguments": { + "type": "string" + }, + "command": { + "type": "string" + }, + "variant": { + "type": "string" + } + }, + "required": ["arguments", "command"] + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.session.command({\n ...\n})" + } + ] + } + }, + "/session/{sessionID}/shell": { + "post": { + "operationId": "session.shell", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "sessionID", + "schema": { + "type": "string" + }, + "required": true, + "description": "Session ID" + } + ], + "summary": "Run shell command", + "description": "Execute a shell command within the session context and return the AI's response.", + "responses": { + "200": { + "description": "Created message", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssistantMessage" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "agent": { + "type": "string" + }, + "model": { + "type": "object", + "properties": { + "providerID": { + "type": "string" + }, + "modelID": { + "type": "string" + } + }, + "required": ["providerID", "modelID"] + }, + "command": { + "type": "string" + } + }, + "required": ["agent", "command"] + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.session.shell({\n ...\n})" + } + ] + } + }, + "/session/{sessionID}/revert": { + "post": { + "operationId": "session.revert", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "sessionID", + "schema": { + "type": "string" + }, + "required": true + } + ], + "summary": "Revert message", + "description": "Revert a specific message in a session, undoing its effects and restoring the previous state.", + "responses": { + "200": { + "description": "Updated session", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Session" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "messageID": { + "type": "string", + "pattern": "^msg.*" + }, + "partID": { + "type": "string", + "pattern": "^prt.*" + } + }, + "required": ["messageID"] + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.session.revert({\n ...\n})" + } + ] + } + }, + "/session/{sessionID}/unrevert": { + "post": { + "operationId": "session.unrevert", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "sessionID", + "schema": { + "type": "string" + }, + "required": true + } + ], + "summary": "Restore reverted messages", + "description": "Restore all previously reverted messages in a session.", + "responses": { + "200": { + "description": "Updated session", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Session" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.session.unrevert({\n ...\n})" + } + ] + } + }, + "/session/{sessionID}/permissions/{permissionID}": { + "post": { + "operationId": "permission.respond", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "sessionID", + "schema": { + "type": "string" + }, + "required": true + }, + { + "in": "path", + "name": "permissionID", + "schema": { + "type": "string" + }, + "required": true + } + ], + "summary": "Respond to permission", + "deprecated": true, + "description": "Approve or deny a permission request from the AI assistant.", + "responses": { + "200": { + "description": "Permission processed successfully", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "response": { + "type": "string", + "enum": ["once", "always", "reject"] + } + }, + "required": ["response"] + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.permission.respond({\n ...\n})" + } + ] + } + }, + "/permission/{requestID}/reply": { + "post": { + "operationId": "permission.reply", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "requestID", + "schema": { + "type": "string" + }, + "required": true + } + ], + "summary": "Respond to permission request", + "description": "Approve or deny a permission request from the AI assistant.", + "responses": { + "200": { + "description": "Permission processed successfully", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "reply": { + "type": "string", + "enum": ["once", "always", "reject"] + } + }, + "required": ["reply"] + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.permission.reply({\n ...\n})" + } + ] + } + }, + "/permission": { + "get": { + "operationId": "permission.list", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "List pending permissions", + "description": "Get all pending permission requests across all sessions.", + "responses": { + "200": { + "description": "List of pending permissions", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PermissionRequest" + } + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.permission.list({\n ...\n})" + } + ] + } + }, + "/command": { + "get": { + "operationId": "command.list", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "List commands", + "description": "Get a list of all available commands in the OpenCode system.", + "responses": { + "200": { + "description": "List of commands", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Command" + } + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.command.list({\n ...\n})" + } + ] + } + }, + "/config/providers": { + "get": { + "operationId": "config.providers", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "List config providers", + "description": "Get a list of all configured AI providers and their default models.", + "responses": { + "200": { + "description": "List of providers", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "providers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Provider" + } + }, + "default": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "string" + } + } + }, + "required": ["providers", "default"] + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.config.providers({\n ...\n})" + } + ] + } + }, + "/provider": { + "get": { + "operationId": "provider.list", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "List providers", + "description": "Get a list of all available AI providers, including both available and connected ones.", + "responses": { + "200": { + "description": "List of providers", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "all": { + "type": "array", + "items": { + "type": "object", + "properties": { + "api": { + "type": "string" + }, + "name": { + "type": "string" + }, + "env": { + "type": "array", + "items": { + "type": "string" + } + }, + "id": { + "type": "string" + }, + "npm": { + "type": "string" + }, + "models": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "family": { + "type": "string" + }, + "release_date": { + "type": "string" + }, + "attachment": { + "type": "boolean" + }, + "reasoning": { + "type": "boolean" + }, + "temperature": { + "type": "boolean" + }, + "tool_call": { + "type": "boolean" + }, + "interleaved": { + "anyOf": [ + { + "type": "boolean", + "const": true + }, + { + "type": "object", + "properties": { + "field": { + "type": "string", + "enum": ["reasoning_content", "reasoning_details"] + } + }, + "required": ["field"], + "additionalProperties": false + } + ] + }, + "cost": { + "type": "object", + "properties": { + "input": { + "type": "number" + }, + "output": { + "type": "number" + }, + "cache_read": { + "type": "number" + }, + "cache_write": { + "type": "number" + }, + "context_over_200k": { + "type": "object", + "properties": { + "input": { + "type": "number" + }, + "output": { + "type": "number" + }, + "cache_read": { + "type": "number" + }, + "cache_write": { + "type": "number" + } + }, + "required": ["input", "output"] + } + }, + "required": ["input", "output"] + }, + "limit": { + "type": "object", + "properties": { + "context": { + "type": "number" + }, + "output": { + "type": "number" + } + }, + "required": ["context", "output"] + }, + "modalities": { + "type": "object", + "properties": { + "input": { + "type": "array", + "items": { + "type": "string", + "enum": ["text", "audio", "image", "video", "pdf"] + } + }, + "output": { + "type": "array", + "items": { + "type": "string", + "enum": ["text", "audio", "image", "video", "pdf"] + } + } + }, + "required": ["input", "output"] + }, + "experimental": { + "type": "boolean" + }, + "status": { + "type": "string", + "enum": ["alpha", "beta", "deprecated"] + }, + "options": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + }, + "headers": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "string" + } + }, + "provider": { + "type": "object", + "properties": { + "npm": { + "type": "string" + } + }, + "required": ["npm"] + }, + "variants": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + } + }, + "required": [ + "id", + "name", + "release_date", + "attachment", + "reasoning", + "temperature", + "tool_call", + "limit", + "options" + ] + } + } + }, + "required": ["name", "env", "id", "models"] + } + }, + "default": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "string" + } + }, + "connected": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": ["all", "default", "connected"] + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.provider.list({\n ...\n})" + } + ] + } + }, + "/provider/auth": { + "get": { + "operationId": "provider.auth", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "Get provider auth methods", + "description": "Retrieve available authentication methods for all AI providers.", + "responses": { + "200": { + "description": "Provider auth methods", + "content": { + "application/json": { + "schema": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProviderAuthMethod" + } + } + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.provider.auth({\n ...\n})" + } + ] + } + }, + "/provider/{providerID}/oauth/authorize": { + "post": { + "operationId": "provider.oauth.authorize", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "providerID", + "schema": { + "type": "string" + }, + "required": true, + "description": "Provider ID" + } + ], + "summary": "OAuth authorize", + "description": "Initiate OAuth authorization for a specific AI provider to get an authorization URL.", + "responses": { + "200": { + "description": "Authorization URL and method", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProviderAuthAuthorization" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "method": { + "description": "Auth method index", + "type": "number" + } + }, + "required": ["method"] + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.provider.oauth.authorize({\n ...\n})" + } + ] + } + }, + "/provider/{providerID}/oauth/callback": { + "post": { + "operationId": "provider.oauth.callback", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "providerID", + "schema": { + "type": "string" + }, + "required": true, + "description": "Provider ID" + } + ], + "summary": "OAuth callback", + "description": "Handle the OAuth callback from a provider after user authorization.", + "responses": { + "200": { + "description": "OAuth callback processed successfully", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "method": { + "description": "Auth method index", + "type": "number" + }, + "code": { + "description": "OAuth authorization code", + "type": "string" + } + }, + "required": ["method"] + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.provider.oauth.callback({\n ...\n})" + } + ] + } + }, + "/find": { + "get": { + "operationId": "find.text", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "pattern", + "schema": { + "type": "string" + }, + "required": true + } + ], + "summary": "Find text", + "description": "Search for text patterns across files in the project using ripgrep.", + "responses": { + "200": { + "description": "Matches", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "path": { + "type": "object", + "properties": { + "text": { + "type": "string" + } + }, + "required": ["text"] + }, + "lines": { + "type": "object", + "properties": { + "text": { + "type": "string" + } + }, + "required": ["text"] + }, + "line_number": { + "type": "number" + }, + "absolute_offset": { + "type": "number" + }, + "submatches": { + "type": "array", + "items": { + "type": "object", + "properties": { + "match": { + "type": "object", + "properties": { + "text": { + "type": "string" + } + }, + "required": ["text"] + }, + "start": { + "type": "number" + }, + "end": { + "type": "number" + } + }, + "required": ["match", "start", "end"] + } + } + }, + "required": ["path", "lines", "line_number", "absolute_offset", "submatches"] + } + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.find.text({\n ...\n})" + } + ] + } + }, + "/find/file": { + "get": { + "operationId": "find.files", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "query", + "schema": { + "type": "string" + }, + "required": true + }, + { + "in": "query", + "name": "dirs", + "schema": { + "type": "string", + "enum": ["true", "false"] + } + }, + { + "in": "query", + "name": "type", + "schema": { + "type": "string", + "enum": ["file", "directory"] + } + }, + { + "in": "query", + "name": "limit", + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 200 + } + } + ], + "summary": "Find files", + "description": "Search for files or directories by name or pattern in the project directory.", + "responses": { + "200": { + "description": "File paths", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.find.files({\n ...\n})" + } + ] + } + }, + "/find/symbol": { + "get": { + "operationId": "find.symbols", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "query", + "schema": { + "type": "string" + }, + "required": true + } + ], + "summary": "Find symbols", + "description": "Search for workspace symbols like functions, classes, and variables using LSP.", + "responses": { + "200": { + "description": "Symbols", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Symbol" + } + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.find.symbols({\n ...\n})" + } + ] + } + }, + "/file": { + "get": { + "operationId": "file.list", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "summary": "List files", + "description": "List files and directories in a specified path.", + "responses": { + "200": { + "description": "Files and directories", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileNode" + } + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.file.list({\n ...\n})" + } + ] + } + }, + "/file/content": { + "get": { + "operationId": "file.read", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "summary": "Read file", + "description": "Read the content of a specified file.", + "responses": { + "200": { + "description": "File content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FileContent" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.file.read({\n ...\n})" + } + ] + } + }, + "/file/status": { + "get": { + "operationId": "file.status", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "Get file status", + "description": "Get the git status of all files in the project.", + "responses": { + "200": { + "description": "File status", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/File" + } + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.file.status({\n ...\n})" + } + ] + } + }, + "/log": { + "post": { + "operationId": "app.log", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "Write log", + "description": "Write a log entry to the server logs with specified level and metadata.", + "responses": { + "200": { + "description": "Log entry written successfully", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "service": { + "description": "Service name for the log entry", + "type": "string" + }, + "level": { + "description": "Log level", + "type": "string", + "enum": ["debug", "info", "error", "warn"] + }, + "message": { + "description": "Log message", + "type": "string" + }, + "extra": { + "description": "Additional metadata for the log entry", + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": ["service", "level", "message"] + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.app.log({\n ...\n})" + } + ] + } + }, + "/agent": { + "get": { + "operationId": "app.agents", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "List agents", + "description": "Get a list of all available AI agents in the OpenCode system.", + "responses": { + "200": { + "description": "List of agents", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Agent" + } + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.app.agents({\n ...\n})" + } + ] + } + }, + "/mcp": { + "get": { + "operationId": "mcp.status", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "Get MCP status", + "description": "Get the status of all Model Context Protocol (MCP) servers.", + "responses": { + "200": { + "description": "MCP server status", + "content": { + "application/json": { + "schema": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "$ref": "#/components/schemas/MCPStatus" + } + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.mcp.status({\n ...\n})" + } + ] + }, + "post": { + "operationId": "mcp.add", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "Add MCP server", + "description": "Dynamically add a new Model Context Protocol (MCP) server to the system.", + "responses": { + "200": { + "description": "MCP server added successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "$ref": "#/components/schemas/MCPStatus" + } + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "config": { + "anyOf": [ + { + "$ref": "#/components/schemas/McpLocalConfig" + }, + { + "$ref": "#/components/schemas/McpRemoteConfig" + } + ] + } + }, + "required": ["name", "config"] + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.mcp.add({\n ...\n})" + } + ] + } + }, + "/mcp/{name}/auth": { + "post": { + "operationId": "mcp.auth.start", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "name", + "required": true + } + ], + "summary": "Start MCP OAuth", + "description": "Start OAuth authentication flow for a Model Context Protocol (MCP) server.", + "responses": { + "200": { + "description": "OAuth flow started", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "authorizationUrl": { + "description": "URL to open in browser for authorization", + "type": "string" + } + }, + "required": ["authorizationUrl"] + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.mcp.auth.start({\n ...\n})" + } + ] + }, + "delete": { + "operationId": "mcp.auth.remove", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "name", + "required": true + } + ], + "summary": "Remove MCP OAuth", + "description": "Remove OAuth credentials for an MCP server", + "responses": { + "200": { + "description": "OAuth credentials removed", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "const": true + } + }, + "required": ["success"] + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.mcp.auth.remove({\n ...\n})" + } + ] + } + }, + "/mcp/{name}/auth/callback": { + "post": { + "operationId": "mcp.auth.callback", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "name", + "required": true + } + ], + "summary": "Complete MCP OAuth", + "description": "Complete OAuth authentication for a Model Context Protocol (MCP) server using the authorization code.", + "responses": { + "200": { + "description": "OAuth authentication completed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MCPStatus" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "code": { + "description": "Authorization code from OAuth callback", + "type": "string" + } + }, + "required": ["code"] + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.mcp.auth.callback({\n ...\n})" + } + ] + } + }, + "/mcp/{name}/auth/authenticate": { + "post": { + "operationId": "mcp.auth.authenticate", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "schema": { + "type": "string" + }, + "in": "path", + "name": "name", + "required": true + } + ], + "summary": "Authenticate MCP OAuth", + "description": "Start OAuth flow and wait for callback (opens browser)", + "responses": { + "200": { + "description": "OAuth authentication completed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MCPStatus" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.mcp.auth.authenticate({\n ...\n})" + } + ] + } + }, + "/mcp/{name}/connect": { + "post": { + "operationId": "mcp.connect", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "name", + "schema": { + "type": "string" + }, + "required": true + } + ], + "description": "Connect an MCP server", + "responses": { + "200": { + "description": "MCP server connected successfully", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.mcp.connect({\n ...\n})" + } + ] + } + }, + "/mcp/{name}/disconnect": { + "post": { + "operationId": "mcp.disconnect", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "name", + "schema": { + "type": "string" + }, + "required": true + } + ], + "description": "Disconnect an MCP server", + "responses": { + "200": { + "description": "MCP server disconnected successfully", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.mcp.disconnect({\n ...\n})" + } + ] + } + }, + "/lsp": { + "get": { + "operationId": "lsp.status", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "Get LSP status", + "description": "Get LSP server status", + "responses": { + "200": { + "description": "LSP server status", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LSPStatus" + } + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.lsp.status({\n ...\n})" + } + ] + } + }, + "/formatter": { + "get": { + "operationId": "formatter.status", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "Get formatter status", + "description": "Get formatter status", + "responses": { + "200": { + "description": "Formatter status", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FormatterStatus" + } + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.formatter.status({\n ...\n})" + } + ] + } + }, + "/tui/append-prompt": { + "post": { + "operationId": "tui.appendPrompt", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "Append TUI prompt", + "description": "Append prompt to the TUI", + "responses": { + "200": { + "description": "Prompt processed successfully", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "text": { + "type": "string" + } + }, + "required": ["text"] + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.tui.appendPrompt({\n ...\n})" + } + ] + } + }, + "/tui/open-help": { + "post": { + "operationId": "tui.openHelp", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "Open help dialog", + "description": "Open the help dialog in the TUI to display user assistance information.", + "responses": { + "200": { + "description": "Help dialog opened successfully", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.tui.openHelp({\n ...\n})" + } + ] + } + }, + "/tui/open-sessions": { + "post": { + "operationId": "tui.openSessions", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "Open sessions dialog", + "description": "Open the session dialog", + "responses": { + "200": { + "description": "Session dialog opened successfully", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.tui.openSessions({\n ...\n})" + } + ] + } + }, + "/tui/open-themes": { + "post": { + "operationId": "tui.openThemes", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "Open themes dialog", + "description": "Open the theme dialog", + "responses": { + "200": { + "description": "Theme dialog opened successfully", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.tui.openThemes({\n ...\n})" + } + ] + } + }, + "/tui/open-models": { + "post": { + "operationId": "tui.openModels", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "Open models dialog", + "description": "Open the model dialog", + "responses": { + "200": { + "description": "Model dialog opened successfully", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.tui.openModels({\n ...\n})" + } + ] + } + }, + "/tui/submit-prompt": { + "post": { + "operationId": "tui.submitPrompt", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "Submit TUI prompt", + "description": "Submit the prompt", + "responses": { + "200": { + "description": "Prompt submitted successfully", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.tui.submitPrompt({\n ...\n})" + } + ] + } + }, + "/tui/clear-prompt": { + "post": { + "operationId": "tui.clearPrompt", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "Clear TUI prompt", + "description": "Clear the prompt", + "responses": { + "200": { + "description": "Prompt cleared successfully", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.tui.clearPrompt({\n ...\n})" + } + ] + } + }, + "/tui/execute-command": { + "post": { + "operationId": "tui.executeCommand", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "Execute TUI command", + "description": "Execute a TUI command (e.g. agent_cycle)", + "responses": { + "200": { + "description": "Command executed successfully", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "command": { + "type": "string" + } + }, + "required": ["command"] + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.tui.executeCommand({\n ...\n})" + } + ] + } + }, + "/tui/show-toast": { + "post": { + "operationId": "tui.showToast", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "Show TUI toast", + "description": "Show a toast notification in the TUI", + "responses": { + "200": { + "description": "Toast notification shown successfully", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "message": { + "type": "string" + }, + "variant": { + "type": "string", + "enum": ["info", "success", "warning", "error"] + }, + "duration": { + "description": "Duration in milliseconds", + "default": 5000, + "type": "number" + } + }, + "required": ["message", "variant"] + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.tui.showToast({\n ...\n})" + } + ] + } + }, + "/tui/publish": { + "post": { + "operationId": "tui.publish", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "Publish TUI event", + "description": "Publish a TUI event", + "responses": { + "200": { + "description": "Event published successfully", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/Event.tui.prompt.append" + }, + { + "$ref": "#/components/schemas/Event.tui.command.execute" + }, + { + "$ref": "#/components/schemas/Event.tui.toast.show" + } + ] + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.tui.publish({\n ...\n})" + } + ] + } + }, + "/tui/control/next": { + "get": { + "operationId": "tui.control.next", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "Get next TUI request", + "description": "Retrieve the next TUI (Terminal User Interface) request from the queue for processing.", + "responses": { + "200": { + "description": "Next TUI request", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "body": {} + }, + "required": ["path", "body"] + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.tui.control.next({\n ...\n})" + } + ] + } + }, + "/tui/control/response": { + "post": { + "operationId": "tui.control.response", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "Submit TUI response", + "description": "Submit a response to the TUI request queue to complete a pending request.", + "responses": { + "200": { + "description": "Response submitted successfully", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": {} + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.tui.control.response({\n ...\n})" + } + ] + } + }, + "/auth/{providerID}": { + "put": { + "operationId": "auth.set", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + }, + { + "in": "path", + "name": "providerID", + "schema": { + "type": "string" + }, + "required": true + } + ], + "summary": "Set auth credentials", + "description": "Set authentication credentials", + "responses": { + "200": { + "description": "Successfully set authentication credentials", + "content": { + "application/json": { + "schema": { + "type": "boolean" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BadRequestError" + } + } + } + } + }, + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Auth" + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.auth.set({\n ...\n})" + } + ] + } + }, + "/event": { + "get": { + "operationId": "event.subscribe", + "parameters": [ + { + "in": "query", + "name": "directory", + "schema": { + "type": "string" + } + } + ], + "summary": "Subscribe to events", + "description": "Get events", + "responses": { + "200": { + "description": "Event stream", + "content": { + "text/event-stream": { + "schema": { + "$ref": "#/components/schemas/Event" + } + } + } + } + }, + "x-codeSamples": [ + { + "lang": "js", + "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.event.subscribe({\n ...\n})" + } + ] + } + } + }, + "components": { + "schemas": { + "Event.installation.updated": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "installation.updated" + }, + "properties": { + "type": "object", + "properties": { + "version": { + "type": "string" + } + }, + "required": ["version"] + } + }, + "required": ["type", "properties"] + }, + "Event.installation.update-available": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "installation.update-available" + }, + "properties": { + "type": "object", + "properties": { + "version": { + "type": "string" + } + }, + "required": ["version"] + } + }, + "required": ["type", "properties"] + }, + "Project": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "worktree": { + "type": "string" + }, + "vcs": { + "type": "string", + "const": "git" + }, + "name": { + "type": "string" + }, + "icon": { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "color": { + "type": "string" + } + } + }, + "time": { + "type": "object", + "properties": { + "created": { + "type": "number" + }, + "updated": { + "type": "number" + }, + "initialized": { + "type": "number" + } + }, + "required": ["created", "updated"] + } + }, + "required": ["id", "worktree", "time"] + }, + "Event.project.updated": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "project.updated" + }, + "properties": { + "$ref": "#/components/schemas/Project" + } + }, + "required": ["type", "properties"] + }, + "Event.server.instance.disposed": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "server.instance.disposed" + }, + "properties": { + "type": "object", + "properties": { + "directory": { + "type": "string" + } + }, + "required": ["directory"] + } + }, + "required": ["type", "properties"] + }, + "Event.lsp.client.diagnostics": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "lsp.client.diagnostics" + }, + "properties": { + "type": "object", + "properties": { + "serverID": { + "type": "string" + }, + "path": { + "type": "string" + } + }, + "required": ["serverID", "path"] + } + }, + "required": ["type", "properties"] + }, + "Event.lsp.updated": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "lsp.updated" + }, + "properties": { + "type": "object", + "properties": {} + } + }, + "required": ["type", "properties"] + }, + "FileDiff": { + "type": "object", + "properties": { + "file": { + "type": "string" + }, + "before": { + "type": "string" + }, + "after": { + "type": "string" + }, + "additions": { + "type": "number" + }, + "deletions": { + "type": "number" + } + }, + "required": ["file", "before", "after", "additions", "deletions"] + }, + "UserMessage": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "sessionID": { + "type": "string" + }, + "role": { + "type": "string", + "const": "user" + }, + "time": { + "type": "object", + "properties": { + "created": { + "type": "number" + } + }, + "required": ["created"] + }, + "summary": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "body": { + "type": "string" + }, + "diffs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileDiff" + } + } + }, + "required": ["diffs"] + }, + "agent": { + "type": "string" + }, + "model": { + "type": "object", + "properties": { + "providerID": { + "type": "string" + }, + "modelID": { + "type": "string" + } + }, + "required": ["providerID", "modelID"] + }, + "system": { + "type": "string" + }, + "tools": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "boolean" + } + }, + "variant": { + "type": "string" + } + }, + "required": ["id", "sessionID", "role", "time", "agent", "model"] + }, + "ProviderAuthError": { + "type": "object", + "properties": { + "name": { + "type": "string", + "const": "ProviderAuthError" + }, + "data": { + "type": "object", + "properties": { + "providerID": { + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": ["providerID", "message"] + } + }, + "required": ["name", "data"] + }, + "UnknownError": { + "type": "object", + "properties": { + "name": { + "type": "string", + "const": "UnknownError" + }, + "data": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + }, + "required": ["message"] + } + }, + "required": ["name", "data"] + }, + "MessageOutputLengthError": { + "type": "object", + "properties": { + "name": { + "type": "string", + "const": "MessageOutputLengthError" + }, + "data": { + "type": "object", + "properties": {} + } + }, + "required": ["name", "data"] + }, + "MessageAbortedError": { + "type": "object", + "properties": { + "name": { + "type": "string", + "const": "MessageAbortedError" + }, + "data": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + }, + "required": ["message"] + } + }, + "required": ["name", "data"] + }, + "APIError": { + "type": "object", + "properties": { + "name": { + "type": "string", + "const": "APIError" + }, + "data": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "statusCode": { + "type": "number" + }, + "isRetryable": { + "type": "boolean" + }, + "responseHeaders": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "string" + } + }, + "responseBody": { + "type": "string" + }, + "metadata": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "string" + } + } + }, + "required": ["message", "isRetryable"] + } + }, + "required": ["name", "data"] + }, + "AssistantMessage": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "sessionID": { + "type": "string" + }, + "role": { + "type": "string", + "const": "assistant" + }, + "time": { + "type": "object", + "properties": { + "created": { + "type": "number" + }, + "completed": { + "type": "number" + } + }, + "required": ["created"] + }, + "error": { + "anyOf": [ + { + "$ref": "#/components/schemas/ProviderAuthError" + }, + { + "$ref": "#/components/schemas/UnknownError" + }, + { + "$ref": "#/components/schemas/MessageOutputLengthError" + }, + { + "$ref": "#/components/schemas/MessageAbortedError" + }, + { + "$ref": "#/components/schemas/APIError" + } + ] + }, + "parentID": { + "type": "string" + }, + "modelID": { + "type": "string" + }, + "providerID": { + "type": "string" + }, + "mode": { + "type": "string" + }, + "agent": { + "type": "string" + }, + "path": { + "type": "object", + "properties": { + "cwd": { + "type": "string" + }, + "root": { + "type": "string" + } + }, + "required": ["cwd", "root"] + }, + "summary": { + "type": "boolean" + }, + "cost": { + "type": "number" + }, + "tokens": { + "type": "object", + "properties": { + "input": { + "type": "number" + }, + "output": { + "type": "number" + }, + "reasoning": { + "type": "number" + }, + "cache": { + "type": "object", + "properties": { + "read": { + "type": "number" + }, + "write": { + "type": "number" + } + }, + "required": ["read", "write"] + } + }, + "required": ["input", "output", "reasoning", "cache"] + }, + "finish": { + "type": "string" + } + }, + "required": [ + "id", + "sessionID", + "role", + "time", + "parentID", + "modelID", + "providerID", + "mode", + "agent", + "path", + "cost", + "tokens" + ] + }, + "Message": { + "anyOf": [ + { + "$ref": "#/components/schemas/UserMessage" + }, + { + "$ref": "#/components/schemas/AssistantMessage" + } + ] + }, + "Event.message.updated": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "message.updated" + }, + "properties": { + "type": "object", + "properties": { + "info": { + "$ref": "#/components/schemas/Message" + } + }, + "required": ["info"] + } + }, + "required": ["type", "properties"] + }, + "Event.message.removed": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "message.removed" + }, + "properties": { + "type": "object", + "properties": { + "sessionID": { + "type": "string" + }, + "messageID": { + "type": "string" + } + }, + "required": ["sessionID", "messageID"] + } + }, + "required": ["type", "properties"] + }, + "TextPart": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "sessionID": { + "type": "string" + }, + "messageID": { + "type": "string" + }, + "type": { + "type": "string", + "const": "text" + }, + "text": { + "type": "string" + }, + "synthetic": { + "type": "boolean" + }, + "ignored": { + "type": "boolean" + }, + "time": { + "type": "object", + "properties": { + "start": { + "type": "number" + }, + "end": { + "type": "number" + } + }, + "required": ["start"] + }, + "metadata": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": ["id", "sessionID", "messageID", "type", "text"] + }, + "ReasoningPart": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "sessionID": { + "type": "string" + }, + "messageID": { + "type": "string" + }, + "type": { + "type": "string", + "const": "reasoning" + }, + "text": { + "type": "string" + }, + "metadata": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + }, + "time": { + "type": "object", + "properties": { + "start": { + "type": "number" + }, + "end": { + "type": "number" + } + }, + "required": ["start"] + } + }, + "required": ["id", "sessionID", "messageID", "type", "text", "time"] + }, + "FilePartSourceText": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "start": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "end": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + } + }, + "required": ["value", "start", "end"] + }, + "FileSource": { + "type": "object", + "properties": { + "text": { + "$ref": "#/components/schemas/FilePartSourceText" + }, + "type": { + "type": "string", + "const": "file" + }, + "path": { + "type": "string" + } + }, + "required": ["text", "type", "path"] + }, + "Range": { + "type": "object", + "properties": { + "start": { + "type": "object", + "properties": { + "line": { + "type": "number" + }, + "character": { + "type": "number" + } + }, + "required": ["line", "character"] + }, + "end": { + "type": "object", + "properties": { + "line": { + "type": "number" + }, + "character": { + "type": "number" + } + }, + "required": ["line", "character"] + } + }, + "required": ["start", "end"] + }, + "SymbolSource": { + "type": "object", + "properties": { + "text": { + "$ref": "#/components/schemas/FilePartSourceText" + }, + "type": { + "type": "string", + "const": "symbol" + }, + "path": { + "type": "string" + }, + "range": { + "$ref": "#/components/schemas/Range" + }, + "name": { + "type": "string" + }, + "kind": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + } + }, + "required": ["text", "type", "path", "range", "name", "kind"] + }, + "FilePartSource": { + "anyOf": [ + { + "$ref": "#/components/schemas/FileSource" + }, + { + "$ref": "#/components/schemas/SymbolSource" + } + ] + }, + "FilePart": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "sessionID": { + "type": "string" + }, + "messageID": { + "type": "string" + }, + "type": { + "type": "string", + "const": "file" + }, + "mime": { + "type": "string" + }, + "filename": { + "type": "string" + }, + "url": { + "type": "string" + }, + "source": { + "$ref": "#/components/schemas/FilePartSource" + } + }, + "required": ["id", "sessionID", "messageID", "type", "mime", "url"] + }, + "ToolStatePending": { + "type": "object", + "properties": { + "status": { + "type": "string", + "const": "pending" + }, + "input": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + }, + "raw": { + "type": "string" + } + }, + "required": ["status", "input", "raw"] + }, + "ToolStateRunning": { + "type": "object", + "properties": { + "status": { + "type": "string", + "const": "running" + }, + "input": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + }, + "title": { + "type": "string" + }, + "metadata": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + }, + "time": { + "type": "object", + "properties": { + "start": { + "type": "number" + } + }, + "required": ["start"] + } + }, + "required": ["status", "input", "time"] + }, + "ToolStateCompleted": { + "type": "object", + "properties": { + "status": { + "type": "string", + "const": "completed" + }, + "input": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + }, + "output": { + "type": "string" + }, + "title": { + "type": "string" + }, + "metadata": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + }, + "time": { + "type": "object", + "properties": { + "start": { + "type": "number" + }, + "end": { + "type": "number" + }, + "compacted": { + "type": "number" + } + }, + "required": ["start", "end"] + }, + "attachments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FilePart" + } + } + }, + "required": ["status", "input", "output", "title", "metadata", "time"] + }, + "ToolStateError": { + "type": "object", + "properties": { + "status": { + "type": "string", + "const": "error" + }, + "input": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + }, + "error": { + "type": "string" + }, + "metadata": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + }, + "time": { + "type": "object", + "properties": { + "start": { + "type": "number" + }, + "end": { + "type": "number" + } + }, + "required": ["start", "end"] + } + }, + "required": ["status", "input", "error", "time"] + }, + "ToolState": { + "anyOf": [ + { + "$ref": "#/components/schemas/ToolStatePending" + }, + { + "$ref": "#/components/schemas/ToolStateRunning" + }, + { + "$ref": "#/components/schemas/ToolStateCompleted" + }, + { + "$ref": "#/components/schemas/ToolStateError" + } + ] + }, + "ToolPart": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "sessionID": { + "type": "string" + }, + "messageID": { + "type": "string" + }, + "type": { + "type": "string", + "const": "tool" + }, + "callID": { + "type": "string" + }, + "tool": { + "type": "string" + }, + "state": { + "$ref": "#/components/schemas/ToolState" + }, + "metadata": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": ["id", "sessionID", "messageID", "type", "callID", "tool", "state"] + }, + "StepStartPart": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "sessionID": { + "type": "string" + }, + "messageID": { + "type": "string" + }, + "type": { + "type": "string", + "const": "step-start" + }, + "snapshot": { + "type": "string" + } + }, + "required": ["id", "sessionID", "messageID", "type"] + }, + "StepFinishPart": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "sessionID": { + "type": "string" + }, + "messageID": { + "type": "string" + }, + "type": { + "type": "string", + "const": "step-finish" + }, + "reason": { + "type": "string" + }, + "snapshot": { + "type": "string" + }, + "cost": { + "type": "number" + }, + "tokens": { + "type": "object", + "properties": { + "input": { + "type": "number" + }, + "output": { + "type": "number" + }, + "reasoning": { + "type": "number" + }, + "cache": { + "type": "object", + "properties": { + "read": { + "type": "number" + }, + "write": { + "type": "number" + } + }, + "required": ["read", "write"] + } + }, + "required": ["input", "output", "reasoning", "cache"] + } + }, + "required": ["id", "sessionID", "messageID", "type", "reason", "cost", "tokens"] + }, + "SnapshotPart": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "sessionID": { + "type": "string" + }, + "messageID": { + "type": "string" + }, + "type": { + "type": "string", + "const": "snapshot" + }, + "snapshot": { + "type": "string" + } + }, + "required": ["id", "sessionID", "messageID", "type", "snapshot"] + }, + "PatchPart": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "sessionID": { + "type": "string" + }, + "messageID": { + "type": "string" + }, + "type": { + "type": "string", + "const": "patch" + }, + "hash": { + "type": "string" + }, + "files": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": ["id", "sessionID", "messageID", "type", "hash", "files"] + }, + "AgentPart": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "sessionID": { + "type": "string" + }, + "messageID": { + "type": "string" + }, + "type": { + "type": "string", + "const": "agent" + }, + "name": { + "type": "string" + }, + "source": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "start": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "end": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + } + }, + "required": ["value", "start", "end"] + } + }, + "required": ["id", "sessionID", "messageID", "type", "name"] + }, + "RetryPart": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "sessionID": { + "type": "string" + }, + "messageID": { + "type": "string" + }, + "type": { + "type": "string", + "const": "retry" + }, + "attempt": { + "type": "number" + }, + "error": { + "$ref": "#/components/schemas/APIError" + }, + "time": { + "type": "object", + "properties": { + "created": { + "type": "number" + } + }, + "required": ["created"] + } + }, + "required": ["id", "sessionID", "messageID", "type", "attempt", "error", "time"] + }, + "CompactionPart": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "sessionID": { + "type": "string" + }, + "messageID": { + "type": "string" + }, + "type": { + "type": "string", + "const": "compaction" + }, + "auto": { + "type": "boolean" + } + }, + "required": ["id", "sessionID", "messageID", "type", "auto"] + }, + "Part": { + "anyOf": [ + { + "$ref": "#/components/schemas/TextPart" + }, + { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "sessionID": { + "type": "string" + }, + "messageID": { + "type": "string" + }, + "type": { + "type": "string", + "const": "subtask" + }, + "prompt": { + "type": "string" + }, + "description": { + "type": "string" + }, + "agent": { + "type": "string" + }, + "command": { + "type": "string" + } + }, + "required": ["id", "sessionID", "messageID", "type", "prompt", "description", "agent"] + }, + { + "$ref": "#/components/schemas/ReasoningPart" + }, + { + "$ref": "#/components/schemas/FilePart" + }, + { + "$ref": "#/components/schemas/ToolPart" + }, + { + "$ref": "#/components/schemas/StepStartPart" + }, + { + "$ref": "#/components/schemas/StepFinishPart" + }, + { + "$ref": "#/components/schemas/SnapshotPart" + }, + { + "$ref": "#/components/schemas/PatchPart" + }, + { + "$ref": "#/components/schemas/AgentPart" + }, + { + "$ref": "#/components/schemas/RetryPart" + }, + { + "$ref": "#/components/schemas/CompactionPart" + } + ] + }, + "Event.message.part.updated": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "message.part.updated" + }, + "properties": { + "type": "object", + "properties": { + "part": { + "$ref": "#/components/schemas/Part" + }, + "delta": { + "type": "string" + } + }, + "required": ["part"] + } + }, + "required": ["type", "properties"] + }, + "Event.message.part.removed": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "message.part.removed" + }, + "properties": { + "type": "object", + "properties": { + "sessionID": { + "type": "string" + }, + "messageID": { + "type": "string" + }, + "partID": { + "type": "string" + } + }, + "required": ["sessionID", "messageID", "partID"] + } + }, + "required": ["type", "properties"] + }, + "PermissionRequest": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^per.*" + }, + "sessionID": { + "type": "string", + "pattern": "^ses.*" + }, + "permission": { + "type": "string" + }, + "patterns": { + "type": "array", + "items": { + "type": "string" + } + }, + "metadata": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + }, + "always": { + "type": "array", + "items": { + "type": "string" + } + }, + "tool": { + "type": "object", + "properties": { + "messageID": { + "type": "string" + }, + "callID": { + "type": "string" + } + }, + "required": ["messageID", "callID"] + } + }, + "required": ["id", "sessionID", "permission", "patterns", "metadata", "always"] + }, + "Event.permission.asked": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "permission.asked" + }, + "properties": { + "$ref": "#/components/schemas/PermissionRequest" + } + }, + "required": ["type", "properties"] + }, + "Event.permission.replied": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "permission.replied" + }, + "properties": { + "type": "object", + "properties": { + "sessionID": { + "type": "string" + }, + "requestID": { + "type": "string" + }, + "reply": { + "type": "string", + "enum": ["once", "always", "reject"] + } + }, + "required": ["sessionID", "requestID", "reply"] + } + }, + "required": ["type", "properties"] + }, + "SessionStatus": { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "idle" + } + }, + "required": ["type"] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "retry" + }, + "attempt": { + "type": "number" + }, + "message": { + "type": "string" + }, + "next": { + "type": "number" + } + }, + "required": ["type", "attempt", "message", "next"] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "busy" + } + }, + "required": ["type"] + } + ] + }, + "Event.session.status": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "session.status" + }, + "properties": { + "type": "object", + "properties": { + "sessionID": { + "type": "string" + }, + "status": { + "$ref": "#/components/schemas/SessionStatus" + } + }, + "required": ["sessionID", "status"] + } + }, + "required": ["type", "properties"] + }, + "Event.session.idle": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "session.idle" + }, + "properties": { + "type": "object", + "properties": { + "sessionID": { + "type": "string" + } + }, + "required": ["sessionID"] + } + }, + "required": ["type", "properties"] + }, + "Event.session.compacted": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "session.compacted" + }, + "properties": { + "type": "object", + "properties": { + "sessionID": { + "type": "string" + } + }, + "required": ["sessionID"] + } + }, + "required": ["type", "properties"] + }, + "Event.file.edited": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "file.edited" + }, + "properties": { + "type": "object", + "properties": { + "file": { + "type": "string" + } + }, + "required": ["file"] + } + }, + "required": ["type", "properties"] + }, + "Todo": { + "type": "object", + "properties": { + "content": { + "description": "Brief description of the task", + "type": "string" + }, + "status": { + "description": "Current status of the task: pending, in_progress, completed, cancelled", + "type": "string" + }, + "priority": { + "description": "Priority level of the task: high, medium, low", + "type": "string" + }, + "id": { + "description": "Unique identifier for the todo item", + "type": "string" + } + }, + "required": ["content", "status", "priority", "id"] + }, + "Event.todo.updated": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "todo.updated" + }, + "properties": { + "type": "object", + "properties": { + "sessionID": { + "type": "string" + }, + "todos": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Todo" + } + } + }, + "required": ["sessionID", "todos"] + } + }, + "required": ["type", "properties"] + }, + "Event.tui.prompt.append": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "tui.prompt.append" + }, + "properties": { + "type": "object", + "properties": { + "text": { + "type": "string" + } + }, + "required": ["text"] + } + }, + "required": ["type", "properties"] + }, + "Event.tui.command.execute": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "tui.command.execute" + }, + "properties": { + "type": "object", + "properties": { + "command": { + "anyOf": [ + { + "type": "string", + "enum": [ + "session.list", + "session.new", + "session.share", + "session.interrupt", + "session.compact", + "session.page.up", + "session.page.down", + "session.half.page.up", + "session.half.page.down", + "session.first", + "session.last", + "prompt.clear", + "prompt.submit", + "agent.cycle" + ] + }, + { + "type": "string" + } + ] + } + }, + "required": ["command"] + } + }, + "required": ["type", "properties"] + }, + "Event.tui.toast.show": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "tui.toast.show" + }, + "properties": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "message": { + "type": "string" + }, + "variant": { + "type": "string", + "enum": ["info", "success", "warning", "error"] + }, + "duration": { + "description": "Duration in milliseconds", + "default": 5000, + "type": "number" + } + }, + "required": ["message", "variant"] + } + }, + "required": ["type", "properties"] + }, + "Event.mcp.tools.changed": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "mcp.tools.changed" + }, + "properties": { + "type": "object", + "properties": { + "server": { + "type": "string" + } + }, + "required": ["server"] + } + }, + "required": ["type", "properties"] + }, + "Event.command.executed": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "command.executed" + }, + "properties": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "sessionID": { + "type": "string", + "pattern": "^ses.*" + }, + "arguments": { + "type": "string" + }, + "messageID": { + "type": "string", + "pattern": "^msg.*" + } + }, + "required": ["name", "sessionID", "arguments", "messageID"] + } + }, + "required": ["type", "properties"] + }, + "PermissionAction": { + "type": "string", + "enum": ["allow", "deny", "ask"] + }, + "PermissionRule": { + "type": "object", + "properties": { + "permission": { + "type": "string" + }, + "pattern": { + "type": "string" + }, + "action": { + "$ref": "#/components/schemas/PermissionAction" + } + }, + "required": ["permission", "pattern", "action"] + }, + "PermissionRuleset": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PermissionRule" + } + }, + "Session": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^ses.*" + }, + "projectID": { + "type": "string" + }, + "directory": { + "type": "string" + }, + "parentID": { + "type": "string", + "pattern": "^ses.*" + }, + "summary": { + "type": "object", + "properties": { + "additions": { + "type": "number" + }, + "deletions": { + "type": "number" + }, + "files": { + "type": "number" + }, + "diffs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileDiff" + } + } + }, + "required": ["additions", "deletions", "files"] + }, + "share": { + "type": "object", + "properties": { + "url": { + "type": "string" + } + }, + "required": ["url"] + }, + "title": { + "type": "string" + }, + "version": { + "type": "string" + }, + "time": { + "type": "object", + "properties": { + "created": { + "type": "number" + }, + "updated": { + "type": "number" + }, + "compacting": { + "type": "number" + }, + "archived": { + "type": "number" + } + }, + "required": ["created", "updated"] + }, + "permission": { + "$ref": "#/components/schemas/PermissionRuleset" + }, + "revert": { + "type": "object", + "properties": { + "messageID": { + "type": "string" + }, + "partID": { + "type": "string" + }, + "snapshot": { + "type": "string" + }, + "diff": { + "type": "string" + } + }, + "required": ["messageID"] + } + }, + "required": ["id", "projectID", "directory", "title", "version", "time"] + }, + "Event.session.created": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "session.created" + }, + "properties": { + "type": "object", + "properties": { + "info": { + "$ref": "#/components/schemas/Session" + } + }, + "required": ["info"] + } + }, + "required": ["type", "properties"] + }, + "Event.session.updated": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "session.updated" + }, + "properties": { + "type": "object", + "properties": { + "info": { + "$ref": "#/components/schemas/Session" + } + }, + "required": ["info"] + } + }, + "required": ["type", "properties"] + }, + "Event.session.deleted": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "session.deleted" + }, + "properties": { + "type": "object", + "properties": { + "info": { + "$ref": "#/components/schemas/Session" + } + }, + "required": ["info"] + } + }, + "required": ["type", "properties"] + }, + "Event.session.diff": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "session.diff" + }, + "properties": { + "type": "object", + "properties": { + "sessionID": { + "type": "string" + }, + "diff": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileDiff" + } + } + }, + "required": ["sessionID", "diff"] + } + }, + "required": ["type", "properties"] + }, + "Event.session.error": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "session.error" + }, + "properties": { + "type": "object", + "properties": { + "sessionID": { + "type": "string" + }, + "error": { + "anyOf": [ + { + "$ref": "#/components/schemas/ProviderAuthError" + }, + { + "$ref": "#/components/schemas/UnknownError" + }, + { + "$ref": "#/components/schemas/MessageOutputLengthError" + }, + { + "$ref": "#/components/schemas/MessageAbortedError" + }, + { + "$ref": "#/components/schemas/APIError" + } + ] + } + } + } + }, + "required": ["type", "properties"] + }, + "Event.file.watcher.updated": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "file.watcher.updated" + }, + "properties": { + "type": "object", + "properties": { + "file": { + "type": "string" + }, + "event": { + "anyOf": [ + { + "type": "string", + "const": "add" + }, + { + "type": "string", + "const": "change" + }, + { + "type": "string", + "const": "unlink" + } + ] + } + }, + "required": ["file", "event"] + } + }, + "required": ["type", "properties"] + }, + "Event.vcs.branch.updated": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "vcs.branch.updated" + }, + "properties": { + "type": "object", + "properties": { + "branch": { + "type": "string" + } + } + } + }, + "required": ["type", "properties"] + }, + "Pty": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^pty.*" + }, + "title": { + "type": "string" + }, + "command": { + "type": "string" + }, + "args": { + "type": "array", + "items": { + "type": "string" + } + }, + "cwd": { + "type": "string" + }, + "status": { + "type": "string", + "enum": ["running", "exited"] + }, + "pid": { + "type": "number" + } + }, + "required": ["id", "title", "command", "args", "cwd", "status", "pid"] + }, + "Event.pty.created": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "pty.created" + }, + "properties": { + "type": "object", + "properties": { + "info": { + "$ref": "#/components/schemas/Pty" + } + }, + "required": ["info"] + } + }, + "required": ["type", "properties"] + }, + "Event.pty.updated": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "pty.updated" + }, + "properties": { + "type": "object", + "properties": { + "info": { + "$ref": "#/components/schemas/Pty" + } + }, + "required": ["info"] + } + }, + "required": ["type", "properties"] + }, + "Event.pty.exited": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "pty.exited" + }, + "properties": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^pty.*" + }, + "exitCode": { + "type": "number" + } + }, + "required": ["id", "exitCode"] + } + }, + "required": ["type", "properties"] + }, + "Event.pty.deleted": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "pty.deleted" + }, + "properties": { + "type": "object", + "properties": { + "id": { + "type": "string", + "pattern": "^pty.*" + } + }, + "required": ["id"] + } + }, + "required": ["type", "properties"] + }, + "Event.server.connected": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "server.connected" + }, + "properties": { + "type": "object", + "properties": {} + } + }, + "required": ["type", "properties"] + }, + "Event.global.disposed": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "global.disposed" + }, + "properties": { + "type": "object", + "properties": {} + } + }, + "required": ["type", "properties"] + }, + "Event": { + "anyOf": [ + { + "$ref": "#/components/schemas/Event.installation.updated" + }, + { + "$ref": "#/components/schemas/Event.installation.update-available" + }, + { + "$ref": "#/components/schemas/Event.project.updated" + }, + { + "$ref": "#/components/schemas/Event.server.instance.disposed" + }, + { + "$ref": "#/components/schemas/Event.lsp.client.diagnostics" + }, + { + "$ref": "#/components/schemas/Event.lsp.updated" + }, + { + "$ref": "#/components/schemas/Event.message.updated" + }, + { + "$ref": "#/components/schemas/Event.message.removed" + }, + { + "$ref": "#/components/schemas/Event.message.part.updated" + }, + { + "$ref": "#/components/schemas/Event.message.part.removed" + }, + { + "$ref": "#/components/schemas/Event.permission.asked" + }, + { + "$ref": "#/components/schemas/Event.permission.replied" + }, + { + "$ref": "#/components/schemas/Event.session.status" + }, + { + "$ref": "#/components/schemas/Event.session.idle" + }, + { + "$ref": "#/components/schemas/Event.session.compacted" + }, + { + "$ref": "#/components/schemas/Event.file.edited" + }, + { + "$ref": "#/components/schemas/Event.todo.updated" + }, + { + "$ref": "#/components/schemas/Event.tui.prompt.append" + }, + { + "$ref": "#/components/schemas/Event.tui.command.execute" + }, + { + "$ref": "#/components/schemas/Event.tui.toast.show" + }, + { + "$ref": "#/components/schemas/Event.mcp.tools.changed" + }, + { + "$ref": "#/components/schemas/Event.command.executed" + }, + { + "$ref": "#/components/schemas/Event.session.created" + }, + { + "$ref": "#/components/schemas/Event.session.updated" + }, + { + "$ref": "#/components/schemas/Event.session.deleted" + }, + { + "$ref": "#/components/schemas/Event.session.diff" + }, + { + "$ref": "#/components/schemas/Event.session.error" + }, + { + "$ref": "#/components/schemas/Event.file.watcher.updated" + }, + { + "$ref": "#/components/schemas/Event.vcs.branch.updated" + }, + { + "$ref": "#/components/schemas/Event.pty.created" + }, + { + "$ref": "#/components/schemas/Event.pty.updated" + }, + { + "$ref": "#/components/schemas/Event.pty.exited" + }, + { + "$ref": "#/components/schemas/Event.pty.deleted" + }, + { + "$ref": "#/components/schemas/Event.server.connected" + }, + { + "$ref": "#/components/schemas/Event.global.disposed" + } + ] + }, + "GlobalEvent": { + "type": "object", + "properties": { + "directory": { + "type": "string" + }, + "payload": { + "$ref": "#/components/schemas/Event" + } + }, + "required": ["directory", "payload"] + }, + "BadRequestError": { + "type": "object", + "properties": { + "data": {}, + "errors": { + "type": "array", + "items": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "success": { + "type": "boolean", + "const": false + } + }, + "required": ["data", "errors", "success"] + }, + "NotFoundError": { + "type": "object", + "properties": { + "name": { + "type": "string", + "const": "NotFoundError" + }, + "data": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + }, + "required": ["message"] + } + }, + "required": ["name", "data"] + }, + "KeybindsConfig": { + "description": "Custom keybind configurations", + "type": "object", + "properties": { + "leader": { + "description": "Leader key for keybind combinations", + "default": "ctrl+x", + "type": "string" + }, + "app_exit": { + "description": "Exit the application", + "default": "ctrl+c,ctrl+d,q", + "type": "string" + }, + "editor_open": { + "description": "Open external editor", + "default": "e", + "type": "string" + }, + "theme_list": { + "description": "List available themes", + "default": "t", + "type": "string" + }, + "sidebar_toggle": { + "description": "Toggle sidebar", + "default": "b", + "type": "string" + }, + "scrollbar_toggle": { + "description": "Toggle session scrollbar", + "default": "none", + "type": "string" + }, + "username_toggle": { + "description": "Toggle username visibility", + "default": "none", + "type": "string" + }, + "status_view": { + "description": "View status", + "default": "s", + "type": "string" + }, + "session_export": { + "description": "Export session to editor", + "default": "x", + "type": "string" + }, + "session_new": { + "description": "Create a new session", + "default": "n", + "type": "string" + }, + "session_list": { + "description": "List all sessions", + "default": "l", + "type": "string" + }, + "session_timeline": { + "description": "Show session timeline", + "default": "g", + "type": "string" + }, + "session_fork": { + "description": "Fork session from message", + "default": "none", + "type": "string" + }, + "session_rename": { + "description": "Rename session", + "default": "none", + "type": "string" + }, + "session_share": { + "description": "Share current session", + "default": "none", + "type": "string" + }, + "session_unshare": { + "description": "Unshare current session", + "default": "none", + "type": "string" + }, + "session_interrupt": { + "description": "Interrupt current session", + "default": "escape", + "type": "string" + }, + "session_compact": { + "description": "Compact the session", + "default": "c", + "type": "string" + }, + "messages_page_up": { + "description": "Scroll messages up by one page", + "default": "pageup", + "type": "string" + }, + "messages_page_down": { + "description": "Scroll messages down by one page", + "default": "pagedown", + "type": "string" + }, + "messages_half_page_up": { + "description": "Scroll messages up by half page", + "default": "ctrl+alt+u", + "type": "string" + }, + "messages_half_page_down": { + "description": "Scroll messages down by half page", + "default": "ctrl+alt+d", + "type": "string" + }, + "messages_first": { + "description": "Navigate to first message", + "default": "ctrl+g,home", + "type": "string" + }, + "messages_last": { + "description": "Navigate to last message", + "default": "ctrl+alt+g,end", + "type": "string" + }, + "messages_next": { + "description": "Navigate to next message", + "default": "none", + "type": "string" + }, + "messages_previous": { + "description": "Navigate to previous message", + "default": "none", + "type": "string" + }, + "messages_last_user": { + "description": "Navigate to last user message", + "default": "none", + "type": "string" + }, + "messages_copy": { + "description": "Copy message", + "default": "y", + "type": "string" + }, + "messages_undo": { + "description": "Undo message", + "default": "u", + "type": "string" + }, + "messages_redo": { + "description": "Redo message", + "default": "r", + "type": "string" + }, + "messages_toggle_conceal": { + "description": "Toggle code block concealment in messages", + "default": "h", + "type": "string" + }, + "tool_details": { + "description": "Toggle tool details visibility", + "default": "none", + "type": "string" + }, + "model_list": { + "description": "List available models", + "default": "m", + "type": "string" + }, + "model_cycle_recent": { + "description": "Next recently used model", + "default": "f2", + "type": "string" + }, + "model_cycle_recent_reverse": { + "description": "Previous recently used model", + "default": "shift+f2", + "type": "string" + }, + "model_cycle_favorite": { + "description": "Next favorite model", + "default": "none", + "type": "string" + }, + "model_cycle_favorite_reverse": { + "description": "Previous favorite model", + "default": "none", + "type": "string" + }, + "command_list": { + "description": "List available commands", + "default": "ctrl+p", + "type": "string" + }, + "agent_list": { + "description": "List agents", + "default": "a", + "type": "string" + }, + "agent_cycle": { + "description": "Next agent", + "default": "tab", + "type": "string" + }, + "agent_cycle_reverse": { + "description": "Previous agent", + "default": "shift+tab", + "type": "string" + }, + "variant_cycle": { + "description": "Cycle model variants", + "default": "ctrl+t", + "type": "string" + }, + "input_clear": { + "description": "Clear input field", + "default": "ctrl+c", + "type": "string" + }, + "input_paste": { + "description": "Paste from clipboard", + "default": "ctrl+v", + "type": "string" + }, + "input_submit": { + "description": "Submit input", + "default": "return", + "type": "string" + }, + "input_newline": { + "description": "Insert newline in input", + "default": "shift+return,ctrl+return,alt+return,ctrl+j", + "type": "string" + }, + "input_move_left": { + "description": "Move cursor left in input", + "default": "left,ctrl+b", + "type": "string" + }, + "input_move_right": { + "description": "Move cursor right in input", + "default": "right,ctrl+f", + "type": "string" + }, + "input_move_up": { + "description": "Move cursor up in input", + "default": "up", + "type": "string" + }, + "input_move_down": { + "description": "Move cursor down in input", + "default": "down", + "type": "string" + }, + "input_select_left": { + "description": "Select left in input", + "default": "shift+left", + "type": "string" + }, + "input_select_right": { + "description": "Select right in input", + "default": "shift+right", + "type": "string" + }, + "input_select_up": { + "description": "Select up in input", + "default": "shift+up", + "type": "string" + }, + "input_select_down": { + "description": "Select down in input", + "default": "shift+down", + "type": "string" + }, + "input_line_home": { + "description": "Move to start of line in input", + "default": "ctrl+a", + "type": "string" + }, + "input_line_end": { + "description": "Move to end of line in input", + "default": "ctrl+e", + "type": "string" + }, + "input_select_line_home": { + "description": "Select to start of line in input", + "default": "ctrl+shift+a", + "type": "string" + }, + "input_select_line_end": { + "description": "Select to end of line in input", + "default": "ctrl+shift+e", + "type": "string" + }, + "input_visual_line_home": { + "description": "Move to start of visual line in input", + "default": "alt+a", + "type": "string" + }, + "input_visual_line_end": { + "description": "Move to end of visual line in input", + "default": "alt+e", + "type": "string" + }, + "input_select_visual_line_home": { + "description": "Select to start of visual line in input", + "default": "alt+shift+a", + "type": "string" + }, + "input_select_visual_line_end": { + "description": "Select to end of visual line in input", + "default": "alt+shift+e", + "type": "string" + }, + "input_buffer_home": { + "description": "Move to start of buffer in input", + "default": "home", + "type": "string" + }, + "input_buffer_end": { + "description": "Move to end of buffer in input", + "default": "end", + "type": "string" + }, + "input_select_buffer_home": { + "description": "Select to start of buffer in input", + "default": "shift+home", + "type": "string" + }, + "input_select_buffer_end": { + "description": "Select to end of buffer in input", + "default": "shift+end", + "type": "string" + }, + "input_delete_line": { + "description": "Delete line in input", + "default": "ctrl+shift+d", + "type": "string" + }, + "input_delete_to_line_end": { + "description": "Delete to end of line in input", + "default": "ctrl+k", + "type": "string" + }, + "input_delete_to_line_start": { + "description": "Delete to start of line in input", + "default": "ctrl+u", + "type": "string" + }, + "input_backspace": { + "description": "Backspace in input", + "default": "backspace,shift+backspace", + "type": "string" + }, + "input_delete": { + "description": "Delete character in input", + "default": "ctrl+d,delete,shift+delete", + "type": "string" + }, + "input_undo": { + "description": "Undo in input", + "default": "ctrl+-,super+z", + "type": "string" + }, + "input_redo": { + "description": "Redo in input", + "default": "ctrl+.,super+shift+z", + "type": "string" + }, + "input_word_forward": { + "description": "Move word forward in input", + "default": "alt+f,alt+right,ctrl+right", + "type": "string" + }, + "input_word_backward": { + "description": "Move word backward in input", + "default": "alt+b,alt+left,ctrl+left", + "type": "string" + }, + "input_select_word_forward": { + "description": "Select word forward in input", + "default": "alt+shift+f,alt+shift+right", + "type": "string" + }, + "input_select_word_backward": { + "description": "Select word backward in input", + "default": "alt+shift+b,alt+shift+left", + "type": "string" + }, + "input_delete_word_forward": { + "description": "Delete word forward in input", + "default": "alt+d,alt+delete,ctrl+delete", + "type": "string" + }, + "input_delete_word_backward": { + "description": "Delete word backward in input", + "default": "ctrl+w,ctrl+backspace,alt+backspace", + "type": "string" + }, + "history_previous": { + "description": "Previous history item", + "default": "up", + "type": "string" + }, + "history_next": { + "description": "Next history item", + "default": "down", + "type": "string" + }, + "session_child_cycle": { + "description": "Next child session", + "default": "right", + "type": "string" + }, + "session_child_cycle_reverse": { + "description": "Previous child session", + "default": "left", + "type": "string" + }, + "session_parent": { + "description": "Go to parent session", + "default": "up", + "type": "string" + }, + "terminal_suspend": { + "description": "Suspend terminal", + "default": "ctrl+z", + "type": "string" + }, + "terminal_title_toggle": { + "description": "Toggle terminal title", + "default": "none", + "type": "string" + }, + "tips_toggle": { + "description": "Toggle tips on home screen", + "default": "h", + "type": "string" + } + }, + "additionalProperties": false + }, + "LogLevel": { + "description": "Log level", + "type": "string", + "enum": ["DEBUG", "INFO", "WARN", "ERROR"] + }, + "ServerConfig": { + "description": "Server configuration for opencode serve and web commands", + "type": "object", + "properties": { + "port": { + "description": "Port to listen on", + "type": "integer", + "exclusiveMinimum": 0, + "maximum": 9007199254740991 + }, + "hostname": { + "description": "Hostname to listen on", + "type": "string" + }, + "mdns": { + "description": "Enable mDNS service discovery", + "type": "boolean" + }, + "cors": { + "description": "Additional domains to allow for CORS", + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "PermissionActionConfig": { + "type": "string", + "enum": ["ask", "allow", "deny"] + }, + "PermissionObjectConfig": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "$ref": "#/components/schemas/PermissionActionConfig" + } + }, + "PermissionRuleConfig": { + "anyOf": [ + { + "$ref": "#/components/schemas/PermissionActionConfig" + }, + { + "$ref": "#/components/schemas/PermissionObjectConfig" + } + ] + }, + "PermissionConfig": { + "anyOf": [ + { + "type": "object", + "properties": { + "read": { + "$ref": "#/components/schemas/PermissionRuleConfig" + }, + "edit": { + "$ref": "#/components/schemas/PermissionRuleConfig" + }, + "glob": { + "$ref": "#/components/schemas/PermissionRuleConfig" + }, + "grep": { + "$ref": "#/components/schemas/PermissionRuleConfig" + }, + "list": { + "$ref": "#/components/schemas/PermissionRuleConfig" + }, + "bash": { + "$ref": "#/components/schemas/PermissionRuleConfig" + }, + "task": { + "$ref": "#/components/schemas/PermissionRuleConfig" + }, + "external_directory": { + "$ref": "#/components/schemas/PermissionRuleConfig" + }, + "todowrite": { + "$ref": "#/components/schemas/PermissionActionConfig" + }, + "todoread": { + "$ref": "#/components/schemas/PermissionActionConfig" + }, + "webfetch": { + "$ref": "#/components/schemas/PermissionActionConfig" + }, + "websearch": { + "$ref": "#/components/schemas/PermissionActionConfig" + }, + "codesearch": { + "$ref": "#/components/schemas/PermissionActionConfig" + }, + "lsp": { + "$ref": "#/components/schemas/PermissionRuleConfig" + }, + "doom_loop": { + "$ref": "#/components/schemas/PermissionActionConfig" + } + }, + "additionalProperties": { + "$ref": "#/components/schemas/PermissionRuleConfig" + } + }, + { + "$ref": "#/components/schemas/PermissionActionConfig" + } + ] + }, + "AgentConfig": { + "type": "object", + "properties": { + "model": { + "type": "string" + }, + "temperature": { + "type": "number" + }, + "top_p": { + "type": "number" + }, + "prompt": { + "type": "string" + }, + "tools": { + "description": "@deprecated Use 'permission' field instead", + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "boolean" + } + }, + "disable": { + "type": "boolean" + }, + "description": { + "description": "Description of when to use the agent", + "type": "string" + }, + "mode": { + "type": "string", + "enum": ["subagent", "primary", "all"] + }, + "options": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + }, + "color": { + "description": "Hex color code for the agent (e.g., #FF5733)", + "type": "string", + "pattern": "^#[0-9a-fA-F]{6}$" + }, + "steps": { + "description": "Maximum number of agentic iterations before forcing text-only response", + "type": "integer", + "exclusiveMinimum": 0, + "maximum": 9007199254740991 + }, + "maxSteps": { + "description": "@deprecated Use 'steps' field instead.", + "type": "integer", + "exclusiveMinimum": 0, + "maximum": 9007199254740991 + }, + "permission": { + "$ref": "#/components/schemas/PermissionConfig" + } + }, + "additionalProperties": {} + }, + "ProviderConfig": { + "type": "object", + "properties": { + "api": { + "type": "string" + }, + "name": { + "type": "string" + }, + "env": { + "type": "array", + "items": { + "type": "string" + } + }, + "id": { + "type": "string" + }, + "npm": { + "type": "string" + }, + "models": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "family": { + "type": "string" + }, + "release_date": { + "type": "string" + }, + "attachment": { + "type": "boolean" + }, + "reasoning": { + "type": "boolean" + }, + "temperature": { + "type": "boolean" + }, + "tool_call": { + "type": "boolean" + }, + "interleaved": { + "anyOf": [ + { + "type": "boolean", + "const": true + }, + { + "type": "object", + "properties": { + "field": { + "type": "string", + "enum": ["reasoning_content", "reasoning_details"] + } + }, + "required": ["field"], + "additionalProperties": false + } + ] + }, + "cost": { + "type": "object", + "properties": { + "input": { + "type": "number" + }, + "output": { + "type": "number" + }, + "cache_read": { + "type": "number" + }, + "cache_write": { + "type": "number" + }, + "context_over_200k": { + "type": "object", + "properties": { + "input": { + "type": "number" + }, + "output": { + "type": "number" + }, + "cache_read": { + "type": "number" + }, + "cache_write": { + "type": "number" + } + }, + "required": ["input", "output"] + } + }, + "required": ["input", "output"] + }, + "limit": { + "type": "object", + "properties": { + "context": { + "type": "number" + }, + "output": { + "type": "number" + } + }, + "required": ["context", "output"] + }, + "modalities": { + "type": "object", + "properties": { + "input": { + "type": "array", + "items": { + "type": "string", + "enum": ["text", "audio", "image", "video", "pdf"] + } + }, + "output": { + "type": "array", + "items": { + "type": "string", + "enum": ["text", "audio", "image", "video", "pdf"] + } + } + }, + "required": ["input", "output"] + }, + "experimental": { + "type": "boolean" + }, + "status": { + "type": "string", + "enum": ["alpha", "beta", "deprecated"] + }, + "options": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + }, + "headers": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "string" + } + }, + "provider": { + "type": "object", + "properties": { + "npm": { + "type": "string" + } + }, + "required": ["npm"] + }, + "variants": { + "description": "Variant-specific configuration", + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "object", + "properties": { + "disabled": { + "description": "Disable this variant for the model", + "type": "boolean" + } + }, + "additionalProperties": {} + } + } + } + } + }, + "whitelist": { + "type": "array", + "items": { + "type": "string" + } + }, + "blacklist": { + "type": "array", + "items": { + "type": "string" + } + }, + "options": { + "type": "object", + "properties": { + "apiKey": { + "type": "string" + }, + "baseURL": { + "type": "string" + }, + "enterpriseUrl": { + "description": "GitHub Enterprise URL for copilot authentication", + "type": "string" + }, + "setCacheKey": { + "description": "Enable promptCacheKey for this provider (default false)", + "type": "boolean" + }, + "timeout": { + "description": "Timeout in milliseconds for requests to this provider. Default is 300000 (5 minutes). Set to false to disable timeout.", + "anyOf": [ + { + "description": "Timeout in milliseconds for requests to this provider. Default is 300000 (5 minutes). Set to false to disable timeout.", + "type": "integer", + "exclusiveMinimum": 0, + "maximum": 9007199254740991 + }, + { + "description": "Disable timeout for this provider entirely.", + "type": "boolean", + "const": false + } + ] + } + }, + "additionalProperties": {} + } + }, + "additionalProperties": false + }, + "McpLocalConfig": { + "type": "object", + "properties": { + "type": { + "description": "Type of MCP server connection", + "type": "string", + "const": "local" + }, + "command": { + "description": "Command and arguments to run the MCP server", + "type": "array", + "items": { + "type": "string" + } + }, + "environment": { + "description": "Environment variables to set when running the MCP server", + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "string" + } + }, + "enabled": { + "description": "Enable or disable the MCP server on startup", + "type": "boolean" + }, + "timeout": { + "description": "Timeout in ms for fetching tools from the MCP server. Defaults to 5000 (5 seconds) if not specified.", + "type": "integer", + "exclusiveMinimum": 0, + "maximum": 9007199254740991 + } + }, + "required": ["type", "command"], + "additionalProperties": false + }, + "McpOAuthConfig": { + "type": "object", + "properties": { + "clientId": { + "description": "OAuth client ID. If not provided, dynamic client registration (RFC 7591) will be attempted.", + "type": "string" + }, + "clientSecret": { + "description": "OAuth client secret (if required by the authorization server)", + "type": "string" + }, + "scope": { + "description": "OAuth scopes to request during authorization", + "type": "string" + } + }, + "additionalProperties": false + }, + "McpRemoteConfig": { + "type": "object", + "properties": { + "type": { + "description": "Type of MCP server connection", + "type": "string", + "const": "remote" + }, + "url": { + "description": "URL of the remote MCP server", + "type": "string" + }, + "enabled": { + "description": "Enable or disable the MCP server on startup", + "type": "boolean" + }, + "headers": { + "description": "Headers to send with the request", + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "string" + } + }, + "oauth": { + "description": "OAuth authentication configuration for the MCP server. Set to false to disable OAuth auto-detection.", + "anyOf": [ + { + "$ref": "#/components/schemas/McpOAuthConfig" + }, + { + "type": "boolean", + "const": false + } + ] + }, + "timeout": { + "description": "Timeout in ms for fetching tools from the MCP server. Defaults to 5000 (5 seconds) if not specified.", + "type": "integer", + "exclusiveMinimum": 0, + "maximum": 9007199254740991 + } + }, + "required": ["type", "url"], + "additionalProperties": false + }, + "LayoutConfig": { + "description": "@deprecated Always uses stretch layout.", + "type": "string", + "enum": ["auto", "stretch"] + }, + "Config": { + "type": "object", + "properties": { + "$schema": { + "description": "JSON schema reference for configuration validation", + "type": "string" + }, + "theme": { + "description": "Theme name to use for the interface", + "type": "string" + }, + "keybinds": { + "$ref": "#/components/schemas/KeybindsConfig" + }, + "logLevel": { + "$ref": "#/components/schemas/LogLevel" + }, + "tui": { + "description": "TUI specific settings", + "type": "object", + "properties": { + "scroll_speed": { + "description": "TUI scroll speed", + "type": "number", + "minimum": 0.001 + }, + "scroll_acceleration": { + "description": "Scroll acceleration settings", + "type": "object", + "properties": { + "enabled": { + "description": "Enable scroll acceleration", + "type": "boolean" + } + }, + "required": ["enabled"] + }, + "diff_style": { + "description": "Control diff rendering style: 'auto' adapts to terminal width, 'stacked' always shows single column", + "type": "string", + "enum": ["auto", "stacked"] + } + } + }, + "server": { + "$ref": "#/components/schemas/ServerConfig" + }, + "command": { + "description": "Command configuration, see https://opencode.ai/docs/commands", + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "object", + "properties": { + "template": { + "type": "string" + }, + "description": { + "type": "string" + }, + "agent": { + "type": "string" + }, + "model": { + "type": "string" + }, + "subtask": { + "type": "boolean" + } + }, + "required": ["template"] + } + }, + "watcher": { + "type": "object", + "properties": { + "ignore": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "plugin": { + "type": "array", + "items": { + "type": "string" + } + }, + "snapshot": { + "type": "boolean" + }, + "share": { + "description": "Control sharing behavior:'manual' allows manual sharing via commands, 'auto' enables automatic sharing, 'disabled' disables all sharing", + "type": "string", + "enum": ["manual", "auto", "disabled"] + }, + "autoshare": { + "description": "@deprecated Use 'share' field instead. Share newly created sessions automatically", + "type": "boolean" + }, + "autoupdate": { + "description": "Automatically update to the latest version. Set to true to auto-update, false to disable, or 'notify' to show update notifications", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "string", + "const": "notify" + } + ] + }, + "disabled_providers": { + "description": "Disable providers that are loaded automatically", + "type": "array", + "items": { + "type": "string" + } + }, + "enabled_providers": { + "description": "When set, ONLY these providers will be enabled. All other providers will be ignored", + "type": "array", + "items": { + "type": "string" + } + }, + "model": { + "description": "Model to use in the format of provider/model, eg anthropic/claude-2", + "type": "string" + }, + "small_model": { + "description": "Small model to use for tasks like title generation in the format of provider/model", + "type": "string" + }, + "default_agent": { + "description": "Default agent to use when none is specified. Must be a primary agent. Falls back to 'build' if not set or if the specified agent is invalid.", + "type": "string" + }, + "username": { + "description": "Custom username to display in conversations instead of system username", + "type": "string" + }, + "mode": { + "description": "@deprecated Use `agent` field instead.", + "type": "object", + "properties": { + "build": { + "$ref": "#/components/schemas/AgentConfig" + }, + "plan": { + "$ref": "#/components/schemas/AgentConfig" + } + }, + "additionalProperties": { + "$ref": "#/components/schemas/AgentConfig" + } + }, + "agent": { + "description": "Agent configuration, see https://opencode.ai/docs/agent", + "type": "object", + "properties": { + "plan": { + "$ref": "#/components/schemas/AgentConfig" + }, + "build": { + "$ref": "#/components/schemas/AgentConfig" + }, + "general": { + "$ref": "#/components/schemas/AgentConfig" + }, + "explore": { + "$ref": "#/components/schemas/AgentConfig" + }, + "title": { + "$ref": "#/components/schemas/AgentConfig" + }, + "summary": { + "$ref": "#/components/schemas/AgentConfig" + }, + "compaction": { + "$ref": "#/components/schemas/AgentConfig" + } + }, + "additionalProperties": { + "$ref": "#/components/schemas/AgentConfig" + } + }, + "provider": { + "description": "Custom provider configurations and model overrides", + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "$ref": "#/components/schemas/ProviderConfig" + } + }, + "mcp": { + "description": "MCP (Model Context Protocol) server configurations", + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "anyOf": [ + { + "$ref": "#/components/schemas/McpLocalConfig" + }, + { + "$ref": "#/components/schemas/McpRemoteConfig" + } + ] + } + }, + "formatter": { + "anyOf": [ + { + "type": "boolean", + "const": false + }, + { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "object", + "properties": { + "disabled": { + "type": "boolean" + }, + "command": { + "type": "array", + "items": { + "type": "string" + } + }, + "environment": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "string" + } + }, + "extensions": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + ] + }, + "lsp": { + "anyOf": [ + { + "type": "boolean", + "const": false + }, + { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "anyOf": [ + { + "type": "object", + "properties": { + "disabled": { + "type": "boolean", + "const": true + } + }, + "required": ["disabled"] + }, + { + "type": "object", + "properties": { + "command": { + "type": "array", + "items": { + "type": "string" + } + }, + "extensions": { + "type": "array", + "items": { + "type": "string" + } + }, + "disabled": { + "type": "boolean" + }, + "env": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "string" + } + }, + "initialization": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": ["command"] + } + ] + } + } + ] + }, + "instructions": { + "description": "Additional instruction files or patterns to include", + "type": "array", + "items": { + "type": "string" + } + }, + "layout": { + "$ref": "#/components/schemas/LayoutConfig" + }, + "permission": { + "$ref": "#/components/schemas/PermissionConfig" + }, + "tools": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "boolean" + } + }, + "enterprise": { + "type": "object", + "properties": { + "url": { + "description": "Enterprise URL", + "type": "string" + } + } + }, + "compaction": { + "type": "object", + "properties": { + "auto": { + "description": "Enable automatic compaction when context is full (default: true)", + "type": "boolean" + }, + "prune": { + "description": "Enable pruning of old tool outputs (default: true)", + "type": "boolean" + } + } + }, + "experimental": { + "type": "object", + "properties": { + "hook": { + "type": "object", + "properties": { + "file_edited": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "array", + "items": { + "type": "object", + "properties": { + "command": { + "type": "array", + "items": { + "type": "string" + } + }, + "environment": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "string" + } + } + }, + "required": ["command"] + } + } + }, + "session_completed": { + "type": "array", + "items": { + "type": "object", + "properties": { + "command": { + "type": "array", + "items": { + "type": "string" + } + }, + "environment": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "string" + } + } + }, + "required": ["command"] + } + } + } + }, + "chatMaxRetries": { + "description": "Number of retries for chat completions on failure", + "type": "number" + }, + "disable_paste_summary": { + "type": "boolean" + }, + "batch_tool": { + "description": "Enable the batch tool", + "type": "boolean" + }, + "openTelemetry": { + "description": "Enable OpenTelemetry spans for AI SDK calls (using the 'experimental_telemetry' flag)", + "type": "boolean" + }, + "primary_tools": { + "description": "Tools that should only be available to primary agents.", + "type": "array", + "items": { + "type": "string" + } + }, + "continue_loop_on_deny": { + "description": "Continue the agent loop when a tool call is denied", + "type": "boolean" + }, + "mcp_timeout": { + "description": "Timeout in milliseconds for model context protocol (MCP) requests", + "type": "integer", + "exclusiveMinimum": 0, + "maximum": 9007199254740991 + } + } + } + }, + "additionalProperties": false + }, + "ToolIDs": { + "type": "array", + "items": { + "type": "string" + } + }, + "ToolListItem": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "parameters": {} + }, + "required": ["id", "description", "parameters"] + }, + "ToolList": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ToolListItem" + } + }, + "Path": { + "type": "object", + "properties": { + "home": { + "type": "string" + }, + "state": { + "type": "string" + }, + "config": { + "type": "string" + }, + "worktree": { + "type": "string" + }, + "directory": { + "type": "string" + } + }, + "required": ["home", "state", "config", "worktree", "directory"] + }, + "VcsInfo": { + "type": "object", + "properties": { + "branch": { + "type": "string" + } + }, + "required": ["branch"] + }, + "TextPartInput": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "const": "text" + }, + "text": { + "type": "string" + }, + "synthetic": { + "type": "boolean" + }, + "ignored": { + "type": "boolean" + }, + "time": { + "type": "object", + "properties": { + "start": { + "type": "number" + }, + "end": { + "type": "number" + } + }, + "required": ["start"] + }, + "metadata": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": ["type", "text"] + }, + "FilePartInput": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "const": "file" + }, + "mime": { + "type": "string" + }, + "filename": { + "type": "string" + }, + "url": { + "type": "string" + }, + "source": { + "$ref": "#/components/schemas/FilePartSource" + } + }, + "required": ["type", "mime", "url"] + }, + "AgentPartInput": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "const": "agent" + }, + "name": { + "type": "string" + }, + "source": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "start": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "end": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + } + }, + "required": ["value", "start", "end"] + } + }, + "required": ["type", "name"] + }, + "SubtaskPartInput": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "const": "subtask" + }, + "prompt": { + "type": "string" + }, + "description": { + "type": "string" + }, + "agent": { + "type": "string" + }, + "command": { + "type": "string" + } + }, + "required": ["type", "prompt", "description", "agent"] + }, + "Command": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "agent": { + "type": "string" + }, + "model": { + "type": "string" + }, + "mcp": { + "type": "boolean" + }, + "template": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "string" + } + ] + }, + "subtask": { + "type": "boolean" + }, + "hints": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": ["name", "template", "hints"] + }, + "Model": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "providerID": { + "type": "string" + }, + "api": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "url": { + "type": "string" + }, + "npm": { + "type": "string" + } + }, + "required": ["id", "url", "npm"] + }, + "name": { + "type": "string" + }, + "family": { + "type": "string" + }, + "capabilities": { + "type": "object", + "properties": { + "temperature": { + "type": "boolean" + }, + "reasoning": { + "type": "boolean" + }, + "attachment": { + "type": "boolean" + }, + "toolcall": { + "type": "boolean" + }, + "input": { + "type": "object", + "properties": { + "text": { + "type": "boolean" + }, + "audio": { + "type": "boolean" + }, + "image": { + "type": "boolean" + }, + "video": { + "type": "boolean" + }, + "pdf": { + "type": "boolean" + } + }, + "required": ["text", "audio", "image", "video", "pdf"] + }, + "output": { + "type": "object", + "properties": { + "text": { + "type": "boolean" + }, + "audio": { + "type": "boolean" + }, + "image": { + "type": "boolean" + }, + "video": { + "type": "boolean" + }, + "pdf": { + "type": "boolean" + } + }, + "required": ["text", "audio", "image", "video", "pdf"] + }, + "interleaved": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "field": { + "type": "string", + "enum": ["reasoning_content", "reasoning_details"] + } + }, + "required": ["field"] + } + ] + } + }, + "required": [ + "temperature", + "reasoning", + "attachment", + "toolcall", + "input", + "output", + "interleaved" + ] + }, + "cost": { + "type": "object", + "properties": { + "input": { + "type": "number" + }, + "output": { + "type": "number" + }, + "cache": { + "type": "object", + "properties": { + "read": { + "type": "number" + }, + "write": { + "type": "number" + } + }, + "required": ["read", "write"] + }, + "experimentalOver200K": { + "type": "object", + "properties": { + "input": { + "type": "number" + }, + "output": { + "type": "number" + }, + "cache": { + "type": "object", + "properties": { + "read": { + "type": "number" + }, + "write": { + "type": "number" + } + }, + "required": ["read", "write"] + } + }, + "required": ["input", "output", "cache"] + } + }, + "required": ["input", "output", "cache"] + }, + "limit": { + "type": "object", + "properties": { + "context": { + "type": "number" + }, + "output": { + "type": "number" + } + }, + "required": ["context", "output"] + }, + "status": { + "type": "string", + "enum": ["alpha", "beta", "deprecated", "active"] + }, + "options": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + }, + "headers": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "string" + } + }, + "release_date": { + "type": "string" + }, + "variants": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + } + }, + "required": [ + "id", + "providerID", + "api", + "name", + "capabilities", + "cost", + "limit", + "status", + "options", + "headers", + "release_date" + ] + }, + "Provider": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "source": { + "type": "string", + "enum": ["env", "config", "custom", "api"] + }, + "env": { + "type": "array", + "items": { + "type": "string" + } + }, + "key": { + "type": "string" + }, + "options": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + }, + "models": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "$ref": "#/components/schemas/Model" + } + } + }, + "required": ["id", "name", "source", "env", "options", "models"] + }, + "ProviderAuthMethod": { + "type": "object", + "properties": { + "type": { + "anyOf": [ + { + "type": "string", + "const": "oauth" + }, + { + "type": "string", + "const": "api" + } + ] + }, + "label": { + "type": "string" + } + }, + "required": ["type", "label"] + }, + "ProviderAuthAuthorization": { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "method": { + "anyOf": [ + { + "type": "string", + "const": "auto" + }, + { + "type": "string", + "const": "code" + } + ] + }, + "instructions": { + "type": "string" + } + }, + "required": ["url", "method", "instructions"] + }, + "Symbol": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "kind": { + "type": "number" + }, + "location": { + "type": "object", + "properties": { + "uri": { + "type": "string" + }, + "range": { + "$ref": "#/components/schemas/Range" + } + }, + "required": ["uri", "range"] + } + }, + "required": ["name", "kind", "location"] + }, + "FileNode": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "path": { + "type": "string" + }, + "absolute": { + "type": "string" + }, + "type": { + "type": "string", + "enum": ["file", "directory"] + }, + "ignored": { + "type": "boolean" + } + }, + "required": ["name", "path", "absolute", "type", "ignored"] + }, + "FileContent": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "text" + }, + "content": { + "type": "string" + }, + "diff": { + "type": "string" + }, + "patch": { + "type": "object", + "properties": { + "oldFileName": { + "type": "string" + }, + "newFileName": { + "type": "string" + }, + "oldHeader": { + "type": "string" + }, + "newHeader": { + "type": "string" + }, + "hunks": { + "type": "array", + "items": { + "type": "object", + "properties": { + "oldStart": { + "type": "number" + }, + "oldLines": { + "type": "number" + }, + "newStart": { + "type": "number" + }, + "newLines": { + "type": "number" + }, + "lines": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": ["oldStart", "oldLines", "newStart", "newLines", "lines"] + } + }, + "index": { + "type": "string" + } + }, + "required": ["oldFileName", "newFileName", "hunks"] + }, + "encoding": { + "type": "string", + "const": "base64" + }, + "mimeType": { + "type": "string" + } + }, + "required": ["type", "content"] + }, + "File": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "added": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "removed": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991 + }, + "status": { + "type": "string", + "enum": ["added", "deleted", "modified"] + } + }, + "required": ["path", "added", "removed", "status"] + }, + "Agent": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "mode": { + "type": "string", + "enum": ["subagent", "primary", "all"] + }, + "native": { + "type": "boolean" + }, + "hidden": { + "type": "boolean" + }, + "topP": { + "type": "number" + }, + "temperature": { + "type": "number" + }, + "color": { + "type": "string" + }, + "permission": { + "$ref": "#/components/schemas/PermissionRuleset" + }, + "model": { + "type": "object", + "properties": { + "modelID": { + "type": "string" + }, + "providerID": { + "type": "string" + } + }, + "required": ["modelID", "providerID"] + }, + "prompt": { + "type": "string" + }, + "options": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + }, + "steps": { + "type": "integer", + "exclusiveMinimum": 0, + "maximum": 9007199254740991 + } + }, + "required": ["name", "mode", "permission", "options"] + }, + "MCPStatusConnected": { + "type": "object", + "properties": { + "status": { + "type": "string", + "const": "connected" + } + }, + "required": ["status"] + }, + "MCPStatusDisabled": { + "type": "object", + "properties": { + "status": { + "type": "string", + "const": "disabled" + } + }, + "required": ["status"] + }, + "MCPStatusFailed": { + "type": "object", + "properties": { + "status": { + "type": "string", + "const": "failed" + }, + "error": { + "type": "string" + } + }, + "required": ["status", "error"] + }, + "MCPStatusNeedsAuth": { + "type": "object", + "properties": { + "status": { + "type": "string", + "const": "needs_auth" + } + }, + "required": ["status"] + }, + "MCPStatusNeedsClientRegistration": { + "type": "object", + "properties": { + "status": { + "type": "string", + "const": "needs_client_registration" + }, + "error": { + "type": "string" + } + }, + "required": ["status", "error"] + }, + "MCPStatus": { + "anyOf": [ + { + "$ref": "#/components/schemas/MCPStatusConnected" + }, + { + "$ref": "#/components/schemas/MCPStatusDisabled" + }, + { + "$ref": "#/components/schemas/MCPStatusFailed" + }, + { + "$ref": "#/components/schemas/MCPStatusNeedsAuth" + }, + { + "$ref": "#/components/schemas/MCPStatusNeedsClientRegistration" + } + ] + }, + "LSPStatus": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "root": { + "type": "string" + }, + "status": { + "anyOf": [ + { + "type": "string", + "const": "connected" + }, + { + "type": "string", + "const": "error" + } + ] + } + }, + "required": ["id", "name", "root", "status"] + }, + "FormatterStatus": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "extensions": { + "type": "array", + "items": { + "type": "string" + } + }, + "enabled": { + "type": "boolean" + } + }, + "required": ["name", "extensions", "enabled"] + }, + "OAuth": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "oauth" + }, + "refresh": { + "type": "string" + }, + "access": { + "type": "string" + }, + "expires": { + "type": "number" + }, + "enterpriseUrl": { + "type": "string" + } + }, + "required": ["type", "refresh", "access", "expires"] + }, + "ApiAuth": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "api" + }, + "key": { + "type": "string" + } + }, + "required": ["type", "key"] + }, + "WellKnownAuth": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "wellknown" + }, + "key": { + "type": "string" + }, + "token": { + "type": "string" + } + }, + "required": ["type", "key", "token"] + }, + "Auth": { + "anyOf": [ + { + "$ref": "#/components/schemas/OAuth" + }, + { + "$ref": "#/components/schemas/ApiAuth" + }, + { + "$ref": "#/components/schemas/WellKnownAuth" + } + ] + } + } + } +} diff --git a/dev/package.json b/dev/package.json index d37fb99467..cf3ec74e88 100644 --- a/dev/package.json +++ b/dev/package.json @@ -12,6 +12,7 @@ "@hey-api/codegen-core": "workspace:*", "@hey-api/openapi-python": "workspace:*", "@hey-api/openapi-ts": "workspace:*", + "@msw/source": "0.6.1", "@opencode-ai/sdk": "1.2.27", "@orpc/contract": "1.13.9", "@pinia/colada": "0.19.1", diff --git a/dev/playground.ts b/dev/playground.ts index 20a61adf64..18f2824711 100644 --- a/dev/playground.ts +++ b/dev/playground.ts @@ -1,10 +1,12 @@ import type { DefinePlugin, IR } from '@hey-api/openapi-ts'; +import { fromOpenApi } from '@msw/source/open-api'; import { setupServer } from 'msw/node'; import { client } from './gen/typescript/client.gen'; // import { createOpencode } from '@opencode-ai/sdk'; -import { createMswHandlers, handleTuiPublish } from './gen/typescript/msw.gen'; +import { createMswHandlers } from './gen/typescript/msw.gen'; import { OpenCode } from './gen/typescript/sdk.gen'; +import spec from './opencode.json'; type MyPluginConfig = { readonly name: 'myplugin' }; type MyPlugin = DefinePlugin; @@ -19,30 +21,65 @@ export const handler: MyPlugin['Handler'] = ({ plugin }) => { }); }; +const sourceHandlers = await fromOpenApi({ + ...(spec as any), + basePath: 'https://api.example.com', +}); const handlers = createMswHandlers({ baseUrl: 'https://api.example.com', }); const server = setupServer( - // ...handlers.all({ - // // overrides: { - // // tuiPublish: { - // // result: true, - // // }, - // // }, - // }), - handleTuiPublish({ - result: false, - }), - handlers.one.tuiPublish( - { - result: false, - // status: 200, - }, - { - // ... + // ...sourceHandlers, + ...handlers.all({ + one: { + // projectUpdate(info) { + // console.log('Received request for projectUpdate with info:', info); + // }, + projectUpdate: [ + (info) => { + console.log('Received request for projectUpdate with info:', info); + }, + // { + // result: { + // id: '123', + // name: 'Updated Project Name', + // time: { + // created: 1678900000000, + // updated: 1678900000000, + // }, + // worktree: 'main', + // icon: { + // url: 'https://example.com/icon.png', + // color: 'blue', + // }, + // vcs: 'git', + // }, + // status: 200, + // }, + { + // baseUrl: 'https://api.example.com', + }, + ], + // projectUpdate: { + // result: { + // id: '123', + // name: 'Updated Project Name', + // time: { + // created: 1678900000000, + // updated: 1678900000000, + // }, + // worktree: 'main', + // icon: { + // url: 'https://example.com/icon.png', + // color: 'blue', + // }, + // vcs: 'git', + // }, + // }, }, - ), + }), + // handlers.one.projectUpdate(), ); server.listen(); @@ -53,17 +90,27 @@ async function run() { baseUrl: 'https://api.example.com', }); const sdk = new OpenCode({ client }); - const published = await sdk.tui.publish({ - body: { - properties: { - message: 'Hello from Hey API OpenAPI TypeScript Playground!', - variant: 'success', - }, - type: 'tui.toast.show', - }, + // const published = await sdk.tui.publish({ + // body: { + // properties: { + // message: 'Hello from Hey API OpenAPI TypeScript Playground!', + // variant: 'success', + // }, + // type: 'tui.toast.show', + // }, + // directory: 'main', + // }); + // console.log('Published:', published.data, published.error); + const project = await sdk.project.update({ + projectID: '123', directory: 'main', + icon: { + color: 'blue', + url: 'https://example.com/icon.png', + }, + name: 'Updated Project Name', }); - console.log('Published:', published.data, published.error); + console.log('Updated Project:', project.data, project.error); } run(); diff --git a/packages/openapi-ts/src/plugins/msw/v2/plugin.ts b/packages/openapi-ts/src/plugins/msw/v2/plugin.ts index 839bfd0edf..ee646a342d 100644 --- a/packages/openapi-ts/src/plugins/msw/v2/plugin.ts +++ b/packages/openapi-ts/src/plugins/msw/v2/plugin.ts @@ -33,7 +33,12 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { const symbolAll = plugin.symbol('all'); const symbolFactory = plugin.symbol('createMswHandlers'); + const symbolHandler = plugin.symbol('Handler'); + const symbolInvoke = plugin.symbol('invoke'); const symbolOne = plugin.symbol('one'); + const symbolOverrideValue = plugin.symbol('OverrideValue'); + const symbolWrap = plugin.symbol('wrap'); + const oneObject = $.object().pretty(); const oneType = $.type.object(); const handlerInfo: Array = []; @@ -48,25 +53,13 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { plugin, }); - const symbolResponse = plugin.symbol('resolver'); - const symbolOptions = plugin.symbol('options'); const name = operation.id; oneType.prop(name, (p) => p .type($(symbolHandler).typeofType()) .$if(plugin.config.comments && getOperationComment(operation), (f, v) => f.doc(v)), ); - oneObject.prop( - name, - $.func() - .param(symbolResponse) - .param(symbolOptions) - .do( - $(symbolHandler) - .call(symbolResponse, $.object().spread('config').spread(symbolOptions)) - .return(), - ), - ); + oneObject.prop(name, $(symbolWrap).call(symbolHandler)); handlerInfo.push({ name, path: operation.path }); }, { @@ -94,16 +87,21 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { .func() .param('options', (p) => p.optional().type( - $.type.object().prop('overrides', (p) => + $.type.object().prop('one', (p) => p.optional().type( $.type .mapped('K') .key($.type.operator().keyof($.type(symbolHandlerFactoriesType))) .optional() .type( - $.type('Parameters') - .generic($.type(symbolHandlerFactoriesType).idx('K')) - .idx($.type.literal(0)), + $.type.or( + $.type('Parameters') + .generic($.type(symbolHandlerFactoriesType).idx('K')) + .idx($.type.literal(0)), + $.type('Parameters').generic( + $.type(symbolHandlerFactoriesType).idx('K'), + ), + ), ), ), ), @@ -121,6 +119,32 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { .param('config', (p) => p.type(symbolRequestHandlerOptions).assign($.object())) .returns(symbolFactoryReturnType) .do( + $.type + .alias(symbolHandler) + .generic('R') + .type( + $.type + .func() + .param('resolver', (p) => p.optional().type('R')) + .param('options', (p) => p.optional().type(symbolRequestHandlerOptions)) + .returns(symbolHttpHandler), + ), + $.func(symbolWrap) + .generic('R') + .param('handler', (p) => p.type($.type(symbolHandler).generic('R'))) + .returns($.type(symbolHandler).generic('R')) + .do( + $.return( + $.func() + .param('resolver') + .param('options') + .do( + $.return( + $('handler').call('resolver', $.object().spread('config').spread('options')), + ), + ), + ), + ), $.const(symbolOne) .type($.type(symbolFactoryReturnType).idx($.type.literal(factoryResultOne))) .assign(oneObject), @@ -130,10 +154,39 @@ export const handlerV2: MswPlugin['Handler'] = ({ plugin }) => { $.func() .param('options', (p) => p.assign($.object())) .do( - $.const('overrides').assign($('options').attr('overrides').coalesce($.object())), + $.type + .alias(symbolOverrideValue) + .generic('R') + .type( + $.type.or( + $.type('R'), + $.type.tuple( + $.type.tupleMember('resolver').optional().type('R'), + $.type.tupleMember('options').optional().type(symbolRequestHandlerOptions), + ), + ), + ), + $.func(symbolInvoke) + .generic('R') + .param('fn', (p) => p.type($.type(symbolHandler).generic('R'))) + .param('override', (p) => + p.optional().type($.type(symbolOverrideValue).generic('R')), + ) + .returns(symbolHttpHandler) + .do( + $.return( + $.ternary($('Array').attr('isArray').call('override')) + .do($('fn').call($.spread('override'))) + .otherwise($('fn').call('override')), + ), + ), + $.const('overrides').assign($('options').attr('one').coalesce($.object())), $.array( ...sortHandlers(handlerInfo).map((info) => - $(symbolOne).attr(info.name).call($('overrides').attr(info.name)), + $(symbolInvoke).call( + $(symbolOne).attr(info.name), + $('overrides').attr(info.name), + ), ), ).return(), ), diff --git a/packages/openapi-ts/src/ts-dsl/expr/array.ts b/packages/openapi-ts/src/ts-dsl/expr/array.ts index 1d1c820079..3e13c1da6b 100644 --- a/packages/openapi-ts/src/ts-dsl/expr/array.ts +++ b/packages/openapi-ts/src/ts-dsl/expr/array.ts @@ -6,19 +6,19 @@ import { TsDsl } from '../base'; import { AsMixin } from '../mixins/as'; import { ExprMixin } from '../mixins/expr'; import { LayoutMixin } from '../mixins/layout'; +import { SpreadMixin } from '../mixins/spread'; import { LiteralTsDsl } from './literal'; -const Mixed = AsMixin(ExprMixin(LayoutMixin(TsDsl))); +export type ArrayExpr = string | number | boolean | MaybeTsDsl; + +const Mixed = AsMixin(ExprMixin(LayoutMixin(SpreadMixin(TsDsl)))); export class ArrayTsDsl extends Mixed { readonly '~dsl' = 'ArrayTsDsl'; - protected _elements: Array< - | { expr: MaybeTsDsl; kind: 'element' } - | { expr: MaybeTsDsl; kind: 'spread' } - > = []; + protected _elements: Array> = []; - constructor(...exprs: Array>) { + constructor(...exprs: Array) { super(); this.elements(...exprs); } @@ -26,40 +26,29 @@ export class ArrayTsDsl extends Mixed { override analyze(ctx: AnalysisContext): void { super.analyze(ctx); for (const item of this._elements) { - ctx.analyze(item.expr); + ctx.analyze(item); } } /** Adds a single array element. */ - element(expr: string | number | boolean | MaybeTsDsl): this { + element(expr: ArrayExpr): this { const node = typeof expr === 'string' || typeof expr === 'number' || typeof expr === 'boolean' ? new LiteralTsDsl(expr) : expr; - this._elements.push({ expr: node, kind: 'element' }); + this._elements.push(node); return this; } /** Adds multiple array elements. */ - elements(...exprs: ReadonlyArray>): this { + elements(...exprs: ReadonlyArray): this { for (const expr of exprs) this.element(expr); return this; } - /** Adds a spread element (`...expr`). */ - spread(expr: MaybeTsDsl): this { - this._elements.push({ expr, kind: 'spread' }); - return this; - } - override toAst() { - const elements = this._elements.map((item) => { - const node = this.$node(item.expr); - return item.kind === 'spread' ? ts.factory.createSpreadElement(node) : node; - }); - return ts.factory.createArrayLiteralExpression( - elements, + this._elements.map((item) => this.$node(item)), this.$multiline(this._elements.length), ); } diff --git a/packages/openapi-ts/src/ts-dsl/expr/attr.ts b/packages/openapi-ts/src/ts-dsl/expr/attr.ts index a00077bd75..3d6c19d4ed 100644 --- a/packages/openapi-ts/src/ts-dsl/expr/attr.ts +++ b/packages/openapi-ts/src/ts-dsl/expr/attr.ts @@ -8,6 +8,7 @@ import { AsMixin } from '../mixins/as'; import { ExprMixin } from '../mixins/expr'; import { OperatorMixin } from '../mixins/operator'; import { OptionalMixin } from '../mixins/optional'; +import { SpreadMixin } from '../mixins/spread'; import { TokenTsDsl } from '../token'; import { f } from '../utils/factories'; import { regexp } from '../utils/regexp'; @@ -18,7 +19,9 @@ export type AttrCtor = (left: AttrLeft, right: NodeName) => AttrTsDsl; const Mixed = AsMixin( ExprMixin( - OperatorMixin(OptionalMixin(TsDsl)), + OperatorMixin( + OptionalMixin(SpreadMixin(TsDsl)), + ), ), ); diff --git a/packages/openapi-ts/src/ts-dsl/expr/call.ts b/packages/openapi-ts/src/ts-dsl/expr/call.ts index 9eff383e2b..c1001024e9 100644 --- a/packages/openapi-ts/src/ts-dsl/expr/call.ts +++ b/packages/openapi-ts/src/ts-dsl/expr/call.ts @@ -7,6 +7,7 @@ import { TsDsl } from '../base'; import { ArgsMixin } from '../mixins/args'; import { AsMixin } from '../mixins/as'; import { ExprMixin } from '../mixins/expr'; +import { SpreadMixin } from '../mixins/spread'; import { TypeArgsMixin } from '../mixins/type-args'; import { f } from '../utils/factories'; @@ -14,7 +15,7 @@ export type CallArgs = ReadonlyArray; export type CallCallee = NodeName | MaybeTsDsl; export type CallCtor = (callee: CallCallee, ...args: CallArgs) => CallTsDsl; -const Mixed = ArgsMixin(AsMixin(ExprMixin(TypeArgsMixin(TsDsl)))); +const Mixed = ArgsMixin(AsMixin(ExprMixin(SpreadMixin(TypeArgsMixin(TsDsl))))); export class CallTsDsl extends Mixed { readonly '~dsl' = 'CallTsDsl'; diff --git a/packages/openapi-ts/src/ts-dsl/expr/expr.ts b/packages/openapi-ts/src/ts-dsl/expr/expr.ts index 01374884e8..0a9a58dfef 100644 --- a/packages/openapi-ts/src/ts-dsl/expr/expr.ts +++ b/packages/openapi-ts/src/ts-dsl/expr/expr.ts @@ -7,11 +7,12 @@ import { TsDsl } from '../base'; import { AsMixin } from '../mixins/as'; import { ExprMixin } from '../mixins/expr'; import { OperatorMixin } from '../mixins/operator'; +import { SpreadMixin } from '../mixins/spread'; import { TypeExprMixin } from '../mixins/type-expr'; type Id = NodeName | MaybeTsDsl; -const Mixed = AsMixin(ExprMixin(OperatorMixin(TypeExprMixin(TsDsl)))); +const Mixed = AsMixin(ExprMixin(OperatorMixin(SpreadMixin(TypeExprMixin(TsDsl))))); export class ExprTsDsl extends Mixed { readonly '~dsl' = 'ExprTsDsl'; diff --git a/packages/openapi-ts/src/ts-dsl/expr/new.ts b/packages/openapi-ts/src/ts-dsl/expr/new.ts index 909dad9493..cc857da7d3 100644 --- a/packages/openapi-ts/src/ts-dsl/expr/new.ts +++ b/packages/openapi-ts/src/ts-dsl/expr/new.ts @@ -7,6 +7,7 @@ import { TsDsl } from '../base'; import { ArgsMixin } from '../mixins/args'; import { AsMixin } from '../mixins/as'; import { ExprMixin } from '../mixins/expr'; +import { SpreadMixin } from '../mixins/spread'; import { TypeArgsMixin } from '../mixins/type-args'; import { f } from '../utils/factories'; @@ -14,7 +15,7 @@ export type NewArgs = ReadonlyArray; export type NewExpr = NodeName | MaybeTsDsl; export type NewCtor = (expr: NewExpr, ...args: NewArgs) => NewTsDsl; -const Mixed = ArgsMixin(AsMixin(ExprMixin(TypeArgsMixin(TsDsl)))); +const Mixed = ArgsMixin(AsMixin(ExprMixin(SpreadMixin(TypeArgsMixin(TsDsl))))); export class NewTsDsl extends Mixed { readonly '~dsl' = 'NewTsDsl'; diff --git a/packages/openapi-ts/src/ts-dsl/expr/spread.ts b/packages/openapi-ts/src/ts-dsl/expr/spread.ts new file mode 100644 index 0000000000..084eea422b --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/expr/spread.ts @@ -0,0 +1,34 @@ +import type { AnalysisContext, NodeName, Ref } from '@hey-api/codegen-core'; +import { ref } from '@hey-api/codegen-core'; +import ts from 'typescript'; + +import type { MaybeTsDsl } from '../base'; +import { TsDsl } from '../base'; +import { f } from '../utils/factories'; + +export type SpreadExpr = NodeName | MaybeTsDsl; +export type SpreadCtor = (expr: SpreadExpr) => SpreadTsDsl; + +const Mixed = TsDsl; + +export class SpreadTsDsl extends Mixed { + readonly '~dsl' = 'SpreadTsDsl'; + + protected _expr: Ref; + + constructor(expr: SpreadExpr) { + super(); + this._expr = ref(expr); + } + + override analyze(ctx: AnalysisContext): void { + super.analyze(ctx); + ctx.analyze(this._expr); + } + + override toAst() { + return ts.factory.createSpreadElement(this.$node(this._expr)); + } +} + +f.spread.set((...args) => new SpreadTsDsl(...args)); diff --git a/packages/openapi-ts/src/ts-dsl/index.ts b/packages/openapi-ts/src/ts-dsl/index.ts index e8b14a4eb1..282f25c398 100644 --- a/packages/openapi-ts/src/ts-dsl/index.ts +++ b/packages/openapi-ts/src/ts-dsl/index.ts @@ -29,6 +29,7 @@ import { PostfixTsDsl } from './expr/postfix'; import { PrefixTsDsl } from './expr/prefix'; import { ObjectPropTsDsl } from './expr/prop'; import { RegExpTsDsl } from './expr/regexp'; +import { SpreadTsDsl } from './expr/spread'; import { TemplateTsDsl } from './expr/template'; import { TernaryTsDsl } from './expr/ternary'; import { TypeOfExprTsDsl } from './expr/typeof'; @@ -62,6 +63,7 @@ import { TypeParamTsDsl } from './type/param'; import { TypeQueryTsDsl } from './type/query'; import { TypeTemplateTsDsl } from './type/template'; import { TypeTupleTsDsl } from './type/tuple'; +import { TypeTupleMemberTsDsl } from './type/tuple-member'; import { LazyTsDsl } from './utils/lazy'; const tsDsl = { @@ -214,6 +216,9 @@ const tsDsl = { /** Creates a setter method declaration. */ setter: (...args: ConstructorParameters) => new SetterTsDsl(...args), + /** Creates a spread element from an expression (e.g., `...expr`). */ + spread: (...args: ConstructorParameters) => new SpreadTsDsl(...args), + /** Wraps an expression or statement-like value into a `StmtTsDsl`. */ stmt: (...args: ConstructorParameters) => new StmtTsDsl(...args), @@ -288,6 +293,10 @@ const tsDsl = { /** Creates a tuple type (e.g., [A, B, C]). */ tuple: (...args: ConstructorParameters) => new TypeTupleTsDsl(...args), + + /** Creates a named tuple element (e.g., `[resolver?: R]`). */ + tupleMember: (...args: ConstructorParameters) => + new TypeTupleMemberTsDsl(...args), }, ), diff --git a/packages/openapi-ts/src/ts-dsl/mixins/args.ts b/packages/openapi-ts/src/ts-dsl/mixins/args.ts index e299df0196..da6f382f50 100644 --- a/packages/openapi-ts/src/ts-dsl/mixins/args.ts +++ b/packages/openapi-ts/src/ts-dsl/mixins/args.ts @@ -5,11 +5,11 @@ import type ts from 'typescript'; import type { MaybeTsDsl } from '../base'; import type { BaseCtor, MixinCtor } from './types'; -type Arg = NodeName | MaybeTsDsl; +type Arg = NodeName | MaybeTsDsl; export interface ArgsMethods extends Node { - /** Renders the arguments into an array of `Expression`s. */ - $args(): ReadonlyArray; + /** Renders the arguments into an array of `Expression`s or `SpreadElement`s. */ + $args(): ReadonlyArray; /** Adds a single expression argument. */ arg(arg: Arg | undefined): this; /** Adds one or more expression arguments. */ @@ -42,7 +42,7 @@ export function ArgsMixin>(Base: TB return this; } - protected $args(): ReadonlyArray { + protected $args(): ReadonlyArray { return this.$node(this._args).map((arg) => this.$node(arg)); } } diff --git a/packages/openapi-ts/src/ts-dsl/mixins/spread.ts b/packages/openapi-ts/src/ts-dsl/mixins/spread.ts new file mode 100644 index 0000000000..e2417972f2 --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/mixins/spread.ts @@ -0,0 +1,24 @@ +import type { AnalysisContext, Node } from '@hey-api/codegen-core'; +import type ts from 'typescript'; + +import { f } from '../utils/factories'; +import type { BaseCtor, MixinCtor } from './types'; + +export interface SpreadMethods extends Node { + /** Produces a spread element from the current expression (e.g., `...expr`). */ + spread(): ReturnType; +} + +export function SpreadMixin>(Base: TBase) { + abstract class Spread extends Base { + override analyze(ctx: AnalysisContext): void { + super.analyze(ctx); + } + + protected spread(): ReturnType { + return f.spread(this); + } + } + + return Spread as unknown as MixinCtor; +} diff --git a/packages/openapi-ts/src/ts-dsl/type/tuple-member.ts b/packages/openapi-ts/src/ts-dsl/type/tuple-member.ts new file mode 100644 index 0000000000..cb02f9d7e6 --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/type/tuple-member.ts @@ -0,0 +1,64 @@ +import type { AnalysisContext, NodeName, NodeScope, Ref } from '@hey-api/codegen-core'; +import { ref } from '@hey-api/codegen-core'; +import ts from 'typescript'; + +import type { TypeTsDsl as TypeTsDslType } from '../base'; +import { TsDsl } from '../base'; +import { OptionalMixin } from '../mixins/optional'; +import { f } from '../utils/factories'; + +export type TypeTupleMemberCtor = (name: NodeName) => TypeTupleMemberTsDsl; + +const Mixed = OptionalMixin(TsDsl); + +export class TypeTupleMemberTsDsl extends Mixed { + readonly '~dsl' = 'TypeTupleMemberTsDsl'; + override scope: NodeScope = 'type'; + + protected _type?: Ref; + + constructor(name: NodeName) { + super(); + this.name.set(name); + } + + override analyze(ctx: AnalysisContext): void { + super.analyze(ctx); + ctx.analyze(this.name); + ctx.analyze(this._type); + } + + /** Returns true when all required builder calls are present. */ + get isValid(): boolean { + return !this.missingRequiredCalls().length; + } + + type(node: NodeName | TypeTsDslType): this { + this._type = ref(node); + return this; + } + + override toAst() { + this.$validate(); + return ts.factory.createNamedTupleMember( + undefined, + this.$node(this.name) as ts.Identifier, + this._optional ? ts.factory.createToken(ts.SyntaxKind.QuestionToken) : undefined, + this.$type(this._type!), + ); + } + + $validate(): asserts this { + const missing = this.missingRequiredCalls(); + if (!missing.length) return; + throw new Error(`Tuple member missing ${missing.join(' and ')}`); + } + + private missingRequiredCalls(): Array { + const missing: Array = []; + if (!this._type) missing.push('.\u200Btype()'); + return missing; + } +} + +f.type.tupleMember.set((name) => new TypeTupleMemberTsDsl(name)); diff --git a/packages/openapi-ts/src/ts-dsl/type/tuple.ts b/packages/openapi-ts/src/ts-dsl/type/tuple.ts index 6577650eb2..2d1b5a0eb7 100644 --- a/packages/openapi-ts/src/ts-dsl/type/tuple.ts +++ b/packages/openapi-ts/src/ts-dsl/type/tuple.ts @@ -4,15 +4,17 @@ import ts from 'typescript'; import type { TypeTsDsl } from '../base'; import { TsDsl } from '../base'; +export type TupleElement = string | ts.TypeNode | TypeTsDsl; + const Mixed = TsDsl; export class TypeTupleTsDsl extends Mixed { readonly '~dsl' = 'TypeTupleTsDsl'; override scope: NodeScope = 'type'; - protected _elements: Array = []; + protected _elements: Array = []; - constructor(...nodes: Array) { + constructor(...nodes: Array) { super(); this.elements(...nodes); } @@ -24,7 +26,7 @@ export class TypeTupleTsDsl extends Mixed { } } - elements(...types: Array): this { + elements(...types: Array): this { this._elements.push(...types); return this; } diff --git a/packages/openapi-ts/src/ts-dsl/utils/factories.ts b/packages/openapi-ts/src/ts-dsl/utils/factories.ts index c6defabf7f..bad16c31bf 100644 --- a/packages/openapi-ts/src/ts-dsl/utils/factories.ts +++ b/packages/openapi-ts/src/ts-dsl/utils/factories.ts @@ -4,12 +4,14 @@ import type { AttrCtor } from '../expr/attr'; import type { AwaitCtor } from '../expr/await'; import type { CallCtor } from '../expr/call'; import type { NewCtor } from '../expr/new'; +import type { SpreadCtor } from '../expr/spread'; import type { TypeOfExprCtor } from '../expr/typeof'; import type { ReturnCtor } from '../stmt/return'; import type { TypeExprCtor } from '../type/expr'; import type { TypeIdxCtor } from '../type/idx'; import type { TypeOperatorCtor } from '../type/operator'; import type { TypeQueryCtor } from '../type/query'; +import type { TypeTupleMemberCtor } from '../type/tuple-member'; type Ctor = (...args: Array) => any; @@ -56,6 +58,9 @@ export const f = { /** Factory for creating return statements. */ return: createFactory('return'), + /** Factory for creating spread expressions (e.g., `...expr`). */ + spread: createFactory('spread'), + /** Factories for creating type nodes. */ type: { /** Factory for creating basic type references or type expressions (e.g., Foo or Foo). */ @@ -69,6 +74,9 @@ export const f = { /** Factory for creating type query nodes (e.g., `typeof Foo`). */ query: createFactory('type.query'), + + /** Factory for creating named tuple elements (e.g., `[resolver?: R]`). */ + tupleMember: createFactory('type.tupleMember'), }, /** Factory for creating `typeof` expressions (e.g., `typeof value`). */ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b781770e0a..4a56df3555 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -115,6 +115,9 @@ importers: '@hey-api/openapi-ts': specifier: workspace:* version: link:../packages/openapi-ts + '@msw/source': + specifier: 0.6.1 + version: 0.6.1(msw@2.12.14(@types/node@25.2.1)(typescript@5.9.3)) '@opencode-ai/sdk': specifier: 1.2.27 version: 1.2.27 @@ -3897,6 +3900,10 @@ packages: '@noble/hashes': optional: true + '@faker-js/faker@8.4.1': + resolution: {integrity: sha512-XQ3cU+Q8Uqmrbf2e0cIC/QN43sTBSC8KF12u29Mb47tWrt2hAgBXSgpZMj4Ao8Uk0iJcU99QsOCaIL8934obCg==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0, npm: '>=6.14.13'} + '@fastify/ajv-compiler@4.0.5': resolution: {integrity: sha512-KoWKW+MhvfTRWL4qrhUwAAZoaChluo0m0vbiJlGMt2GXvL4LVPQEjt8kSpHI3IBq5Rez8fg+XeH3cneztq+C7A==} @@ -4673,6 +4680,16 @@ packages: cpu: [x64] os: [win32] + '@msw/source@0.6.1': + resolution: {integrity: sha512-eKX3x85/Ejo2HoOgfilfB4cMqdzie58F+7vMvuKH2N0m4Hs3GhfqjLSLlWXkNx09O7NIUSilygmrlEeWOPDNUA==} + engines: {node: '>=20'} + peerDependencies: + msw: ^2.10.0 + + '@mswjs/interceptors@0.40.0': + resolution: {integrity: sha512-EFd6cVbHsgLa6wa4RljGj6Wk75qoHxUSyc5asLyyPSyuhIcdS2Q3Phw6ImS1q+CkALthJRShiYfKANcQMuMqsQ==} + engines: {node: '>=18'} + '@mswjs/interceptors@0.41.3': resolution: {integrity: sha512-cXu86tF4VQVfwz8W1SPbhoRyHJkti6mjH/XJIxp40jhO4j2k1m4KYrEykxqWPkFF3vrK4rgQppBh//AwyGSXPA==} engines: {node: '>=18'} @@ -7255,6 +7272,22 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@stoplight/json@3.21.7': + resolution: {integrity: sha512-xcJXgKFqv/uCEgtGlPxy3tPA+4I+ZI4vAuMJ885+ThkTHFVkC+0Fm58lA9NlsyjnkpxFh4YiQWpH+KefHdbA0A==} + engines: {node: '>=8.3.0'} + + '@stoplight/ordered-object-literal@1.0.5': + resolution: {integrity: sha512-COTiuCU5bgMUtbIFBuyyh2/yVVzlr5Om0v5utQDgBCuQUOPgU1DwoffkTfg4UBQOvByi5foF4w4T+H9CoRe5wg==} + engines: {node: '>=8'} + + '@stoplight/path@1.3.2': + resolution: {integrity: sha512-lyIc6JUlUA8Ve5ELywPC8I2Sdnh1zc1zmbYgVarhXIp9YeAB0ReeqmGEOWNtlHkbP2DAA1AL65Wfn2ncjK/jtQ==} + engines: {node: '>=8'} + + '@stoplight/types@13.20.0': + resolution: {integrity: sha512-2FNTv05If7ib79VPDA/r9eUet76jewXFH2y2K5vuge6SXbRHtWBhcaRmu+6QpF4/WRNoJj5XYRSwLGXDxysBGA==} + engines: {node: ^12.20 || >=14.13} + '@sveltejs/adapter-auto@4.0.0': resolution: {integrity: sha512-kmuYSQdD2AwThymQF0haQhM8rE5rhutQXG4LNbnbShwhMO4qQGnKaaTy+88DuNSuoQDi58+thpq8XpHc1+oEKQ==} peerDependencies: @@ -7670,6 +7703,9 @@ packages: '@types/express@4.17.21': resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==} + '@types/har-format@1.2.16': + resolution: {integrity: sha512-fluxdy7ryD3MV6h8pTfTYpy/xQzCFC7m89nOH9y94cNqJ1mDIDPut7MnRHI3F6qRmh/cT2fUjG1MLdCNb4hE9A==} + '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} @@ -8568,6 +8604,9 @@ packages: '@yarnpkg/lockfile@1.1.0': resolution: {integrity: sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==} + '@yellow-ticket/seed-json-schema@0.1.7': + resolution: {integrity: sha512-OQkwqMt6VMMExa74b6ODrDwMyvTAQ4wXXodb0kJuQhI1DkhFm4PIUwj9D1foE5gZwfyGlogtTZsjhyQzhwkyyg==} + abbrev@2.0.0: resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -9914,6 +9953,10 @@ packages: resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==} engines: {node: '>=12'} + drange@1.1.1: + resolution: {integrity: sha512-pYxfDYpued//QpnLIm4Avk7rsNtAtQkUES2cwAYSvD/wd2pKD71gN2Ebj3e7klzXwjocvE8c5vx/1fxwpqmSxA==} + engines: {node: '>=4'} + dts-resolver@2.1.3: resolution: {integrity: sha512-bihc7jPC90VrosXNzK0LTE2cuLP6jr0Ro8jk+kMugHReJVLIpHz/xadeq3MhuwyO4TD4OA3L1Q8pBBFRc08Tsw==} engines: {node: '>=20.19.0'} @@ -11585,6 +11628,9 @@ packages: engines: {node: '>=6'} hasBin: true + jsonc-parser@2.2.1: + resolution: {integrity: sha512-o6/yDBYccGvTz1+QFevz6l6OBZ2+fMVu2JZ9CIhzsYRX4mjaK5IyX9eldUdCmga16zlgQxyrj5pt9kzuj2C02w==} + jsonc-parser@3.3.1: resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} @@ -13498,6 +13544,10 @@ packages: radix3@1.1.2: resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} + randexp@0.5.3: + resolution: {integrity: sha512-U+5l2KrcMNOUPYvazA3h5ekF80FHTUG+87SEAmHZmolh1M+i/WyTCxVzmi+tidIa1tM4BSe8g2Y/D3loWDjj+w==} + engines: {node: '>=4'} + randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} @@ -13736,6 +13786,10 @@ packages: resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} engines: {node: '>=18'} + ret@0.2.2: + resolution: {integrity: sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==} + engines: {node: '>=4'} + ret@0.5.0: resolution: {integrity: sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==} engines: {node: '>=10'} @@ -13890,6 +13944,9 @@ packages: safe-regex2@5.0.0: resolution: {integrity: sha512-YwJwe5a51WlK7KbOJREPdjNrpViQBI3p4T50lfwPuDhZnE3XGVTlGvi+aolc5+RvxDD6bnUmjVsU9n1eboLUYw==} + safe-stable-stringify@1.1.1: + resolution: {integrity: sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw==} + safe-stable-stringify@2.5.0: resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} engines: {node: '>=10'} @@ -15282,6 +15339,10 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + utility-types@3.11.0: + resolution: {integrity: sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==} + engines: {node: '>= 4'} + utils-merge@1.0.1: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} @@ -18634,6 +18695,8 @@ snapshots: '@exodus/bytes@1.11.0': {} + '@faker-js/faker@8.4.1': {} + '@fastify/ajv-compiler@4.0.5': dependencies: ajv: 8.17.1 @@ -19454,6 +19517,26 @@ snapshots: '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3': optional: true + '@msw/source@0.6.1(msw@2.12.14(@types/node@25.2.1)(typescript@5.9.3))': + dependencies: + '@mswjs/interceptors': 0.40.0 + '@stoplight/json': 3.21.7 + '@types/har-format': 1.2.16 + '@yellow-ticket/seed-json-schema': 0.1.7 + msw: 2.12.14(@types/node@25.2.1)(typescript@5.9.3) + openapi-types: 12.1.3 + outvariant: 1.4.3 + yaml: 2.8.2 + + '@mswjs/interceptors@0.40.0': + dependencies: + '@open-draft/deferred-promise': 2.2.0 + '@open-draft/logger': 0.3.0 + '@open-draft/until': 2.1.0 + is-node-process: 1.2.0 + outvariant: 1.4.3 + strict-event-emitter: 0.5.1 + '@mswjs/interceptors@0.41.3': dependencies: '@open-draft/deferred-promise': 2.2.0 @@ -22238,6 +22321,24 @@ snapshots: '@standard-schema/spec@1.1.0': {} + '@stoplight/json@3.21.7': + dependencies: + '@stoplight/ordered-object-literal': 1.0.5 + '@stoplight/path': 1.3.2 + '@stoplight/types': 13.20.0 + jsonc-parser: 2.2.1 + lodash: 4.17.23 + safe-stable-stringify: 1.1.1 + + '@stoplight/ordered-object-literal@1.0.5': {} + + '@stoplight/path@1.3.2': {} + + '@stoplight/types@13.20.0': + dependencies: + '@types/json-schema': 7.0.15 + utility-types: 3.11.0 + '@sveltejs/adapter-auto@4.0.0(@sveltejs/kit@2.17.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.9)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.19.9)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))': dependencies: '@sveltejs/kit': 2.17.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.9)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)))(svelte@5.19.9)(vite@7.3.1(@types/node@25.2.1)(jiti@2.6.1)(less@4.4.2)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.2)) @@ -22643,6 +22744,8 @@ snapshots: '@types/qs': 6.14.0 '@types/serve-static': 1.15.8 + '@types/har-format@1.2.16': {} + '@types/hast@3.0.4': dependencies: '@types/unist': 3.0.3 @@ -23900,6 +24003,13 @@ snapshots: '@yarnpkg/lockfile@1.1.0': {} + '@yellow-ticket/seed-json-schema@0.1.7': + dependencies: + '@faker-js/faker': 8.4.1 + '@types/json-schema': 7.0.15 + outvariant: 1.4.3 + randexp: 0.5.3 + abbrev@2.0.0: {} abbrev@3.0.1: {} @@ -25325,6 +25435,8 @@ snapshots: dotenv@17.2.3: {} + drange@1.1.1: {} + dts-resolver@2.1.3(oxc-resolver@11.19.1): optionalDependencies: oxc-resolver: 11.19.1 @@ -27502,6 +27614,8 @@ snapshots: json5@2.2.3: {} + jsonc-parser@2.2.1: {} + jsonc-parser@3.3.1: {} jsonfile@4.0.0: @@ -30290,6 +30404,11 @@ snapshots: radix3@1.1.2: {} + randexp@0.5.3: + dependencies: + drange: 1.1.1 + ret: 0.2.2 + randombytes@2.1.0: dependencies: safe-buffer: 5.2.1 @@ -30573,6 +30692,8 @@ snapshots: onetime: 7.0.0 signal-exit: 4.1.0 + ret@0.2.2: {} + ret@0.5.0: {} retry@0.12.0: {} @@ -30792,6 +30913,8 @@ snapshots: dependencies: ret: 0.5.0 + safe-stable-stringify@1.1.1: {} + safe-stable-stringify@2.5.0: {} safer-buffer@2.1.2: {} @@ -32594,6 +32717,8 @@ snapshots: util-deprecate@1.0.2: {} + utility-types@3.11.0: {} + utils-merge@1.0.1: {} uuid@11.1.0: {} From e0f4a570bab672d4251413f9c54d8096ffaf3763 Mon Sep 17 00:00:00 2001 From: Lubos Date: Mon, 30 Mar 2026 04:25:03 +0200 Subject: [PATCH 14/16] chore: add responseFallback option --- dev/playground.ts | 7 +++-- packages/openapi-ts/src/plugins/msw/config.ts | 1 + .../src/plugins/msw/shared/handler.ts | 31 +++++++++++++++++-- .../src/plugins/msw/shared/types.ts | 7 ++++- packages/openapi-ts/src/plugins/msw/types.ts | 12 +++++++ 5 files changed, 52 insertions(+), 6 deletions(-) diff --git a/dev/playground.ts b/dev/playground.ts index 18f2824711..2a3a24515b 100644 --- a/dev/playground.ts +++ b/dev/playground.ts @@ -37,9 +37,10 @@ const server = setupServer( // console.log('Received request for projectUpdate with info:', info); // }, projectUpdate: [ - (info) => { - console.log('Received request for projectUpdate with info:', info); - }, + undefined, + // (info) => { + // console.log('Received request for projectUpdate with info:', info); + // }, // { // result: { // id: '123', diff --git a/packages/openapi-ts/src/plugins/msw/config.ts b/packages/openapi-ts/src/plugins/msw/config.ts index 86e2c1e375..4357b09d13 100644 --- a/packages/openapi-ts/src/plugins/msw/config.ts +++ b/packages/openapi-ts/src/plugins/msw/config.ts @@ -8,6 +8,7 @@ export const defaultConfig: MswPlugin['Config'] = { baseUrl: '*', comments: true, includeInEntry: false, + responseFallback: 'error', valueSources: ['example'], }, dependencies: ['@hey-api/typescript'], diff --git a/packages/openapi-ts/src/plugins/msw/shared/handler.ts b/packages/openapi-ts/src/plugins/msw/shared/handler.ts index e86cd6907b..25d06d38bd 100644 --- a/packages/openapi-ts/src/plugins/msw/shared/handler.ts +++ b/packages/openapi-ts/src/plugins/msw/shared/handler.ts @@ -98,7 +98,7 @@ function createHandlerFunc({ responseOrResolverType: ReturnType; }): Symbol { const symbolHttp = plugin.external('msw.http'); - const symbolHttpResponse = plugin.external('msw.HttpResponse'); + // const symbolHttpResponse = plugin.external('msw.HttpResponse'); const symbolResolver = plugin.symbol('resolver'); const symbolOptions = plugin.symbol('options'); @@ -108,6 +108,15 @@ function createHandlerFunc({ }), ); + const notImplementedResponse = $.new( + 'Response', + $.literal('Not Implemented'), + $.object() + .pretty() + .prop('status', $.literal(501)) + .prop('statusText', $.literal('Not Implemented')), + ); + const handlerFunc = $.func(symbol) .export() .$if(plugin.config.comments && getOperationComment(operation), (f, v) => f.doc(v)) @@ -162,7 +171,25 @@ function createHandlerFunc({ ), ), ) - .do($.new(symbolHttpResponse, $.literal(null)).return()), + .$if( + plugin.config.responseFallback === 'error', + (f) => + f.do( + $.if( + $(symbolOptions) + .attr('responseFallback') + .optional() + .eq($.literal('passthrough')), + ).do($.return()), + notImplementedResponse.return(), + ), + (f) => + f.do( + $.if( + $(symbolOptions).attr('responseFallback').optional().eq($.literal('error')), + ).do(notImplementedResponse.return()), + ), + ), symbolOptions, ) .generics(paramsType, bodyType) diff --git a/packages/openapi-ts/src/plugins/msw/shared/types.ts b/packages/openapi-ts/src/plugins/msw/shared/types.ts index 2296499ab6..dd90179873 100644 --- a/packages/openapi-ts/src/plugins/msw/shared/types.ts +++ b/packages/openapi-ts/src/plugins/msw/shared/types.ts @@ -17,7 +17,12 @@ export function createRequestHandlerOptions(plugin: MswPlugin['Instance']): Symb .type( $.type.and( $.type(plugin.external('msw.RequestHandlerOptions')), - $.type.object().prop('baseUrl', (p) => p.type('string').optional()), + $.type + .object() + .prop('baseUrl', (p) => p.type('string').optional()) + .prop('responseFallback', (p) => + p.type($.type.or($.type.literal('error'), $.type.literal('passthrough'))).optional(), + ), ), ); plugin.node(node); diff --git a/packages/openapi-ts/src/plugins/msw/types.ts b/packages/openapi-ts/src/plugins/msw/types.ts index 331d57038f..28dd8c7a1f 100644 --- a/packages/openapi-ts/src/plugins/msw/types.ts +++ b/packages/openapi-ts/src/plugins/msw/types.ts @@ -17,6 +17,16 @@ export type UserConfig = Plugin.Name<'msw'> & * @default '*' */ baseUrl?: string | number | boolean; + /** + * Behavior when a response cannot be generated (no response defined + * in the specification, or configured value sources cannot produce a value). + * + * - `'error'` - throw an error (fail fast) + * - `'passthrough'` - let the request pass through to the network + * + * @default 'error' + */ + responseFallback?: 'error' | 'passthrough'; /** * Sources for default parameter values in handler factories. Order determines * priority (earlier entries take precedence). @@ -34,6 +44,8 @@ export type Config = Plugin.Name<'msw'> & Plugin.Exports & { /** Set a default base URL when creating the handlers. */ baseUrl: string | number | boolean; + /** Behavior when a response cannot be generated. */ + responseFallback: 'error' | 'passthrough'; /** Sources for default parameter values in handler factories. */ valueSources: ReadonlyArray<'example'>; }; From 7f335ffb2477797cec5deebb8d4608b98ca27352 Mon Sep 17 00:00:00 2001 From: Lubos Date: Mon, 30 Mar 2026 05:53:08 +0200 Subject: [PATCH 15/16] test: update snapshots --- dev/playground.ts | 9 + .../v2/__snapshots__/3.1.x/default/msw.gen.ts | 1589 ++++++++++++++--- .../response-example-disabled/msw.gen.ts | 133 +- .../3.1.x/response-example/msw.gen.ts | 130 +- .../3.1.x/response-types/msw.gen.ts | 89 +- .../v2/__snapshots__/3.1.x/servers/msw.gen.ts | 100 +- .../src/plugins/msw/shared/handler.ts | 44 +- .../src/plugins/msw/shared/response.ts | 45 + 8 files changed, 1687 insertions(+), 452 deletions(-) create mode 100644 packages/openapi-ts/src/plugins/msw/shared/response.ts diff --git a/dev/playground.ts b/dev/playground.ts index 2a3a24515b..00625afd95 100644 --- a/dev/playground.ts +++ b/dev/playground.ts @@ -81,6 +81,15 @@ const server = setupServer( }, }), // handlers.one.projectUpdate(), + handlers.one.globalEvent({ + result: { + directory: 'main', + payload: { + properties: {}, + type: 'global.disposed', + }, + }, + }), ); server.listen(); diff --git a/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/default/msw.gen.ts b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/default/msw.gen.ts index af22e4629f..d2b04275c0 100644 --- a/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/default/msw.gen.ts +++ b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/default/msw.gen.ts @@ -1,282 +1,1363 @@ // This file is auto-generated by @hey-api/openapi-ts -import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions } from 'msw'; +import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions as RequestHandlerOptions2 } from 'msw'; import type { ApiVVersionODataControllerCountResponses, CallWithDuplicateResponsesResponses, CallWithNoContentResponseResponses, CallWithParametersData, CallWithResponseAndNoContentResponseResponses, CallWithResponsesResponses, CallWithResultFromHeaderResponses, CallWithWeirdParameterNamesData, ComplexParamsData, ComplexParamsResponses, ComplexTypesResponses, DummyAResponses, DummyBResponses, FileResponseResponses, GetApiVbyApiVersionSimpleOperationResponses, GetCallWithOptionalParamData, ImportData, ImportResponses, MultipartRequestData, MultipartResponseResponses, NonAsciiæøåÆøÅöôêÊ字符串Responses, PostApiVbyApiVersionFormDataData, PostApiVbyApiVersionRequestBodyData, PostCallWithOptionalParamData, PostCallWithOptionalParamResponses, PutWithFormUrlEncodedData, TestErrorCodeResponses, TypesResponses, UploadFileData, UploadFileResponses } from './types.gen'; -const resolveToNull = () => new HttpResponse(null); +export type RequestHandlerOptions = RequestHandlerOptions2 & { + baseUrl?: string; + responseFallback?: 'error' | 'passthrough'; +}; -type OptionalHttpHandlerFactory = (responseOrResolver?: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; +/** + * Handler for the `GET /api/v{api-version}/no+tag` operation. + */ +export function handleExport(resolver?: HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.get(`${options?.baseUrl ?? '*'}/api/v:apiVersion/no+tag`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} -type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; +/** + * Handler for the `PATCH /api/v{api-version}/no+tag` operation. + */ +export function handlePatchApiVbyApiVersionNoTag(resolver?: HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.patch(`${options?.baseUrl ?? '*'}/api/v:apiVersion/no+tag`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} -type ToResponseUnion = { - [K in Extract]: { - status: K; - result: T[K]; - }; -}[Extract]; +/** + * Handler for the `POST /api/v{api-version}/no+tag` operation. + */ +export function handleImport(resolver?: { + result: ImportResponses[200]; + status?: 200; +} | HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.post(`${options?.baseUrl ?? '*'}/api/v:apiVersion/no+tag`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} -export type SingleHandlerFactories = { - exportMock: OptionalHttpHandlerFactory; - patchApiVbyApiVersionNoTagMock: OptionalHttpHandlerFactory; - importMock: HttpHandlerFactory<{ - result: ImportResponses[200]; - status?: 200; - } | HttpResponseResolver>; - fooWowMock: OptionalHttpHandlerFactory; - apiVVersionODataControllerCountMock: HttpHandlerFactory<{ - result: ApiVVersionODataControllerCountResponses[200]; - status?: 200; - } | HttpResponseResolver>; - getApiVbyApiVersionSimpleOperationMock: HttpHandlerFactory<{ - result: GetApiVbyApiVersionSimpleOperationResponses[200]; - status?: 200; - } | HttpResponseResolver<{ - apiVersion: string; - }, never>>; - deleteCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; - getCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; - headCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; - optionsCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; - patchCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; - postCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; - putCallWithoutParametersAndResponseMock: OptionalHttpHandlerFactory; - deleteFooMock: OptionalHttpHandlerFactory, options?: RequestHandlerOptions): HttpHandler { + return http.put(`${options?.baseUrl ?? '*'}/api/v:apiVersion/no+tag`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `GET /api/v{api-version}/simple/$count` operation. + */ +export function handleApiVVersionODataControllerCount(resolver?: { + result: ApiVVersionODataControllerCountResponses[200]; + status?: 200; +} | HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.get(`${options?.baseUrl ?? '*'}/api/v:apiVersion/simple/$count`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `GET /api/v{api-version}/simple:operation` operation. + */ +export function handleGetApiVbyApiVersionSimpleOperation(resolver?: { + result: GetApiVbyApiVersionSimpleOperationResponses[200]; + status?: 200; +} | HttpResponseResolver<{ + foo_param: string; +}, never>, options?: RequestHandlerOptions): HttpHandler { + return http.get<{ + foo_param: string; + }, never>(`${options?.baseUrl ?? '*'}/api/v:apiVersion/simple\\:operation`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `DELETE /api/v{api-version}/simple` operation. + */ +export function handleDeleteCallWithoutParametersAndResponse(resolver?: HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.delete(`${options?.baseUrl ?? '*'}/api/v:apiVersion/simple`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `GET /api/v{api-version}/simple` operation. + */ +export function handleGetCallWithoutParametersAndResponse(resolver?: HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.get(`${options?.baseUrl ?? '*'}/api/v:apiVersion/simple`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `HEAD /api/v{api-version}/simple` operation. + */ +export function handleHeadCallWithoutParametersAndResponse(resolver?: HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.head(`${options?.baseUrl ?? '*'}/api/v:apiVersion/simple`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `OPTIONS /api/v{api-version}/simple` operation. + */ +export function handleOptionsCallWithoutParametersAndResponse(resolver?: HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.options(`${options?.baseUrl ?? '*'}/api/v:apiVersion/simple`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `PATCH /api/v{api-version}/simple` operation. + */ +export function handlePatchCallWithoutParametersAndResponse(resolver?: HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.patch(`${options?.baseUrl ?? '*'}/api/v:apiVersion/simple`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `POST /api/v{api-version}/simple` operation. + */ +export function handlePostCallWithoutParametersAndResponse(resolver?: HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.post(`${options?.baseUrl ?? '*'}/api/v:apiVersion/simple`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `PUT /api/v{api-version}/simple` operation. + */ +export function handlePutCallWithoutParametersAndResponse(resolver?: HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.put(`${options?.baseUrl ?? '*'}/api/v:apiVersion/simple`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `DELETE /api/v{api-version}/foo/{foo_param}/bar/{BarParam}` operation. + */ +export function handleDeleteFoo(resolver?: HttpResponseResolver<{ + foo_param: string; + BarParam: string; +}, never>, options?: RequestHandlerOptions): HttpHandler { + return http.delete<{ foo_param: string; BarParam: string; - }, never>>; - callWithDescriptionsMock: OptionalHttpHandlerFactory; - deprecatedCallMock: OptionalHttpHandlerFactory; - callWithParametersMock: OptionalHttpHandlerFactory(`${options?.baseUrl ?? '*'}/api/v:apiVersion/foo/:foo_param/bar/:BarParam`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `POST /api/v{api-version}/descriptions` operation. + */ +export function handleCallWithDescriptions(resolver?: HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.post(`${options?.baseUrl ?? '*'}/api/v:apiVersion/descriptions`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `POST /api/v{api-version}/parameters/deprecated` operation. + */ +export function handleDeprecatedCall(resolver?: HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.post(`${options?.baseUrl ?? '*'}/api/v:apiVersion/parameters/deprecated`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `POST /api/v{api-version}/parameters/{parameterPath}` operation. + */ +export function handleCallWithParameters(resolver?: HttpResponseResolver<{ + parameterPath: string; + apiVersion: string; +}, CallWithParametersData['body']>, options?: RequestHandlerOptions): HttpHandler { + return http.post<{ parameterPath: string; - }, CallWithParametersData['body']>>; - callWithWeirdParameterNamesMock: OptionalHttpHandlerFactory(`${options?.baseUrl ?? '*'}/api/v:apiVersion/parameters/:parameterPath`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `POST /api/v{api-version}/parameters/{parameter.path.1}/{parameter-path-2}/{PARAMETER-PATH-3}` operation. + */ +export function handleCallWithWeirdParameterNames(resolver?: HttpResponseResolver<{ + parameterPath1: string; + parameterPath2: string; + PARAMETERPATH3: string; + apiVersion: string; +}, CallWithWeirdParameterNamesData['body']>, options?: RequestHandlerOptions): HttpHandler { + return http.post<{ parameterPath1: string; parameterPath2: string; PARAMETERPATH3: string; - }, CallWithWeirdParameterNamesData['body']>>; - getCallWithOptionalParamMock: OptionalHttpHandlerFactory>; - postCallWithOptionalParamMock: HttpHandlerFactory<{ - result: PostCallWithOptionalParamResponses[200]; - status?: 200; - } | ToResponseUnion | HttpResponseResolver>; - postApiVbyApiVersionRequestBodyMock: OptionalHttpHandlerFactory>; - postApiVbyApiVersionFormDataMock: OptionalHttpHandlerFactory>; - callWithDefaultParametersMock: OptionalHttpHandlerFactory; - callWithDefaultOptionalParametersMock: OptionalHttpHandlerFactory; - callToTestOrderOfParamsMock: OptionalHttpHandlerFactory; - duplicateNameMock: OptionalHttpHandlerFactory; - duplicateName2Mock: OptionalHttpHandlerFactory; - duplicateName3Mock: OptionalHttpHandlerFactory; - duplicateName4Mock: OptionalHttpHandlerFactory; - callWithNoContentResponseMock: OptionalHttpHandlerFactory<{ - result: CallWithNoContentResponseResponses[204]; - status?: 204; - } | HttpResponseResolver>; - callWithResponseAndNoContentResponseMock: HttpHandlerFactory<{ - result: CallWithResponseAndNoContentResponseResponses[200]; - status?: 200; - } | ToResponseUnion | HttpResponseResolver>; - dummyAMock: HttpHandlerFactory<{ - result: DummyAResponses[200]; - status?: 200; - } | HttpResponseResolver>; - dummyBMock: OptionalHttpHandlerFactory<{ - result: DummyBResponses[204]; - status?: 204; - } | HttpResponseResolver>; - callWithResponseMock: OptionalHttpHandlerFactory; - callWithDuplicateResponsesMock: HttpHandlerFactory<{ - result: CallWithDuplicateResponsesResponses[200]; - status?: 200; - } | ToResponseUnion | HttpResponseResolver>; - callWithResponsesMock: HttpHandlerFactory<{ - result: CallWithResponsesResponses[200]; - status?: 200; - } | ToResponseUnion | HttpResponseResolver>; - collectionFormatMock: OptionalHttpHandlerFactory; - typesMock: HttpHandlerFactory<{ - result: TypesResponses[200]; - status?: 200; - } | ToResponseUnion | HttpResponseResolver<{ - apiVersion: string; - }, never>>; - uploadFileMock: HttpHandlerFactory<{ - result: UploadFileResponses[200]; - status?: 200; - } | HttpResponseResolver<{ apiVersion: string; - }, UploadFileData['body']>>; - fileResponseMock: HttpHandlerFactory<{ - result: FileResponseResponses[200]; - status?: 200; - } | HttpResponseResolver<{ + }, CallWithWeirdParameterNamesData['body']>(`${options?.baseUrl ?? '*'}/api/v:apiVersion/parameters/:parameterPath1/:parameterPath2/:PARAMETERPATH3`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `GET /api/v{api-version}/parameters` operation. + */ +export function handleGetCallWithOptionalParam(resolver?: HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.get(`${options?.baseUrl ?? '*'}/api/v:apiVersion/parameters`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +type ToResponseUnion = { + [K in Extract]: { + status: K; + result: T[K]; + }; +}[Extract]; + +/** + * Handler for the `POST /api/v{api-version}/parameters` operation. + */ +export function handlePostCallWithOptionalParam(resolver?: { + result: PostCallWithOptionalParamResponses[200]; + status?: 200; +} | ToResponseUnion | HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.post(`${options?.baseUrl ?? '*'}/api/v:apiVersion/parameters`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `POST /api/v{api-version}/requestBody` operation. + */ +export function handlePostApiVbyApiVersionRequestBody(resolver?: HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.post(`${options?.baseUrl ?? '*'}/api/v:apiVersion/requestBody`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `POST /api/v{api-version}/formData` operation. + */ +export function handlePostApiVbyApiVersionFormData(resolver?: HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.post(`${options?.baseUrl ?? '*'}/api/v:apiVersion/formData`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `GET /api/v{api-version}/defaults` operation. + */ +export function handleCallWithDefaultParameters(resolver?: HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.get(`${options?.baseUrl ?? '*'}/api/v:apiVersion/defaults`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `POST /api/v{api-version}/defaults` operation. + */ +export function handleCallWithDefaultOptionalParameters(resolver?: HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.post(`${options?.baseUrl ?? '*'}/api/v:apiVersion/defaults`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `PUT /api/v{api-version}/defaults` operation. + */ +export function handleCallToTestOrderOfParams(resolver?: HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.put(`${options?.baseUrl ?? '*'}/api/v:apiVersion/defaults`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `DELETE /api/v{api-version}/duplicate` operation. + */ +export function handleDuplicateName(resolver?: HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.delete(`${options?.baseUrl ?? '*'}/api/v:apiVersion/duplicate`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `GET /api/v{api-version}/duplicate` operation. + */ +export function handleDuplicateName2(resolver?: HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.get(`${options?.baseUrl ?? '*'}/api/v:apiVersion/duplicate`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `POST /api/v{api-version}/duplicate` operation. + */ +export function handleDuplicateName3(resolver?: HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.post(`${options?.baseUrl ?? '*'}/api/v:apiVersion/duplicate`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `PUT /api/v{api-version}/duplicate` operation. + */ +export function handleDuplicateName4(resolver?: HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.put(`${options?.baseUrl ?? '*'}/api/v:apiVersion/duplicate`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `GET /api/v{api-version}/no-content` operation. + */ +export function handleCallWithNoContentResponse(resolver?: { + result: CallWithNoContentResponseResponses[204]; + status?: 204; +} | HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.get(`${options?.baseUrl ?? '*'}/api/v:apiVersion/no-content`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return new HttpResponse(resolver.result ?? null, { status: resolver.status ?? 204 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `GET /api/v{api-version}/multiple-tags/response-and-no-content` operation. + */ +export function handleCallWithResponseAndNoContentResponse(resolver?: { + result: CallWithResponseAndNoContentResponseResponses[200]; + status?: 200; +} | ToResponseUnion | HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.get(`${options?.baseUrl ?? '*'}/api/v:apiVersion/multiple-tags/response-and-no-content`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `GET /api/v{api-version}/multiple-tags/a` operation. + */ +export function handleDummyA(resolver?: { + result: DummyAResponses[200]; + status?: 200; +} | HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.get(`${options?.baseUrl ?? '*'}/api/v:apiVersion/multiple-tags/a`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `GET /api/v{api-version}/multiple-tags/b` operation. + */ +export function handleDummyB(resolver?: { + result: DummyBResponses[204]; + status?: 204; +} | HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.get(`${options?.baseUrl ?? '*'}/api/v:apiVersion/multiple-tags/b`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return new HttpResponse(resolver.result ?? null, { status: resolver.status ?? 204 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `GET /api/v{api-version}/response` operation. + */ +export function handleCallWithResponse(resolver?: HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.get(`${options?.baseUrl ?? '*'}/api/v:apiVersion/response`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `POST /api/v{api-version}/response` operation. + */ +export function handleCallWithDuplicateResponses(resolver?: { + result: CallWithDuplicateResponsesResponses[200]; + status?: 200; +} | ToResponseUnion | HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.post(`${options?.baseUrl ?? '*'}/api/v:apiVersion/response`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `PUT /api/v{api-version}/response` operation. + */ +export function handleCallWithResponses(resolver?: { + result: CallWithResponsesResponses[200]; + status?: 200; +} | ToResponseUnion | HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.put(`${options?.baseUrl ?? '*'}/api/v:apiVersion/response`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `GET /api/v{api-version}/collectionFormat` operation. + */ +export function handleCollectionFormat(resolver?: HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.get(`${options?.baseUrl ?? '*'}/api/v:apiVersion/collectionFormat`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `GET /api/v{api-version}/types` operation. + */ +export function handleTypes(resolver?: { + result: TypesResponses[200]; + status?: 200; +} | ToResponseUnion | HttpResponseResolver<{ + id: string; +}, never>, options?: RequestHandlerOptions): HttpHandler { + return http.get<{ + id: string; + }, never>(`${options?.baseUrl ?? '*'}/api/v:apiVersion/types`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `POST /api/v{api-version}/upload` operation. + */ +export function handleUploadFile(resolver?: { + result: UploadFileResponses[200]; + status?: 200; +} | HttpResponseResolver<{ + apiVersion: string; +}, UploadFileData['body']>, options?: RequestHandlerOptions): HttpHandler { + return http.post<{ apiVersion: string; + }, UploadFileData['body']>(`${options?.baseUrl ?? '*'}/api/v:apiVersion/upload`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `GET /api/v{api-version}/file/{id}` operation. + */ +export function handleFileResponse(resolver?: { + result: FileResponseResponses[200]; + status?: 200; +} | HttpResponseResolver<{ + id: string; + apiVersion: string; +}, never>, options?: RequestHandlerOptions): HttpHandler { + return http.get<{ id: string; - }, never>>; - complexTypesMock: HttpHandlerFactory<{ - result: ComplexTypesResponses[200]; - status?: 200; - } | HttpResponseResolver>; - multipartResponseMock: HttpHandlerFactory<{ - result: MultipartResponseResponses[200]; - status?: 200; - } | HttpResponseResolver>; - multipartRequestMock: OptionalHttpHandlerFactory>; - complexParamsMock: HttpHandlerFactory<{ - result: ComplexParamsResponses[200]; - status?: 200; - } | HttpResponseResolver<{ apiVersion: string; + }, never>(`${options?.baseUrl ?? '*'}/api/v:apiVersion/file/:id`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return new HttpResponse(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `GET /api/v{api-version}/complex` operation. + */ +export function handleComplexTypes(resolver?: { + result: ComplexTypesResponses[200]; + status?: 200; +} | HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.get(`${options?.baseUrl ?? '*'}/api/v:apiVersion/complex`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `GET /api/v{api-version}/multipart` operation. + */ +export function handleMultipartResponse(resolver?: { + result: MultipartResponseResponses[200]; + status?: 200; +} | HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.get(`${options?.baseUrl ?? '*'}/api/v:apiVersion/multipart`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `POST /api/v{api-version}/multipart` operation. + */ +export function handleMultipartRequest(resolver?: HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.post(`${options?.baseUrl ?? '*'}/api/v:apiVersion/multipart`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `PUT /api/v{api-version}/complex/{id}` operation. + */ +export function handleComplexParams(resolver?: { + result: ComplexParamsResponses[200]; + status?: 200; +} | HttpResponseResolver<{ + id: string; + apiVersion: string; +}, ComplexParamsData['body']>, options?: RequestHandlerOptions): HttpHandler { + return http.put<{ id: string; - }, ComplexParamsData['body']>>; - callWithResultFromHeaderMock: OptionalHttpHandlerFactory<{ - result: CallWithResultFromHeaderResponses[200]; - status?: 200; - } | HttpResponseResolver>; - testErrorCodeMock: OptionalHttpHandlerFactory<{ - result: TestErrorCodeResponses[200]; - status?: 200; - } | HttpResponseResolver>; - nonAsciiæøåÆøÅöôêÊ字符串Mock: HttpHandlerFactory<{ - result: NonAsciiæøåÆøÅöôêÊ字符串Responses[200]; - status?: 200; - } | HttpResponseResolver>; - putWithFormUrlEncodedMock: OptionalHttpHandlerFactory>; -}; + apiVersion: string; + }, ComplexParamsData['body']>(`${options?.baseUrl ?? '*'}/api/v:apiVersion/complex/:id`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} -export type GetAllMocksOptions = { - onMissingMock?: 'error' | 'skip'; - overrides?: { - [K in keyof SingleHandlerFactories]?: Parameters[0]; - }; +/** + * Handler for the `POST /api/v{api-version}/header` operation. + */ +export function handleCallWithResultFromHeader(resolver?: { + result: CallWithResultFromHeaderResponses[200]; + status?: 200; +} | HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.post(`${options?.baseUrl ?? '*'}/api/v:apiVersion/header`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return new HttpResponse(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `POST /api/v{api-version}/error` operation. + */ +export function handleTestErrorCode(resolver?: { + result: TestErrorCodeResponses[200]; + status?: 200; +} | HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.post(`${options?.baseUrl ?? '*'}/api/v:apiVersion/error`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return new HttpResponse(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `POST /api/v{api-version}/non-ascii-æøåÆØÅöôêÊ字符串` operation. + */ +export function handleNonAsciiæøåÆøÅöôêÊ字符串(resolver?: { + result: NonAsciiæøåÆøÅöôêÊ字符串Responses[200]; + status?: 200; +} | HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.post(`${options?.baseUrl ?? '*'}/api/v:apiVersion/non-ascii-æøåÆØÅöôêÊ字符串`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +/** + * Handler for the `PUT /api/v{api-version}/non-ascii-æøåÆØÅöôêÊ字符串` operation. + */ +export function handlePutWithFormUrlEncoded(resolver?: HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.put(`${options?.baseUrl ?? '*'}/api/v:apiVersion/non-ascii-æøåÆØÅöôêÊ字符串`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +export type MswHandlerFactories = { + /** + * Handler for the `GET /api/v{api-version}/no+tag` operation. + */ + export: typeof handleExport; + /** + * Handler for the `PATCH /api/v{api-version}/no+tag` operation. + */ + patchApiVbyApiVersionNoTag: typeof handlePatchApiVbyApiVersionNoTag; + /** + * Handler for the `POST /api/v{api-version}/no+tag` operation. + */ + import: typeof handleImport; + /** + * Handler for the `PUT /api/v{api-version}/no+tag` operation. + */ + fooWow: typeof handleFooWow; + /** + * Handler for the `GET /api/v{api-version}/simple/$count` operation. + */ + apiVVersionODataControllerCount: typeof handleApiVVersionODataControllerCount; + /** + * Handler for the `GET /api/v{api-version}/simple:operation` operation. + */ + getApiVbyApiVersionSimpleOperation: typeof handleGetApiVbyApiVersionSimpleOperation; + /** + * Handler for the `DELETE /api/v{api-version}/simple` operation. + */ + deleteCallWithoutParametersAndResponse: typeof handleDeleteCallWithoutParametersAndResponse; + /** + * Handler for the `GET /api/v{api-version}/simple` operation. + */ + getCallWithoutParametersAndResponse: typeof handleGetCallWithoutParametersAndResponse; + /** + * Handler for the `HEAD /api/v{api-version}/simple` operation. + */ + headCallWithoutParametersAndResponse: typeof handleHeadCallWithoutParametersAndResponse; + /** + * Handler for the `OPTIONS /api/v{api-version}/simple` operation. + */ + optionsCallWithoutParametersAndResponse: typeof handleOptionsCallWithoutParametersAndResponse; + /** + * Handler for the `PATCH /api/v{api-version}/simple` operation. + */ + patchCallWithoutParametersAndResponse: typeof handlePatchCallWithoutParametersAndResponse; + /** + * Handler for the `POST /api/v{api-version}/simple` operation. + */ + postCallWithoutParametersAndResponse: typeof handlePostCallWithoutParametersAndResponse; + /** + * Handler for the `PUT /api/v{api-version}/simple` operation. + */ + putCallWithoutParametersAndResponse: typeof handlePutCallWithoutParametersAndResponse; + /** + * Handler for the `DELETE /api/v{api-version}/foo/{foo_param}/bar/{BarParam}` operation. + */ + deleteFoo: typeof handleDeleteFoo; + /** + * Handler for the `POST /api/v{api-version}/descriptions` operation. + */ + callWithDescriptions: typeof handleCallWithDescriptions; + /** + * Handler for the `POST /api/v{api-version}/parameters/deprecated` operation. + */ + deprecatedCall: typeof handleDeprecatedCall; + /** + * Handler for the `POST /api/v{api-version}/parameters/{parameterPath}` operation. + */ + callWithParameters: typeof handleCallWithParameters; + /** + * Handler for the `POST /api/v{api-version}/parameters/{parameter.path.1}/{parameter-path-2}/{PARAMETER-PATH-3}` operation. + */ + callWithWeirdParameterNames: typeof handleCallWithWeirdParameterNames; + /** + * Handler for the `GET /api/v{api-version}/parameters` operation. + */ + getCallWithOptionalParam: typeof handleGetCallWithOptionalParam; + /** + * Handler for the `POST /api/v{api-version}/parameters` operation. + */ + postCallWithOptionalParam: typeof handlePostCallWithOptionalParam; + /** + * Handler for the `POST /api/v{api-version}/requestBody` operation. + */ + postApiVbyApiVersionRequestBody: typeof handlePostApiVbyApiVersionRequestBody; + /** + * Handler for the `POST /api/v{api-version}/formData` operation. + */ + postApiVbyApiVersionFormData: typeof handlePostApiVbyApiVersionFormData; + /** + * Handler for the `GET /api/v{api-version}/defaults` operation. + */ + callWithDefaultParameters: typeof handleCallWithDefaultParameters; + /** + * Handler for the `POST /api/v{api-version}/defaults` operation. + */ + callWithDefaultOptionalParameters: typeof handleCallWithDefaultOptionalParameters; + /** + * Handler for the `PUT /api/v{api-version}/defaults` operation. + */ + callToTestOrderOfParams: typeof handleCallToTestOrderOfParams; + /** + * Handler for the `DELETE /api/v{api-version}/duplicate` operation. + */ + duplicateName: typeof handleDuplicateName; + /** + * Handler for the `GET /api/v{api-version}/duplicate` operation. + */ + duplicateName2: typeof handleDuplicateName2; + /** + * Handler for the `POST /api/v{api-version}/duplicate` operation. + */ + duplicateName3: typeof handleDuplicateName3; + /** + * Handler for the `PUT /api/v{api-version}/duplicate` operation. + */ + duplicateName4: typeof handleDuplicateName4; + /** + * Handler for the `GET /api/v{api-version}/no-content` operation. + */ + callWithNoContentResponse: typeof handleCallWithNoContentResponse; + /** + * Handler for the `GET /api/v{api-version}/multiple-tags/response-and-no-content` operation. + */ + callWithResponseAndNoContentResponse: typeof handleCallWithResponseAndNoContentResponse; + /** + * Handler for the `GET /api/v{api-version}/multiple-tags/a` operation. + */ + dummyA: typeof handleDummyA; + /** + * Handler for the `GET /api/v{api-version}/multiple-tags/b` operation. + */ + dummyB: typeof handleDummyB; + /** + * Handler for the `GET /api/v{api-version}/response` operation. + */ + callWithResponse: typeof handleCallWithResponse; + /** + * Handler for the `POST /api/v{api-version}/response` operation. + */ + callWithDuplicateResponses: typeof handleCallWithDuplicateResponses; + /** + * Handler for the `PUT /api/v{api-version}/response` operation. + */ + callWithResponses: typeof handleCallWithResponses; + /** + * Handler for the `GET /api/v{api-version}/collectionFormat` operation. + */ + collectionFormat: typeof handleCollectionFormat; + /** + * Handler for the `GET /api/v{api-version}/types` operation. + */ + types: typeof handleTypes; + /** + * Handler for the `POST /api/v{api-version}/upload` operation. + */ + uploadFile: typeof handleUploadFile; + /** + * Handler for the `GET /api/v{api-version}/file/{id}` operation. + */ + fileResponse: typeof handleFileResponse; + /** + * Handler for the `GET /api/v{api-version}/complex` operation. + */ + complexTypes: typeof handleComplexTypes; + /** + * Handler for the `GET /api/v{api-version}/multipart` operation. + */ + multipartResponse: typeof handleMultipartResponse; + /** + * Handler for the `POST /api/v{api-version}/multipart` operation. + */ + multipartRequest: typeof handleMultipartRequest; + /** + * Handler for the `PUT /api/v{api-version}/complex/{id}` operation. + */ + complexParams: typeof handleComplexParams; + /** + * Handler for the `POST /api/v{api-version}/header` operation. + */ + callWithResultFromHeader: typeof handleCallWithResultFromHeader; + /** + * Handler for the `POST /api/v{api-version}/error` operation. + */ + testErrorCode: typeof handleTestErrorCode; + /** + * Handler for the `POST /api/v{api-version}/non-ascii-æøåÆØÅöôêÊ字符串` operation. + */ + nonAsciiæøåÆøÅöôêÊ字符串: typeof handleNonAsciiæøåÆøÅöôêÊ字符串; + /** + * Handler for the `PUT /api/v{api-version}/non-ascii-æøåÆØÅöôêÊ字符串` operation. + */ + putWithFormUrlEncoded: typeof handlePutWithFormUrlEncoded; }; -export type MswHandlerFactory = SingleHandlerFactories & { - getAllMocks: (options?: GetAllMocksOptions) => Array; +export type CreateMswHandlersResult = { + all: (options?: { + one?: { + [K in keyof MswHandlerFactories]?: Parameters[0] | Parameters; + }; + }) => ReadonlyArray; + one: MswHandlerFactories; }; -export const createMswHandlerFactory = (config?: { - baseUrl?: string; -}): MswHandlerFactory => { - const baseUrl = config?.baseUrl ?? '*'; - const mocks: SingleHandlerFactories = { - exportMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/no+tag'}`, typeof res === 'function' ? res : resolveToNull, options), - patchApiVbyApiVersionNoTagMock: (res, options) => http.patch(`${baseUrl}${'/api/v:apiVersion/no+tag'}`, typeof res === 'function' ? res : resolveToNull, options), - importMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/no+tag'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - fooWowMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/no+tag'}`, typeof res === 'function' ? res : resolveToNull, options), - apiVVersionODataControllerCountMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/simple/$count'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - getApiVbyApiVersionSimpleOperationMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/simple\\:operation'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - deleteCallWithoutParametersAndResponseMock: (res, options) => http.delete(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), - getCallWithoutParametersAndResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), - headCallWithoutParametersAndResponseMock: (res, options) => http.head(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), - optionsCallWithoutParametersAndResponseMock: (res, options) => http.options(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), - patchCallWithoutParametersAndResponseMock: (res, options) => http.patch(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), - postCallWithoutParametersAndResponseMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), - putCallWithoutParametersAndResponseMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/simple'}`, typeof res === 'function' ? res : resolveToNull, options), - deleteFooMock: (res, options) => http.delete(`${baseUrl}${'/api/v:apiVersion/foo/:foo_param/bar/:BarParam'}`, typeof res === 'function' ? res : resolveToNull, options), - callWithDescriptionsMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/descriptions'}`, typeof res === 'function' ? res : resolveToNull, options), - deprecatedCallMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/parameters/deprecated'}`, typeof res === 'function' ? res : resolveToNull, options), - callWithParametersMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/parameters/:parameterPath'}`, typeof res === 'function' ? res : resolveToNull, options), - callWithWeirdParameterNamesMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/parameters/:parameterPath1/:parameterPath2/:PARAMETERPATH3'}`, typeof res === 'function' ? res : resolveToNull, options), - getCallWithOptionalParamMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/parameters'}`, typeof res === 'function' ? res : resolveToNull, options), - postCallWithOptionalParamMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/parameters'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - postApiVbyApiVersionRequestBodyMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/requestBody'}`, typeof res === 'function' ? res : resolveToNull, options), - postApiVbyApiVersionFormDataMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/formData'}`, typeof res === 'function' ? res : resolveToNull, options), - callWithDefaultParametersMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/defaults'}`, typeof res === 'function' ? res : resolveToNull, options), - callWithDefaultOptionalParametersMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/defaults'}`, typeof res === 'function' ? res : resolveToNull, options), - callToTestOrderOfParamsMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/defaults'}`, typeof res === 'function' ? res : resolveToNull, options), - duplicateNameMock: (res, options) => http.delete(`${baseUrl}${'/api/v:apiVersion/duplicate'}`, typeof res === 'function' ? res : resolveToNull, options), - duplicateName2Mock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/duplicate'}`, typeof res === 'function' ? res : resolveToNull, options), - duplicateName3Mock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/duplicate'}`, typeof res === 'function' ? res : resolveToNull, options), - duplicateName4Mock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/duplicate'}`, typeof res === 'function' ? res : resolveToNull, options), - callWithNoContentResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/no-content'}`, typeof res === 'object' && res.result ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 204 }) : typeof res === 'function' ? res : resolveToNull, options), - callWithResponseAndNoContentResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/multiple-tags/response-and-no-content'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - dummyAMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/multiple-tags/a'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - dummyBMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/multiple-tags/b'}`, typeof res === 'object' && res.result ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 204 }) : typeof res === 'function' ? res : resolveToNull, options), - callWithResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/response'}`, typeof res === 'function' ? res : resolveToNull, options), - callWithDuplicateResponsesMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/response'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - callWithResponsesMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/response'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - collectionFormatMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/collectionFormat'}`, typeof res === 'function' ? res : resolveToNull, options), - typesMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/types'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - uploadFileMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/upload'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - fileResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/file/:id'}`, typeof res === 'object' && res.result ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - complexTypesMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/complex'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - multipartResponseMock: (res, options) => http.get(`${baseUrl}${'/api/v:apiVersion/multipart'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - multipartRequestMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/multipart'}`, typeof res === 'function' ? res : resolveToNull, options), - complexParamsMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/complex/:id'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - callWithResultFromHeaderMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/header'}`, typeof res === 'object' && res.result ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - testErrorCodeMock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/error'}`, typeof res === 'object' && res.result ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - nonAsciiæøåÆøÅöôêÊ字符串Mock: (res, options) => http.post(`${baseUrl}${'/api/v:apiVersion/non-ascii-æøåÆØÅöôêÊ字符串'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - putWithFormUrlEncodedMock: (res, options) => http.put(`${baseUrl}${'/api/v:apiVersion/non-ascii-æøåÆØÅöôêÊ字符串'}`, typeof res === 'function' ? res : resolveToNull, options) +export function createMswHandlers(config: RequestHandlerOptions = {}): CreateMswHandlersResult { + type Handler = (resolver?: R, options?: RequestHandlerOptions) => HttpHandler; + function wrap(handler: Handler): Handler { + return (resolver, options) => handler(resolver, { ...config, ...options }); + } + const one: CreateMswHandlersResult['one'] = { + export: wrap(handleExport), + patchApiVbyApiVersionNoTag: wrap(handlePatchApiVbyApiVersionNoTag), + import: wrap(handleImport), + fooWow: wrap(handleFooWow), + apiVVersionODataControllerCount: wrap(handleApiVVersionODataControllerCount), + getApiVbyApiVersionSimpleOperation: wrap(handleGetApiVbyApiVersionSimpleOperation), + deleteCallWithoutParametersAndResponse: wrap(handleDeleteCallWithoutParametersAndResponse), + getCallWithoutParametersAndResponse: wrap(handleGetCallWithoutParametersAndResponse), + headCallWithoutParametersAndResponse: wrap(handleHeadCallWithoutParametersAndResponse), + optionsCallWithoutParametersAndResponse: wrap(handleOptionsCallWithoutParametersAndResponse), + patchCallWithoutParametersAndResponse: wrap(handlePatchCallWithoutParametersAndResponse), + postCallWithoutParametersAndResponse: wrap(handlePostCallWithoutParametersAndResponse), + putCallWithoutParametersAndResponse: wrap(handlePutCallWithoutParametersAndResponse), + deleteFoo: wrap(handleDeleteFoo), + callWithDescriptions: wrap(handleCallWithDescriptions), + deprecatedCall: wrap(handleDeprecatedCall), + callWithParameters: wrap(handleCallWithParameters), + callWithWeirdParameterNames: wrap(handleCallWithWeirdParameterNames), + getCallWithOptionalParam: wrap(handleGetCallWithOptionalParam), + postCallWithOptionalParam: wrap(handlePostCallWithOptionalParam), + postApiVbyApiVersionRequestBody: wrap(handlePostApiVbyApiVersionRequestBody), + postApiVbyApiVersionFormData: wrap(handlePostApiVbyApiVersionFormData), + callWithDefaultParameters: wrap(handleCallWithDefaultParameters), + callWithDefaultOptionalParameters: wrap(handleCallWithDefaultOptionalParameters), + callToTestOrderOfParams: wrap(handleCallToTestOrderOfParams), + duplicateName: wrap(handleDuplicateName), + duplicateName2: wrap(handleDuplicateName2), + duplicateName3: wrap(handleDuplicateName3), + duplicateName4: wrap(handleDuplicateName4), + callWithNoContentResponse: wrap(handleCallWithNoContentResponse), + callWithResponseAndNoContentResponse: wrap(handleCallWithResponseAndNoContentResponse), + dummyA: wrap(handleDummyA), + dummyB: wrap(handleDummyB), + callWithResponse: wrap(handleCallWithResponse), + callWithDuplicateResponses: wrap(handleCallWithDuplicateResponses), + callWithResponses: wrap(handleCallWithResponses), + collectionFormat: wrap(handleCollectionFormat), + types: wrap(handleTypes), + uploadFile: wrap(handleUploadFile), + fileResponse: wrap(handleFileResponse), + complexTypes: wrap(handleComplexTypes), + multipartResponse: wrap(handleMultipartResponse), + multipartRequest: wrap(handleMultipartRequest), + complexParams: wrap(handleComplexParams), + callWithResultFromHeader: wrap(handleCallWithResultFromHeader), + testErrorCode: wrap(handleTestErrorCode), + nonAsciiæøåÆøÅöôêÊ字符串: wrap(handleNonAsciiæøåÆøÅöôêÊ字符串), + putWithFormUrlEncoded: wrap(handlePutWithFormUrlEncoded) }; - const getAllMocks = (options?: GetAllMocksOptions): Array => { - const onMissingMock = options?.onMissingMock ?? 'skip'; - const overrides = options?.overrides; - const handlers: Array = []; - const addRequiredHandler = (handler: (value: Value | (() => HttpResponse)) => HttpHandler, override: Value | undefined) => { - if (override != null) { - handlers.push(handler(override)); - } - else { - if (onMissingMock === 'error') { - handlers.push(handler(() => new HttpResponse('[heyapi-msw] The mock of this request is not implemented.', { status: 501 }))); - } - } - }; - handlers.push(mocks.deleteFooMock(overrides?.deleteFooMock)); - handlers.push(mocks.callWithWeirdParameterNamesMock(overrides?.callWithWeirdParameterNamesMock)); - addRequiredHandler(mocks.apiVVersionODataControllerCountMock, overrides?.apiVVersionODataControllerCountMock); - handlers.push(mocks.deprecatedCallMock(overrides?.deprecatedCallMock)); - addRequiredHandler(mocks.callWithResponseAndNoContentResponseMock, overrides?.callWithResponseAndNoContentResponseMock); - addRequiredHandler(mocks.dummyAMock, overrides?.dummyAMock); - handlers.push(mocks.dummyBMock(overrides?.dummyBMock)); - handlers.push(mocks.callWithParametersMock(overrides?.callWithParametersMock)); - addRequiredHandler(mocks.fileResponseMock, overrides?.fileResponseMock); - addRequiredHandler(mocks.complexParamsMock, overrides?.complexParamsMock); - handlers.push(mocks.exportMock(overrides?.exportMock)); - handlers.push(mocks.patchApiVbyApiVersionNoTagMock(overrides?.patchApiVbyApiVersionNoTagMock)); - addRequiredHandler(mocks.importMock, overrides?.importMock); - handlers.push(mocks.fooWowMock(overrides?.fooWowMock)); - addRequiredHandler(mocks.getApiVbyApiVersionSimpleOperationMock, overrides?.getApiVbyApiVersionSimpleOperationMock); - handlers.push(mocks.deleteCallWithoutParametersAndResponseMock(overrides?.deleteCallWithoutParametersAndResponseMock)); - handlers.push(mocks.getCallWithoutParametersAndResponseMock(overrides?.getCallWithoutParametersAndResponseMock)); - handlers.push(mocks.headCallWithoutParametersAndResponseMock(overrides?.headCallWithoutParametersAndResponseMock)); - handlers.push(mocks.optionsCallWithoutParametersAndResponseMock(overrides?.optionsCallWithoutParametersAndResponseMock)); - handlers.push(mocks.patchCallWithoutParametersAndResponseMock(overrides?.patchCallWithoutParametersAndResponseMock)); - handlers.push(mocks.postCallWithoutParametersAndResponseMock(overrides?.postCallWithoutParametersAndResponseMock)); - handlers.push(mocks.putCallWithoutParametersAndResponseMock(overrides?.putCallWithoutParametersAndResponseMock)); - handlers.push(mocks.callWithDescriptionsMock(overrides?.callWithDescriptionsMock)); - handlers.push(mocks.getCallWithOptionalParamMock(overrides?.getCallWithOptionalParamMock)); - addRequiredHandler(mocks.postCallWithOptionalParamMock, overrides?.postCallWithOptionalParamMock); - handlers.push(mocks.postApiVbyApiVersionRequestBodyMock(overrides?.postApiVbyApiVersionRequestBodyMock)); - handlers.push(mocks.postApiVbyApiVersionFormDataMock(overrides?.postApiVbyApiVersionFormDataMock)); - handlers.push(mocks.callWithDefaultParametersMock(overrides?.callWithDefaultParametersMock)); - handlers.push(mocks.callWithDefaultOptionalParametersMock(overrides?.callWithDefaultOptionalParametersMock)); - handlers.push(mocks.callToTestOrderOfParamsMock(overrides?.callToTestOrderOfParamsMock)); - handlers.push(mocks.duplicateNameMock(overrides?.duplicateNameMock)); - handlers.push(mocks.duplicateName2Mock(overrides?.duplicateName2Mock)); - handlers.push(mocks.duplicateName3Mock(overrides?.duplicateName3Mock)); - handlers.push(mocks.duplicateName4Mock(overrides?.duplicateName4Mock)); - handlers.push(mocks.callWithNoContentResponseMock(overrides?.callWithNoContentResponseMock)); - handlers.push(mocks.callWithResponseMock(overrides?.callWithResponseMock)); - addRequiredHandler(mocks.callWithDuplicateResponsesMock, overrides?.callWithDuplicateResponsesMock); - addRequiredHandler(mocks.callWithResponsesMock, overrides?.callWithResponsesMock); - handlers.push(mocks.collectionFormatMock(overrides?.collectionFormatMock)); - addRequiredHandler(mocks.typesMock, overrides?.typesMock); - addRequiredHandler(mocks.uploadFileMock, overrides?.uploadFileMock); - addRequiredHandler(mocks.complexTypesMock, overrides?.complexTypesMock); - addRequiredHandler(mocks.multipartResponseMock, overrides?.multipartResponseMock); - handlers.push(mocks.multipartRequestMock(overrides?.multipartRequestMock)); - handlers.push(mocks.callWithResultFromHeaderMock(overrides?.callWithResultFromHeaderMock)); - handlers.push(mocks.testErrorCodeMock(overrides?.testErrorCodeMock)); - addRequiredHandler(mocks.nonAsciiæøåÆøÅöôêÊ字符串Mock, overrides?.nonAsciiæøåÆøÅöôêÊ字符串Mock); - handlers.push(mocks.putWithFormUrlEncodedMock(overrides?.putWithFormUrlEncodedMock)); - return handlers; + const all: CreateMswHandlersResult['all'] = (options = {}) => { + type OverrideValue = R | [ + resolver?: R, + options?: RequestHandlerOptions + ]; + function invoke(fn: Handler, override?: OverrideValue): HttpHandler { + return Array.isArray(override) ? fn(...override) : fn(override); + } + const overrides = options.one ?? {}; + return [ + invoke(one.deleteFoo, overrides.deleteFoo), + invoke(one.callWithWeirdParameterNames, overrides.callWithWeirdParameterNames), + invoke(one.apiVVersionODataControllerCount, overrides.apiVVersionODataControllerCount), + invoke(one.deprecatedCall, overrides.deprecatedCall), + invoke(one.callWithResponseAndNoContentResponse, overrides.callWithResponseAndNoContentResponse), + invoke(one.dummyA, overrides.dummyA), + invoke(one.dummyB, overrides.dummyB), + invoke(one.callWithParameters, overrides.callWithParameters), + invoke(one.fileResponse, overrides.fileResponse), + invoke(one.complexParams, overrides.complexParams), + invoke(one.export, overrides.export), + invoke(one.patchApiVbyApiVersionNoTag, overrides.patchApiVbyApiVersionNoTag), + invoke(one.import, overrides.import), + invoke(one.fooWow, overrides.fooWow), + invoke(one.getApiVbyApiVersionSimpleOperation, overrides.getApiVbyApiVersionSimpleOperation), + invoke(one.deleteCallWithoutParametersAndResponse, overrides.deleteCallWithoutParametersAndResponse), + invoke(one.getCallWithoutParametersAndResponse, overrides.getCallWithoutParametersAndResponse), + invoke(one.headCallWithoutParametersAndResponse, overrides.headCallWithoutParametersAndResponse), + invoke(one.optionsCallWithoutParametersAndResponse, overrides.optionsCallWithoutParametersAndResponse), + invoke(one.patchCallWithoutParametersAndResponse, overrides.patchCallWithoutParametersAndResponse), + invoke(one.postCallWithoutParametersAndResponse, overrides.postCallWithoutParametersAndResponse), + invoke(one.putCallWithoutParametersAndResponse, overrides.putCallWithoutParametersAndResponse), + invoke(one.callWithDescriptions, overrides.callWithDescriptions), + invoke(one.getCallWithOptionalParam, overrides.getCallWithOptionalParam), + invoke(one.postCallWithOptionalParam, overrides.postCallWithOptionalParam), + invoke(one.postApiVbyApiVersionRequestBody, overrides.postApiVbyApiVersionRequestBody), + invoke(one.postApiVbyApiVersionFormData, overrides.postApiVbyApiVersionFormData), + invoke(one.callWithDefaultParameters, overrides.callWithDefaultParameters), + invoke(one.callWithDefaultOptionalParameters, overrides.callWithDefaultOptionalParameters), + invoke(one.callToTestOrderOfParams, overrides.callToTestOrderOfParams), + invoke(one.duplicateName, overrides.duplicateName), + invoke(one.duplicateName2, overrides.duplicateName2), + invoke(one.duplicateName3, overrides.duplicateName3), + invoke(one.duplicateName4, overrides.duplicateName4), + invoke(one.callWithNoContentResponse, overrides.callWithNoContentResponse), + invoke(one.callWithResponse, overrides.callWithResponse), + invoke(one.callWithDuplicateResponses, overrides.callWithDuplicateResponses), + invoke(one.callWithResponses, overrides.callWithResponses), + invoke(one.collectionFormat, overrides.collectionFormat), + invoke(one.types, overrides.types), + invoke(one.uploadFile, overrides.uploadFile), + invoke(one.complexTypes, overrides.complexTypes), + invoke(one.multipartResponse, overrides.multipartResponse), + invoke(one.multipartRequest, overrides.multipartRequest), + invoke(one.callWithResultFromHeader, overrides.callWithResultFromHeader), + invoke(one.testErrorCode, overrides.testErrorCode), + invoke(one.nonAsciiæøåÆøÅöôêÊ字符串, overrides.nonAsciiæøåÆøÅöôêÊ字符串), + invoke(one.putWithFormUrlEncoded, overrides.putWithFormUrlEncoded) + ]; }; - return { ...mocks, getAllMocks }; -}; + return { all, one }; +} diff --git a/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-example-disabled/msw.gen.ts b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-example-disabled/msw.gen.ts index dfa6f9a911..1f216e5be8 100644 --- a/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-example-disabled/msw.gen.ts +++ b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-example-disabled/msw.gen.ts @@ -1,12 +1,37 @@ // This file is auto-generated by @hey-api/openapi-ts -import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions } from 'msw'; +import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions as RequestHandlerOptions2 } from 'msw'; import type { GetFooResponses, PostFooData, PostFooResponses } from './types.gen'; -const resolveToNull = () => new HttpResponse(null); +export type RequestHandlerOptions = RequestHandlerOptions2 & { + baseUrl?: string; + responseFallback?: 'error' | 'passthrough'; +}; -type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; +/** + * Handler for the `GET /foo` operation. + */ +export function handleGetFoo(resolver?: { + result: GetFooResponses[200]; + status?: 200; +} | HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.get(`${options?.baseUrl ?? '*'}/foo`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} type ToResponseUnion = { [K in Extract]: { @@ -15,53 +40,69 @@ type ToResponseUnion = { }; }[Extract]; -export type SingleHandlerFactories = { - getFooMock: HttpHandlerFactory<{ - result: GetFooResponses[200]; - status?: 200; - } | HttpResponseResolver>; - postFooMock: HttpHandlerFactory<{ - result: PostFooResponses[200]; - status?: 200; - } | ToResponseUnion | HttpResponseResolver>; -}; +/** + * Handler for the `POST /foo` operation. + */ +export function handlePostFoo(resolver?: { + result: PostFooResponses[200]; + status?: 200; +} | ToResponseUnion | HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.post(`${options?.baseUrl ?? '*'}/foo`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} -export type GetAllMocksOptions = { - onMissingMock?: 'error' | 'skip'; - overrides?: { - [K in keyof SingleHandlerFactories]?: Parameters[0]; - }; +export type MswHandlerFactories = { + /** + * Handler for the `GET /foo` operation. + */ + getFoo: typeof handleGetFoo; + /** + * Handler for the `POST /foo` operation. + */ + postFoo: typeof handlePostFoo; }; -export type MswHandlerFactory = SingleHandlerFactories & { - getAllMocks: (options?: GetAllMocksOptions) => Array; +export type CreateMswHandlersResult = { + all: (options?: { + one?: { + [K in keyof MswHandlerFactories]?: Parameters[0] | Parameters; + }; + }) => ReadonlyArray; + one: MswHandlerFactories; }; -export const createMswHandlerFactory = (config?: { - baseUrl?: string; -}): MswHandlerFactory => { - const baseUrl = config?.baseUrl ?? '*'; - const mocks: SingleHandlerFactories = { - getFooMock: (res, options) => http.get(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - postFooMock: (res, options) => http.post(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options) +export function createMswHandlers(config: RequestHandlerOptions = {}): CreateMswHandlersResult { + type Handler = (resolver?: R, options?: RequestHandlerOptions) => HttpHandler; + function wrap(handler: Handler): Handler { + return (resolver, options) => handler(resolver, { ...config, ...options }); + } + const one: CreateMswHandlersResult['one'] = { + getFoo: wrap(handleGetFoo), + postFoo: wrap(handlePostFoo) }; - const getAllMocks = (options?: GetAllMocksOptions): Array => { - const onMissingMock = options?.onMissingMock ?? 'skip'; - const overrides = options?.overrides; - const handlers: Array = []; - const addRequiredHandler = (handler: (value: Value | (() => HttpResponse)) => HttpHandler, override: Value | undefined) => { - if (override != null) { - handlers.push(handler(override)); - } - else { - if (onMissingMock === 'error') { - handlers.push(handler(() => new HttpResponse('[heyapi-msw] The mock of this request is not implemented.', { status: 501 }))); - } - } - }; - addRequiredHandler(mocks.getFooMock, overrides?.getFooMock); - addRequiredHandler(mocks.postFooMock, overrides?.postFooMock); - return handlers; + const all: CreateMswHandlersResult['all'] = (options = {}) => { + type OverrideValue = R | [ + resolver?: R, + options?: RequestHandlerOptions + ]; + function invoke(fn: Handler, override?: OverrideValue): HttpHandler { + return Array.isArray(override) ? fn(...override) : fn(override); + } + const overrides = options.one ?? {}; + return [invoke(one.getFoo, overrides.getFoo), invoke(one.postFoo, overrides.postFoo)]; }; - return { ...mocks, getAllMocks }; -}; + return { all, one }; +} diff --git a/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-example/msw.gen.ts b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-example/msw.gen.ts index 2b59b7b873..46e6bcde0d 100644 --- a/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-example/msw.gen.ts +++ b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-example/msw.gen.ts @@ -1,12 +1,41 @@ // This file is auto-generated by @hey-api/openapi-ts -import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions } from 'msw'; +import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions as RequestHandlerOptions2 } from 'msw'; import type { GetFooResponses, PostFooData, PostFooResponses } from './types.gen'; -const resolveToNull = () => new HttpResponse(null); +export type RequestHandlerOptions = RequestHandlerOptions2 & { + baseUrl?: string; + responseFallback?: 'error' | 'passthrough'; +}; -type OptionalHttpHandlerFactory = (responseOrResolver?: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; +/** + * Handler for the `GET /foo` operation. + */ +export function handleGetFoo(resolver?: { + result: GetFooResponses[200]; + status?: 200; +} | HttpResponseResolver = { result: { + firstName: 'Marry', + lastName: 'Jane', + age: 30 + }, status: 200 }, options?: RequestHandlerOptions): HttpHandler { + return http.get(`${options?.baseUrl ?? '*'}/foo`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} type ToResponseUnion = { [K in Extract]: { @@ -15,46 +44,69 @@ type ToResponseUnion = { }; }[Extract]; -export type SingleHandlerFactories = { - getFooMock: OptionalHttpHandlerFactory<{ - result: GetFooResponses[200]; - status?: 200; - } | HttpResponseResolver>; - postFooMock: OptionalHttpHandlerFactory<{ - result: PostFooResponses[200]; - status?: 200; - } | ToResponseUnion | HttpResponseResolver>; -}; +/** + * Handler for the `POST /foo` operation. + */ +export function handlePostFoo(resolver?: { + result: PostFooResponses[200]; + status?: 200; +} | ToResponseUnion | HttpResponseResolver = { result: { fullName: 'John Doe', age: 34 }, status: 200 }, options?: RequestHandlerOptions): HttpHandler { + return http.post(`${options?.baseUrl ?? '*'}/foo`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} -export type GetAllMocksOptions = { - onMissingMock?: 'error' | 'skip'; - overrides?: { - [K in keyof SingleHandlerFactories]?: Parameters[0]; - }; +export type MswHandlerFactories = { + /** + * Handler for the `GET /foo` operation. + */ + getFoo: typeof handleGetFoo; + /** + * Handler for the `POST /foo` operation. + */ + postFoo: typeof handlePostFoo; }; -export type MswHandlerFactory = SingleHandlerFactories & { - getAllMocks: (options?: GetAllMocksOptions) => Array; +export type CreateMswHandlersResult = { + all: (options?: { + one?: { + [K in keyof MswHandlerFactories]?: Parameters[0] | Parameters; + }; + }) => ReadonlyArray; + one: MswHandlerFactories; }; -export const createMswHandlerFactory = (config?: { - baseUrl?: string; -}): MswHandlerFactory => { - const baseUrl = config?.baseUrl ?? '*'; - const mocks: SingleHandlerFactories = { - getFooMock: (res = { result: { - firstName: 'Marry', - lastName: 'Jane', - age: 30 - }, status: 200 }, options) => http.get(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options), - postFooMock: (res = { result: { fullName: 'John Doe', age: 34 }, status: 200 }, options) => http.post(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options) +export function createMswHandlers(config: RequestHandlerOptions = {}): CreateMswHandlersResult { + type Handler = (resolver?: R, options?: RequestHandlerOptions) => HttpHandler; + function wrap(handler: Handler): Handler { + return (resolver, options) => handler(resolver, { ...config, ...options }); + } + const one: CreateMswHandlersResult['one'] = { + getFoo: wrap(handleGetFoo), + postFoo: wrap(handlePostFoo) }; - const getAllMocks = (options?: GetAllMocksOptions): Array => { - const overrides = options?.overrides; - const handlers: Array = []; - handlers.push(mocks.getFooMock(overrides?.getFooMock)); - handlers.push(mocks.postFooMock(overrides?.postFooMock)); - return handlers; + const all: CreateMswHandlersResult['all'] = (options = {}) => { + type OverrideValue = R | [ + resolver?: R, + options?: RequestHandlerOptions + ]; + function invoke(fn: Handler, override?: OverrideValue): HttpHandler { + return Array.isArray(override) ? fn(...override) : fn(override); + } + const overrides = options.one ?? {}; + return [invoke(one.getFoo, overrides.getFoo), invoke(one.postFoo, overrides.postFoo)]; }; - return { ...mocks, getAllMocks }; -}; + return { all, one }; +} diff --git a/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-types/msw.gen.ts b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-types/msw.gen.ts index 3be5d7128f..aac377d6e5 100644 --- a/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-types/msw.gen.ts +++ b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/response-types/msw.gen.ts @@ -1,43 +1,72 @@ // This file is auto-generated by @hey-api/openapi-ts -import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions } from 'msw'; +import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions as RequestHandlerOptions2 } from 'msw'; import type { GetFooResponses } from './types.gen'; -const resolveToNull = () => new HttpResponse(null); - -type OptionalHttpHandlerFactory = (responseOrResolver?: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; - -export type SingleHandlerFactories = { - getFooMock: OptionalHttpHandlerFactory<{ - result: GetFooResponses[200]; - status?: 200; - } | HttpResponseResolver>; +export type RequestHandlerOptions = RequestHandlerOptions2 & { + baseUrl?: string; + responseFallback?: 'error' | 'passthrough'; }; -export type GetAllMocksOptions = { - onMissingMock?: 'error' | 'skip'; - overrides?: { - [K in keyof SingleHandlerFactories]?: Parameters[0]; - }; +/** + * Handler for the `GET /foo` operation. + */ +export function handleGetFoo(resolver?: { + result: GetFooResponses[200]; + status?: 200; +} | HttpResponseResolver = { result: { name: 'Alice' }, status: 200 }, options?: RequestHandlerOptions): HttpHandler { + return http.get(`${options?.baseUrl ?? '*'}/foo`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +export type MswHandlerFactories = { + /** + * Handler for the `GET /foo` operation. + */ + getFoo: typeof handleGetFoo; }; -export type MswHandlerFactory = SingleHandlerFactories & { - getAllMocks: (options?: GetAllMocksOptions) => Array; +export type CreateMswHandlersResult = { + all: (options?: { + one?: { + [K in keyof MswHandlerFactories]?: Parameters[0] | Parameters; + }; + }) => ReadonlyArray; + one: MswHandlerFactories; }; -export const createMswHandlerFactory = (config?: { - baseUrl?: string; -}): MswHandlerFactory => { - const baseUrl = config?.baseUrl ?? '*'; - const mocks: SingleHandlerFactories = { - getFooMock: (res = { result: { name: 'Alice' }, status: 200 }, options) => http.get(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options) +export function createMswHandlers(config: RequestHandlerOptions = {}): CreateMswHandlersResult { + type Handler = (resolver?: R, options?: RequestHandlerOptions) => HttpHandler; + function wrap(handler: Handler): Handler { + return (resolver, options) => handler(resolver, { ...config, ...options }); + } + const one: CreateMswHandlersResult['one'] = { + getFoo: wrap(handleGetFoo) }; - const getAllMocks = (options?: GetAllMocksOptions): Array => { - const overrides = options?.overrides; - const handlers: Array = []; - handlers.push(mocks.getFooMock(overrides?.getFooMock)); - return handlers; + const all: CreateMswHandlersResult['all'] = (options = {}) => { + type OverrideValue = R | [ + resolver?: R, + options?: RequestHandlerOptions + ]; + function invoke(fn: Handler, override?: OverrideValue): HttpHandler { + return Array.isArray(override) ? fn(...override) : fn(override); + } + const overrides = options.one ?? {}; + return [invoke(one.getFoo, overrides.getFoo)]; }; - return { ...mocks, getAllMocks }; -}; + return { all, one }; +} diff --git a/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/servers/msw.gen.ts b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/servers/msw.gen.ts index 3ac93d847f..04a6a410bf 100644 --- a/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/servers/msw.gen.ts +++ b/packages/openapi-ts-tests/msw/v2/__snapshots__/3.1.x/servers/msw.gen.ts @@ -1,54 +1,72 @@ // This file is auto-generated by @hey-api/openapi-ts -import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions } from 'msw'; +import { http, type HttpHandler, HttpResponse, type HttpResponseResolver, type RequestHandlerOptions as RequestHandlerOptions2 } from 'msw'; import type { GetFooResponses } from './types.gen'; -const resolveToNull = () => new HttpResponse(null); - -type HttpHandlerFactory = (responseOrResolver: ResponseOrResolver, options?: RequestHandlerOptions) => HttpHandler; - -export type SingleHandlerFactories = { - getFooMock: HttpHandlerFactory<{ - result: GetFooResponses[200]; - status?: 200; - } | HttpResponseResolver>; +export type RequestHandlerOptions = RequestHandlerOptions2 & { + baseUrl?: string; + responseFallback?: 'error' | 'passthrough'; }; -export type GetAllMocksOptions = { - onMissingMock?: 'error' | 'skip'; - overrides?: { - [K in keyof SingleHandlerFactories]?: Parameters[0]; - }; +/** + * Handler for the `GET /foo` operation. + */ +export function handleGetFoo(resolver?: { + result: GetFooResponses[200]; + status?: 200; +} | HttpResponseResolver, options?: RequestHandlerOptions): HttpHandler { + return http.get(`${options?.baseUrl ?? '*'}/foo`, info => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented' + }); + }, options); +} + +export type MswHandlerFactories = { + /** + * Handler for the `GET /foo` operation. + */ + getFoo: typeof handleGetFoo; }; -export type MswHandlerFactory = SingleHandlerFactories & { - getAllMocks: (options?: GetAllMocksOptions) => Array; +export type CreateMswHandlersResult = { + all: (options?: { + one?: { + [K in keyof MswHandlerFactories]?: Parameters[0] | Parameters; + }; + }) => ReadonlyArray; + one: MswHandlerFactories; }; -export const createMswHandlerFactory = (config?: { - baseUrl?: string; -}): MswHandlerFactory => { - const baseUrl = config?.baseUrl ?? '*'; - const mocks: SingleHandlerFactories = { - getFooMock: (res, options) => http.get(`${baseUrl}${'/foo'}`, typeof res === 'object' && res.result ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) : typeof res === 'function' ? res : resolveToNull, options) +export function createMswHandlers(config: RequestHandlerOptions = {}): CreateMswHandlersResult { + type Handler = (resolver?: R, options?: RequestHandlerOptions) => HttpHandler; + function wrap(handler: Handler): Handler { + return (resolver, options) => handler(resolver, { ...config, ...options }); + } + const one: CreateMswHandlersResult['one'] = { + getFoo: wrap(handleGetFoo) }; - const getAllMocks = (options?: GetAllMocksOptions): Array => { - const onMissingMock = options?.onMissingMock ?? 'skip'; - const overrides = options?.overrides; - const handlers: Array = []; - const addRequiredHandler = (handler: (value: Value | (() => HttpResponse)) => HttpHandler, override: Value | undefined) => { - if (override != null) { - handlers.push(handler(override)); - } - else { - if (onMissingMock === 'error') { - handlers.push(handler(() => new HttpResponse('[heyapi-msw] The mock of this request is not implemented.', { status: 501 }))); - } - } - }; - addRequiredHandler(mocks.getFooMock, overrides?.getFooMock); - return handlers; + const all: CreateMswHandlersResult['all'] = (options = {}) => { + type OverrideValue = R | [ + resolver?: R, + options?: RequestHandlerOptions + ]; + function invoke(fn: Handler, override?: OverrideValue): HttpHandler { + return Array.isArray(override) ? fn(...override) : fn(override); + } + const overrides = options.one ?? {}; + return [invoke(one.getFoo, overrides.getFoo)]; }; - return { ...mocks, getAllMocks }; -}; + return { all, one }; +} diff --git a/packages/openapi-ts/src/plugins/msw/shared/handler.ts b/packages/openapi-ts/src/plugins/msw/shared/handler.ts index 25d06d38bd..4449e8d3ea 100644 --- a/packages/openapi-ts/src/plugins/msw/shared/handler.ts +++ b/packages/openapi-ts/src/plugins/msw/shared/handler.ts @@ -7,6 +7,7 @@ import type { MswPlugin } from '../types'; import { computeDominantResponse, type DominantResponse } from './computeDominantResponse'; import { getOperationComment } from './operation'; import { sanitizeParamName, sanitizePath } from './path'; +import { createHandlerResponse } from './response'; const emitToResponseUnion = (plugin: MswPlugin['Instance']) => { const symbol = plugin.symbol('ToResponseUnion', { @@ -38,46 +39,6 @@ const emitToResponseUnion = (plugin: MswPlugin['Instance']) => { plugin.node(toResponseUnionType); }; -/** - * Builds the response override expression for the `res` parameter. - */ -function buildResponseOverrideExpr({ - dominantResponse: { kind: responseKind, statusCode: responseStatusCode }, - plugin, - symbolResolver, -}: { - dominantResponse: DominantResponse; - plugin: MswPlugin['Instance']; - symbolResolver: Symbol; -}) { - const symbolHttpResponse = plugin.external('msw.HttpResponse'); - - const statusOption = $.object().prop( - 'status', - responseStatusCode - ? $(symbolResolver).attr('status').coalesce($.literal(responseStatusCode)) - : $(symbolResolver).attr('status'), - ); - const resultExpr = $(symbolResolver).attr('result'); - - switch (responseKind) { - case 'binary': - return $.new(symbolHttpResponse, resultExpr.coalesce($.literal(null)), statusOption).return(); - case 'json': - return $(symbolHttpResponse) - .attr('json') - .call(resultExpr.coalesce($.literal(null)), statusOption) - .return(); - case 'text': - return $(symbolHttpResponse) - .attr('text') - .call(resultExpr.coalesce($.literal(null)), statusOption) - .return(); - case 'void': - return $.new(symbolHttpResponse, resultExpr.coalesce($.literal(null)), statusOption).return(); - } -} - function createHandlerFunc({ baseUrl, bodyType, @@ -98,7 +59,6 @@ function createHandlerFunc({ responseOrResolverType: ReturnType; }): Symbol { const symbolHttp = plugin.external('msw.http'); - // const symbolHttpResponse = plugin.external('msw.HttpResponse'); const symbolResolver = plugin.symbol('resolver'); const symbolOptions = plugin.symbol('options'); @@ -163,7 +123,7 @@ function createHandlerFunc({ .$if(dominantResponse.statusCode != null, (f) => f.do( $.if(symbolResolver).do( - buildResponseOverrideExpr({ + createHandlerResponse({ dominantResponse, plugin, symbolResolver, diff --git a/packages/openapi-ts/src/plugins/msw/shared/response.ts b/packages/openapi-ts/src/plugins/msw/shared/response.ts new file mode 100644 index 0000000000..acbefbe374 --- /dev/null +++ b/packages/openapi-ts/src/plugins/msw/shared/response.ts @@ -0,0 +1,45 @@ +import type { Symbol } from '@hey-api/codegen-core'; + +import { $ } from '../../../ts-dsl'; +import type { MswPlugin } from '../types'; +import type { DominantResponse } from './computeDominantResponse'; + +/** + * Builds the response override expression for the `res` parameter. + */ +export function createHandlerResponse({ + dominantResponse: { kind: responseKind, statusCode: responseStatusCode }, + plugin, + symbolResolver, +}: { + dominantResponse: DominantResponse; + plugin: MswPlugin['Instance']; + symbolResolver: Symbol; +}) { + const symbolHttpResponse = plugin.external('msw.HttpResponse'); + + const statusOption = $.object().prop( + 'status', + responseStatusCode + ? $(symbolResolver).attr('status').coalesce($.literal(responseStatusCode)) + : $(symbolResolver).attr('status'), + ); + const resultExpr = $(symbolResolver).attr('result'); + + switch (responseKind) { + case 'binary': + return $.new(symbolHttpResponse, resultExpr.coalesce($.literal(null)), statusOption).return(); + case 'json': + return $(symbolHttpResponse) + .attr('json') + .call(resultExpr.coalesce($.literal(null)), statusOption) + .return(); + case 'text': + return $(symbolHttpResponse) + .attr('text') + .call(resultExpr.coalesce($.literal(null)), statusOption) + .return(); + case 'void': + return $.new(symbolHttpResponse, resultExpr.coalesce($.literal(null)), statusOption).return(); + } +} From 95d887132b80f45f091277a01df98420bab64d53 Mon Sep 17 00:00:00 2001 From: Lubos Date: Mon, 30 Mar 2026 06:25:00 +0200 Subject: [PATCH 16/16] test: update tests --- .../openapi-ts-fetch/src/client/msw.gen.ts | 1160 +++++++++++------ .../openapi-ts-fetch/test/msw-types.test-d.ts | 78 +- examples/openapi-ts-fetch/test/msw.test.ts | 38 +- .../src/plugins/msw/shared/handler.ts | 2 +- .../src/plugins/msw/shared/response.ts | 17 +- 5 files changed, 839 insertions(+), 456 deletions(-) diff --git a/examples/openapi-ts-fetch/src/client/msw.gen.ts b/examples/openapi-ts-fetch/src/client/msw.gen.ts index 6395f74f8d..eddb85d63d 100644 --- a/examples/openapi-ts-fetch/src/client/msw.gen.ts +++ b/examples/openapi-ts-fetch/src/client/msw.gen.ts @@ -5,7 +5,7 @@ import { type HttpHandler, HttpResponse, type HttpResponseResolver, - type RequestHandlerOptions, + type RequestHandlerOptions as RequestHandlerOptions2, } from 'msw'; import type { @@ -37,55 +37,193 @@ import type { UploadFileResponses, } from './types.gen'; -const resolveToNull = () => new HttpResponse(null); - -type HttpHandlerFactory = ( - responseOrResolver: ResponseOrResolver, - options?: RequestHandlerOptions, -) => HttpHandler; +export type RequestHandlerOptions = RequestHandlerOptions2 & { + baseUrl?: string; + responseFallback?: 'error' | 'passthrough'; +}; -type OptionalHttpHandlerFactory = ( - responseOrResolver?: ResponseOrResolver, +/** + * Handler for the `POST /pet` operation. + */ +export function handleAddPet( + resolver?: + | { + result: AddPetResponses[200]; + status?: 200; + } + | HttpResponseResolver, options?: RequestHandlerOptions, -) => HttpHandler; +): HttpHandler { + return http.post( + `${options?.baseUrl ?? '*'}/pet`, + (info) => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented', + }); + }, + options, + ); +} -export type SingleHandlerFactories = { - addPetMock: HttpHandlerFactory< +/** + * Handler for the `PUT /pet` operation. + */ +export function handleUpdatePet( + resolver?: | { - result: AddPetResponses[200]; + result: UpdatePetResponses[200]; status?: 200; } - | HttpResponseResolver - >; - createUserMock: HttpHandlerFactory< + | HttpResponseResolver, + options?: RequestHandlerOptions, +): HttpHandler { + return http.put( + `${options?.baseUrl ?? '*'}/pet`, + (info) => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented', + }); + }, + options, + ); +} + +/** + * Handler for the `GET /pet/findByStatus` operation. + */ +export function handleFindPetsByStatus( + resolver?: | { - result: CreateUserResponses[200]; + result: FindPetsByStatusResponses[200]; status?: 200; } - | HttpResponseResolver - >; - createUsersWithListInputMock: HttpHandlerFactory< + | HttpResponseResolver, + options?: RequestHandlerOptions, +): HttpHandler { + return http.get( + `${options?.baseUrl ?? '*'}/pet/findByStatus`, + (info) => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented', + }); + }, + options, + ); +} + +/** + * Handler for the `GET /pet/findByTags` operation. + */ +export function handleFindPetsByTags( + resolver?: | { - result: CreateUsersWithListInputResponses[200]; + result: FindPetsByTagsResponses[200]; status?: 200; } - | HttpResponseResolver - >; - deleteOrderMock: OptionalHttpHandlerFactory< + | HttpResponseResolver, + options?: RequestHandlerOptions, +): HttpHandler { + return http.get( + `${options?.baseUrl ?? '*'}/pet/findByTags`, + (info) => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented', + }); + }, + options, + ); +} + +/** + * Handler for the `DELETE /pet/{petId}` operation. + */ +export function handleDeletePet( + resolver?: | { - result: DeleteOrderResponses[200]; + result: DeletePetResponses[200]; status?: 200; } | HttpResponseResolver< { - orderId: string; + petId: string; }, never - > - >; - deletePetMock: OptionalHttpHandlerFactory< + >, + options?: RequestHandlerOptions, +): HttpHandler { + return http.delete< + { + petId: string; + }, + never + >( + `${options?.baseUrl ?? '*'}/pet/:petId`, + (info) => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return new HttpResponse(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented', + }); + }, + options, + ); +} + +/** + * Handler for the `GET /pet/{petId}` operation. + */ +export function handleGetPetById( + resolver?: | { - result: DeletePetResponses[200]; + result: GetPetByIdResponses[200]; status?: 200; } | HttpResponseResolver< @@ -93,433 +231,677 @@ export type SingleHandlerFactories = { petId: string; }, never - > - >; - deleteUserMock: OptionalHttpHandlerFactory< + >, + options?: RequestHandlerOptions, +): HttpHandler { + return http.get< + { + petId: string; + }, + never + >( + `${options?.baseUrl ?? '*'}/pet/:petId`, + (info) => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented', + }); + }, + options, + ); +} + +/** + * Handler for the `POST /pet/{petId}` operation. + */ +export function handleUpdatePetWithForm( + resolver?: | { - result: DeleteUserResponses[200]; + result: UpdatePetWithFormResponses[200]; status?: 200; } | HttpResponseResolver< { - username: string; + petId: string; }, never - > - >; - findPetsByStatusMock: HttpHandlerFactory< - | { - result: FindPetsByStatusResponses[200]; - status?: 200; + >, + options?: RequestHandlerOptions, +): HttpHandler { + return http.post< + { + petId: string; + }, + never + >( + `${options?.baseUrl ?? '*'}/pet/:petId`, + (info) => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); } - | HttpResponseResolver - >; - findPetsByTagsMock: HttpHandlerFactory< + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented', + }); + }, + options, + ); +} + +/** + * Handler for the `POST /pet/{petId}/uploadImage` operation. + */ +export function handleUploadFile( + resolver?: | { - result: FindPetsByTagsResponses[200]; + result: UploadFileResponses[200]; status?: 200; } - | HttpResponseResolver - >; - getInventoryMock: HttpHandlerFactory< + | HttpResponseResolver< + { + petId: string; + }, + UploadFileData['body'] + >, + options?: RequestHandlerOptions, +): HttpHandler { + return http.post< + { + petId: string; + }, + UploadFileData['body'] + >( + `${options?.baseUrl ?? '*'}/pet/:petId/uploadImage`, + (info) => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented', + }); + }, + options, + ); +} + +/** + * Handler for the `GET /store/inventory` operation. + */ +export function handleGetInventory( + resolver?: | { result: GetInventoryResponses[200]; status?: 200; } - | HttpResponseResolver - >; - getOrderByIdMock: HttpHandlerFactory< + | HttpResponseResolver, + options?: RequestHandlerOptions, +): HttpHandler { + return http.get( + `${options?.baseUrl ?? '*'}/store/inventory`, + (info) => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented', + }); + }, + options, + ); +} + +/** + * Handler for the `POST /store/order` operation. + */ +export function handlePlaceOrder( + resolver?: | { - result: GetOrderByIdResponses[200]; + result: PlaceOrderResponses[200]; status?: 200; } - | HttpResponseResolver< - { - orderId: string; - }, - never - > - >; - getPetByIdMock: HttpHandlerFactory< + | HttpResponseResolver, + options?: RequestHandlerOptions, +): HttpHandler { + return http.post( + `${options?.baseUrl ?? '*'}/store/order`, + (info) => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented', + }); + }, + options, + ); +} + +/** + * Handler for the `DELETE /store/order/{orderId}` operation. + */ +export function handleDeleteOrder( + resolver?: | { - result: GetPetByIdResponses[200]; + result: DeleteOrderResponses[200]; status?: 200; } | HttpResponseResolver< { - petId: string; + orderId: string; }, never - > - >; - getUserByNameMock: HttpHandlerFactory< + >, + options?: RequestHandlerOptions, +): HttpHandler { + return http.delete< + { + orderId: string; + }, + never + >( + `${options?.baseUrl ?? '*'}/store/order/:orderId`, + (info) => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return new HttpResponse(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented', + }); + }, + options, + ); +} + +/** + * Handler for the `GET /store/order/{orderId}` operation. + */ +export function handleGetOrderById( + resolver?: | { - result: GetUserByNameResponses[200]; + result: GetOrderByIdResponses[200]; status?: 200; } | HttpResponseResolver< { - username: string; + orderId: string; }, never - > - >; - loginUserMock: HttpHandlerFactory< + >, + options?: RequestHandlerOptions, +): HttpHandler { + return http.get< + { + orderId: string; + }, + never + >( + `${options?.baseUrl ?? '*'}/store/order/:orderId`, + (info) => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented', + }); + }, + options, + ); +} + +/** + * Handler for the `POST /user` operation. + */ +export function handleCreateUser( + resolver?: | { - result: LoginUserResponses[200]; + result: CreateUserResponses[200]; status?: 200; } - | HttpResponseResolver - >; - logoutUserMock: OptionalHttpHandlerFactory< + | HttpResponseResolver, + options?: RequestHandlerOptions, +): HttpHandler { + return http.post( + `${options?.baseUrl ?? '*'}/user`, + (info) => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented', + }); + }, + options, + ); +} + +/** + * Handler for the `POST /user/createWithList` operation. + */ +export function handleCreateUsersWithListInput( + resolver?: | { - result: LogoutUserResponses[200]; + result: CreateUsersWithListInputResponses[200]; status?: 200; } - | HttpResponseResolver - >; - placeOrderMock: HttpHandlerFactory< + | HttpResponseResolver, + options?: RequestHandlerOptions, +): HttpHandler { + return http.post( + `${options?.baseUrl ?? '*'}/user/createWithList`, + (info) => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented', + }); + }, + options, + ); +} + +/** + * Handler for the `GET /user/login` operation. + */ +export function handleLoginUser( + resolver?: | { - result: PlaceOrderResponses[200]; + result: LoginUserResponses[200]; status?: 200; } - | HttpResponseResolver - >; - updatePetMock: HttpHandlerFactory< + | HttpResponseResolver, + options?: RequestHandlerOptions, +): HttpHandler { + return http.get( + `${options?.baseUrl ?? '*'}/user/login`, + (info) => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented', + }); + }, + options, + ); +} + +/** + * Handler for the `GET /user/logout` operation. + */ +export function handleLogoutUser( + resolver?: | { - result: UpdatePetResponses[200]; + result: LogoutUserResponses[200]; status?: 200; } - | HttpResponseResolver - >; - updatePetWithFormMock: HttpHandlerFactory< + | HttpResponseResolver, + options?: RequestHandlerOptions, +): HttpHandler { + return http.get( + `${options?.baseUrl ?? '*'}/user/logout`, + (info) => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return new HttpResponse(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented', + }); + }, + options, + ); +} + +/** + * Handler for the `DELETE /user/{username}` operation. + */ +export function handleDeleteUser( + resolver?: | { - result: UpdatePetWithFormResponses[200]; + result: DeleteUserResponses[200]; status?: 200; } | HttpResponseResolver< { - petId: string; + username: string; }, never - > - >; - updateUserMock: OptionalHttpHandlerFactory< + >, + options?: RequestHandlerOptions, +): HttpHandler { + return http.delete< + { + username: string; + }, + never + >( + `${options?.baseUrl ?? '*'}/user/:username`, + (info) => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return new HttpResponse(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented', + }); + }, + options, + ); +} + +/** + * Handler for the `GET /user/{username}` operation. + */ +export function handleGetUserByName( + resolver?: | { - result: UpdateUserResponses[200]; + result: GetUserByNameResponses[200]; status?: 200; } | HttpResponseResolver< { username: string; }, - UpdateUserData['body'] - > - >; - uploadFileMock: HttpHandlerFactory< + never + >, + options?: RequestHandlerOptions, +): HttpHandler { + return http.get< + { + username: string; + }, + never + >( + `${options?.baseUrl ?? '*'}/user/:username`, + (info) => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return HttpResponse.json(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented', + }); + }, + options, + ); +} + +/** + * Handler for the `PUT /user/{username}` operation. + */ +export function handleUpdateUser( + resolver?: | { - result: UploadFileResponses[200]; + result: UpdateUserResponses[200]; status?: 200; } | HttpResponseResolver< { - petId: string; + username: string; }, - UploadFileData['body'] - > - >; -}; + UpdateUserData['body'] + >, + options?: RequestHandlerOptions, +): HttpHandler { + return http.put< + { + username: string; + }, + UpdateUserData['body'] + >( + `${options?.baseUrl ?? '*'}/user/:username`, + (info) => { + if (typeof resolver === 'function') { + return resolver(info); + } + if (resolver) { + return new HttpResponse(resolver.result ?? null, { status: resolver.status ?? 200 }); + } + if (options?.responseFallback === 'passthrough') { + return; + } + return new Response('Not Implemented', { + status: 501, + statusText: 'Not Implemented', + }); + }, + options, + ); +} -export type GetAllMocksOptions = { - onMissingMock?: 'error' | 'skip'; - overrides?: { - [K in keyof SingleHandlerFactories]?: Parameters[0]; - }; +export type MswHandlerFactories = { + /** + * Handler for the `POST /pet` operation. + */ + addPet: typeof handleAddPet; + /** + * Handler for the `POST /user` operation. + */ + createUser: typeof handleCreateUser; + /** + * Handler for the `POST /user/createWithList` operation. + */ + createUsersWithListInput: typeof handleCreateUsersWithListInput; + /** + * Handler for the `DELETE /store/order/{orderId}` operation. + */ + deleteOrder: typeof handleDeleteOrder; + /** + * Handler for the `DELETE /pet/{petId}` operation. + */ + deletePet: typeof handleDeletePet; + /** + * Handler for the `DELETE /user/{username}` operation. + */ + deleteUser: typeof handleDeleteUser; + /** + * Handler for the `GET /pet/findByStatus` operation. + */ + findPetsByStatus: typeof handleFindPetsByStatus; + /** + * Handler for the `GET /pet/findByTags` operation. + */ + findPetsByTags: typeof handleFindPetsByTags; + /** + * Handler for the `GET /store/inventory` operation. + */ + getInventory: typeof handleGetInventory; + /** + * Handler for the `GET /store/order/{orderId}` operation. + */ + getOrderById: typeof handleGetOrderById; + /** + * Handler for the `GET /pet/{petId}` operation. + */ + getPetById: typeof handleGetPetById; + /** + * Handler for the `GET /user/{username}` operation. + */ + getUserByName: typeof handleGetUserByName; + /** + * Handler for the `GET /user/login` operation. + */ + loginUser: typeof handleLoginUser; + /** + * Handler for the `GET /user/logout` operation. + */ + logoutUser: typeof handleLogoutUser; + /** + * Handler for the `POST /store/order` operation. + */ + placeOrder: typeof handlePlaceOrder; + /** + * Handler for the `PUT /pet` operation. + */ + updatePet: typeof handleUpdatePet; + /** + * Handler for the `POST /pet/{petId}` operation. + */ + updatePetWithForm: typeof handleUpdatePetWithForm; + /** + * Handler for the `PUT /user/{username}` operation. + */ + updateUser: typeof handleUpdateUser; + /** + * Handler for the `POST /pet/{petId}/uploadImage` operation. + */ + uploadFile: typeof handleUploadFile; }; -export type MswHandlerFactory = SingleHandlerFactories & { - getAllMocks: (options?: GetAllMocksOptions) => Array; +export type CreateMswHandlersResult = { + all: (options?: { + one?: { + [K in keyof MswHandlerFactories]?: + | Parameters[0] + | Parameters; + }; + }) => ReadonlyArray; + one: MswHandlerFactories; }; -export const createMswHandlerFactory = (config?: { baseUrl?: string }): MswHandlerFactory => { - const baseUrl = config?.baseUrl ?? 'https://petstore3.swagger.io/api/v3'; - const mocks: SingleHandlerFactories = { - addPetMock: (res, options) => - http.post( - `${baseUrl}${'/pet'}`, - typeof res === 'object' && res.result - ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) - : typeof res === 'function' - ? res - : resolveToNull, - options, - ), - createUserMock: (res, options) => - http.post( - `${baseUrl}${'/user'}`, - typeof res === 'object' && res.result - ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) - : typeof res === 'function' - ? res - : resolveToNull, - options, - ), - createUsersWithListInputMock: (res, options) => - http.post( - `${baseUrl}${'/user/createWithList'}`, - typeof res === 'object' && res.result - ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) - : typeof res === 'function' - ? res - : resolveToNull, - options, - ), - deleteOrderMock: (res, options) => - http.delete( - `${baseUrl}${'/store/order/:orderId'}`, - typeof res === 'object' && res.result - ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 200 }) - : typeof res === 'function' - ? res - : resolveToNull, - options, - ), - deletePetMock: (res, options) => - http.delete( - `${baseUrl}${'/pet/:petId'}`, - typeof res === 'object' && res.result - ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 200 }) - : typeof res === 'function' - ? res - : resolveToNull, - options, - ), - deleteUserMock: (res, options) => - http.delete( - `${baseUrl}${'/user/:username'}`, - typeof res === 'object' && res.result - ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 200 }) - : typeof res === 'function' - ? res - : resolveToNull, - options, - ), - findPetsByStatusMock: (res, options) => - http.get( - `${baseUrl}${'/pet/findByStatus'}`, - typeof res === 'object' && res.result - ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) - : typeof res === 'function' - ? res - : resolveToNull, - options, - ), - findPetsByTagsMock: (res, options) => - http.get( - `${baseUrl}${'/pet/findByTags'}`, - typeof res === 'object' && res.result - ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) - : typeof res === 'function' - ? res - : resolveToNull, - options, - ), - getInventoryMock: (res, options) => - http.get( - `${baseUrl}${'/store/inventory'}`, - typeof res === 'object' && res.result - ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) - : typeof res === 'function' - ? res - : resolveToNull, - options, - ), - getOrderByIdMock: (res, options) => - http.get( - `${baseUrl}${'/store/order/:orderId'}`, - typeof res === 'object' && res.result - ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) - : typeof res === 'function' - ? res - : resolveToNull, - options, - ), - getPetByIdMock: (res, options) => - http.get( - `${baseUrl}${'/pet/:petId'}`, - typeof res === 'object' && res.result - ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) - : typeof res === 'function' - ? res - : resolveToNull, - options, - ), - getUserByNameMock: (res, options) => - http.get( - `${baseUrl}${'/user/:username'}`, - typeof res === 'object' && res.result - ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) - : typeof res === 'function' - ? res - : resolveToNull, - options, - ), - loginUserMock: (res, options) => - http.get( - `${baseUrl}${'/user/login'}`, - typeof res === 'object' && res.result - ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) - : typeof res === 'function' - ? res - : resolveToNull, - options, - ), - logoutUserMock: (res, options) => - http.get( - `${baseUrl}${'/user/logout'}`, - typeof res === 'object' && res.result - ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 200 }) - : typeof res === 'function' - ? res - : resolveToNull, - options, - ), - placeOrderMock: (res, options) => - http.post( - `${baseUrl}${'/store/order'}`, - typeof res === 'object' && res.result - ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) - : typeof res === 'function' - ? res - : resolveToNull, - options, - ), - updatePetMock: (res, options) => - http.put( - `${baseUrl}${'/pet'}`, - typeof res === 'object' && res.result - ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) - : typeof res === 'function' - ? res - : resolveToNull, - options, - ), - updatePetWithFormMock: (res, options) => - http.post( - `${baseUrl}${'/pet/:petId'}`, - typeof res === 'object' && res.result - ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) - : typeof res === 'function' - ? res - : resolveToNull, - options, - ), - updateUserMock: (res, options) => - http.put( - `${baseUrl}${'/user/:username'}`, - typeof res === 'object' && res.result - ? () => new HttpResponse(res.result ?? null, { status: res.status ?? 200 }) - : typeof res === 'function' - ? res - : resolveToNull, - options, - ), - uploadFileMock: (res, options) => - http.post( - `${baseUrl}${'/pet/:petId/uploadImage'}`, - typeof res === 'object' && res.result - ? () => HttpResponse.json(res.result ?? null, { status: res.status ?? 200 }) - : typeof res === 'function' - ? res - : resolveToNull, - options, - ), +export function createMswHandlers(config: RequestHandlerOptions = {}): CreateMswHandlersResult { + type Handler = (resolver?: R, options?: RequestHandlerOptions) => HttpHandler; + function wrap(handler: Handler): Handler { + return (resolver, options) => handler(resolver, { ...config, ...options }); + } + const one: CreateMswHandlersResult['one'] = { + addPet: wrap(handleAddPet), + createUser: wrap(handleCreateUser), + createUsersWithListInput: wrap(handleCreateUsersWithListInput), + deleteOrder: wrap(handleDeleteOrder), + deletePet: wrap(handleDeletePet), + deleteUser: wrap(handleDeleteUser), + findPetsByStatus: wrap(handleFindPetsByStatus), + findPetsByTags: wrap(handleFindPetsByTags), + getInventory: wrap(handleGetInventory), + getOrderById: wrap(handleGetOrderById), + getPetById: wrap(handleGetPetById), + getUserByName: wrap(handleGetUserByName), + loginUser: wrap(handleLoginUser), + logoutUser: wrap(handleLogoutUser), + placeOrder: wrap(handlePlaceOrder), + updatePet: wrap(handleUpdatePet), + updatePetWithForm: wrap(handleUpdatePetWithForm), + updateUser: wrap(handleUpdateUser), + uploadFile: wrap(handleUploadFile), }; - const getAllMocks = (options?: GetAllMocksOptions): Array => { - const onMissingMock = options?.onMissingMock ?? 'skip'; - const overrides = options?.overrides; - const handlers: Array = []; - const addRequiredHandler = ( - handler: (value: Value | (() => HttpResponse)) => HttpHandler, - override: Value | undefined, - ) => { - if (override != null) { - handlers.push(handler(override)); - } else { - if (onMissingMock === 'error') { - handlers.push( - handler( - () => - new HttpResponse('[heyapi-msw] The mock of this request is not implemented.', { - status: 501, - }), - ), - ); - } - } - }; - handlers.push(mocks.deleteOrderMock(overrides?.deleteOrderMock)); - addRequiredHandler(mocks.getOrderByIdMock, overrides?.getOrderByIdMock); - addRequiredHandler(mocks.uploadFileMock, overrides?.uploadFileMock); - addRequiredHandler(mocks.findPetsByStatusMock, overrides?.findPetsByStatusMock); - addRequiredHandler(mocks.findPetsByTagsMock, overrides?.findPetsByTagsMock); - addRequiredHandler(mocks.getInventoryMock, overrides?.getInventoryMock); - addRequiredHandler(mocks.placeOrderMock, overrides?.placeOrderMock); - addRequiredHandler(mocks.createUsersWithListInputMock, overrides?.createUsersWithListInputMock); - addRequiredHandler(mocks.loginUserMock, overrides?.loginUserMock); - handlers.push(mocks.logoutUserMock(overrides?.logoutUserMock)); - handlers.push(mocks.deletePetMock(overrides?.deletePetMock)); - addRequiredHandler(mocks.getPetByIdMock, overrides?.getPetByIdMock); - addRequiredHandler(mocks.updatePetWithFormMock, overrides?.updatePetWithFormMock); - handlers.push(mocks.deleteUserMock(overrides?.deleteUserMock)); - addRequiredHandler(mocks.getUserByNameMock, overrides?.getUserByNameMock); - handlers.push(mocks.updateUserMock(overrides?.updateUserMock)); - addRequiredHandler(mocks.addPetMock, overrides?.addPetMock); - addRequiredHandler(mocks.updatePetMock, overrides?.updatePetMock); - addRequiredHandler(mocks.createUserMock, overrides?.createUserMock); - return handlers; + const all: CreateMswHandlersResult['all'] = (options = {}) => { + type OverrideValue = R | [resolver?: R, options?: RequestHandlerOptions]; + function invoke(fn: Handler, override?: OverrideValue): HttpHandler { + return Array.isArray(override) ? fn(...override) : fn(override); + } + const overrides = options.one ?? {}; + return [ + invoke(one.deleteOrder, overrides.deleteOrder), + invoke(one.getOrderById, overrides.getOrderById), + invoke(one.uploadFile, overrides.uploadFile), + invoke(one.findPetsByStatus, overrides.findPetsByStatus), + invoke(one.findPetsByTags, overrides.findPetsByTags), + invoke(one.getInventory, overrides.getInventory), + invoke(one.placeOrder, overrides.placeOrder), + invoke(one.createUsersWithListInput, overrides.createUsersWithListInput), + invoke(one.loginUser, overrides.loginUser), + invoke(one.logoutUser, overrides.logoutUser), + invoke(one.deletePet, overrides.deletePet), + invoke(one.getPetById, overrides.getPetById), + invoke(one.updatePetWithForm, overrides.updatePetWithForm), + invoke(one.deleteUser, overrides.deleteUser), + invoke(one.getUserByName, overrides.getUserByName), + invoke(one.updateUser, overrides.updateUser), + invoke(one.addPet, overrides.addPet), + invoke(one.updatePet, overrides.updatePet), + invoke(one.createUser, overrides.createUser), + ]; }; - return { ...mocks, getAllMocks }; -}; - -const _defaults = createMswHandlerFactory({ baseUrl: '*' }); - -export const addPetMock = _defaults.addPetMock; - -export const updatePetMock = _defaults.updatePetMock; - -export const findPetsByStatusMock = _defaults.findPetsByStatusMock; - -export const findPetsByTagsMock = _defaults.findPetsByTagsMock; - -export const deletePetMock = _defaults.deletePetMock; - -export const getPetByIdMock = _defaults.getPetByIdMock; - -export const updatePetWithFormMock = _defaults.updatePetWithFormMock; - -export const uploadFileMock = _defaults.uploadFileMock; - -export const getInventoryMock = _defaults.getInventoryMock; - -export const placeOrderMock = _defaults.placeOrderMock; - -export const deleteOrderMock = _defaults.deleteOrderMock; - -export const getOrderByIdMock = _defaults.getOrderByIdMock; - -export const createUserMock = _defaults.createUserMock; - -export const createUsersWithListInputMock = _defaults.createUsersWithListInputMock; - -export const loginUserMock = _defaults.loginUserMock; - -export const logoutUserMock = _defaults.logoutUserMock; - -export const deleteUserMock = _defaults.deleteUserMock; - -export const getUserByNameMock = _defaults.getUserByNameMock; - -export const updateUserMock = _defaults.updateUserMock; - -export const getAllMocks = _defaults.getAllMocks; + return { all, one }; +} diff --git a/examples/openapi-ts-fetch/test/msw-types.test-d.ts b/examples/openapi-ts-fetch/test/msw-types.test-d.ts index 574e767dfc..1a8388d535 100644 --- a/examples/openapi-ts-fetch/test/msw-types.test-d.ts +++ b/examples/openapi-ts-fetch/test/msw-types.test-d.ts @@ -1,123 +1,123 @@ import { type HttpHandler, HttpResponse } from 'msw'; import { describe, expectTypeOf, it } from 'vitest'; -import { createMswHandlerFactory } from '../src/client/msw.gen'; +import { createMswHandlers } from '../src/client/msw.gen'; import type { Order, Pet } from '../src/client/types.gen'; -const createMock = createMswHandlerFactory(); +const handlers = createMswHandlers(); describe('MSW plugin type-level tests', () => { describe('static response values', () => { it('accepts correct response type (Pet) with status', () => { const pet: Pet = { name: 'Fido', photoUrls: [] }; - createMock.getPetByIdMock({ result: pet, status: 200 }); - createMock.addPetMock({ result: pet, status: 200 }); - createMock.updatePetMock({ result: pet, status: 200 }); - createMock.findPetsByStatusMock({ result: [pet], status: 200 }); + handlers.one.getPetById({ result: pet, status: 200 }); + handlers.one.addPet({ result: pet, status: 200 }); + handlers.one.updatePet({ result: pet, status: 200 }); + handlers.one.findPetsByStatus({ result: [pet], status: 200 }); }); it('accepts correct response type (Order) with status', () => { const order: Order = { id: 1, petId: 1, quantity: 1 }; - createMock.placeOrderMock({ result: order, status: 200 }); - createMock.getOrderByIdMock({ result: order, status: 200 }); + handlers.one.placeOrder({ result: order, status: 200 }); + handlers.one.getOrderById({ result: order, status: 200 }); }); it('accepts correct response type (string) with status', () => { - createMock.loginUserMock({ result: 'session-token', status: 200 }); + handlers.one.loginUser({ result: 'session-token', status: 200 }); }); it('accepts correct response type (record) with status', () => { - createMock.getInventoryMock({ result: { available: 10, pending: 5 }, status: 200 }); + handlers.one.getInventory({ result: { available: 10, pending: 5 }, status: 200 }); }); it('rejects wrong response type for getPetById', () => { // @ts-expect-error - string is not a valid Pet response - createMock.getPetByIdMock({ result: 'wrong type', status: 200 }); + handlers.one.getPetById({ result: 'wrong type', status: 200 }); }); it('rejects wrong response type for addPet', () => { // @ts-expect-error - number is not a valid Pet response - createMock.addPetMock({ result: 42, status: 200 }); + handlers.one.addPet({ result: 42, status: 200 }); }); it('rejects wrong response type for findPetsByStatus', () => { // @ts-expect-error - a single Pet is not Array - createMock.findPetsByStatusMock({ result: { name: 'Fido', photoUrls: [] }, status: 200 }); + handlers.one.findPetsByStatus({ result: { name: 'Fido', photoUrls: [] }, status: 200 }); }); it('rejects wrong response type for placeOrder', () => { // @ts-expect-error - Pet is not a valid Order response - createMock.placeOrderMock({ result: { name: 'Fido', photoUrls: [] }, status: 200 }); + handlers.one.placeOrder({ result: { name: 'Fido', photoUrls: [] }, status: 200 }); }); it('rejects wrong response type for loginUser', () => { // @ts-expect-error - number is not a valid string response - createMock.loginUserMock({ result: 123, status: 200 }); + handlers.one.loginUser({ result: 123, status: 200 }); }); it('rejects wrong status code', () => { const pet: Pet = { name: 'Fido', photoUrls: [] }; // @ts-expect-error - 999 is not a valid status code - createMock.getPetByIdMock({ result: pet, status: 999 }); + handlers.one.getPetById({ result: pet, status: 999 }); }); it('accepts result without status (uses dominant response default)', () => { const pet: Pet = { name: 'Fido', photoUrls: [] }; - createMock.getPetByIdMock({ result: pet }); - createMock.addPetMock({ result: pet }); - createMock.updatePetMock({ result: pet }); - createMock.findPetsByStatusMock({ result: [pet] }); + handlers.one.getPetById({ result: pet }); + handlers.one.addPet({ result: pet }); + handlers.one.updatePet({ result: pet }); + handlers.one.findPetsByStatus({ result: [pet] }); }); it('accepts result without status for Order operations', () => { const order: Order = { id: 1, petId: 1, quantity: 1 }; - createMock.placeOrderMock({ result: order }); - createMock.getOrderByIdMock({ result: order }); + handlers.one.placeOrder({ result: order }); + handlers.one.getOrderById({ result: order }); }); it('accepts result without status for string response', () => { - createMock.loginUserMock({ result: 'session-token' }); + handlers.one.loginUser({ result: 'session-token' }); }); it('accepts result without status for record response', () => { - createMock.getInventoryMock({ result: { available: 10, pending: 5 } }); + handlers.one.getInventory({ result: { available: 10, pending: 5 } }); }); it('rejects wrong response type even without status', () => { // @ts-expect-error - string is not a valid Pet response - createMock.getPetByIdMock({ result: 'wrong type' }); + handlers.one.getPetById({ result: 'wrong type' }); }); }); describe('void operations accept no arguments', () => { it('logoutUser accepts no arguments', () => { - createMock.logoutUserMock(); + handlers.one.logoutUser(); }); it('deletePet accepts no arguments', () => { - createMock.deletePetMock(); + handlers.one.deletePet(); }); it('deleteOrder accepts no arguments', () => { - createMock.deleteOrderMock(); + handlers.one.deleteOrder(); }); it('deleteUser accepts no arguments', () => { - createMock.deleteUserMock(); + handlers.one.deleteUser(); }); }); describe('resolver function typing', () => { it('accepts HttpResponseResolver', () => { - createMock.getInventoryMock(() => HttpResponse.json({ available: 1 })); + handlers.one.getInventory(() => HttpResponse.json({ available: 1 })); }); it('accepts async HttpResponseResolver', () => { - createMock.getInventoryMock(async () => HttpResponse.json({ available: 1 })); + handlers.one.getInventory(async () => HttpResponse.json({ available: 1 })); }); it('resolver for path-param operation receives typed params', () => { - createMock.getPetByIdMock(({ params }) => { + handlers.one.getPetById(({ params }) => { // params.petId should be string (StringifyPathParams) expectTypeOf(params.petId).toEqualTypeOf(); return HttpResponse.json({ name: 'Test', photoUrls: [] }); @@ -125,7 +125,7 @@ describe('MSW plugin type-level tests', () => { }); it('resolver for body operation receives typed body via request', () => { - createMock.addPetMock(async ({ request }) => { + handlers.one.addPet(async ({ request }) => { const body = await request.json(); // body should be typed as Pet (AddPetData['body']) expectTypeOf(body).toEqualTypeOf(); @@ -134,11 +134,11 @@ describe('MSW plugin type-level tests', () => { }); it('resolver for void operation is typed correctly', () => { - createMock.logoutUserMock(() => HttpResponse.json(null)); + handlers.one.logoutUser(() => HttpResponse.json(null)); }); it('resolver for void operation with path params', () => { - createMock.deletePetMock(({ params }) => { + handlers.one.deletePet(({ params }) => { expectTypeOf(params.petId).toEqualTypeOf(); return new HttpResponse(null); }); @@ -147,7 +147,7 @@ describe('MSW plugin type-level tests', () => { describe('return type', () => { it('all handler creators return HttpHandler', () => { - const handler = createMock.getPetByIdMock({ + const handler = handlers.one.getPetById({ result: { name: 'Test', photoUrls: [] }, status: 200, }); @@ -157,9 +157,9 @@ describe('MSW plugin type-level tests', () => { describe('factory configuration', () => { it('accepts optional config', () => { - createMswHandlerFactory(); - createMswHandlerFactory({}); - createMswHandlerFactory({ baseUrl: 'http://localhost:3000' }); + createMswHandlers(); + createMswHandlers({}); + createMswHandlers({ baseUrl: 'http://localhost:3000' }); }); }); }); diff --git a/examples/openapi-ts-fetch/test/msw.test.ts b/examples/openapi-ts-fetch/test/msw.test.ts index ce47f08fdf..2235b5d75a 100644 --- a/examples/openapi-ts-fetch/test/msw.test.ts +++ b/examples/openapi-ts-fetch/test/msw.test.ts @@ -3,7 +3,7 @@ import { setupServer } from 'msw/node'; import { afterAll, afterEach, beforeAll, describe, expect, it } from 'vitest'; import { client } from '../src/client/client.gen'; -import { createMswHandlerFactory } from '../src/client/msw.gen'; +import { createMswHandlers } from '../src/client/msw.gen'; import { addPet, findPetsByStatus, @@ -17,7 +17,7 @@ import type { Pet } from '../src/client/types.gen'; const BASE_URL = 'http://localhost:3000/api/v3'; -const createMock = createMswHandlerFactory({ baseUrl: BASE_URL }); +const handlers = createMswHandlers({ baseUrl: BASE_URL }); const server = setupServer(); @@ -38,7 +38,7 @@ describe('MSW plugin runtime tests', () => { describe('static response value', () => { it('returns static response for GET without path params', async () => { const mockInventory = { available: 10, pending: 5 }; - server.use(createMock.getInventoryMock({ result: mockInventory, status: 200 })); + server.use(handlers.one.getInventory({ result: mockInventory, status: 200 })); const result = await getInventory({ client }); @@ -52,7 +52,7 @@ describe('MSW plugin runtime tests', () => { photoUrls: ['https://example.com/fido.jpg'], status: 'available', }; - server.use(createMock.getPetByIdMock({ result: mockPet, status: 200 })); + server.use(handlers.one.getPetById({ result: mockPet, status: 200 })); const result = await getPetById({ client, @@ -67,7 +67,7 @@ describe('MSW plugin runtime tests', () => { { id: 1, name: 'Fido', photoUrls: [], status: 'available' }, { id: 2, name: 'Rex', photoUrls: [], status: 'available' }, ]; - server.use(createMock.findPetsByStatusMock({ result: mockPets, status: 200 })); + server.use(handlers.one.findPetsByStatus({ result: mockPets, status: 200 })); const result = await findPetsByStatus({ client, @@ -84,7 +84,7 @@ describe('MSW plugin runtime tests', () => { photoUrls: ['https://example.com/new.jpg'], status: 'pending', }; - server.use(createMock.addPetMock({ result: mockPet, status: 200 })); + server.use(handlers.one.addPet({ result: mockPet, status: 200 })); const result = await addPet({ body: { @@ -106,7 +106,7 @@ describe('MSW plugin runtime tests', () => { photoUrls: ['https://example.com/fido.jpg'], status: 'available', }; - server.use(createMock.getPetByIdMock({ result: mockPet })); + server.use(handlers.one.getPetById({ result: mockPet })); const result = await getPetById({ client, @@ -123,7 +123,7 @@ describe('MSW plugin runtime tests', () => { photoUrls: ['https://example.com/new.jpg'], status: 'pending', }; - server.use(createMock.addPetMock({ result: mockPet })); + server.use(handlers.one.addPet({ result: mockPet })); const result = await addPet({ body: { @@ -140,7 +140,7 @@ describe('MSW plugin runtime tests', () => { describe('custom resolver function', () => { it('supports custom resolver for GET', async () => { server.use( - createMock.getPetByIdMock(({ params }) => + handlers.one.getPetById(({ params }) => HttpResponse.json({ id: Number(params.petId), name: `Pet-${params.petId}`, @@ -165,7 +165,7 @@ describe('MSW plugin runtime tests', () => { it('supports custom resolver with request body', async () => { server.use( - createMock.addPetMock(async ({ request }) => { + handlers.one.addPet(async ({ request }) => { const body = await request.json(); return HttpResponse.json({ id: 99, @@ -190,9 +190,7 @@ describe('MSW plugin runtime tests', () => { it('supports custom status codes', async () => { server.use( - createMock.getPetByIdMock(() => - HttpResponse.json({ message: 'not found' }, { status: 404 }), - ), + handlers.one.getPetById(() => HttpResponse.json({ message: 'not found' }, { status: 404 })), ); const result = await getPetById({ @@ -212,7 +210,7 @@ describe('MSW plugin runtime tests', () => { name: 'PathTest', photoUrls: [], }; - server.use(createMock.getPetByIdMock({ result: mockPet, status: 200 })); + server.use(handlers.one.getPetById({ result: mockPet, status: 200 })); const result = await getPetById({ client, @@ -231,7 +229,7 @@ describe('MSW plugin runtime tests', () => { lastName: 'Doe', username: 'john_doe', }; - server.use(createMock.getUserByNameMock({ result: mockUser, status: 200 })); + server.use(handlers.one.getUserByName({ result: mockUser, status: 200 })); const result = await getUserByName({ client, @@ -244,7 +242,7 @@ describe('MSW plugin runtime tests', () => { it('handles path param mid-path (e.g. /pet/{petId}/uploadImage)', async () => { const mockResponse = { code: 200, message: 'uploaded', type: 'ok' }; - server.use(createMock.uploadFileMock({ result: mockResponse, status: 200 })); + server.use(handlers.one.uploadFile({ result: mockResponse, status: 200 })); const result = await uploadFile({ body: new Blob(['fake-image']), @@ -258,7 +256,7 @@ describe('MSW plugin runtime tests', () => { it('resolver receives correct path param values', async () => { server.use( - createMock.getOrderByIdMock(({ params }) => { + handlers.one.getOrderById(({ params }) => { // MSW normalizes path params to strings expect(typeof params.orderId).toBe('string'); return HttpResponse.json({ @@ -282,8 +280,8 @@ describe('MSW plugin runtime tests', () => { describe('handler override', () => { it('later handlers override earlier ones', async () => { - server.use(createMock.getInventoryMock({ result: { available: 1 }, status: 200 })); - server.use(createMock.getInventoryMock({ result: { available: 999 }, status: 200 })); + server.use(handlers.one.getInventory({ result: { available: 1 }, status: 200 })); + server.use(handlers.one.getInventory({ result: { available: 999 }, status: 200 })); const result = await getInventory({ client }); @@ -293,7 +291,7 @@ describe('MSW plugin runtime tests', () => { describe('void operations', () => { it('handles operations with no response body', async () => { - server.use(createMock.logoutUserMock()); + server.use(handlers.one.logoutUser()); const result = await (await import('../src/client/sdk.gen')).logoutUser({ client }); diff --git a/packages/openapi-ts/src/plugins/msw/shared/handler.ts b/packages/openapi-ts/src/plugins/msw/shared/handler.ts index 4449e8d3ea..a0bc5b6b79 100644 --- a/packages/openapi-ts/src/plugins/msw/shared/handler.ts +++ b/packages/openapi-ts/src/plugins/msw/shared/handler.ts @@ -127,7 +127,7 @@ function createHandlerFunc({ dominantResponse, plugin, symbolResolver, - }), + }).return(), ), ), ) diff --git a/packages/openapi-ts/src/plugins/msw/shared/response.ts b/packages/openapi-ts/src/plugins/msw/shared/response.ts index acbefbe374..1e334c56fd 100644 --- a/packages/openapi-ts/src/plugins/msw/shared/response.ts +++ b/packages/openapi-ts/src/plugins/msw/shared/response.ts @@ -15,7 +15,7 @@ export function createHandlerResponse({ dominantResponse: DominantResponse; plugin: MswPlugin['Instance']; symbolResolver: Symbol; -}) { +}): ReturnType { const symbolHttpResponse = plugin.external('msw.HttpResponse'); const statusOption = $.object().prop( @@ -28,18 +28,21 @@ export function createHandlerResponse({ switch (responseKind) { case 'binary': - return $.new(symbolHttpResponse, resultExpr.coalesce($.literal(null)), statusOption).return(); + return $.new(symbolHttpResponse, resultExpr.coalesce($.literal(null)), statusOption); case 'json': return $(symbolHttpResponse) .attr('json') - .call(resultExpr.coalesce($.literal(null)), statusOption) - .return(); + .call(resultExpr.coalesce($.literal(null)), statusOption); case 'text': return $(symbolHttpResponse) .attr('text') - .call(resultExpr.coalesce($.literal(null)), statusOption) - .return(); + .call( + $('JSON') + .attr('stringify') + .call(resultExpr.coalesce($.literal(''))), + statusOption, + ); case 'void': - return $.new(symbolHttpResponse, resultExpr.coalesce($.literal(null)), statusOption).return(); + return $.new(symbolHttpResponse, resultExpr.coalesce($.literal(null)), statusOption); } }