diff --git a/.changeset/wet-vans-taste.md b/.changeset/wet-vans-taste.md new file mode 100644 index 000000000..91441ef40 --- /dev/null +++ b/.changeset/wet-vans-taste.md @@ -0,0 +1,5 @@ +--- +'@hey-api/openapi-ts': patch +--- + +fix(tanstack-query): correctly access instantiated SDKs diff --git a/dev/openapi-ts.config.ts b/dev/openapi-ts.config.ts index c919e1ed0..ea1c40dbb 100644 --- a/dev/openapi-ts.config.ts +++ b/dev/openapi-ts.config.ts @@ -41,10 +41,9 @@ export default defineConfig(() => { // 'circular.yaml', // 'dutchie.json', // 'invalid', - // 'openai.yaml', // 'full.yaml', - 'opencode.yaml', - // 'sdk-circular-bug.yaml', + 'openai.yaml', + // 'opencode.yaml', // 'sdk-instance.yaml', // 'string-with-format.yaml', // 'transformers.json', @@ -217,8 +216,7 @@ export default defineConfig(() => { { // baseUrl: false, // exportFromIndex: true, - // name: '@hey-api/client-fetch', - // name: 'legacy/angular', + name: '@hey-api/client-fetch', // runtimeConfigPath: path.resolve(__dirname, 'hey-api.ts'), // runtimeConfigPath: './src/hey-api.ts', // strictBaseUrl: true, @@ -256,7 +254,7 @@ export default defineConfig(() => { // classNameBuilder: '{{name}}', // classNameBuilder: '{{name}}Service', // classStructure: 'off', - // client: false, + client: false, // getSignature: ({ fields, signature, operation }) => { // // ... // fields.unwrap('path') @@ -265,7 +263,7 @@ export default defineConfig(() => { instance: true, name: '@hey-api/sdk', // operationId: false, - paramsStructure: 'flat', + // paramsStructure: 'flat', // responseStyle: 'data', // signature: 'auto', // signature: 'client', @@ -299,6 +297,9 @@ export default defineConfig(() => { { // name: 'fastify', }, + { + name: 'swr', + }, { // case: 'SCREAMING_SNAKE_CASE', // comments: false, diff --git a/dev/package.json b/dev/package.json index 83230c8a4..0fa72bc8e 100644 --- a/dev/package.json +++ b/dev/package.json @@ -16,6 +16,7 @@ "@tanstack/svelte-query": "5.73.3", "@tanstack/vue-query": "5.73.3", "arktype": "2.1.25", + "swr": "2.3.6", "typescript": "5.9.3", "valibot": "1.1.0", "zod": "4.1.12" diff --git a/examples/openapi-ts-angular/src/client/sdk.gen.ts b/examples/openapi-ts-angular/src/client/sdk.gen.ts index 9d7d0b4e5..8052bc09e 100644 --- a/examples/openapi-ts-angular/src/client/sdk.gen.ts +++ b/examples/openapi-ts-angular/src/client/sdk.gen.ts @@ -81,9 +81,7 @@ export type Options< meta?: Record; }; -@Injectable({ - providedIn: 'root', -}) +@Injectable({ providedIn: 'root' }) export class PetService { /** * Add a new pet to the store. @@ -295,9 +293,7 @@ export class PetService { } } -@Injectable({ - providedIn: 'root', -}) +@Injectable({ providedIn: 'root' }) export class StoreService { /** * Returns pet inventories by status. @@ -382,9 +378,7 @@ export class StoreService { } } -@Injectable({ - providedIn: 'root', -}) +@Injectable({ providedIn: 'root' }) export class UserService { /** * Create user. diff --git a/examples/openapi-ts-openai/src/client/sdk.gen.ts b/examples/openapi-ts-openai/src/client/sdk.gen.ts index 99bdf823b..405809473 100644 --- a/examples/openapi-ts-openai/src/client/sdk.gen.ts +++ b/examples/openapi-ts-openai/src/client/sdk.gen.ts @@ -365,17 +365,42 @@ export type Options< meta?: Record; }; -class _HeyApiClient { - protected _client: Client = client; +class HeyApiClient { + protected client: Client; constructor(args?: { client?: Client }) { - if (args?.client) { - this._client = args.client; + this.client = args?.client ?? client; + } +} + +class HeyApiRegistry { + private readonly defaultKey = 'default'; + + private readonly instances: Map = new Map(); + + get(key?: string): T { + const instance = this.instances.get(key ?? this.defaultKey); + if (!instance) { + throw new Error( + `No SDK client found. Create one with "new OpenAi()" to fix this error.`, + ); } + return instance; + } + + set(value: T, key?: string): void { + this.instances.set(key ?? this.defaultKey, value); } } -export class OpenAi extends _HeyApiClient { +export class OpenAi extends HeyApiClient { + public static readonly __registry = new HeyApiRegistry(); + + constructor(args?: { client?: Client; key?: string }) { + super(args); + OpenAi.__registry.set(this, args?.key); + } + /** * List assistants * @@ -384,7 +409,7 @@ export class OpenAi extends _HeyApiClient { public listAssistants( options?: Options, ) { - return (options?.client ?? this._client).get< + return (options?.client ?? this.client).get< ListAssistantsResponses, unknown, ThrowOnError @@ -408,7 +433,7 @@ export class OpenAi extends _HeyApiClient { public createAssistant( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateAssistantResponses, unknown, ThrowOnError @@ -436,7 +461,7 @@ export class OpenAi extends _HeyApiClient { public deleteAssistant( options: Options, ) { - return (options.client ?? this._client).delete< + return (options.client ?? this.client).delete< DeleteAssistantResponses, unknown, ThrowOnError @@ -460,7 +485,7 @@ export class OpenAi extends _HeyApiClient { public getAssistant( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< GetAssistantResponses, unknown, ThrowOnError @@ -484,7 +509,7 @@ export class OpenAi extends _HeyApiClient { public modifyAssistant( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< ModifyAssistantResponses, unknown, ThrowOnError @@ -512,7 +537,7 @@ export class OpenAi extends _HeyApiClient { public createSpeech( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateSpeechResponses, unknown, ThrowOnError @@ -540,7 +565,7 @@ export class OpenAi extends _HeyApiClient { public createTranscription( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateTranscriptionResponses, unknown, ThrowOnError @@ -569,7 +594,7 @@ export class OpenAi extends _HeyApiClient { public createTranslation( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateTranslationResponses, unknown, ThrowOnError @@ -598,7 +623,7 @@ export class OpenAi extends _HeyApiClient { public listBatches( options?: Options, ) { - return (options?.client ?? this._client).get< + return (options?.client ?? this.client).get< ListBatchesResponses, unknown, ThrowOnError @@ -622,7 +647,7 @@ export class OpenAi extends _HeyApiClient { public createBatch( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateBatchResponses, unknown, ThrowOnError @@ -650,7 +675,7 @@ export class OpenAi extends _HeyApiClient { public retrieveBatch( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< RetrieveBatchResponses, unknown, ThrowOnError @@ -674,7 +699,7 @@ export class OpenAi extends _HeyApiClient { public cancelBatch( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CancelBatchResponses, unknown, ThrowOnError @@ -700,7 +725,7 @@ export class OpenAi extends _HeyApiClient { public listChatCompletions( options?: Options, ) { - return (options?.client ?? this._client).get< + return (options?.client ?? this.client).get< ListChatCompletionsResponses, unknown, ThrowOnError @@ -739,7 +764,7 @@ export class OpenAi extends _HeyApiClient { public createChatCompletion( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateChatCompletionResponses, unknown, ThrowOnError @@ -769,7 +794,7 @@ export class OpenAi extends _HeyApiClient { public deleteChatCompletion( options: Options, ) { - return (options.client ?? this._client).delete< + return (options.client ?? this.client).delete< DeleteChatCompletionResponses, unknown, ThrowOnError @@ -795,7 +820,7 @@ export class OpenAi extends _HeyApiClient { public getChatCompletion( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< GetChatCompletionResponses, unknown, ThrowOnError @@ -822,7 +847,7 @@ export class OpenAi extends _HeyApiClient { public updateChatCompletion( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< UpdateChatCompletionResponses, unknown, ThrowOnError @@ -853,7 +878,7 @@ export class OpenAi extends _HeyApiClient { public getChatCompletionMessages( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< GetChatCompletionMessagesResponses, unknown, ThrowOnError @@ -877,7 +902,7 @@ export class OpenAi extends _HeyApiClient { public createCompletion( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateCompletionResponses, unknown, ThrowOnError @@ -905,7 +930,7 @@ export class OpenAi extends _HeyApiClient { public listContainers( options?: Options, ) { - return (options?.client ?? this._client).get< + return (options?.client ?? this.client).get< ListContainersResponses, unknown, ThrowOnError @@ -929,7 +954,7 @@ export class OpenAi extends _HeyApiClient { public createContainer( options?: Options, ) { - return (options?.client ?? this._client).post< + return (options?.client ?? this.client).post< CreateContainerResponses, unknown, ThrowOnError @@ -957,7 +982,7 @@ export class OpenAi extends _HeyApiClient { public deleteContainer( options: Options, ) { - return (options.client ?? this._client).delete< + return (options.client ?? this.client).delete< DeleteContainerResponses, unknown, ThrowOnError @@ -981,7 +1006,7 @@ export class OpenAi extends _HeyApiClient { public retrieveContainer( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< RetrieveContainerResponses, unknown, ThrowOnError @@ -1005,7 +1030,7 @@ export class OpenAi extends _HeyApiClient { public listContainerFiles( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< ListContainerFilesResponses, unknown, ThrowOnError @@ -1032,7 +1057,7 @@ export class OpenAi extends _HeyApiClient { public createContainerFile( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateContainerFileResponses, unknown, ThrowOnError @@ -1061,7 +1086,7 @@ export class OpenAi extends _HeyApiClient { public deleteContainerFile( options: Options, ) { - return (options.client ?? this._client).delete< + return (options.client ?? this.client).delete< DeleteContainerFileResponses, unknown, ThrowOnError @@ -1085,7 +1110,7 @@ export class OpenAi extends _HeyApiClient { public retrieveContainerFile( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< RetrieveContainerFileResponses, unknown, ThrowOnError @@ -1109,7 +1134,7 @@ export class OpenAi extends _HeyApiClient { public retrieveContainerFileContent( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< RetrieveContainerFileContentResponses, unknown, ThrowOnError @@ -1133,7 +1158,7 @@ export class OpenAi extends _HeyApiClient { public createEmbedding( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateEmbeddingResponses, unknown, ThrowOnError @@ -1162,7 +1187,7 @@ export class OpenAi extends _HeyApiClient { public listEvals( options?: Options, ) { - return (options?.client ?? this._client).get< + return (options?.client ?? this.client).get< ListEvalsResponses, unknown, ThrowOnError @@ -1189,7 +1214,7 @@ export class OpenAi extends _HeyApiClient { public createEval( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateEvalResponses, unknown, ThrowOnError @@ -1218,7 +1243,7 @@ export class OpenAi extends _HeyApiClient { public deleteEval( options: Options, ) { - return (options.client ?? this._client).delete< + return (options.client ?? this.client).delete< DeleteEvalResponses, DeleteEvalErrors, ThrowOnError @@ -1243,7 +1268,7 @@ export class OpenAi extends _HeyApiClient { public getEval( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< GetEvalResponses, unknown, ThrowOnError @@ -1268,7 +1293,7 @@ export class OpenAi extends _HeyApiClient { public updateEval( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< UpdateEvalResponses, unknown, ThrowOnError @@ -1297,7 +1322,7 @@ export class OpenAi extends _HeyApiClient { public getEvalRuns( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< GetEvalRunsResponses, unknown, ThrowOnError @@ -1322,7 +1347,7 @@ export class OpenAi extends _HeyApiClient { public createEvalRun( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateEvalRunResponses, CreateEvalRunErrors, ThrowOnError @@ -1351,7 +1376,7 @@ export class OpenAi extends _HeyApiClient { public deleteEvalRun( options: Options, ) { - return (options.client ?? this._client).delete< + return (options.client ?? this.client).delete< DeleteEvalRunResponses, DeleteEvalRunErrors, ThrowOnError @@ -1376,7 +1401,7 @@ export class OpenAi extends _HeyApiClient { public getEvalRun( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< GetEvalRunResponses, unknown, ThrowOnError @@ -1401,7 +1426,7 @@ export class OpenAi extends _HeyApiClient { public cancelEvalRun( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CancelEvalRunResponses, unknown, ThrowOnError @@ -1426,7 +1451,7 @@ export class OpenAi extends _HeyApiClient { public getEvalRunOutputItems( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< GetEvalRunOutputItemsResponses, unknown, ThrowOnError @@ -1451,7 +1476,7 @@ export class OpenAi extends _HeyApiClient { public getEvalRunOutputItem( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< GetEvalRunOutputItemResponses, unknown, ThrowOnError @@ -1475,7 +1500,7 @@ export class OpenAi extends _HeyApiClient { public listFiles( options?: Options, ) { - return (options?.client ?? this._client).get< + return (options?.client ?? this.client).get< ListFilesResponses, unknown, ThrowOnError @@ -1508,7 +1533,7 @@ export class OpenAi extends _HeyApiClient { public createFile( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateFileResponses, unknown, ThrowOnError @@ -1537,7 +1562,7 @@ export class OpenAi extends _HeyApiClient { public deleteFile( options: Options, ) { - return (options.client ?? this._client).delete< + return (options.client ?? this.client).delete< DeleteFileResponses, unknown, ThrowOnError @@ -1561,7 +1586,7 @@ export class OpenAi extends _HeyApiClient { public retrieveFile( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< RetrieveFileResponses, unknown, ThrowOnError @@ -1585,7 +1610,7 @@ export class OpenAi extends _HeyApiClient { public downloadFile( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< DownloadFileResponses, unknown, ThrowOnError @@ -1610,7 +1635,7 @@ export class OpenAi extends _HeyApiClient { public runGrader( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< RunGraderResponses, unknown, ThrowOnError @@ -1639,7 +1664,7 @@ export class OpenAi extends _HeyApiClient { public validateGrader( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< ValidateGraderResponses, unknown, ThrowOnError @@ -1670,7 +1695,7 @@ export class OpenAi extends _HeyApiClient { public listFineTuningCheckpointPermissions< ThrowOnError extends boolean = false, >(options: Options) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< ListFineTuningCheckpointPermissionsResponses, unknown, ThrowOnError @@ -1697,7 +1722,7 @@ export class OpenAi extends _HeyApiClient { public createFineTuningCheckpointPermission< ThrowOnError extends boolean = false, >(options: Options) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateFineTuningCheckpointPermissionResponses, unknown, ThrowOnError @@ -1728,7 +1753,7 @@ export class OpenAi extends _HeyApiClient { public deleteFineTuningCheckpointPermission< ThrowOnError extends boolean = false, >(options: Options) { - return (options.client ?? this._client).delete< + return (options.client ?? this.client).delete< DeleteFineTuningCheckpointPermissionResponses, unknown, ThrowOnError @@ -1753,7 +1778,7 @@ export class OpenAi extends _HeyApiClient { public listPaginatedFineTuningJobs( options?: Options, ) { - return (options?.client ?? this._client).get< + return (options?.client ?? this.client).get< ListPaginatedFineTuningJobsResponses, unknown, ThrowOnError @@ -1782,7 +1807,7 @@ export class OpenAi extends _HeyApiClient { public createFineTuningJob( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateFineTuningJobResponses, unknown, ThrowOnError @@ -1813,7 +1838,7 @@ export class OpenAi extends _HeyApiClient { public retrieveFineTuningJob( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< RetrieveFineTuningJobResponses, unknown, ThrowOnError @@ -1838,7 +1863,7 @@ export class OpenAi extends _HeyApiClient { public cancelFineTuningJob( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CancelFineTuningJobResponses, unknown, ThrowOnError @@ -1863,7 +1888,7 @@ export class OpenAi extends _HeyApiClient { public listFineTuningJobCheckpoints( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< ListFineTuningJobCheckpointsResponses, unknown, ThrowOnError @@ -1888,7 +1913,7 @@ export class OpenAi extends _HeyApiClient { public listFineTuningEvents( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< ListFineTuningEventsResponses, unknown, ThrowOnError @@ -1913,7 +1938,7 @@ export class OpenAi extends _HeyApiClient { public pauseFineTuningJob( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< PauseFineTuningJobResponses, unknown, ThrowOnError @@ -1938,7 +1963,7 @@ export class OpenAi extends _HeyApiClient { public resumeFineTuningJob( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< ResumeFineTuningJobResponses, unknown, ThrowOnError @@ -1962,7 +1987,7 @@ export class OpenAi extends _HeyApiClient { public createImageEdit( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateImageEditResponses, unknown, ThrowOnError @@ -1992,7 +2017,7 @@ export class OpenAi extends _HeyApiClient { public createImage( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateImageResponses, unknown, ThrowOnError @@ -2020,7 +2045,7 @@ export class OpenAi extends _HeyApiClient { public createImageVariation( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateImageVariationResponses, unknown, ThrowOnError @@ -2049,7 +2074,7 @@ export class OpenAi extends _HeyApiClient { public listModels( options?: Options, ) { - return (options?.client ?? this._client).get< + return (options?.client ?? this.client).get< ListModelsResponses, unknown, ThrowOnError @@ -2073,7 +2098,7 @@ export class OpenAi extends _HeyApiClient { public deleteModel( options: Options, ) { - return (options.client ?? this._client).delete< + return (options.client ?? this.client).delete< DeleteModelResponses, unknown, ThrowOnError @@ -2097,7 +2122,7 @@ export class OpenAi extends _HeyApiClient { public retrieveModel( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< RetrieveModelResponses, unknown, ThrowOnError @@ -2123,7 +2148,7 @@ export class OpenAi extends _HeyApiClient { public createModeration( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateModerationResponses, unknown, ThrowOnError @@ -2151,7 +2176,7 @@ export class OpenAi extends _HeyApiClient { public adminApiKeysList( options?: Options, ) { - return (options?.client ?? this._client).get< + return (options?.client ?? this.client).get< AdminApiKeysListResponses, unknown, ThrowOnError @@ -2175,7 +2200,7 @@ export class OpenAi extends _HeyApiClient { public adminApiKeysCreate( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< AdminApiKeysCreateResponses, unknown, ThrowOnError @@ -2203,7 +2228,7 @@ export class OpenAi extends _HeyApiClient { public adminApiKeysDelete( options: Options, ) { - return (options.client ?? this._client).delete< + return (options.client ?? this.client).delete< AdminApiKeysDeleteResponses, unknown, ThrowOnError @@ -2227,7 +2252,7 @@ export class OpenAi extends _HeyApiClient { public adminApiKeysGet( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< AdminApiKeysGetResponses, unknown, ThrowOnError @@ -2251,7 +2276,7 @@ export class OpenAi extends _HeyApiClient { public listAuditLogs( options?: Options, ) { - return (options?.client ?? this._client).get< + return (options?.client ?? this.client).get< ListAuditLogsResponses, unknown, ThrowOnError @@ -2284,7 +2309,7 @@ export class OpenAi extends _HeyApiClient { public listOrganizationCertificates( options?: Options, ) { - return (options?.client ?? this._client).get< + return (options?.client ?? this.client).get< ListOrganizationCertificatesResponses, unknown, ThrowOnError @@ -2311,7 +2336,7 @@ export class OpenAi extends _HeyApiClient { public uploadCertificate( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< UploadCertificateResponses, unknown, ThrowOnError @@ -2342,7 +2367,7 @@ export class OpenAi extends _HeyApiClient { public activateOrganizationCertificates( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< ActivateOrganizationCertificatesResponses, unknown, ThrowOnError @@ -2373,7 +2398,7 @@ export class OpenAi extends _HeyApiClient { public deactivateOrganizationCertificates< ThrowOnError extends boolean = false, >(options: Options) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< DeactivateOrganizationCertificatesResponses, unknown, ThrowOnError @@ -2404,7 +2429,7 @@ export class OpenAi extends _HeyApiClient { public deleteCertificate( options?: Options, ) { - return (options?.client ?? this._client).delete< + return (options?.client ?? this.client).delete< DeleteCertificateResponses, unknown, ThrowOnError @@ -2431,7 +2456,7 @@ export class OpenAi extends _HeyApiClient { public getCertificate( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< GetCertificateResponses, unknown, ThrowOnError @@ -2456,7 +2481,7 @@ export class OpenAi extends _HeyApiClient { public modifyCertificate( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< ModifyCertificateResponses, unknown, ThrowOnError @@ -2484,7 +2509,7 @@ export class OpenAi extends _HeyApiClient { public usageCosts( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< UsageCostsResponses, unknown, ThrowOnError @@ -2508,7 +2533,7 @@ export class OpenAi extends _HeyApiClient { public listInvites( options?: Options, ) { - return (options?.client ?? this._client).get< + return (options?.client ?? this.client).get< ListInvitesResponses, unknown, ThrowOnError @@ -2532,7 +2557,7 @@ export class OpenAi extends _HeyApiClient { public inviteUser( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< InviteUserResponses, unknown, ThrowOnError @@ -2560,7 +2585,7 @@ export class OpenAi extends _HeyApiClient { public deleteInvite( options: Options, ) { - return (options.client ?? this._client).delete< + return (options.client ?? this.client).delete< DeleteInviteResponses, unknown, ThrowOnError @@ -2584,7 +2609,7 @@ export class OpenAi extends _HeyApiClient { public retrieveInvite( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< RetrieveInviteResponses, unknown, ThrowOnError @@ -2608,7 +2633,7 @@ export class OpenAi extends _HeyApiClient { public listProjects( options?: Options, ) { - return (options?.client ?? this._client).get< + return (options?.client ?? this.client).get< ListProjectsResponses, unknown, ThrowOnError @@ -2632,7 +2657,7 @@ export class OpenAi extends _HeyApiClient { public createProject( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateProjectResponses, unknown, ThrowOnError @@ -2660,7 +2685,7 @@ export class OpenAi extends _HeyApiClient { public retrieveProject( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< RetrieveProjectResponses, unknown, ThrowOnError @@ -2684,7 +2709,7 @@ export class OpenAi extends _HeyApiClient { public modifyProject( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< ModifyProjectResponses, ModifyProjectErrors, ThrowOnError @@ -2712,7 +2737,7 @@ export class OpenAi extends _HeyApiClient { public listProjectApiKeys( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< ListProjectApiKeysResponses, unknown, ThrowOnError @@ -2736,7 +2761,7 @@ export class OpenAi extends _HeyApiClient { public deleteProjectApiKey( options: Options, ) { - return (options.client ?? this._client).delete< + return (options.client ?? this.client).delete< DeleteProjectApiKeyResponses, DeleteProjectApiKeyErrors, ThrowOnError @@ -2760,7 +2785,7 @@ export class OpenAi extends _HeyApiClient { public retrieveProjectApiKey( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< RetrieveProjectApiKeyResponses, unknown, ThrowOnError @@ -2784,7 +2809,7 @@ export class OpenAi extends _HeyApiClient { public archiveProject( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< ArchiveProjectResponses, unknown, ThrowOnError @@ -2808,7 +2833,7 @@ export class OpenAi extends _HeyApiClient { public listProjectCertificates( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< ListProjectCertificatesResponses, unknown, ThrowOnError @@ -2835,7 +2860,7 @@ export class OpenAi extends _HeyApiClient { public activateProjectCertificates( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< ActivateProjectCertificatesResponses, unknown, ThrowOnError @@ -2865,7 +2890,7 @@ export class OpenAi extends _HeyApiClient { public deactivateProjectCertificates( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< DeactivateProjectCertificatesResponses, unknown, ThrowOnError @@ -2893,7 +2918,7 @@ export class OpenAi extends _HeyApiClient { public listProjectRateLimits( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< ListProjectRateLimitsResponses, unknown, ThrowOnError @@ -2917,7 +2942,7 @@ export class OpenAi extends _HeyApiClient { public updateProjectRateLimits( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< UpdateProjectRateLimitsResponses, UpdateProjectRateLimitsErrors, ThrowOnError @@ -2945,7 +2970,7 @@ export class OpenAi extends _HeyApiClient { public listProjectServiceAccounts( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< ListProjectServiceAccountsResponses, ListProjectServiceAccountsErrors, ThrowOnError @@ -2969,7 +2994,7 @@ export class OpenAi extends _HeyApiClient { public createProjectServiceAccount( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateProjectServiceAccountResponses, CreateProjectServiceAccountErrors, ThrowOnError @@ -2997,7 +3022,7 @@ export class OpenAi extends _HeyApiClient { public deleteProjectServiceAccount( options: Options, ) { - return (options.client ?? this._client).delete< + return (options.client ?? this.client).delete< DeleteProjectServiceAccountResponses, unknown, ThrowOnError @@ -3021,7 +3046,7 @@ export class OpenAi extends _HeyApiClient { public retrieveProjectServiceAccount( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< RetrieveProjectServiceAccountResponses, unknown, ThrowOnError @@ -3045,7 +3070,7 @@ export class OpenAi extends _HeyApiClient { public listProjectUsers( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< ListProjectUsersResponses, ListProjectUsersErrors, ThrowOnError @@ -3069,7 +3094,7 @@ export class OpenAi extends _HeyApiClient { public createProjectUser( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateProjectUserResponses, CreateProjectUserErrors, ThrowOnError @@ -3097,7 +3122,7 @@ export class OpenAi extends _HeyApiClient { public deleteProjectUser( options: Options, ) { - return (options.client ?? this._client).delete< + return (options.client ?? this.client).delete< DeleteProjectUserResponses, DeleteProjectUserErrors, ThrowOnError @@ -3121,7 +3146,7 @@ export class OpenAi extends _HeyApiClient { public retrieveProjectUser( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< RetrieveProjectUserResponses, unknown, ThrowOnError @@ -3145,7 +3170,7 @@ export class OpenAi extends _HeyApiClient { public modifyProjectUser( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< ModifyProjectUserResponses, ModifyProjectUserErrors, ThrowOnError @@ -3173,7 +3198,7 @@ export class OpenAi extends _HeyApiClient { public usageAudioSpeeches( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< UsageAudioSpeechesResponses, unknown, ThrowOnError @@ -3197,7 +3222,7 @@ export class OpenAi extends _HeyApiClient { public usageAudioTranscriptions( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< UsageAudioTranscriptionsResponses, unknown, ThrowOnError @@ -3221,7 +3246,7 @@ export class OpenAi extends _HeyApiClient { public usageCodeInterpreterSessions( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< UsageCodeInterpreterSessionsResponses, unknown, ThrowOnError @@ -3245,7 +3270,7 @@ export class OpenAi extends _HeyApiClient { public usageCompletions( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< UsageCompletionsResponses, unknown, ThrowOnError @@ -3269,7 +3294,7 @@ export class OpenAi extends _HeyApiClient { public usageEmbeddings( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< UsageEmbeddingsResponses, unknown, ThrowOnError @@ -3293,7 +3318,7 @@ export class OpenAi extends _HeyApiClient { public usageImages( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< UsageImagesResponses, unknown, ThrowOnError @@ -3317,7 +3342,7 @@ export class OpenAi extends _HeyApiClient { public usageModerations( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< UsageModerationsResponses, unknown, ThrowOnError @@ -3341,7 +3366,7 @@ export class OpenAi extends _HeyApiClient { public usageVectorStores( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< UsageVectorStoresResponses, unknown, ThrowOnError @@ -3365,7 +3390,7 @@ export class OpenAi extends _HeyApiClient { public listUsers( options?: Options, ) { - return (options?.client ?? this._client).get< + return (options?.client ?? this.client).get< ListUsersResponses, unknown, ThrowOnError @@ -3389,7 +3414,7 @@ export class OpenAi extends _HeyApiClient { public deleteUser( options: Options, ) { - return (options.client ?? this._client).delete< + return (options.client ?? this.client).delete< DeleteUserResponses, unknown, ThrowOnError @@ -3413,7 +3438,7 @@ export class OpenAi extends _HeyApiClient { public retrieveUser( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< RetrieveUserResponses, unknown, ThrowOnError @@ -3437,7 +3462,7 @@ export class OpenAi extends _HeyApiClient { public modifyUser( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< ModifyUserResponses, unknown, ThrowOnError @@ -3472,7 +3497,7 @@ export class OpenAi extends _HeyApiClient { public createRealtimeSession( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateRealtimeSessionResponses, unknown, ThrowOnError @@ -3507,7 +3532,7 @@ export class OpenAi extends _HeyApiClient { public createRealtimeTranscriptionSession< ThrowOnError extends boolean = false, >(options: Options) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateRealtimeTranscriptionSessionResponses, unknown, ThrowOnError @@ -3542,7 +3567,7 @@ export class OpenAi extends _HeyApiClient { public createResponse( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateResponseResponses, unknown, ThrowOnError @@ -3571,7 +3596,7 @@ export class OpenAi extends _HeyApiClient { public deleteResponse( options: Options, ) { - return (options.client ?? this._client).delete< + return (options.client ?? this.client).delete< DeleteResponseResponses, DeleteResponseErrors, ThrowOnError @@ -3596,7 +3621,7 @@ export class OpenAi extends _HeyApiClient { public getResponse( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< GetResponseResponses, unknown, ThrowOnError @@ -3623,7 +3648,7 @@ export class OpenAi extends _HeyApiClient { public cancelResponse( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CancelResponseResponses, CancelResponseErrors, ThrowOnError @@ -3647,7 +3672,7 @@ export class OpenAi extends _HeyApiClient { public listInputItems( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< ListInputItemsResponses, unknown, ThrowOnError @@ -3671,7 +3696,7 @@ export class OpenAi extends _HeyApiClient { public createThread( options?: Options, ) { - return (options?.client ?? this._client).post< + return (options?.client ?? this.client).post< CreateThreadResponses, unknown, ThrowOnError @@ -3699,7 +3724,7 @@ export class OpenAi extends _HeyApiClient { public createThreadAndRun( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateThreadAndRunResponses, unknown, ThrowOnError @@ -3727,7 +3752,7 @@ export class OpenAi extends _HeyApiClient { public deleteThread( options: Options, ) { - return (options.client ?? this._client).delete< + return (options.client ?? this.client).delete< DeleteThreadResponses, unknown, ThrowOnError @@ -3751,7 +3776,7 @@ export class OpenAi extends _HeyApiClient { public getThread( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< GetThreadResponses, unknown, ThrowOnError @@ -3775,7 +3800,7 @@ export class OpenAi extends _HeyApiClient { public modifyThread( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< ModifyThreadResponses, unknown, ThrowOnError @@ -3803,7 +3828,7 @@ export class OpenAi extends _HeyApiClient { public listMessages( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< ListMessagesResponses, unknown, ThrowOnError @@ -3827,7 +3852,7 @@ export class OpenAi extends _HeyApiClient { public createMessage( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateMessageResponses, unknown, ThrowOnError @@ -3855,7 +3880,7 @@ export class OpenAi extends _HeyApiClient { public deleteMessage( options: Options, ) { - return (options.client ?? this._client).delete< + return (options.client ?? this.client).delete< DeleteMessageResponses, unknown, ThrowOnError @@ -3879,7 +3904,7 @@ export class OpenAi extends _HeyApiClient { public getMessage( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< GetMessageResponses, unknown, ThrowOnError @@ -3903,7 +3928,7 @@ export class OpenAi extends _HeyApiClient { public modifyMessage( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< ModifyMessageResponses, unknown, ThrowOnError @@ -3931,7 +3956,7 @@ export class OpenAi extends _HeyApiClient { public listRuns( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< ListRunsResponses, unknown, ThrowOnError @@ -3955,7 +3980,7 @@ export class OpenAi extends _HeyApiClient { public createRun( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateRunResponses, unknown, ThrowOnError @@ -3983,7 +4008,7 @@ export class OpenAi extends _HeyApiClient { public getRun( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< GetRunResponses, unknown, ThrowOnError @@ -4007,7 +4032,7 @@ export class OpenAi extends _HeyApiClient { public modifyRun( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< ModifyRunResponses, unknown, ThrowOnError @@ -4035,7 +4060,7 @@ export class OpenAi extends _HeyApiClient { public cancelRun( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CancelRunResponses, unknown, ThrowOnError @@ -4059,7 +4084,7 @@ export class OpenAi extends _HeyApiClient { public listRunSteps( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< ListRunStepsResponses, unknown, ThrowOnError @@ -4083,7 +4108,7 @@ export class OpenAi extends _HeyApiClient { public getRunStep( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< GetRunStepResponses, unknown, ThrowOnError @@ -4108,7 +4133,7 @@ export class OpenAi extends _HeyApiClient { public submitToolOuputsToRun( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< SubmitToolOuputsToRunResponses, unknown, ThrowOnError @@ -4153,7 +4178,7 @@ export class OpenAi extends _HeyApiClient { public createUpload( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateUploadResponses, unknown, ThrowOnError @@ -4182,7 +4207,7 @@ export class OpenAi extends _HeyApiClient { public cancelUpload( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CancelUploadResponses, unknown, ThrowOnError @@ -4213,7 +4238,7 @@ export class OpenAi extends _HeyApiClient { public completeUpload( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CompleteUploadResponses, unknown, ThrowOnError @@ -4246,7 +4271,7 @@ export class OpenAi extends _HeyApiClient { public addUploadPart( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< AddUploadPartResponses, unknown, ThrowOnError @@ -4275,7 +4300,7 @@ export class OpenAi extends _HeyApiClient { public listVectorStores( options?: Options, ) { - return (options?.client ?? this._client).get< + return (options?.client ?? this.client).get< ListVectorStoresResponses, unknown, ThrowOnError @@ -4299,7 +4324,7 @@ export class OpenAi extends _HeyApiClient { public createVectorStore( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateVectorStoreResponses, unknown, ThrowOnError @@ -4327,7 +4352,7 @@ export class OpenAi extends _HeyApiClient { public deleteVectorStore( options: Options, ) { - return (options.client ?? this._client).delete< + return (options.client ?? this.client).delete< DeleteVectorStoreResponses, unknown, ThrowOnError @@ -4351,7 +4376,7 @@ export class OpenAi extends _HeyApiClient { public getVectorStore( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< GetVectorStoreResponses, unknown, ThrowOnError @@ -4375,7 +4400,7 @@ export class OpenAi extends _HeyApiClient { public modifyVectorStore( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< ModifyVectorStoreResponses, unknown, ThrowOnError @@ -4403,7 +4428,7 @@ export class OpenAi extends _HeyApiClient { public createVectorStoreFileBatch( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateVectorStoreFileBatchResponses, unknown, ThrowOnError @@ -4431,7 +4456,7 @@ export class OpenAi extends _HeyApiClient { public getVectorStoreFileBatch( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< GetVectorStoreFileBatchResponses, unknown, ThrowOnError @@ -4455,7 +4480,7 @@ export class OpenAi extends _HeyApiClient { public cancelVectorStoreFileBatch( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CancelVectorStoreFileBatchResponses, unknown, ThrowOnError @@ -4479,7 +4504,7 @@ export class OpenAi extends _HeyApiClient { public listFilesInVectorStoreBatch( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< ListFilesInVectorStoreBatchResponses, unknown, ThrowOnError @@ -4503,7 +4528,7 @@ export class OpenAi extends _HeyApiClient { public listVectorStoreFiles( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< ListVectorStoreFilesResponses, unknown, ThrowOnError @@ -4527,7 +4552,7 @@ export class OpenAi extends _HeyApiClient { public createVectorStoreFile( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< CreateVectorStoreFileResponses, unknown, ThrowOnError @@ -4555,7 +4580,7 @@ export class OpenAi extends _HeyApiClient { public deleteVectorStoreFile( options: Options, ) { - return (options.client ?? this._client).delete< + return (options.client ?? this.client).delete< DeleteVectorStoreFileResponses, unknown, ThrowOnError @@ -4579,7 +4604,7 @@ export class OpenAi extends _HeyApiClient { public getVectorStoreFile( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< GetVectorStoreFileResponses, unknown, ThrowOnError @@ -4603,7 +4628,7 @@ export class OpenAi extends _HeyApiClient { public updateVectorStoreFileAttributes( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< UpdateVectorStoreFileAttributesResponses, unknown, ThrowOnError @@ -4631,7 +4656,7 @@ export class OpenAi extends _HeyApiClient { public retrieveVectorStoreFileContent( options: Options, ) { - return (options.client ?? this._client).get< + return (options.client ?? this.client).get< RetrieveVectorStoreFileContentResponses, unknown, ThrowOnError @@ -4655,7 +4680,7 @@ export class OpenAi extends _HeyApiClient { public searchVectorStore( options: Options, ) { - return (options.client ?? this._client).post< + return (options.client ?? this.client).post< SearchVectorStoreResponses, unknown, ThrowOnError diff --git a/examples/openapi-ts-tanstack-react-query/openapi-ts.config.ts b/examples/openapi-ts-tanstack-react-query/openapi-ts.config.ts index 0fc4b15c1..aeb40a30e 100644 --- a/examples/openapi-ts-tanstack-react-query/openapi-ts.config.ts +++ b/examples/openapi-ts-tanstack-react-query/openapi-ts.config.ts @@ -11,7 +11,10 @@ export default defineConfig({ plugins: [ '@hey-api/client-fetch', '@hey-api/schemas', - '@hey-api/sdk', + { + instance: true, + name: '@hey-api/sdk', + }, { enums: 'javascript', name: '@hey-api/typescript', diff --git a/examples/openapi-ts-tanstack-react-query/src/client/@tanstack/react-query.gen.ts b/examples/openapi-ts-tanstack-react-query/src/client/@tanstack/react-query.gen.ts index c461fceff..d0b4d2452 100644 --- a/examples/openapi-ts-tanstack-react-query/src/client/@tanstack/react-query.gen.ts +++ b/examples/openapi-ts-tanstack-react-query/src/client/@tanstack/react-query.gen.ts @@ -7,28 +7,7 @@ import { } from '@tanstack/react-query'; import { client } from '../client.gen'; -import { - addPet, - createUser, - createUsersWithListInput, - deleteOrder, - deletePet, - deleteUser, - findPetsByStatus, - findPetsByTags, - getInventory, - getOrderById, - getPetById, - getUserByName, - loginUser, - logoutUser, - type Options, - placeOrder, - updatePet, - updatePetWithForm, - updateUser, - uploadFile, -} from '../sdk.gen'; +import { type Options, Sdk } from '../sdk.gen'; import type { AddPetData, AddPetResponse, @@ -72,7 +51,7 @@ export const addPetMutation = ( Options > = { mutationFn: async (fnOptions) => { - const { data } = await addPet({ + const { data } = await Sdk.__registry.get().addPet({ ...options, ...fnOptions, throwOnError: true, @@ -101,7 +80,7 @@ export const updatePetMutation = ( Options > = { mutationFn: async (fnOptions) => { - const { data } = await updatePet({ + const { data } = await Sdk.__registry.get().updatePet({ ...options, ...fnOptions, throwOnError: true, @@ -166,7 +145,7 @@ export const findPetsByStatusOptions = ( ) => queryOptions({ queryFn: async ({ queryKey, signal }) => { - const { data } = await findPetsByStatus({ + const { data } = await Sdk.__registry.get().findPetsByStatus({ ...options, ...queryKey[0], signal, @@ -188,7 +167,7 @@ export const findPetsByTagsQueryKey = (options: Options) => export const findPetsByTagsOptions = (options: Options) => queryOptions({ queryFn: async ({ queryKey, signal }) => { - const { data } = await findPetsByTags({ + const { data } = await Sdk.__registry.get().findPetsByTags({ ...options, ...queryKey[0], signal, @@ -213,7 +192,7 @@ export const deletePetMutation = ( Options > = { mutationFn: async (fnOptions) => { - const { data } = await deletePet({ + const { data } = await Sdk.__registry.get().deletePet({ ...options, ...fnOptions, throwOnError: true, @@ -235,7 +214,7 @@ export const getPetByIdQueryKey = (options: Options) => export const getPetByIdOptions = (options: Options) => queryOptions({ queryFn: async ({ queryKey, signal }) => { - const { data } = await getPetById({ + const { data } = await Sdk.__registry.get().getPetById({ ...options, ...queryKey[0], signal, @@ -264,7 +243,7 @@ export const updatePetWithFormMutation = ( Options > = { mutationFn: async (fnOptions) => { - const { data } = await updatePetWithForm({ + const { data } = await Sdk.__registry.get().updatePetWithForm({ ...options, ...fnOptions, throwOnError: true, @@ -293,7 +272,7 @@ export const uploadFileMutation = ( Options > = { mutationFn: async (fnOptions) => { - const { data } = await uploadFile({ + const { data } = await Sdk.__registry.get().uploadFile({ ...options, ...fnOptions, throwOnError: true, @@ -315,7 +294,7 @@ export const getInventoryQueryKey = (options?: Options) => export const getInventoryOptions = (options?: Options) => queryOptions({ queryFn: async ({ queryKey, signal }) => { - const { data } = await getInventory({ + const { data } = await Sdk.__registry.get().getInventory({ ...options, ...queryKey[0], signal, @@ -344,7 +323,7 @@ export const placeOrderMutation = ( Options > = { mutationFn: async (fnOptions) => { - const { data } = await placeOrder({ + const { data } = await Sdk.__registry.get().placeOrder({ ...options, ...fnOptions, throwOnError: true, @@ -369,7 +348,7 @@ export const deleteOrderMutation = ( Options > = { mutationFn: async (fnOptions) => { - const { data } = await deleteOrder({ + const { data } = await Sdk.__registry.get().deleteOrder({ ...options, ...fnOptions, throwOnError: true, @@ -391,7 +370,7 @@ export const getOrderByIdQueryKey = (options: Options) => export const getOrderByIdOptions = (options: Options) => queryOptions({ queryFn: async ({ queryKey, signal }) => { - const { data } = await getOrderById({ + const { data } = await Sdk.__registry.get().getOrderById({ ...options, ...queryKey[0], signal, @@ -420,7 +399,7 @@ export const createUserMutation = ( Options > = { mutationFn: async (fnOptions) => { - const { data } = await createUser({ + const { data } = await Sdk.__registry.get().createUser({ ...options, ...fnOptions, throwOnError: true, @@ -449,7 +428,7 @@ export const createUsersWithListInputMutation = ( Options > = { mutationFn: async (fnOptions) => { - const { data } = await createUsersWithListInput({ + const { data } = await Sdk.__registry.get().createUsersWithListInput({ ...options, ...fnOptions, throwOnError: true, @@ -471,7 +450,7 @@ export const loginUserQueryKey = (options?: Options) => export const loginUserOptions = (options?: Options) => queryOptions({ queryFn: async ({ queryKey, signal }) => { - const { data } = await loginUser({ + const { data } = await Sdk.__registry.get().loginUser({ ...options, ...queryKey[0], signal, @@ -493,7 +472,7 @@ export const logoutUserQueryKey = (options?: Options) => export const logoutUserOptions = (options?: Options) => queryOptions({ queryFn: async ({ queryKey, signal }) => { - const { data } = await logoutUser({ + const { data } = await Sdk.__registry.get().logoutUser({ ...options, ...queryKey[0], signal, @@ -518,7 +497,7 @@ export const deleteUserMutation = ( Options > = { mutationFn: async (fnOptions) => { - const { data } = await deleteUser({ + const { data } = await Sdk.__registry.get().deleteUser({ ...options, ...fnOptions, throwOnError: true, @@ -540,7 +519,7 @@ export const getUserByNameQueryKey = (options: Options) => export const getUserByNameOptions = (options: Options) => queryOptions({ queryFn: async ({ queryKey, signal }) => { - const { data } = await getUserByName({ + const { data } = await Sdk.__registry.get().getUserByName({ ...options, ...queryKey[0], signal, @@ -565,7 +544,7 @@ export const updateUserMutation = ( Options > = { mutationFn: async (fnOptions) => { - const { data } = await updateUser({ + const { data } = await Sdk.__registry.get().updateUser({ ...options, ...fnOptions, throwOnError: true, diff --git a/examples/openapi-ts-tanstack-react-query/src/client/sdk.gen.ts b/examples/openapi-ts-tanstack-react-query/src/client/sdk.gen.ts index f424fe675..6753f84e6 100644 --- a/examples/openapi-ts-tanstack-react-query/src/client/sdk.gen.ts +++ b/examples/openapi-ts-tanstack-react-query/src/client/sdk.gen.ts @@ -79,408 +79,468 @@ export type Options< meta?: Record; }; -/** - * Add a new pet to the store. - * - * Add a new pet to the store. - */ -export const addPet = ( - options: Options, -) => - (options.client ?? client).post({ - security: [ - { - scheme: 'bearer', - type: 'http', - }, - ], - url: '/pet', - ...options, - headers: { - 'Content-Type': 'application/json', - ...options.headers, - }, - }); +class HeyApiClient { + protected client: Client; -/** - * Update an existing pet. - * - * Update an existing pet by Id. - */ -export const updatePet = ( - options: Options, -) => - (options.client ?? client).put< - UpdatePetResponses, - UpdatePetErrors, - ThrowOnError - >({ - security: [ - { - scheme: 'bearer', - type: 'http', - }, - ], - url: '/pet', - ...options, - headers: { - 'Content-Type': 'application/json', - ...options.headers, - }, - }); + constructor(args?: { client?: Client }) { + this.client = args?.client ?? client; + } +} -/** - * Finds Pets by status. - * - * Multiple status values can be provided with comma separated strings. - */ -export const findPetsByStatus = ( - options: Options, -) => - (options.client ?? client).get< - FindPetsByStatusResponses, - FindPetsByStatusErrors, - ThrowOnError - >({ - security: [ - { - scheme: 'bearer', - type: 'http', - }, - ], - url: '/pet/findByStatus', - ...options, - }); +class HeyApiRegistry { + private readonly defaultKey = 'default'; -/** - * Finds Pets by tags. - * - * Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. - */ -export const findPetsByTags = ( - options: Options, -) => - (options.client ?? client).get< - FindPetsByTagsResponses, - FindPetsByTagsErrors, - ThrowOnError - >({ - security: [ - { - scheme: 'bearer', - type: 'http', - }, - ], - url: '/pet/findByTags', - ...options, - }); + private readonly instances: Map = new Map(); -/** - * Deletes a pet. - * - * Delete a pet. - */ -export const deletePet = ( - options: Options, -) => - (options.client ?? client).delete< - DeletePetResponses, - DeletePetErrors, - ThrowOnError - >({ - security: [ - { - scheme: 'bearer', - type: 'http', - }, - ], - url: '/pet/{petId}', - ...options, - }); + get(key?: string): T { + const instance = this.instances.get(key ?? this.defaultKey); + if (!instance) { + throw new Error( + `No SDK client found. Create one with "new Sdk()" to fix this error.`, + ); + } + return instance; + } -/** - * Find pet by ID. - * - * Returns a single pet. - */ -export const getPetById = ( - options: Options, -) => - (options.client ?? client).get< - GetPetByIdResponses, - GetPetByIdErrors, - ThrowOnError - >({ - security: [ - { - name: 'api_key', - type: 'apiKey', - }, - { - scheme: 'bearer', - type: 'http', - }, - ], - url: '/pet/{petId}', - ...options, - }); + set(value: T, key?: string): void { + this.instances.set(key ?? this.defaultKey, value); + } +} + +export class Sdk extends HeyApiClient { + public static readonly __registry = new HeyApiRegistry(); -/** - * Updates a pet in the store with form data. - * - * Updates a pet resource based on the form data. - */ -export const updatePetWithForm = ( - options: Options, -) => - (options.client ?? client).post< - UpdatePetWithFormResponses, - UpdatePetWithFormErrors, - ThrowOnError - >({ - security: [ - { - scheme: 'bearer', - type: 'http', + constructor(args?: { client?: Client; key?: string }) { + super(args); + Sdk.__registry.set(this, args?.key); + } + + /** + * Add a new pet to the store. + * + * Add a new pet to the store. + */ + public addPet( + options: Options, + ) { + return (options.client ?? this.client).post< + AddPetResponses, + AddPetErrors, + ThrowOnError + >({ + security: [ + { + scheme: 'bearer', + type: 'http', + }, + ], + url: '/pet', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers, }, - ], - url: '/pet/{petId}', - ...options, - }); + }); + } -/** - * Uploads an image. - * - * Upload image of the pet. - */ -export const uploadFile = ( - options: Options, -) => - (options.client ?? client).post< - UploadFileResponses, - UploadFileErrors, - ThrowOnError - >({ - bodySerializer: null, - security: [ - { - scheme: 'bearer', - type: 'http', + /** + * Update an existing pet. + * + * Update an existing pet by Id. + */ + public updatePet( + options: Options, + ) { + return (options.client ?? this.client).put< + UpdatePetResponses, + UpdatePetErrors, + ThrowOnError + >({ + security: [ + { + scheme: 'bearer', + type: 'http', + }, + ], + url: '/pet', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers, }, - ], - url: '/pet/{petId}/uploadImage', - ...options, - headers: { - 'Content-Type': 'application/octet-stream', - ...options.headers, - }, - }); + }); + } -/** - * Returns pet inventories by status. - * - * Returns a map of status codes to quantities. - */ -export const getInventory = ( - options?: Options, -) => - (options?.client ?? client).get< - GetInventoryResponses, - GetInventoryErrors, - ThrowOnError - >({ - security: [ - { - name: 'api_key', - type: 'apiKey', + /** + * Finds Pets by status. + * + * Multiple status values can be provided with comma separated strings. + */ + public findPetsByStatus( + options: Options, + ) { + return (options.client ?? this.client).get< + FindPetsByStatusResponses, + FindPetsByStatusErrors, + ThrowOnError + >({ + security: [ + { + scheme: 'bearer', + type: 'http', + }, + ], + url: '/pet/findByStatus', + ...options, + }); + } + + /** + * Finds Pets by tags. + * + * Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. + */ + public findPetsByTags( + options: Options, + ) { + return (options.client ?? this.client).get< + FindPetsByTagsResponses, + FindPetsByTagsErrors, + ThrowOnError + >({ + security: [ + { + scheme: 'bearer', + type: 'http', + }, + ], + url: '/pet/findByTags', + ...options, + }); + } + + /** + * Deletes a pet. + * + * Delete a pet. + */ + public deletePet( + options: Options, + ) { + return (options.client ?? this.client).delete< + DeletePetResponses, + DeletePetErrors, + ThrowOnError + >({ + security: [ + { + scheme: 'bearer', + type: 'http', + }, + ], + url: '/pet/{petId}', + ...options, + }); + } + + /** + * Find pet by ID. + * + * Returns a single pet. + */ + public getPetById( + options: Options, + ) { + return (options.client ?? this.client).get< + GetPetByIdResponses, + GetPetByIdErrors, + ThrowOnError + >({ + security: [ + { + name: 'api_key', + type: 'apiKey', + }, + { + scheme: 'bearer', + type: 'http', + }, + ], + url: '/pet/{petId}', + ...options, + }); + } + + /** + * Updates a pet in the store with form data. + * + * Updates a pet resource based on the form data. + */ + public updatePetWithForm( + options: Options, + ) { + return (options.client ?? this.client).post< + UpdatePetWithFormResponses, + UpdatePetWithFormErrors, + ThrowOnError + >({ + security: [ + { + scheme: 'bearer', + type: 'http', + }, + ], + url: '/pet/{petId}', + ...options, + }); + } + + /** + * Uploads an image. + * + * Upload image of the pet. + */ + public uploadFile( + options: Options, + ) { + return (options.client ?? this.client).post< + UploadFileResponses, + UploadFileErrors, + ThrowOnError + >({ + bodySerializer: null, + security: [ + { + scheme: 'bearer', + type: 'http', + }, + ], + url: '/pet/{petId}/uploadImage', + ...options, + headers: { + 'Content-Type': 'application/octet-stream', + ...options.headers, }, - ], - url: '/store/inventory', - ...options, - }); + }); + } + + /** + * Returns pet inventories by status. + * + * Returns a map of status codes to quantities. + */ + public getInventory( + options?: Options, + ) { + return (options?.client ?? this.client).get< + GetInventoryResponses, + GetInventoryErrors, + ThrowOnError + >({ + security: [ + { + name: 'api_key', + type: 'apiKey', + }, + ], + url: '/store/inventory', + ...options, + }); + } -/** - * Place an order for a pet. - * - * Place a new order in the store. - */ -export const placeOrder = ( - options?: Options, -) => - (options?.client ?? client).post< - PlaceOrderResponses, - PlaceOrderErrors, - ThrowOnError - >({ - url: '/store/order', - ...options, - headers: { - 'Content-Type': 'application/json', - ...options?.headers, - }, - }); + /** + * Place an order for a pet. + * + * Place a new order in the store. + */ + public placeOrder( + options?: Options, + ) { + return (options?.client ?? this.client).post< + PlaceOrderResponses, + PlaceOrderErrors, + ThrowOnError + >({ + url: '/store/order', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options?.headers, + }, + }); + } -/** - * Delete purchase order by identifier. - * - * For valid response try integer IDs with value < 1000. Anything above 1000 or non-integers will generate API errors. - */ -export const deleteOrder = ( - options: Options, -) => - (options.client ?? client).delete< - DeleteOrderResponses, - DeleteOrderErrors, - ThrowOnError - >({ - url: '/store/order/{orderId}', - ...options, - }); + /** + * Delete purchase order by identifier. + * + * For valid response try integer IDs with value < 1000. Anything above 1000 or non-integers will generate API errors. + */ + public deleteOrder( + options: Options, + ) { + return (options.client ?? this.client).delete< + DeleteOrderResponses, + DeleteOrderErrors, + ThrowOnError + >({ + url: '/store/order/{orderId}', + ...options, + }); + } -/** - * Find purchase order by ID. - * - * For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions. - */ -export const getOrderById = ( - options: Options, -) => - (options.client ?? client).get< - GetOrderByIdResponses, - GetOrderByIdErrors, - ThrowOnError - >({ - url: '/store/order/{orderId}', - ...options, - }); + /** + * Find purchase order by ID. + * + * For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions. + */ + public getOrderById( + options: Options, + ) { + return (options.client ?? this.client).get< + GetOrderByIdResponses, + GetOrderByIdErrors, + ThrowOnError + >({ + url: '/store/order/{orderId}', + ...options, + }); + } -/** - * Create user. - * - * This can only be done by the logged in user. - */ -export const createUser = ( - options?: Options, -) => - (options?.client ?? client).post< - CreateUserResponses, - CreateUserErrors, - ThrowOnError - >({ - url: '/user', - ...options, - headers: { - 'Content-Type': 'application/json', - ...options?.headers, - }, - }); + /** + * Create user. + * + * This can only be done by the logged in user. + */ + public createUser( + options?: Options, + ) { + return (options?.client ?? this.client).post< + CreateUserResponses, + CreateUserErrors, + ThrowOnError + >({ + url: '/user', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options?.headers, + }, + }); + } -/** - * Creates list of users with given input array. - * - * Creates list of users with given input array. - */ -export const createUsersWithListInput = ( - options?: Options, -) => - (options?.client ?? client).post< - CreateUsersWithListInputResponses, - CreateUsersWithListInputErrors, - ThrowOnError - >({ - url: '/user/createWithList', - ...options, - headers: { - 'Content-Type': 'application/json', - ...options?.headers, - }, - }); + /** + * Creates list of users with given input array. + * + * Creates list of users with given input array. + */ + public createUsersWithListInput( + options?: Options, + ) { + return (options?.client ?? this.client).post< + CreateUsersWithListInputResponses, + CreateUsersWithListInputErrors, + ThrowOnError + >({ + url: '/user/createWithList', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options?.headers, + }, + }); + } -/** - * Logs user into the system. - * - * Log into the system. - */ -export const loginUser = ( - options?: Options, -) => - (options?.client ?? client).get< - LoginUserResponses, - LoginUserErrors, - ThrowOnError - >({ - url: '/user/login', - ...options, - }); + /** + * Logs user into the system. + * + * Log into the system. + */ + public loginUser( + options?: Options, + ) { + return (options?.client ?? this.client).get< + LoginUserResponses, + LoginUserErrors, + ThrowOnError + >({ + url: '/user/login', + ...options, + }); + } -/** - * Logs out current logged in user session. - * - * Log user out of the system. - */ -export const logoutUser = ( - options?: Options, -) => - (options?.client ?? client).get< - LogoutUserResponses, - LogoutUserErrors, - ThrowOnError - >({ - url: '/user/logout', - ...options, - }); + /** + * Logs out current logged in user session. + * + * Log user out of the system. + */ + public logoutUser( + options?: Options, + ) { + return (options?.client ?? this.client).get< + LogoutUserResponses, + LogoutUserErrors, + ThrowOnError + >({ + url: '/user/logout', + ...options, + }); + } -/** - * Delete user resource. - * - * This can only be done by the logged in user. - */ -export const deleteUser = ( - options: Options, -) => - (options.client ?? client).delete< - DeleteUserResponses, - DeleteUserErrors, - ThrowOnError - >({ - url: '/user/{username}', - ...options, - }); + /** + * Delete user resource. + * + * This can only be done by the logged in user. + */ + public deleteUser( + options: Options, + ) { + return (options.client ?? this.client).delete< + DeleteUserResponses, + DeleteUserErrors, + ThrowOnError + >({ + url: '/user/{username}', + ...options, + }); + } -/** - * Get user by user name. - * - * Get user detail based on username. - */ -export const getUserByName = ( - options: Options, -) => - (options.client ?? client).get< - GetUserByNameResponses, - GetUserByNameErrors, - ThrowOnError - >({ - url: '/user/{username}', - ...options, - }); + /** + * Get user by user name. + * + * Get user detail based on username. + */ + public getUserByName( + options: Options, + ) { + return (options.client ?? this.client).get< + GetUserByNameResponses, + GetUserByNameErrors, + ThrowOnError + >({ + url: '/user/{username}', + ...options, + }); + } -/** - * Update user resource. - * - * This can only be done by the logged in user. - */ -export const updateUser = ( - options: Options, -) => - (options.client ?? client).put< - UpdateUserResponses, - UpdateUserErrors, - ThrowOnError - >({ - url: '/user/{username}', - ...options, - headers: { - 'Content-Type': 'application/json', - ...options.headers, - }, - }); + /** + * Update user resource. + * + * This can only be done by the logged in user. + */ + public updateUser( + options: Options, + ) { + return (options.client ?? this.client).put< + UpdateUserResponses, + UpdateUserErrors, + ThrowOnError + >({ + url: '/user/{username}', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers, + }, + }); + } +} diff --git a/examples/openapi-ts-tanstack-react-query/src/main.tsx b/examples/openapi-ts-tanstack-react-query/src/main.tsx index ae13863b5..761a68d68 100644 --- a/examples/openapi-ts-tanstack-react-query/src/main.tsx +++ b/examples/openapi-ts-tanstack-react-query/src/main.tsx @@ -8,6 +8,7 @@ import ReactDOM from 'react-dom/client'; import App from './App.tsx'; import { client } from './client/client.gen'; +import { Sdk } from './client/sdk.gen.ts'; const queryClient = new QueryClient({ defaultOptions: { @@ -26,6 +27,7 @@ client.setConfig({ Authorization: 'Bearer ', }, }); +new Sdk(); ReactDOM.createRoot(document.getElementById('root')!).render( diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/@hey-api/client-fetch/sdk-nested-classes-instance/sdk.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/@hey-api/client-fetch/sdk-nested-classes-instance/sdk.gen.ts index 37c921424..8947e126c 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/@hey-api/client-fetch/sdk-nested-classes-instance/sdk.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/@hey-api/client-fetch/sdk-nested-classes-instance/sdk.gen.ts @@ -18,63 +18,89 @@ export type Options; }; -class _HeyApiClient { - protected _client: Client = client; +class HeyApiClient { + protected client: Client; constructor(args?: { client?: Client; }) { - if (args?.client) { - this._client = args.client; + this.client = args?.client ?? client; + } +} + +class HeyApiRegistry { + private readonly defaultKey = "default"; + + private readonly instances: Map = new Map(); + + get(key?: string): T { + const instance = this.instances.get(key ?? this.defaultKey); + if (!instance) { + throw new Error(`No SDK client found. Create one with "new NestedSdkWithInstance()" to fix this error.`); } + return instance; + } + + set(value: T, key?: string): void { + this.instances.set(key ?? this.defaultKey, value); } } -export class Domains extends _HeyApiClient { +export class Domains extends HeyApiClient { public get(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/business/providers/domains', ...options }); } public post(options?: Options) { - return (options?.client ?? this._client).post({ + return (options?.client ?? this.client).post({ url: '/business/providers/domains', ...options }); } } -export class Providers extends _HeyApiClient { - domains = new Domains({ client: this._client }); +export class Providers extends HeyApiClient { + domains = new Domains({ client: this.client }); } -export class Business extends _HeyApiClient { +export class Business extends HeyApiClient { public get(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/locations/businesses', ...options }); } - providers = new Providers({ client: this._client }); + providers = new Providers({ client: this.client }); } -export class NestedSdkWithInstance extends _HeyApiClient { +export class NestedSdkWithInstance extends HeyApiClient { + public static readonly __registry = new HeyApiRegistry(); + + constructor(args?: { + client?: Client; + key?: string; + }) { + super(args); + NestedSdkWithInstance.__registry.set(this, args?.key); + } + public putBusinessProvidersDomains(options?: Options) { - return (options?.client ?? this._client).put({ + return (options?.client ?? this.client).put({ url: '/business/providers/domains', ...options }); } public get(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/locations', ...options }); } - business = new Business({ client: this._client }); + business = new Business({ client: this.client }); } diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/@hey-api/sdk/instance/sdk.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/@hey-api/sdk/instance/sdk.gen.ts index 5c3fa0664..c50bdba1c 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/@hey-api/sdk/instance/sdk.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/plugins/@hey-api/sdk/instance/sdk.gen.ts @@ -18,66 +18,92 @@ export type Options; }; -class _HeyApiClient { - protected _client: Client = client; +class HeyApiClient { + protected client: Client; constructor(args?: { client?: Client; }) { - if (args?.client) { - this._client = args.client; + this.client = args?.client ?? client; + } +} + +class HeyApiRegistry { + private readonly defaultKey = "default"; + + private readonly instances: Map = new Map(); + + get(key?: string): T { + const instance = this.instances.get(key ?? this.defaultKey); + if (!instance) { + throw new Error(`No SDK client found. Create one with "new Sdk()" to fix this error.`); } + return instance; + } + + set(value: T, key?: string): void { + this.instances.set(key ?? this.defaultKey, value); } } -export class Bar extends _HeyApiClient { +export class Bar extends HeyApiClient { public post(options?: Options) { - return (options?.client ?? this._client).post({ + return (options?.client ?? this.client).post({ url: '/foo/bar', ...options }); } public put(options?: Options) { - return (options?.client ?? this._client).put({ + return (options?.client ?? this.client).put({ url: '/foo/bar', ...options }); } } -export class Foo extends _HeyApiClient { +export class Foo extends HeyApiClient { public post(options?: Options) { - return (options?.client ?? this._client).post({ + return (options?.client ?? this.client).post({ url: '/foo', ...options }); } public put(options?: Options) { - return (options?.client ?? this._client).put({ + return (options?.client ?? this.client).put({ url: '/foo', ...options }); } - bar = new Bar({ client: this._client }); + bar = new Bar({ client: this.client }); } -export class Sdk extends _HeyApiClient { +export class Sdk extends HeyApiClient { + public static readonly __registry = new HeyApiRegistry(); + + constructor(args?: { + client?: Client; + key?: string; + }) { + super(args); + Sdk.__registry.set(this, args?.key); + } + public getFoo(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/foo', ...options }); } public getFooBar(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/foo/bar', ...options }); } - foo = new Foo({ client: this._client }); + foo = new Foo({ client: this.client }); } diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/@hey-api/client-fetch/sdk-nested-classes-instance/sdk.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/@hey-api/client-fetch/sdk-nested-classes-instance/sdk.gen.ts index 37c921424..8947e126c 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/@hey-api/client-fetch/sdk-nested-classes-instance/sdk.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/@hey-api/client-fetch/sdk-nested-classes-instance/sdk.gen.ts @@ -18,63 +18,89 @@ export type Options; }; -class _HeyApiClient { - protected _client: Client = client; +class HeyApiClient { + protected client: Client; constructor(args?: { client?: Client; }) { - if (args?.client) { - this._client = args.client; + this.client = args?.client ?? client; + } +} + +class HeyApiRegistry { + private readonly defaultKey = "default"; + + private readonly instances: Map = new Map(); + + get(key?: string): T { + const instance = this.instances.get(key ?? this.defaultKey); + if (!instance) { + throw new Error(`No SDK client found. Create one with "new NestedSdkWithInstance()" to fix this error.`); } + return instance; + } + + set(value: T, key?: string): void { + this.instances.set(key ?? this.defaultKey, value); } } -export class Domains extends _HeyApiClient { +export class Domains extends HeyApiClient { public get(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/business/providers/domains', ...options }); } public post(options?: Options) { - return (options?.client ?? this._client).post({ + return (options?.client ?? this.client).post({ url: '/business/providers/domains', ...options }); } } -export class Providers extends _HeyApiClient { - domains = new Domains({ client: this._client }); +export class Providers extends HeyApiClient { + domains = new Domains({ client: this.client }); } -export class Business extends _HeyApiClient { +export class Business extends HeyApiClient { public get(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/locations/businesses', ...options }); } - providers = new Providers({ client: this._client }); + providers = new Providers({ client: this.client }); } -export class NestedSdkWithInstance extends _HeyApiClient { +export class NestedSdkWithInstance extends HeyApiClient { + public static readonly __registry = new HeyApiRegistry(); + + constructor(args?: { + client?: Client; + key?: string; + }) { + super(args); + NestedSdkWithInstance.__registry.set(this, args?.key); + } + public putBusinessProvidersDomains(options?: Options) { - return (options?.client ?? this._client).put({ + return (options?.client ?? this.client).put({ url: '/business/providers/domains', ...options }); } public get(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/locations', ...options }); } - business = new Business({ client: this._client }); + business = new Business({ client: this.client }); } diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/@hey-api/sdk/instance/sdk.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/@hey-api/sdk/instance/sdk.gen.ts index 5c3fa0664..c50bdba1c 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/@hey-api/sdk/instance/sdk.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.0.x/plugins/@hey-api/sdk/instance/sdk.gen.ts @@ -18,66 +18,92 @@ export type Options; }; -class _HeyApiClient { - protected _client: Client = client; +class HeyApiClient { + protected client: Client; constructor(args?: { client?: Client; }) { - if (args?.client) { - this._client = args.client; + this.client = args?.client ?? client; + } +} + +class HeyApiRegistry { + private readonly defaultKey = "default"; + + private readonly instances: Map = new Map(); + + get(key?: string): T { + const instance = this.instances.get(key ?? this.defaultKey); + if (!instance) { + throw new Error(`No SDK client found. Create one with "new Sdk()" to fix this error.`); } + return instance; + } + + set(value: T, key?: string): void { + this.instances.set(key ?? this.defaultKey, value); } } -export class Bar extends _HeyApiClient { +export class Bar extends HeyApiClient { public post(options?: Options) { - return (options?.client ?? this._client).post({ + return (options?.client ?? this.client).post({ url: '/foo/bar', ...options }); } public put(options?: Options) { - return (options?.client ?? this._client).put({ + return (options?.client ?? this.client).put({ url: '/foo/bar', ...options }); } } -export class Foo extends _HeyApiClient { +export class Foo extends HeyApiClient { public post(options?: Options) { - return (options?.client ?? this._client).post({ + return (options?.client ?? this.client).post({ url: '/foo', ...options }); } public put(options?: Options) { - return (options?.client ?? this._client).put({ + return (options?.client ?? this.client).put({ url: '/foo', ...options }); } - bar = new Bar({ client: this._client }); + bar = new Bar({ client: this.client }); } -export class Sdk extends _HeyApiClient { +export class Sdk extends HeyApiClient { + public static readonly __registry = new HeyApiRegistry(); + + constructor(args?: { + client?: Client; + key?: string; + }) { + super(args); + Sdk.__registry.set(this, args?.key); + } + public getFoo(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/foo', ...options }); } public getFooBar(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/foo/bar', ...options }); } - foo = new Foo({ client: this._client }); + foo = new Foo({ client: this.client }); } diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/@hey-api/client-fetch/sdk-nested-classes-instance/sdk.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/@hey-api/client-fetch/sdk-nested-classes-instance/sdk.gen.ts index 37c921424..8947e126c 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/@hey-api/client-fetch/sdk-nested-classes-instance/sdk.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/@hey-api/client-fetch/sdk-nested-classes-instance/sdk.gen.ts @@ -18,63 +18,89 @@ export type Options; }; -class _HeyApiClient { - protected _client: Client = client; +class HeyApiClient { + protected client: Client; constructor(args?: { client?: Client; }) { - if (args?.client) { - this._client = args.client; + this.client = args?.client ?? client; + } +} + +class HeyApiRegistry { + private readonly defaultKey = "default"; + + private readonly instances: Map = new Map(); + + get(key?: string): T { + const instance = this.instances.get(key ?? this.defaultKey); + if (!instance) { + throw new Error(`No SDK client found. Create one with "new NestedSdkWithInstance()" to fix this error.`); } + return instance; + } + + set(value: T, key?: string): void { + this.instances.set(key ?? this.defaultKey, value); } } -export class Domains extends _HeyApiClient { +export class Domains extends HeyApiClient { public get(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/business/providers/domains', ...options }); } public post(options?: Options) { - return (options?.client ?? this._client).post({ + return (options?.client ?? this.client).post({ url: '/business/providers/domains', ...options }); } } -export class Providers extends _HeyApiClient { - domains = new Domains({ client: this._client }); +export class Providers extends HeyApiClient { + domains = new Domains({ client: this.client }); } -export class Business extends _HeyApiClient { +export class Business extends HeyApiClient { public get(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/locations/businesses', ...options }); } - providers = new Providers({ client: this._client }); + providers = new Providers({ client: this.client }); } -export class NestedSdkWithInstance extends _HeyApiClient { +export class NestedSdkWithInstance extends HeyApiClient { + public static readonly __registry = new HeyApiRegistry(); + + constructor(args?: { + client?: Client; + key?: string; + }) { + super(args); + NestedSdkWithInstance.__registry.set(this, args?.key); + } + public putBusinessProvidersDomains(options?: Options) { - return (options?.client ?? this._client).put({ + return (options?.client ?? this.client).put({ url: '/business/providers/domains', ...options }); } public get(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/locations', ...options }); } - business = new Business({ client: this._client }); + business = new Business({ client: this.client }); } diff --git a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/@hey-api/sdk/instance/sdk.gen.ts b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/@hey-api/sdk/instance/sdk.gen.ts index 5c3fa0664..c50bdba1c 100644 --- a/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/@hey-api/sdk/instance/sdk.gen.ts +++ b/packages/openapi-ts-tests/main/test/__snapshots__/3.1.x/plugins/@hey-api/sdk/instance/sdk.gen.ts @@ -18,66 +18,92 @@ export type Options; }; -class _HeyApiClient { - protected _client: Client = client; +class HeyApiClient { + protected client: Client; constructor(args?: { client?: Client; }) { - if (args?.client) { - this._client = args.client; + this.client = args?.client ?? client; + } +} + +class HeyApiRegistry { + private readonly defaultKey = "default"; + + private readonly instances: Map = new Map(); + + get(key?: string): T { + const instance = this.instances.get(key ?? this.defaultKey); + if (!instance) { + throw new Error(`No SDK client found. Create one with "new Sdk()" to fix this error.`); } + return instance; + } + + set(value: T, key?: string): void { + this.instances.set(key ?? this.defaultKey, value); } } -export class Bar extends _HeyApiClient { +export class Bar extends HeyApiClient { public post(options?: Options) { - return (options?.client ?? this._client).post({ + return (options?.client ?? this.client).post({ url: '/foo/bar', ...options }); } public put(options?: Options) { - return (options?.client ?? this._client).put({ + return (options?.client ?? this.client).put({ url: '/foo/bar', ...options }); } } -export class Foo extends _HeyApiClient { +export class Foo extends HeyApiClient { public post(options?: Options) { - return (options?.client ?? this._client).post({ + return (options?.client ?? this.client).post({ url: '/foo', ...options }); } public put(options?: Options) { - return (options?.client ?? this._client).put({ + return (options?.client ?? this.client).put({ url: '/foo', ...options }); } - bar = new Bar({ client: this._client }); + bar = new Bar({ client: this.client }); } -export class Sdk extends _HeyApiClient { +export class Sdk extends HeyApiClient { + public static readonly __registry = new HeyApiRegistry(); + + constructor(args?: { + client?: Client; + key?: string; + }) { + super(args); + Sdk.__registry.set(this, args?.key); + } + public getFoo(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/foo', ...options }); } public getFooBar(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/foo/bar', ...options }); } - foo = new Foo({ client: this._client }); + foo = new Foo({ client: this.client }); } diff --git a/packages/openapi-ts-tests/sdks/__snapshots__/method-class-conflict/instance/sdk.gen.ts b/packages/openapi-ts-tests/sdks/__snapshots__/method-class-conflict/instance/sdk.gen.ts index d85c5f90f..903db25be 100644 --- a/packages/openapi-ts-tests/sdks/__snapshots__/method-class-conflict/instance/sdk.gen.ts +++ b/packages/openapi-ts-tests/sdks/__snapshots__/method-class-conflict/instance/sdk.gen.ts @@ -18,244 +18,260 @@ export type Options; }; -class _HeyApiClient { - protected _client: Client = client; +class HeyApiClient { + protected client: Client; constructor(args?: { client?: Client; }) { - if (args?.client) { - this._client = args.client; + this.client = args?.client ?? client; + } +} + +class HeyApiRegistry { + private readonly defaultKey = "default"; + + private readonly instances: Map = new Map(); + + get(key?: string): T { + const instance = this.instances.get(key ?? this.defaultKey); + if (!instance) { + throw new Error(`No SDK client found. Create one with "new Sdk()" to fix this error.`); } + return instance; + } + + set(value: T, key?: string): void { + this.instances.set(key ?? this.defaultKey, value); } } -export class AccountingCompanies extends _HeyApiClient { +export class AccountingCompanies extends HeyApiClient { public count(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/AccountingCompanies/$count', ...options }); } } -export class AccountingCompanyMemberships extends _HeyApiClient { +export class AccountingCompanyMemberships extends HeyApiClient { public count(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/AccountingCompanyMemberships/$count', ...options }); } } -export class BankAccounts extends _HeyApiClient { +export class BankAccounts extends HeyApiClient { public count(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/BankAccounts/$count', ...options }); } } -export class BusinessAccountantAssignments extends _HeyApiClient { +export class BusinessAccountantAssignments extends HeyApiClient { public count(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/BusinessAccountantAssignments/$count', ...options }); } } -export class BusinessDocumentActivities extends _HeyApiClient { +export class BusinessDocumentActivities extends HeyApiClient { public count(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/BusinessDocumentActivities/$count', ...options }); } } -export class BusinessDocuments extends _HeyApiClient { +export class BusinessDocuments extends HeyApiClient { public count(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/BusinessDocuments/$count', ...options }); } } -export class BusinessDocumentsSummaries extends _HeyApiClient { +export class BusinessDocumentsSummaries extends HeyApiClient { /** * @deprecated */ public count(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/BusinessDocumentsSummaries/$count', ...options }); } } -export class Businesses extends _HeyApiClient { +export class Businesses extends HeyApiClient { public count(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/Businesses/$count', ...options }); } public key(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/Businesses/{key}', ...options }); } } -export class BusinessSummaries extends _HeyApiClient { +export class BusinessSummaries extends HeyApiClient { public count(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/BusinessSummaries/$count', ...options }); } } -export class Counterparties extends _HeyApiClient { +export class Counterparties extends HeyApiClient { public count(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/Counterparties/$count', ...options }); } } -export class DataBoxCredentials extends _HeyApiClient { +export class DataBoxCredentials extends HeyApiClient { public count(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/DataBoxCredentials/$count', ...options }); } } -export class DocumentTypes extends _HeyApiClient { +export class DocumentTypes extends HeyApiClient { public count(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/DocumentTypes/$count', ...options }); } } -export class Invitations extends _HeyApiClient { +export class Invitations extends HeyApiClient { public count(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/Invitations/$count', ...options }); } } -export class Invoices extends _HeyApiClient { +export class Invoices extends HeyApiClient { public count(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/Invoices/$count', ...options }); } } -export class InvoiceSettings extends _HeyApiClient { +export class InvoiceSettings extends HeyApiClient { public count(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/InvoiceSettings/$count', ...options }); } } -export class Licenses extends _HeyApiClient { +export class Licenses extends HeyApiClient { public count(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/Licenses/$count', ...options }); } } -export class PersonalDocuments extends _HeyApiClient { +export class PersonalDocuments extends HeyApiClient { public count(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/PersonalDocuments/$count', ...options }); } } -export class RecurringTasks extends _HeyApiClient { +export class RecurringTasks extends HeyApiClient { public count(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/RecurringTasks/$count', ...options }); } } -export class Tasks extends _HeyApiClient { +export class Tasks extends HeyApiClient { public count(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/Tasks/$count', ...options }); } public key(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/Tasks/{key}', ...options }); } } -export class Odata extends _HeyApiClient { +export class Odata extends HeyApiClient { public accountingCompanies(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/AccountingCompanies', ...options }); } public accountingCompanyMemberships(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/AccountingCompanyMemberships', ...options }); } public bankAccounts(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/BankAccounts', ...options }); } public businessAccountantAssignments(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/BusinessAccountantAssignments', ...options }); } public businessDocumentActivities(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/BusinessDocumentActivities', ...options }); } public businessDocuments(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/BusinessDocuments', ...options }); @@ -265,175 +281,185 @@ export class Odata extends _HeyApiClient { * @deprecated */ public businessDocumentsSummaries(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/BusinessDocumentsSummaries', ...options }); } public businesses(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/Businesses', ...options }); } public businessesKey(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/Businesses({key})', ...options }); } public businessSummaries(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/BusinessSummaries', ...options }); } public counterparties(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/Counterparties', ...options }); } public dataBoxCredentials(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/DataBoxCredentials', ...options }); } public documentTypes(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/DocumentTypes', ...options }); } public invitations(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/Invitations', ...options }); } public invoices(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/Invoices', ...options }); } public invoiceSettings(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/InvoiceSettings', ...options }); } public licenses(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/Licenses', ...options }); } public personalDocuments(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/PersonalDocuments', ...options }); } public recurringTasks(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/RecurringTasks', ...options }); } public tasks(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/Tasks', ...options }); } public tasksKey(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/odata/Tasks({key})', ...options }); } - accountingCompanies2 = new AccountingCompanies({ client: this._client }); + accountingCompanies2 = new AccountingCompanies({ client: this.client }); - accountingCompanyMemberships2 = new AccountingCompanyMemberships({ client: this._client }); + accountingCompanyMemberships2 = new AccountingCompanyMemberships({ client: this.client }); - bankAccounts2 = new BankAccounts({ client: this._client }); + bankAccounts2 = new BankAccounts({ client: this.client }); - businessAccountantAssignments2 = new BusinessAccountantAssignments({ client: this._client }); + businessAccountantAssignments2 = new BusinessAccountantAssignments({ client: this.client }); - businessDocumentActivities2 = new BusinessDocumentActivities({ client: this._client }); + businessDocumentActivities2 = new BusinessDocumentActivities({ client: this.client }); - businessDocuments2 = new BusinessDocuments({ client: this._client }); + businessDocuments2 = new BusinessDocuments({ client: this.client }); - businessDocumentsSummaries2 = new BusinessDocumentsSummaries({ client: this._client }); + businessDocumentsSummaries2 = new BusinessDocumentsSummaries({ client: this.client }); - businesses2 = new Businesses({ client: this._client }); + businesses2 = new Businesses({ client: this.client }); - businessSummaries2 = new BusinessSummaries({ client: this._client }); + businessSummaries2 = new BusinessSummaries({ client: this.client }); - counterparties2 = new Counterparties({ client: this._client }); + counterparties2 = new Counterparties({ client: this.client }); - dataBoxCredentials2 = new DataBoxCredentials({ client: this._client }); + dataBoxCredentials2 = new DataBoxCredentials({ client: this.client }); - documentTypes2 = new DocumentTypes({ client: this._client }); + documentTypes2 = new DocumentTypes({ client: this.client }); - invitations2 = new Invitations({ client: this._client }); + invitations2 = new Invitations({ client: this.client }); - invoices2 = new Invoices({ client: this._client }); + invoices2 = new Invoices({ client: this.client }); - invoiceSettings2 = new InvoiceSettings({ client: this._client }); + invoiceSettings2 = new InvoiceSettings({ client: this.client }); - licenses2 = new Licenses({ client: this._client }); + licenses2 = new Licenses({ client: this.client }); - personalDocuments2 = new PersonalDocuments({ client: this._client }); + personalDocuments2 = new PersonalDocuments({ client: this.client }); - recurringTasks2 = new RecurringTasks({ client: this._client }); + recurringTasks2 = new RecurringTasks({ client: this.client }); - tasks2 = new Tasks({ client: this._client }); + tasks2 = new Tasks({ client: this.client }); } -export class User extends _HeyApiClient { +export class User extends HeyApiClient { public confirmEmail(options: Options) { - return (options.client ?? this._client).get({ + return (options.client ?? this.client).get({ url: '/api/v1/user/confirmEmail', ...options }); } } -export class VVersionApiVersion extends _HeyApiClient { - odata = new Odata({ client: this._client }); +export class VVersionApiVersion extends HeyApiClient { + odata = new Odata({ client: this.client }); - user = new User({ client: this._client }); + user = new User({ client: this.client }); } -export class Api extends _HeyApiClient { - vVersionApiVersion = new VVersionApiVersion({ client: this._client }); +export class Api extends HeyApiClient { + vVersionApiVersion = new VVersionApiVersion({ client: this.client }); } -export class MapIdentityApi extends _HeyApiClient { - api = new Api({ client: this._client }); +export class MapIdentityApi extends HeyApiClient { + api = new Api({ client: this.client }); } -export class Sdk extends _HeyApiClient { +export class Sdk extends HeyApiClient { + public static readonly __registry = new HeyApiRegistry(); + + constructor(args?: { + client?: Client; + key?: string; + }) { + super(args); + Sdk.__registry.set(this, args?.key); + } + public postApiV1AccountingCompanies(options?: Options) { - return (options?.client ?? this._client).post({ + return (options?.client ?? this.client).post({ url: '/api/v1/accounting-companies', ...options, headers: { @@ -444,14 +470,14 @@ export class Sdk extends _HeyApiClient { } public deleteApiV1AccountingCompaniesById(options: Options) { - return (options.client ?? this._client).delete({ + return (options.client ?? this.client).delete({ url: '/api/v1/accounting-companies/{id}', ...options }); } public postApiV1AccountingCompaniesById(options: Options) { - return (options.client ?? this._client).post({ + return (options.client ?? this.client).post({ url: '/api/v1/accounting-companies/{id}', ...options, headers: { @@ -462,7 +488,7 @@ export class Sdk extends _HeyApiClient { } public putApiV1AccountingCompanyMemberships(options?: Options) { - return (options?.client ?? this._client).put({ + return (options?.client ?? this.client).put({ url: '/api/v1/accounting-company-memberships', ...options, headers: { @@ -473,14 +499,14 @@ export class Sdk extends _HeyApiClient { } public deleteApiV1AccountingCompanyMembershipsById(options: Options) { - return (options.client ?? this._client).delete({ + return (options.client ?? this.client).delete({ url: '/api/v1/accounting-company-memberships/{id}', ...options }); } public putApiV1BankAccounts(options?: Options) { - return (options?.client ?? this._client).put({ + return (options?.client ?? this.client).put({ url: '/api/v1/bank-accounts', ...options, headers: { @@ -491,14 +517,14 @@ export class Sdk extends _HeyApiClient { } public deleteApiV1BankAccountsById(options: Options) { - return (options.client ?? this._client).delete({ + return (options.client ?? this.client).delete({ url: '/api/v1/bank-accounts/{id}', ...options }); } public putApiV1BusinessAccountantAssignments(options?: Options) { - return (options?.client ?? this._client).put({ + return (options?.client ?? this.client).put({ url: '/api/v1/business-accountant-assignments', ...options, headers: { @@ -509,21 +535,21 @@ export class Sdk extends _HeyApiClient { } public deleteApiV1BusinessAccountantAssignmentsById(options: Options) { - return (options.client ?? this._client).delete({ + return (options.client ?? this.client).delete({ url: '/api/v1/business-accountant-assignments/{id}', ...options }); } public getApiV1BusinessDocumentsByIdRaw(options: Options) { - return (options.client ?? this._client).get({ + return (options.client ?? this.client).get({ url: '/api/v1/business-documents/{id}/raw', ...options }); } public postApiV1BusinessDocuments(options?: Options) { - return (options?.client ?? this._client).post({ + return (options?.client ?? this.client).post({ ...formDataBodySerializer, url: '/api/v1/business-documents', ...options, @@ -535,14 +561,14 @@ export class Sdk extends _HeyApiClient { } public deleteApiV1BusinessDocumentsById(options: Options) { - return (options.client ?? this._client).delete({ + return (options.client ?? this.client).delete({ url: '/api/v1/business-documents/{id}', ...options }); } public putApiV1BusinessDocumentsById(options: Options) { - return (options.client ?? this._client).put({ + return (options.client ?? this.client).put({ url: '/api/v1/business-documents/{id}', ...options, headers: { @@ -553,28 +579,28 @@ export class Sdk extends _HeyApiClient { } public postApiV1BusinessDocumentsByIdApprove(options: Options) { - return (options.client ?? this._client).post({ + return (options.client ?? this.client).post({ url: '/api/v1/business-documents/{id}/approve', ...options }); } public postApiV1BusinessDocumentsByIdUnapprove(options: Options) { - return (options.client ?? this._client).post({ + return (options.client ?? this.client).post({ url: '/api/v1/business-documents/{id}/unapprove', ...options }); } public postApiV1BusinessDocumentsByIdMoveToPersonal(options: Options) { - return (options.client ?? this._client).post({ + return (options.client ?? this.client).post({ url: '/api/v1/business-documents/{id}/move-to-personal', ...options }); } public postApiV1BusinessDocumentsByIdMoveToBusiness(options: Options) { - return (options.client ?? this._client).post({ + return (options.client ?? this.client).post({ url: '/api/v1/business-documents/{id}/move-to-business', ...options, headers: { @@ -585,14 +611,14 @@ export class Sdk extends _HeyApiClient { } public getApiV1BusinessesByIdDocumentTypesSummary(options: Options) { - return (options.client ?? this._client).get({ + return (options.client ?? this.client).get({ url: '/api/v1/businesses/{id}/document-types-summary', ...options }); } public postApiV1Businesses(options?: Options) { - return (options?.client ?? this._client).post({ + return (options?.client ?? this.client).post({ url: '/api/v1/businesses', ...options, headers: { @@ -603,14 +629,14 @@ export class Sdk extends _HeyApiClient { } public deleteApiV1BusinessesById(options: Options) { - return (options.client ?? this._client).delete({ + return (options.client ?? this.client).delete({ url: '/api/v1/businesses/{id}', ...options }); } public putApiV1BusinessesById(options: Options) { - return (options.client ?? this._client).put({ + return (options.client ?? this.client).put({ url: '/api/v1/businesses/{id}', ...options, headers: { @@ -621,7 +647,7 @@ export class Sdk extends _HeyApiClient { } public putApiV1BusinessesByIdContact(options: Options) { - return (options.client ?? this._client).put({ + return (options.client ?? this.client).put({ url: '/api/v1/businesses/{id}/contact', ...options, headers: { @@ -632,14 +658,14 @@ export class Sdk extends _HeyApiClient { } public postApiV1BusinessesByIdDisconnect(options: Options) { - return (options.client ?? this._client).post({ + return (options.client ?? this.client).post({ url: '/api/v1/businesses/{id}/disconnect', ...options }); } public putApiV1BusinessMemberships(options?: Options) { - return (options?.client ?? this._client).put({ + return (options?.client ?? this.client).put({ url: '/api/v1/business-memberships', ...options, headers: { @@ -650,7 +676,7 @@ export class Sdk extends _HeyApiClient { } public postApiV1Counterparties(options?: Options) { - return (options?.client ?? this._client).post({ + return (options?.client ?? this.client).post({ url: '/api/v1/counterparties', ...options, headers: { @@ -661,14 +687,14 @@ export class Sdk extends _HeyApiClient { } public deleteApiV1CounterpartiesById(options: Options) { - return (options.client ?? this._client).delete({ + return (options.client ?? this.client).delete({ url: '/api/v1/counterparties/{id}', ...options }); } public patchApiV1CounterpartiesById(options: Options) { - return (options.client ?? this._client).patch({ + return (options.client ?? this.client).patch({ url: '/api/v1/counterparties/{id}', ...options, headers: { @@ -679,7 +705,7 @@ export class Sdk extends _HeyApiClient { } public putApiV1DataBoxCredentials(options?: Options) { - return (options?.client ?? this._client).put({ + return (options?.client ?? this.client).put({ url: '/api/v1/data-box-credentials', ...options, headers: { @@ -690,105 +716,105 @@ export class Sdk extends _HeyApiClient { } public deleteApiV1DataBoxCredentialsById(options: Options) { - return (options.client ?? this._client).delete({ + return (options.client ?? this.client).delete({ url: '/api/v1/data-box-credentials/{id}', ...options }); } public getApiDev(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/dev', ...options }); } public getApiDevReseedDb(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/dev/reseed-db', ...options }); } public getApiDevDbReset(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/dev/db-reset', ...options }); } public getApiDevDbReset2(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/dev/db/reset', ...options }); } public getApiDevDbCreate(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/dev/db/create', ...options }); } public getApiDevDbTouch(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/dev/db/touch', ...options }); } public getApiDevSeed(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/dev/seed', ...options }); } public getApiDevSeedAll(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/dev/seed-all', ...options }); } public getApiDevSeedProd(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/dev/seed-prod', ...options }); } public getApiDevJobProcessRecurringTasks(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/dev/job/process-recurring-tasks', ...options }); } public getApiDevNotificationsSendTest(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/dev/notifications/send-test', ...options }); } public getApiDevConfirmEmail(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/dev/confirm-email', ...options }); } public getApiDevEmailSendTest(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/dev/email/send-test', ...options }); } public deleteApiV1NotificationsDeviceTokens(options?: Options) { - return (options?.client ?? this._client).delete({ + return (options?.client ?? this.client).delete({ url: '/api/v1/notifications/device-tokens', ...options, headers: { @@ -799,7 +825,7 @@ export class Sdk extends _HeyApiClient { } public putApiV1NotificationsDeviceTokens(options?: Options) { - return (options?.client ?? this._client).put({ + return (options?.client ?? this.client).put({ url: '/api/v1/notifications/device-tokens', ...options, headers: { @@ -810,7 +836,7 @@ export class Sdk extends _HeyApiClient { } public postApiV1Feedback(options?: Options) { - return (options?.client ?? this._client).post({ + return (options?.client ?? this.client).post({ url: '/api/v1/feedback', ...options, headers: { @@ -821,7 +847,7 @@ export class Sdk extends _HeyApiClient { } public postApiV1Invitations(options?: Options) { - return (options?.client ?? this._client).post({ + return (options?.client ?? this.client).post({ url: '/api/v1/invitations', ...options, headers: { @@ -832,7 +858,7 @@ export class Sdk extends _HeyApiClient { } public postApiV1InvitationsByIdAccept(options: Options) { - return (options.client ?? this._client).post({ + return (options.client ?? this.client).post({ url: '/api/v1/invitations/{id}/accept', ...options, headers: { @@ -843,21 +869,21 @@ export class Sdk extends _HeyApiClient { } public postApiV1InvitationsByIdReject(options: Options) { - return (options.client ?? this._client).post({ + return (options.client ?? this.client).post({ url: '/api/v1/invitations/{id}/reject', ...options }); } public deleteApiV1InvitationsById(options: Options) { - return (options.client ?? this._client).delete({ + return (options.client ?? this.client).delete({ url: '/api/v1/invitations/{id}', ...options }); } public patchApiV1InvitationsById(options: Options) { - return (options.client ?? this._client).patch({ + return (options.client ?? this.client).patch({ url: '/api/v1/invitations/{id}', ...options, headers: { @@ -868,7 +894,7 @@ export class Sdk extends _HeyApiClient { } public postApiV1Invoices(options?: Options) { - return (options?.client ?? this._client).post({ + return (options?.client ?? this.client).post({ url: '/api/v1/invoices', ...options, headers: { @@ -879,14 +905,14 @@ export class Sdk extends _HeyApiClient { } public deleteApiV1InvoicesById(options: Options) { - return (options.client ?? this._client).delete({ + return (options.client ?? this.client).delete({ url: '/api/v1/invoices/{id}', ...options }); } public patchApiV1InvoicesById(options: Options) { - return (options.client ?? this._client).patch({ + return (options.client ?? this.client).patch({ url: '/api/v1/invoices/{id}', ...options, headers: { @@ -897,14 +923,14 @@ export class Sdk extends _HeyApiClient { } public getApiV1InvoicesByIdPreview(options: Options) { - return (options.client ?? this._client).get({ + return (options.client ?? this.client).get({ url: '/api/v1/invoices/{id}/preview', ...options }); } public postApiV1InvoicesByIdSend(options: Options) { - return (options.client ?? this._client).post({ + return (options.client ?? this.client).post({ url: '/api/v1/invoices/{id}/send', ...options, headers: { @@ -915,14 +941,14 @@ export class Sdk extends _HeyApiClient { } public postApiV1InvoicesByIdSnapshot(options: Options) { - return (options.client ?? this._client).post({ + return (options.client ?? this.client).post({ url: '/api/v1/invoices/{id}/snapshot', ...options }); } public putApiV1InvoiceSettings(options?: Options) { - return (options?.client ?? this._client).put({ + return (options?.client ?? this.client).put({ url: '/api/v1/invoice-settings', ...options, headers: { @@ -933,7 +959,7 @@ export class Sdk extends _HeyApiClient { } public postApiV1NotificationsTest(options?: Options) { - return (options?.client ?? this._client).post({ + return (options?.client ?? this.client).post({ url: '/api/v1/notifications/test', ...options, headers: { @@ -944,14 +970,14 @@ export class Sdk extends _HeyApiClient { } public getApiV1PersonalDocumentsByIdRaw(options: Options) { - return (options.client ?? this._client).get({ + return (options.client ?? this.client).get({ url: '/api/v1/personal-documents/{id}/raw', ...options }); } public postApiV1PersonalDocuments(options?: Options) { - return (options?.client ?? this._client).post({ + return (options?.client ?? this.client).post({ ...formDataBodySerializer, url: '/api/v1/personal-documents', ...options, @@ -963,7 +989,7 @@ export class Sdk extends _HeyApiClient { } public postApiV1PersonalDocumentsByIdMoveToBusiness(options: Options) { - return (options.client ?? this._client).post({ + return (options.client ?? this.client).post({ url: '/api/v1/personal-documents/{id}/move-to-business', ...options, headers: { @@ -974,21 +1000,21 @@ export class Sdk extends _HeyApiClient { } public deleteApiV1PersonalDocumentsById(options: Options) { - return (options.client ?? this._client).delete({ + return (options.client ?? this.client).delete({ url: '/api/v1/personal-documents/{id}', ...options }); } public getApiV1PersonalDocumentsSummary(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/personal-documents/summary', ...options }); } public postApiV1RecurringTasks(options?: Options) { - return (options?.client ?? this._client).post({ + return (options?.client ?? this.client).post({ url: '/api/v1/recurring-tasks', ...options, headers: { @@ -999,14 +1025,14 @@ export class Sdk extends _HeyApiClient { } public deleteApiV1RecurringTasksById(options: Options) { - return (options.client ?? this._client).delete({ + return (options.client ?? this.client).delete({ url: '/api/v1/recurring-tasks/{id}', ...options }); } public patchApiV1RecurringTasksById(options: Options) { - return (options.client ?? this._client).patch({ + return (options.client ?? this.client).patch({ url: '/api/v1/recurring-tasks/{id}', ...options, headers: { @@ -1017,14 +1043,14 @@ export class Sdk extends _HeyApiClient { } public get(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/', ...options }); } public postApiV1Tasks(options?: Options) { - return (options?.client ?? this._client).post({ + return (options?.client ?? this.client).post({ url: '/api/v1/tasks', ...options, headers: { @@ -1035,7 +1061,7 @@ export class Sdk extends _HeyApiClient { } public putApiV1TasksById(options: Options) { - return (options.client ?? this._client).put({ + return (options.client ?? this.client).put({ url: '/api/v1/tasks/{id}', ...options, headers: { @@ -1046,7 +1072,7 @@ export class Sdk extends _HeyApiClient { } public postApiV1TasksByIdSubmit(options: Options) { - return (options.client ?? this._client).post({ + return (options.client ?? this.client).post({ url: '/api/v1/tasks/{id}/submit', ...options, headers: { @@ -1057,14 +1083,14 @@ export class Sdk extends _HeyApiClient { } public postApiV1TasksByIdApprove(options: Options) { - return (options.client ?? this._client).post({ + return (options.client ?? this.client).post({ url: '/api/v1/tasks/{id}/approve', ...options }); } public postApiV1TasksByIdReject(options: Options) { - return (options.client ?? this._client).post({ + return (options.client ?? this.client).post({ url: '/api/v1/tasks/{id}/reject', ...options, headers: { @@ -1075,21 +1101,21 @@ export class Sdk extends _HeyApiClient { } public getApiV1TasksByIdComments(options: Options) { - return (options.client ?? this._client).get({ + return (options.client ?? this.client).get({ url: '/api/v1/tasks/{id}/comments', ...options }); } public getApiV1TasksByIdDocuments(options: Options) { - return (options.client ?? this._client).get({ + return (options.client ?? this.client).get({ url: '/api/v1/tasks/{id}/documents', ...options }); } public postApiV1UserRegister(options: Options) { - return (options.client ?? this._client).post({ + return (options.client ?? this.client).post({ url: '/api/v1/user/register', ...options, headers: { @@ -1100,7 +1126,7 @@ export class Sdk extends _HeyApiClient { } public postApiV1UserLogin(options: Options) { - return (options.client ?? this._client).post({ + return (options.client ?? this.client).post({ url: '/api/v1/user/login', ...options, headers: { @@ -1111,7 +1137,7 @@ export class Sdk extends _HeyApiClient { } public postApiV1UserRefresh(options: Options) { - return (options.client ?? this._client).post({ + return (options.client ?? this.client).post({ url: '/api/v1/user/refresh', ...options, headers: { @@ -1122,7 +1148,7 @@ export class Sdk extends _HeyApiClient { } public postApiV1UserResendConfirmationEmail(options: Options) { - return (options.client ?? this._client).post({ + return (options.client ?? this.client).post({ url: '/api/v1/user/resendConfirmationEmail', ...options, headers: { @@ -1133,7 +1159,7 @@ export class Sdk extends _HeyApiClient { } public postApiV1UserForgotPassword(options: Options) { - return (options.client ?? this._client).post({ + return (options.client ?? this.client).post({ url: '/api/v1/user/forgotPassword', ...options, headers: { @@ -1144,7 +1170,7 @@ export class Sdk extends _HeyApiClient { } public postApiV1UserResetPassword(options: Options) { - return (options.client ?? this._client).post({ + return (options.client ?? this.client).post({ url: '/api/v1/user/resetPassword', ...options, headers: { @@ -1155,7 +1181,7 @@ export class Sdk extends _HeyApiClient { } public postApiV1UserManage2Fa(options: Options) { - return (options.client ?? this._client).post({ + return (options.client ?? this.client).post({ url: '/api/v1/user/manage/2fa', ...options, headers: { @@ -1166,14 +1192,14 @@ export class Sdk extends _HeyApiClient { } public getApiV1UserManageInfo(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/user/manage/info', ...options }); } public postApiV1UserManageInfo(options: Options) { - return (options.client ?? this._client).post({ + return (options.client ?? this.client).post({ url: '/api/v1/user/manage/info', ...options, headers: { @@ -1184,7 +1210,7 @@ export class Sdk extends _HeyApiClient { } public postApiV1UserLogout(options?: Options) { - return (options?.client ?? this._client).post({ + return (options?.client ?? this.client).post({ url: '/api/v1/user/logout', ...options, headers: { @@ -1198,28 +1224,28 @@ export class Sdk extends _HeyApiClient { * @deprecated */ public getApiV1UserDocumentsSummary(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/user/documents-summary', ...options }); } public deleteApiV1User(options?: Options) { - return (options?.client ?? this._client).delete({ + return (options?.client ?? this.client).delete({ url: '/api/v1/user', ...options }); } public getApiV1UsersMe(options?: Options) { - return (options?.client ?? this._client).get({ + return (options?.client ?? this.client).get({ url: '/api/v1/users/me', ...options }); } public patchApiV1UsersById(options: Options) { - return (options.client ?? this._client).patch({ + return (options.client ?? this.client).patch({ url: '/api/v1/users/{id}', ...options, headers: { @@ -1229,7 +1255,7 @@ export class Sdk extends _HeyApiClient { }); } - api = new Api({ client: this._client }); + api = new Api({ client: this.client }); - mapIdentityApi = new MapIdentityApi({ client: this._client }); + mapIdentityApi = new MapIdentityApi({ client: this.client }); } diff --git a/packages/openapi-ts/src/plugins/@hey-api/sdk/shared/class.ts b/packages/openapi-ts/src/plugins/@hey-api/sdk/shared/class.ts index e2dc81908..50d8c2062 100644 --- a/packages/openapi-ts/src/plugins/@hey-api/sdk/shared/class.ts +++ b/packages/openapi-ts/src/plugins/@hey-api/sdk/shared/class.ts @@ -1,3 +1,4 @@ +import type { Symbol } from '@hey-api/codegen-core'; import type ts from 'typescript'; import { getClientPlugin } from '~/plugins/@hey-api/client-core/utils'; @@ -5,7 +6,9 @@ import { createOperationComment, isOperationOptionsRequired, } from '~/plugins/shared/utils/operation'; -import { tsc } from '~/tsc'; +import type { TsDsl } from '~/ts-dsl'; +import { $ } from '~/ts-dsl'; +import { toParameterDeclarations } from '~/tsc/types'; import { stringCase } from '~/utils/stringCase'; import type { HeyApiSdkPlugin } from '../types'; @@ -36,85 +39,118 @@ type SdkClassEntry = { /** * List of class nodes containing methods. */ - nodes: Array; + nodes: Array; /** * Is this a root class? */ root: boolean; }; -const createClientClassNodes = ({ +export const registryName = '__registry'; + +const createRegistryClass = ({ + sdkName, + symbol, +}: { + plugin: HeyApiSdkPlugin['Instance']; + sdkName: string; + symbol: Symbol; +}): TsDsl => { + const defaultKey = 'defaultKey'; + const instances = 'instances'; + return $.class(symbol.placeholder) + .export(symbol.exported) + .generic('T') + .field(defaultKey, (f) => + f.private().readonly().assign($.literal('default')), + ) + .newline() + .field(instances, (f) => + f + .private() + .readonly() + .type($.type('Map').generics('string', 'T')) + .assign($.new('Map')), + ) + .newline() + .method('get', (m) => + m + .returns('T') + .param('key', (p) => p.type('string').optional()) + .do( + $.const('instance').assign( + $('this') + .attr('instances') + .attr('get') + .call($('key').coalesce($('this').attr(defaultKey))), + ), + $.if($.not('instance')).do( + $.throw('Error').message( + $.template('No SDK client found. Create one with "new ') + .add(sdkName) + .add('()" to fix this error.'), + ), + ), + $.return('instance'), + ), + ) + .newline() + .method('set', (m) => + m + .returns('void') + .param('value', (p) => p.type('T')) + .param('key', (p) => p.type('string').optional()) + .do( + $('this') + .attr(instances) + .attr('set') + .call($('key').coalesce($('this').attr(defaultKey)), 'value'), + ), + ); +}; + +const createClientClass = ({ plugin, + symbol, }: { plugin: HeyApiSdkPlugin['Instance']; -}): ReadonlyArray => { - const clientAssignmentStatement = tsc.expressionToStatement({ - expression: tsc.binaryExpression({ - left: tsc.propertyAccessExpression({ - expression: tsc.this(), - name: '_client', - }), - operator: '=', - right: tsc.propertyAccessExpression({ - expression: tsc.identifier({ text: 'args' }), - name: 'client', - }), - }), + symbol: Symbol; +}): TsDsl => { + const symClient = plugin.getSymbol({ + category: 'client', }); - + const optionalClient = Boolean(plugin.config.client && symClient); const symbolClient = plugin.referenceSymbol({ category: 'external', resource: 'client.Client', }); - const symClient = plugin.getSymbol({ - category: 'client', - }); - - return [ - tsc.propertyDeclaration({ - initializer: symClient - ? tsc.identifier({ text: symClient.placeholder }) - : undefined, - modifier: 'protected', - name: '_client', - type: tsc.typeReferenceNode({ typeName: symbolClient.placeholder }), - }), - // @ts-expect-error - tsc.identifier({ text: '\n' }), - tsc.constructorDeclaration({ - multiLine: true, - parameters: [ - { - isRequired: !plugin.config.client, - name: 'args', - type: tsc.typeInterfaceNode({ - properties: [ - { - isRequired: !plugin.config.client, - name: 'client', - type: symbolClient.placeholder, - }, - ], - useLegacyResolution: false, - }), - }, - ], - statements: [ - !plugin.config.client - ? clientAssignmentStatement - : tsc.ifStatement({ - expression: tsc.propertyAccessExpression({ - expression: tsc.identifier({ text: 'args' }), - isOptional: true, - name: 'client', - }), - thenStatement: tsc.block({ - statements: [clientAssignmentStatement], - }), - }), - ], - }), - ]; + return $.class(symbol.placeholder) + .export(symbol.exported) + .field('client', (f) => f.protected().type(symbolClient.placeholder)) + .newline() + .init((i) => + i + .param('args', (p) => + p + .optional(optionalClient) + .type() + .object((o) => + o.prop('client', (p) => + p.optional(optionalClient).type(symbolClient.placeholder), + ), + ), + ) + .do( + $('this') + .attr('client') + .assign( + $('args') + .attr('client') + .optional(optionalClient) + .$if(optionalClient, (a) => a.coalesce(symClient!.placeholder)), + ), + ), + ); }; export const generateClassSdk = ({ @@ -131,10 +167,6 @@ export const generateClassSdk = ({ */ const generatedClasses = new Set(); - const clientClassNodes = plugin.config.instance - ? createClientClassNodes({ plugin }) - : []; - plugin.forEach( 'operation', ({ operation }) => { @@ -222,60 +254,51 @@ export const generateClassSdk = ({ operation, plugin, }); - const functionNode = tsc.methodDeclaration({ - accessLevel: 'public', - comment: createOperationComment({ operation }), - isStatic: isAngularClient ? false : !plugin.config.instance, - name: entry.methodName, - parameters: opParameters.parameters, - returnType: undefined, - statements, - types: isNuxtClient - ? [ - { - default: tsc.ots.string('$fetch'), - extends: tsc.typeNode( - plugin.referenceSymbol({ - category: 'external', - resource: 'client.Composable', - }).placeholder, + const functionNode = $.method(entry.methodName, (m) => + m + .$if(createOperationComment({ operation }), (m, v) => + m.describe(v as Array), + ) + .public() + .static(!isAngularClient && !plugin.config.instance) + .$if( + isNuxtClient, + (m) => + m + .generic(nuxtTypeComposable, (t) => + t + .extends( + plugin.referenceSymbol({ + category: 'external', + resource: 'client.Composable', + }).placeholder, + ) + .default($.type.literal('$fetch')), + ) + .generic(nuxtTypeDefault, (t) => + t.$if(symbolResponse, (t, s) => + t.extends(s.placeholder).default(s.placeholder), + ), ), - name: nuxtTypeComposable, - }, - { - default: symbolResponse - ? tsc.typeReferenceNode({ - typeName: symbolResponse.placeholder, - }) - : tsc.typeNode('undefined'), - extends: symbolResponse - ? tsc.typeReferenceNode({ - typeName: symbolResponse.placeholder, - }) - : undefined, - name: nuxtTypeDefault, - }, - ] - : [ - { - default: - ('throwOnError' in client.config - ? client.config.throwOnError - : false) ?? false, - extends: 'boolean', - name: 'ThrowOnError', - }, - ], - }); + (m) => + m.generic('ThrowOnError', (t) => + t + .extends('boolean') + .default( + ('throwOnError' in client.config + ? client.config.throwOnError + : false) ?? false, + ), + ), + ) + .params(...toParameterDeclarations(opParameters.parameters)) + .do(...statements), + ); if (!currentClass.nodes.length) { currentClass.nodes.push(functionNode); } else { - currentClass.nodes.push( - // @ts-expect-error - tsc.identifier({ text: '\n' }), - functionNode, - ); + currentClass.nodes.push($.newline(), functionNode); } currentClass.methods.add(entry.methodName); @@ -289,17 +312,32 @@ export const generateClassSdk = ({ }, ); - const symbolHeyApiClient = plugin.registerSymbol({ - exported: false, - kind: 'class', - meta: { - category: 'utility', - resource: 'class', - resourceId: '_HeyApiClient', - tool: 'sdk', - }, - name: '_HeyApiClient', - }); + const symbolHeyApiClient = plugin.config.instance + ? plugin.registerSymbol({ + exported: false, + kind: 'class', + meta: { + category: 'utility', + resource: 'class', + resourceId: 'HeyApiClient', + tool: 'sdk', + }, + name: 'HeyApiClient', + }) + : undefined; + const symbolHeyApiRegistry = plugin.config.instance + ? plugin.registerSymbol({ + exported: false, + kind: 'class', + meta: { + category: 'utility', + resource: 'class', + resourceId: 'HeyApiRegistry', + tool: 'sdk', + }, + name: 'HeyApiRegistry', + }) + : undefined; const generateClass = (currentClass: SdkClassEntry) => { if (generatedClasses.has(currentClass.className)) { @@ -339,87 +377,59 @@ export const generateClassSdk = ({ let subClassReferenceNode: | ts.GetAccessorDeclaration - | ts.PropertyDeclaration; + | ts.PropertyDeclaration + | TsDsl; if (plugin.isSymbolRegistered(refChildClass.id)) { - subClassReferenceNode = tsc.propertyDeclaration({ - initializer: plugin.config.instance - ? tsc.newExpression({ - argumentsArray: plugin.config.instance - ? [ - tsc.objectExpression({ - multiLine: false, - obj: [ - { - key: 'client', - value: tsc.propertyAccessExpression({ - expression: tsc.this(), - name: '_client', - }), - }, - ], - }), - ] - : [], - expression: tsc.identifier({ - text: refChildClass.placeholder, - }), - }) - : tsc.identifier({ text: refChildClass.placeholder }), - modifier: plugin.config.instance ? undefined : 'static', - name: memberName, - }); + subClassReferenceNode = $.field(memberName, (f) => + f + .static(!plugin.config.instance) + .assign( + plugin.config.instance + ? $.new(refChildClass.placeholder).args( + $.object((o) => + o.prop('client', () => $('this').attr('client')), + ), + ) + : $(refChildClass.placeholder), + ), + ); } else { - subClassReferenceNode = tsc.getAccessorDeclaration({ - modifiers: plugin.config.instance - ? undefined - : ['public', 'static'], - name: memberName, - statements: plugin.config.instance - ? [ - tsc.returnStatement({ - expression: tsc.newExpression({ - argumentsArray: [ - tsc.objectExpression({ - multiLine: false, - obj: [ - { - key: 'client', - value: tsc.propertyAccessExpression({ - expression: tsc.this(), - name: '_client', - }), - }, - ], - }), - ], - expression: tsc.identifier({ - text: refChildClass.placeholder, - }), - }), - }), - ] - : [ - tsc.returnStatement({ - expression: tsc.identifier({ - text: refChildClass.placeholder, - }), - }), - ], - }); + subClassReferenceNode = $.getter(memberName, (g) => + g + .$if(!plugin.config.instance, (g) => g.public().static()) + .do( + plugin.config.instance + ? $.return( + $.new(refChildClass.placeholder).args( + $.object((o) => + o.prop('client', () => $('this').attr('client')), + ), + ), + ) + : $.return(refChildClass.placeholder), + ), + ); } if (!currentClass.nodes.length) { currentClass.nodes.push(subClassReferenceNode); } else { - currentClass.nodes.push( - // @ts-expect-error - tsc.identifier({ text: '\n' }), - subClassReferenceNode, - ); + currentClass.nodes.push($.newline(), subClassReferenceNode); } } } + if ( + symbolHeyApiClient && + !plugin.gen.symbols.hasValue(symbolHeyApiClient.id) + ) { + const node = createClientClass({ + plugin, + symbol: symbolHeyApiClient, + }).$render(); + plugin.setSymbolValue(symbolHeyApiClient, node); + } + const symbol = plugin.registerSymbol({ exported: true, kind: 'class', @@ -431,40 +441,82 @@ export const generateClassSdk = ({ }, name: resourceId, }); - const node = tsc.classDeclaration({ - decorator: - currentClass.root && isAngularClient - ? { - args: [ - { - providedIn: 'root', - }, - ], - name: plugin.referenceSymbol({ - category: 'external', - resource: '@angular/core.Injectable', - }).placeholder, - } - : undefined, - exportClass: symbol.exported, - extendedClasses: plugin.config.instance - ? [symbolHeyApiClient.placeholder] - : undefined, - name: symbol.placeholder, - nodes: currentClass.nodes, - }); + + if (currentClass.root && symbolHeyApiRegistry) { + const symClient = plugin.getSymbol({ + category: 'client', + }); + const isClientRequired = !plugin.config.client || !symClient; + const symbolClient = plugin.referenceSymbol({ + category: 'external', + resource: 'client.Client', + }); + const ctor = $.init((i) => + i + .param('args', (p) => + p + .optional(!isClientRequired) + .type() + .object((o) => + o + .prop('client', (p) => + p + .optional(!isClientRequired) + .type(symbolClient.placeholder), + ) + .prop('key', (p) => p.optional().type('string')), + ), + ) + .do( + $('super').call('args'), + $(symbol.placeholder) + .attr(registryName) + .attr('set') + .call('this', $('args').attr('key').optional(!isClientRequired)), + ), + ); + + if (!currentClass.nodes.length) { + currentClass.nodes.unshift(ctor); + } else { + currentClass.nodes.unshift(ctor, $.newline()); + } + + const node = createRegistryClass({ + plugin, + sdkName: symbol.placeholder, + symbol: symbolHeyApiRegistry, + }).$render(); + plugin.setSymbolValue(symbolHeyApiRegistry, node); + const registryNode = $.field(registryName, (f) => + f + .public() + .static() + .readonly() + .assign( + $.new(symbolHeyApiRegistry.placeholder).generic(symbol.placeholder), + ), + ); + currentClass.nodes.unshift(registryNode, $.newline()); + } + + const node = $.class(symbol.placeholder) + .export(symbol.exported) + .extends(symbolHeyApiClient?.placeholder) + .$if(currentClass.root && isAngularClient, (c) => + c.decorator( + plugin.referenceSymbol({ + category: 'external', + resource: '@angular/core.Injectable', + }).placeholder, + (o) => o.prop('providedIn', () => $.literal('root')), + ), + ) + .do(...currentClass.nodes) + .$render(); plugin.setSymbolValue(symbol, node); }; - if (clientClassNodes.length) { - const node = tsc.classDeclaration({ - exportClass: symbolHeyApiClient.exported, - name: symbolHeyApiClient.placeholder, - nodes: clientClassNodes, - }); - plugin.setSymbolValue(symbolHeyApiClient, node); - } - for (const sdkClass of sdkClasses.values()) { generateClass(sdkClass); } diff --git a/packages/openapi-ts/src/plugins/@hey-api/sdk/shared/operation.ts b/packages/openapi-ts/src/plugins/@hey-api/sdk/shared/operation.ts index 26084d154..880ce01f3 100644 --- a/packages/openapi-ts/src/plugins/@hey-api/sdk/shared/operation.ts +++ b/packages/openapi-ts/src/plugins/@hey-api/sdk/shared/operation.ts @@ -690,7 +690,7 @@ export const operationStatements = ({ operator: '??', right: tsc.propertyAccessExpression({ expression: tsc.this(), - name: '_client', + name: 'client', }), }); } else if (symbolClient) { diff --git a/packages/openapi-ts/src/plugins/@hey-api/sdk/shared/typeOptions.ts b/packages/openapi-ts/src/plugins/@hey-api/sdk/shared/typeOptions.ts index bd31d3c3a..25d913b69 100644 --- a/packages/openapi-ts/src/plugins/@hey-api/sdk/shared/typeOptions.ts +++ b/packages/openapi-ts/src/plugins/@hey-api/sdk/shared/typeOptions.ts @@ -72,7 +72,7 @@ export const createTypeOptions = ({ 'individual options. This might be also useful if you want to implement a', 'custom client.', ], - isRequired: !plugin.config.client, + isRequired: !plugin.config.client && !plugin.config.instance, name: 'client', type: tsc.typeReferenceNode({ typeName: symbolClient.placeholder, diff --git a/packages/openapi-ts/src/plugins/@pinia/colada/plugin.ts b/packages/openapi-ts/src/plugins/@pinia/colada/plugin.ts index e6d0574c2..0e023020e 100644 --- a/packages/openapi-ts/src/plugins/@pinia/colada/plugin.ts +++ b/packages/openapi-ts/src/plugins/@pinia/colada/plugin.ts @@ -1,110 +1,4 @@ -import { operationClasses } from '~/plugins/@hey-api/sdk/shared/operation'; -import { stringCase } from '~/utils/stringCase'; - -import { createMutationOptions } from './mutationOptions'; -import { createQueryOptions } from './queryOptions'; import type { PiniaColadaPlugin } from './types'; +import { handlerV0 } from './v0/plugin'; -export const handler: PiniaColadaPlugin['Handler'] = ({ plugin }) => { - plugin.registerSymbol({ - external: plugin.name, - meta: { - category: 'external', - resource: `${plugin.name}.defineQueryOptions`, - }, - name: 'defineQueryOptions', - }); - plugin.registerSymbol({ - external: plugin.name, - kind: 'type', - meta: { - category: 'external', - resource: `${plugin.name}.UseMutationOptions`, - }, - name: 'UseMutationOptions', - }); - plugin.registerSymbol({ - external: plugin.name, - kind: 'type', - meta: { - category: 'external', - resource: `${plugin.name}.UseQueryOptions`, - }, - name: 'UseQueryOptions', - }); - plugin.registerSymbol({ - external: plugin.name, - kind: 'type', - meta: { - category: 'external', - resource: `${plugin.name}._JSONValue`, - }, - name: '_JSONValue', - }); - plugin.registerSymbol({ - external: 'axios', - kind: 'type', - meta: { - category: 'external', - resource: 'axios.AxiosError', - }, - name: 'AxiosError', - }); - - const sdkPlugin = plugin.getPluginOrThrow('@hey-api/sdk'); - - plugin.forEach( - 'operation', - ({ operation }) => { - const classes = sdkPlugin.config.asClass - ? operationClasses({ - context: plugin.context, - operation, - plugin: sdkPlugin, - }) - : undefined; - const entry = classes ? classes.values().next().value : undefined; - const queryFn = - // TODO: this should use class graph to determine correct path string - // as it's really easy to break once we change the class casing - entry - ? [ - plugin.referenceSymbol({ - category: 'utility', - resource: 'class', - resourceId: entry.path[0], - tool: 'sdk', - }).placeholder, - ...entry.path.slice(1).map((className: string) => - stringCase({ - case: 'camelCase', - value: className, - }), - ), - entry.methodName, - ] - .filter(Boolean) - .join('.') - : plugin.referenceSymbol({ - category: 'sdk', - resource: 'operation', - resourceId: operation.id, - }).placeholder; - - if (plugin.hooks.operation.isQuery(operation)) { - if (plugin.config.queryOptions.enabled) { - createQueryOptions({ operation, plugin, queryFn }); - } - } - - if (plugin.hooks.operation.isMutation(operation)) { - if (plugin.config.mutationOptions.enabled) { - createMutationOptions({ operation, plugin, queryFn }); - } - } - }, - { - order: 'declarations', - }, - ); -}; +export const handler: PiniaColadaPlugin['Handler'] = (args) => handlerV0(args); diff --git a/packages/openapi-ts/src/plugins/@pinia/colada/v0/plugin.ts b/packages/openapi-ts/src/plugins/@pinia/colada/v0/plugin.ts new file mode 100644 index 000000000..6f115d619 --- /dev/null +++ b/packages/openapi-ts/src/plugins/@pinia/colada/v0/plugin.ts @@ -0,0 +1,110 @@ +import { operationClasses } from '~/plugins/@hey-api/sdk/shared/operation'; +import { stringCase } from '~/utils/stringCase'; + +import { createMutationOptions } from '../mutationOptions'; +import { createQueryOptions } from '../queryOptions'; +import type { PiniaColadaPlugin } from '../types'; + +export const handlerV0: PiniaColadaPlugin['Handler'] = ({ plugin }) => { + plugin.registerSymbol({ + external: plugin.name, + meta: { + category: 'external', + resource: `${plugin.name}.defineQueryOptions`, + }, + name: 'defineQueryOptions', + }); + plugin.registerSymbol({ + external: plugin.name, + kind: 'type', + meta: { + category: 'external', + resource: `${plugin.name}.UseMutationOptions`, + }, + name: 'UseMutationOptions', + }); + plugin.registerSymbol({ + external: plugin.name, + kind: 'type', + meta: { + category: 'external', + resource: `${plugin.name}.UseQueryOptions`, + }, + name: 'UseQueryOptions', + }); + plugin.registerSymbol({ + external: plugin.name, + kind: 'type', + meta: { + category: 'external', + resource: `${plugin.name}._JSONValue`, + }, + name: '_JSONValue', + }); + plugin.registerSymbol({ + external: 'axios', + kind: 'type', + meta: { + category: 'external', + resource: 'axios.AxiosError', + }, + name: 'AxiosError', + }); + + const sdkPlugin = plugin.getPluginOrThrow('@hey-api/sdk'); + + plugin.forEach( + 'operation', + ({ operation }) => { + const classes = sdkPlugin.config.asClass + ? operationClasses({ + context: plugin.context, + operation, + plugin: sdkPlugin, + }) + : undefined; + const entry = classes ? classes.values().next().value : undefined; + const queryFn = + // TODO: this should use class graph to determine correct path string + // as it's really easy to break once we change the class casing + entry + ? [ + plugin.referenceSymbol({ + category: 'utility', + resource: 'class', + resourceId: entry.path[0], + tool: 'sdk', + }).placeholder, + ...entry.path.slice(1).map((className: string) => + stringCase({ + case: 'camelCase', + value: className, + }), + ), + entry.methodName, + ] + .filter(Boolean) + .join('.') + : plugin.referenceSymbol({ + category: 'sdk', + resource: 'operation', + resourceId: operation.id, + }).placeholder; + + if (plugin.hooks.operation.isQuery(operation)) { + if (plugin.config.queryOptions.enabled) { + createQueryOptions({ operation, plugin, queryFn }); + } + } + + if (plugin.hooks.operation.isMutation(operation)) { + if (plugin.config.mutationOptions.enabled) { + createMutationOptions({ operation, plugin, queryFn }); + } + } + }, + { + order: 'declarations', + }, + ); +}; diff --git a/packages/openapi-ts/src/plugins/@tanstack/query-core/infiniteQueryOptions.ts b/packages/openapi-ts/src/plugins/@tanstack/query-core/infiniteQueryOptions.ts index d83b5b34b..364bfa502 100644 --- a/packages/openapi-ts/src/plugins/@tanstack/query-core/infiniteQueryOptions.ts +++ b/packages/openapi-ts/src/plugins/@tanstack/query-core/infiniteQueryOptions.ts @@ -10,14 +10,14 @@ import { import { tsc } from '~/tsc'; import { tsNodeToString } from '~/tsc/utils'; -import { handleMeta } from './meta'; import { createQueryKeyFunction, createQueryKeyType, queryKeyStatement, } from './queryKey'; +import { handleMeta } from './shared/meta'; +import { useTypeData, useTypeError, useTypeResponse } from './shared/useType'; import type { PluginInstance } from './types'; -import { useTypeData, useTypeError, useTypeResponse } from './useType'; const createInfiniteParamsFunction = ({ plugin, diff --git a/packages/openapi-ts/src/plugins/@tanstack/query-core/mutationOptions.ts b/packages/openapi-ts/src/plugins/@tanstack/query-core/mutationOptions.ts index ac9d22277..a8043ce80 100644 --- a/packages/openapi-ts/src/plugins/@tanstack/query-core/mutationOptions.ts +++ b/packages/openapi-ts/src/plugins/@tanstack/query-core/mutationOptions.ts @@ -5,9 +5,9 @@ import { buildName } from '~/openApi/shared/utils/name'; import { createOperationComment } from '~/plugins/shared/utils/operation'; import { tsc } from '~/tsc'; -import { handleMeta } from './meta'; +import { handleMeta } from './shared/meta'; +import { useTypeData, useTypeError, useTypeResponse } from './shared/useType'; import type { PluginInstance } from './types'; -import { useTypeData, useTypeError, useTypeResponse } from './useType'; export const createMutationOptions = ({ operation, diff --git a/packages/openapi-ts/src/plugins/@tanstack/query-core/plugin.ts b/packages/openapi-ts/src/plugins/@tanstack/query-core/plugin.ts index 78c752792..d1382e17b 100644 --- a/packages/openapi-ts/src/plugins/@tanstack/query-core/plugin.ts +++ b/packages/openapi-ts/src/plugins/@tanstack/query-core/plugin.ts @@ -1,142 +1,5 @@ -import { operationClasses } from '~/plugins/@hey-api/sdk/shared/operation'; -import { stringCase } from '~/utils/stringCase'; - -import { createInfiniteQueryOptions } from './infiniteQueryOptions'; -import { createMutationOptions } from './mutationOptions'; -import { createQueryOptions } from './queryOptions'; import type { PluginHandler } from './types'; -import { createUseQuery } from './useQuery'; - -export const handler: PluginHandler = ({ plugin }) => { - plugin.registerSymbol({ - external: plugin.name, - kind: 'type', - meta: { - category: 'external', - resource: `${plugin.name}.DefaultError`, - }, - name: 'DefaultError', - }); - plugin.registerSymbol({ - external: plugin.name, - kind: 'type', - meta: { - category: 'external', - resource: `${plugin.name}.InfiniteData`, - }, - name: 'InfiniteData', - }); - const mutationsType = - plugin.name === '@tanstack/angular-query-experimental' || - plugin.name === '@tanstack/svelte-query' || - plugin.name === '@tanstack/solid-query' - ? 'MutationOptions' - : 'UseMutationOptions'; - plugin.registerSymbol({ - external: plugin.name, - kind: 'type', - meta: { - category: 'external', - resource: `${plugin.name}.MutationOptions`, - }, - name: mutationsType, - }); - plugin.registerSymbol({ - external: plugin.name, - meta: { - category: 'external', - resource: `${plugin.name}.infiniteQueryOptions`, - }, - name: 'infiniteQueryOptions', - }); - plugin.registerSymbol({ - external: plugin.name, - meta: { - category: 'external', - resource: `${plugin.name}.queryOptions`, - }, - name: 'queryOptions', - }); - plugin.registerSymbol({ - external: plugin.name, - meta: { - category: 'external', - resource: `${plugin.name}.useQuery`, - }, - name: 'useQuery', - }); - plugin.registerSymbol({ - external: 'axios', - kind: 'type', - meta: { - category: 'external', - resource: 'axios.AxiosError', - }, - name: 'AxiosError', - }); - - const sdkPlugin = plugin.getPluginOrThrow('@hey-api/sdk'); - - plugin.forEach( - 'operation', - ({ operation }) => { - const classes = sdkPlugin.config.asClass - ? operationClasses({ - context: plugin.context, - operation, - plugin: sdkPlugin, - }) - : undefined; - const entry = classes ? classes.values().next().value : undefined; - const queryFn = - // TODO: this should use class graph to determine correct path string - // as it's really easy to break once we change the class casing - entry - ? [ - plugin.referenceSymbol({ - category: 'utility', - resource: 'class', - resourceId: entry.path[0], - tool: 'sdk', - }).placeholder, - ...entry.path.slice(1).map((className) => - stringCase({ - case: 'camelCase', - value: className, - }), - ), - entry.methodName, - ] - .filter(Boolean) - .join('.') - : plugin.referenceSymbol({ - category: 'sdk', - resource: 'operation', - resourceId: operation.id, - }).placeholder; - - if (plugin.hooks.operation.isQuery(operation)) { - if (plugin.config.queryOptions.enabled) { - createQueryOptions({ operation, plugin, queryFn }); - } - - if (plugin.config.infiniteQueryOptions.enabled) { - createInfiniteQueryOptions({ operation, plugin, queryFn }); - } - - if ('useQuery' in plugin.config && plugin.config.useQuery.enabled) { - createUseQuery({ operation, plugin }); - } - } +import { handlerV5 } from './v5/plugin'; - if (plugin.hooks.operation.isMutation(operation)) { - if (plugin.config.mutationOptions.enabled) { - createMutationOptions({ operation, plugin, queryFn }); - } - } - }, - { - order: 'declarations', - }, - ); -}; +export const handler: PluginHandler = (args) => + handlerV5(args as Parameters[0]); diff --git a/packages/openapi-ts/src/plugins/@tanstack/query-core/queryKey.ts b/packages/openapi-ts/src/plugins/@tanstack/query-core/queryKey.ts index 349cf96f8..6d2e52005 100644 --- a/packages/openapi-ts/src/plugins/@tanstack/query-core/queryKey.ts +++ b/packages/openapi-ts/src/plugins/@tanstack/query-core/queryKey.ts @@ -7,8 +7,8 @@ import { buildName } from '~/openApi/shared/utils/name'; import { getClientBaseUrlKey } from '~/plugins/@hey-api/client-core/utils'; import { type Property, tsc } from '~/tsc'; +import { useTypeData } from './shared/useType'; import type { PluginInstance } from './types'; -import { useTypeData } from './useType'; const TOptionsType = 'TOptions'; diff --git a/packages/openapi-ts/src/plugins/@tanstack/query-core/meta.ts b/packages/openapi-ts/src/plugins/@tanstack/query-core/shared/meta.ts similarity index 91% rename from packages/openapi-ts/src/plugins/@tanstack/query-core/meta.ts rename to packages/openapi-ts/src/plugins/@tanstack/query-core/shared/meta.ts index a5bbb901e..11e2bcb4c 100644 --- a/packages/openapi-ts/src/plugins/@tanstack/query-core/meta.ts +++ b/packages/openapi-ts/src/plugins/@tanstack/query-core/shared/meta.ts @@ -3,7 +3,7 @@ import type ts from 'typescript'; import type { IR } from '~/ir/types'; import { tsc } from '~/tsc'; -import type { PluginInstance } from './types'; +import type { PluginInstance } from '../types'; export const handleMeta = ( plugin: PluginInstance, diff --git a/packages/openapi-ts/src/plugins/@tanstack/query-core/useType.ts b/packages/openapi-ts/src/plugins/@tanstack/query-core/shared/useType.ts similarity index 97% rename from packages/openapi-ts/src/plugins/@tanstack/query-core/useType.ts rename to packages/openapi-ts/src/plugins/@tanstack/query-core/shared/useType.ts index 0b16b0b43..7fce33fe5 100644 --- a/packages/openapi-ts/src/plugins/@tanstack/query-core/useType.ts +++ b/packages/openapi-ts/src/plugins/@tanstack/query-core/shared/useType.ts @@ -2,7 +2,7 @@ import type { IR } from '~/ir/types'; import { getClientPlugin } from '~/plugins/@hey-api/client-core/utils'; import { operationOptionsType } from '~/plugins/@hey-api/sdk/shared/operation'; -import type { PluginInstance } from './types'; +import type { PluginInstance } from '../types'; export const useTypeData = ({ operation, diff --git a/packages/openapi-ts/src/plugins/@tanstack/query-core/v5/plugin.ts b/packages/openapi-ts/src/plugins/@tanstack/query-core/v5/plugin.ts new file mode 100644 index 000000000..e942ac069 --- /dev/null +++ b/packages/openapi-ts/src/plugins/@tanstack/query-core/v5/plugin.ts @@ -0,0 +1,147 @@ +import { registryName } from '~/plugins/@hey-api/sdk/shared/class'; +import { operationClasses } from '~/plugins/@hey-api/sdk/shared/operation'; +import { stringCase } from '~/utils/stringCase'; + +import { createInfiniteQueryOptions } from '../infiniteQueryOptions'; +import { createMutationOptions } from '../mutationOptions'; +import type { PluginHandler } from '../types'; +import { createQueryOptions } from './queryOptions'; +import { createUseQuery } from './useQuery'; + +export const handlerV5: PluginHandler = ({ plugin }) => { + plugin.registerSymbol({ + external: plugin.name, + kind: 'type', + meta: { + category: 'external', + resource: `${plugin.name}.DefaultError`, + }, + name: 'DefaultError', + }); + plugin.registerSymbol({ + external: plugin.name, + kind: 'type', + meta: { + category: 'external', + resource: `${plugin.name}.InfiniteData`, + }, + name: 'InfiniteData', + }); + const mutationsType = + plugin.name === '@tanstack/angular-query-experimental' || + plugin.name === '@tanstack/svelte-query' || + plugin.name === '@tanstack/solid-query' + ? 'MutationOptions' + : 'UseMutationOptions'; + plugin.registerSymbol({ + external: plugin.name, + kind: 'type', + meta: { + category: 'external', + resource: `${plugin.name}.MutationOptions`, + }, + name: mutationsType, + }); + plugin.registerSymbol({ + external: plugin.name, + meta: { + category: 'external', + resource: `${plugin.name}.infiniteQueryOptions`, + }, + name: 'infiniteQueryOptions', + }); + plugin.registerSymbol({ + external: plugin.name, + meta: { + category: 'external', + resource: `${plugin.name}.queryOptions`, + }, + name: 'queryOptions', + }); + plugin.registerSymbol({ + external: plugin.name, + meta: { + category: 'external', + resource: `${plugin.name}.useQuery`, + }, + name: 'useQuery', + }); + plugin.registerSymbol({ + external: 'axios', + kind: 'type', + meta: { + category: 'external', + resource: 'axios.AxiosError', + }, + name: 'AxiosError', + }); + + const sdkPlugin = plugin.getPluginOrThrow('@hey-api/sdk'); + + plugin.forEach( + 'operation', + ({ operation }) => { + const classes = sdkPlugin.config.asClass + ? operationClasses({ + context: plugin.context, + operation, + plugin: sdkPlugin, + }) + : undefined; + const entry = classes ? classes.values().next().value : undefined; + // TODO: this should use class graph to determine correct path string + // as it's really easy to break once we change the class casing + let queryFn: string; + if (entry) { + const symbolClass = plugin.referenceSymbol({ + category: 'utility', + resource: 'class', + resourceId: entry.path[0], + tool: 'sdk', + }); + queryFn = [ + symbolClass.placeholder, + ...(sdkPlugin.config.instance ? [registryName, 'get()'] : []), + ...entry.path.slice(1).map((className) => + stringCase({ + case: 'camelCase', + value: className, + }), + ), + entry.methodName, + ] + .filter(Boolean) + .join('.'); + } else { + queryFn = plugin.referenceSymbol({ + category: 'sdk', + resource: 'operation', + resourceId: operation.id, + }).placeholder; + } + + if (plugin.hooks.operation.isQuery(operation)) { + if (plugin.config.queryOptions.enabled) { + createQueryOptions({ operation, plugin, queryFn }); + } + + if (plugin.config.infiniteQueryOptions.enabled) { + createInfiniteQueryOptions({ operation, plugin, queryFn }); + } + + if ('useQuery' in plugin.config && plugin.config.useQuery.enabled) { + createUseQuery({ operation, plugin }); + } + } + + if (plugin.hooks.operation.isMutation(operation)) { + if (plugin.config.mutationOptions.enabled) { + createMutationOptions({ operation, plugin, queryFn }); + } + } + }, + { + order: 'declarations', + }, + ); +}; diff --git a/packages/openapi-ts/src/plugins/@tanstack/query-core/queryOptions.ts b/packages/openapi-ts/src/plugins/@tanstack/query-core/v5/queryOptions.ts similarity index 96% rename from packages/openapi-ts/src/plugins/@tanstack/query-core/queryOptions.ts rename to packages/openapi-ts/src/plugins/@tanstack/query-core/v5/queryOptions.ts index 3b979cc07..8e007a660 100644 --- a/packages/openapi-ts/src/plugins/@tanstack/query-core/queryOptions.ts +++ b/packages/openapi-ts/src/plugins/@tanstack/query-core/v5/queryOptions.ts @@ -9,14 +9,14 @@ import { } from '~/plugins/shared/utils/operation'; import { tsc } from '~/tsc'; -import { handleMeta } from './meta'; import { createQueryKeyFunction, createQueryKeyType, queryKeyStatement, -} from './queryKey'; -import type { PluginInstance } from './types'; -import { useTypeData } from './useType'; +} from '../queryKey'; +import { handleMeta } from '../shared/meta'; +import { useTypeData } from '../shared/useType'; +import type { PluginInstance } from '../types'; const optionsParamName = 'options'; diff --git a/packages/openapi-ts/src/plugins/@tanstack/query-core/useQuery.ts b/packages/openapi-ts/src/plugins/@tanstack/query-core/v5/useQuery.ts similarity index 95% rename from packages/openapi-ts/src/plugins/@tanstack/query-core/useQuery.ts rename to packages/openapi-ts/src/plugins/@tanstack/query-core/v5/useQuery.ts index 3d49c2aa0..077b1cbfb 100644 --- a/packages/openapi-ts/src/plugins/@tanstack/query-core/useQuery.ts +++ b/packages/openapi-ts/src/plugins/@tanstack/query-core/v5/useQuery.ts @@ -7,8 +7,8 @@ import { } from '~/plugins/shared/utils/operation'; import { tsc } from '~/tsc'; -import type { PluginInstance } from './types'; -import { useTypeData } from './useType'; +import { useTypeData } from '../shared/useType'; +import type { PluginInstance } from '../types'; const optionsParamName = 'options'; diff --git a/packages/openapi-ts/src/plugins/swr/config.ts b/packages/openapi-ts/src/plugins/swr/config.ts index 32314b536..9da5a557b 100644 --- a/packages/openapi-ts/src/plugins/swr/config.ts +++ b/packages/openapi-ts/src/plugins/swr/config.ts @@ -86,11 +86,11 @@ export const defaultConfig: SwrPlugin['Config'] = { value: plugin.config.queryOptions, }); - plugin.config.useQuery = context.valueToObject({ + plugin.config.useSwr = context.valueToObject({ defaultValue: { case: plugin.config.case ?? 'camelCase', - enabled: false, - name: 'use{{name}}Query', + enabled: true, + name: 'use{{name}}', }, mappers: { boolean: (enabled) => ({ enabled }), @@ -98,11 +98,11 @@ export const defaultConfig: SwrPlugin['Config'] = { object: (fields) => ({ enabled: true, ...fields }), string: (name) => ({ enabled: true, name }), }, - value: plugin.config.useQuery, + value: plugin.config.useSwr, }); - if (plugin.config.useQuery.enabled) { - // useQuery hooks consume queryOptions + if (plugin.config.useSwr.enabled) { + // useSwr hooks consume queryOptions if (!plugin.config.queryOptions.enabled) { plugin.config.queryOptions.enabled = true; plugin.config.queryOptions.exported = false; diff --git a/packages/openapi-ts/src/plugins/swr/plugin.ts b/packages/openapi-ts/src/plugins/swr/plugin.ts index 94803c467..d5ebb4d11 100644 --- a/packages/openapi-ts/src/plugins/swr/plugin.ts +++ b/packages/openapi-ts/src/plugins/swr/plugin.ts @@ -1,5 +1,4 @@ import type { SwrPlugin } from './types'; +import { handlerV2 } from './v2/plugin'; -export const handler: SwrPlugin['Handler'] = ({ plugin }) => { - console.log(plugin.name); -}; +export const handler: SwrPlugin['Handler'] = (args) => handlerV2(args); diff --git a/packages/openapi-ts/src/plugins/swr/types.d.ts b/packages/openapi-ts/src/plugins/swr/types.d.ts index e28b13069..ed557bdfa 100644 --- a/packages/openapi-ts/src/plugins/swr/types.d.ts +++ b/packages/openapi-ts/src/plugins/swr/types.d.ts @@ -11,7 +11,7 @@ export type UserConfig = Plugin.Name<'swr'> & */ case?: StringCase; /** - * Add comments from SDK functions to the generated TanStack Query code? + * Add comments from SDK functions to the generated SWR code? * * Duplicating comments this way is useful so you don't need to drill into * the underlying SDK function to learn what it does or whether it's @@ -308,18 +308,18 @@ export type UserConfig = Plugin.Name<'swr'> & name?: StringName; }; /** - * Configuration for generated `useQuery()` function helpers. + * Configuration for generated `useSwr()` function helpers. * - * See {@link https://tanstack.com/query/v5/docs/framework/react/reference/useQuery useQuery} + * See {@link https://swr.vercel.app/docs/api API} * * Can be: * - `boolean`: Shorthand for `{ enabled: boolean }` * - `string` or `function`: Shorthand for `{ name: string | function }` * - `object`: Full configuration object * - * @default false + * @default true */ - useQuery?: + useSwr?: | boolean | StringName | { @@ -330,18 +330,18 @@ export type UserConfig = Plugin.Name<'swr'> & */ case?: StringCase; /** - * Whether to generate `useQuery()` function helpers. + * Whether to generate `useSwr()` function helpers. * * @default true */ enabled?: boolean; /** - * Custom naming pattern for generated `useQuery()` function names. The name variable is + * Custom naming pattern for generated `useSwr()` function names. The name variable is * obtained from the SDK function name. * - * See {@link https://tanstack.com/query/v5/docs/framework/react/reference/useQuery useQuery} + * See {@link https://swr.vercel.app/docs/api API} * - * @default 'use{{name}}Query' + * @default 'use{{name}}' */ name?: StringName; }; @@ -356,7 +356,7 @@ export type Config = Plugin.Name<'swr'> & */ case: StringCase; /** - * Add comments from SDK functions to the generated TanStack Query code? + * Add comments from SDK functions to the generated SWR code? * * @default true */ @@ -592,11 +592,11 @@ export type Config = Plugin.Name<'swr'> & name: StringName; }; /** - * Configuration for generated `useQuery()` function helpers. + * Configuration for generated `useSwr()` function helpers. * - * See {@link https://tanstack.com/query/v5/docs/framework/react/reference/useQuery useQuery} + * See {@link https://swr.vercel.app/docs/api API} */ - useQuery: { + useSwr: { /** * The casing convention to use for generated names. * @@ -604,18 +604,18 @@ export type Config = Plugin.Name<'swr'> & */ case: StringCase; /** - * Whether to generate `useQuery()` function helpers. + * Whether to generate `useSwr()` function helpers. * * @default true */ enabled: boolean; /** - * Custom naming pattern for generated `useQuery()` function names. The name variable is + * Custom naming pattern for generated `useSwr()` function names. The name variable is * obtained from the SDK function name. * - * See {@link https://tanstack.com/query/v5/docs/framework/react/reference/useQuery useQuery} + * See {@link https://swr.vercel.app/docs/api API} * - * @default 'use{{name}}Query' + * @default 'use{{name}}' */ name: StringName; }; diff --git a/packages/openapi-ts/src/plugins/swr/v2/plugin.ts b/packages/openapi-ts/src/plugins/swr/v2/plugin.ts new file mode 100644 index 000000000..7dbbbccde --- /dev/null +++ b/packages/openapi-ts/src/plugins/swr/v2/plugin.ts @@ -0,0 +1,77 @@ +import { operationClasses } from '~/plugins/@hey-api/sdk/shared/operation'; +import { stringCase } from '~/utils/stringCase'; + +import type { SwrPlugin } from '../types'; +import { createUseSwr } from './useSwr'; + +export const handlerV2: SwrPlugin['Handler'] = ({ plugin }) => { + plugin.registerSymbol({ + external: 'swr', + importKind: 'default', + kind: 'function', + meta: { + category: 'external', + resource: 'swr', + }, + name: 'useSWR', + }); + + const sdkPlugin = plugin.getPluginOrThrow('@hey-api/sdk'); + + plugin.forEach( + 'operation', + ({ operation }) => { + const classes = sdkPlugin.config.asClass + ? operationClasses({ + context: plugin.context, + operation, + plugin: sdkPlugin, + }) + : undefined; + const entry = classes ? classes.values().next().value : undefined; + const queryFn = + // TODO: this should use class graph to determine correct path string + // as it's really easy to break once we change the class casing + entry + ? [ + plugin.referenceSymbol({ + category: 'utility', + resource: 'class', + resourceId: entry.path[0], + tool: 'sdk', + }).placeholder, + ...entry.path.slice(1).map((className) => + stringCase({ + case: 'camelCase', + value: className, + }), + ), + entry.methodName, + ] + .filter(Boolean) + .join('.') + : plugin.referenceSymbol({ + category: 'sdk', + resource: 'operation', + resourceId: operation.id, + }).placeholder; + + if (plugin.hooks.operation.isQuery(operation)) { + // if (plugin.config.queryOptions.enabled) { + // createQueryOptions({ operation, plugin, queryFn }); + // } + + // if (plugin.config.infiniteQueryOptions.enabled) { + // createInfiniteQueryOptions({ operation, plugin, queryFn }); + // } + + if (plugin.config.useSwr.enabled) { + createUseSwr({ operation, plugin, queryFn }); + } + } + }, + { + order: 'declarations', + }, + ); +}; diff --git a/packages/openapi-ts/src/plugins/swr/v2/useSwr.ts b/packages/openapi-ts/src/plugins/swr/v2/useSwr.ts new file mode 100644 index 000000000..79d19b24d --- /dev/null +++ b/packages/openapi-ts/src/plugins/swr/v2/useSwr.ts @@ -0,0 +1,120 @@ +import type ts from 'typescript'; + +import type { IR } from '~/ir/types'; +import { buildName } from '~/openApi/shared/utils/name'; +import { + createOperationComment, + hasOperationSse, +} from '~/plugins/shared/utils/operation'; +import { tsc } from '~/tsc'; + +import type { SwrPlugin } from '../types'; + +export const createUseSwr = ({ + operation, + plugin, + queryFn, +}: { + operation: IR.OperationObject; + plugin: SwrPlugin['Instance']; + queryFn: string; +}): void => { + if (hasOperationSse({ operation })) { + return; + } + + const symbolUseSwr = plugin.referenceSymbol({ + category: 'external', + resource: 'swr', + }); + const symbolUseQueryFn = plugin.registerSymbol({ + exported: true, + name: buildName({ + config: plugin.config.useSwr, + name: operation.id, + }), + }); + + const awaitSdkExpression = tsc.awaitExpression({ + expression: tsc.callExpression({ + functionName: queryFn, + parameters: [ + tsc.objectExpression({ + multiLine: true, + obj: [ + // { + // spread: optionsParamName, + // }, + // { + // spread: 'queryKey[0]', + // }, + // { + // key: 'signal', + // shorthand: true, + // value: tsc.identifier({ + // text: 'signal', + // }), + // }, + { + key: 'throwOnError', + value: true, + }, + ], + }), + ], + }), + }); + const statements: Array = []; + if (plugin.getPluginOrThrow('@hey-api/sdk').config.responseStyle === 'data') { + statements.push( + tsc.returnVariable({ + expression: awaitSdkExpression, + }), + ); + } else { + statements.push( + tsc.constVariable({ + destructure: true, + expression: awaitSdkExpression, + name: 'data', + }), + tsc.returnVariable({ + expression: 'data', + }), + ); + } + + const statement = tsc.constVariable({ + comment: plugin.config.comments + ? createOperationComment({ operation }) + : undefined, + exportConst: symbolUseQueryFn.exported, + expression: tsc.arrowFunction({ + parameters: [ + // { + // isRequired: isRequiredOptions, + // name: optionsParamName, + // type: typeData, + // }, + ], + statements: [ + tsc.returnStatement({ + expression: tsc.callExpression({ + functionName: symbolUseSwr.placeholder, + parameters: [ + tsc.stringLiteral({ + text: operation.path, + }), + tsc.arrowFunction({ + async: true, + statements, + }), + ], + }), + }), + ], + }), + name: symbolUseQueryFn.placeholder, + }); + plugin.setSymbolValue(symbolUseQueryFn, statement); +}; diff --git a/packages/openapi-ts/src/ts-dsl/attr.ts b/packages/openapi-ts/src/ts-dsl/attr.ts new file mode 100644 index 000000000..bb12cc13f --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/attr.ts @@ -0,0 +1,43 @@ +/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */ +import ts from 'typescript'; + +import type { ExprInput, MaybeTsDsl } from './base'; +import { TsDsl } from './base'; +import { AccessMixin } from './mixins/access'; +import { mixin } from './mixins/apply'; +import { AssignmentMixin } from './mixins/assignment'; +import { OperatorMixin } from './mixins/operator'; +import { OptionalMixin } from './mixins/optional'; + +export class AttrTsDsl extends TsDsl { + private left: MaybeTsDsl; + private right: string; + + constructor(left: MaybeTsDsl, right: string) { + super(); + this.left = left; + this.right = right; + } + + $render(): ts.PropertyAccessExpression { + const leftNode = this.$node(this.left); + if (this.isOptional) { + return ts.factory.createPropertyAccessChain( + leftNode, + ts.factory.createToken(ts.SyntaxKind.QuestionDotToken), + ts.factory.createIdentifier(this.right), + ); + } + return ts.factory.createPropertyAccessExpression( + leftNode, + ts.factory.createIdentifier(this.right), + ); + } +} + +export interface AttrTsDsl + extends AccessMixin, + AssignmentMixin, + OperatorMixin, + OptionalMixin {} +mixin(AttrTsDsl, AccessMixin, AssignmentMixin, OperatorMixin, OptionalMixin); diff --git a/packages/openapi-ts/src/ts-dsl/base.ts b/packages/openapi-ts/src/ts-dsl/base.ts new file mode 100644 index 000000000..cfe2e3af5 --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/base.ts @@ -0,0 +1,133 @@ +import ts from 'typescript'; + +export type ExprInput = T | string; + +export type TypeInput = string | boolean | MaybeTsDsl; + +export interface ITsDsl { + $render(): T; +} + +export abstract class TsDsl implements ITsDsl { + abstract $render(): T; + + protected $expr(expr: ExprInput): T { + return typeof expr === 'string' + ? (ts.factory.createIdentifier(expr) as T) + : expr; + } + + /** Conditionally applies a callback to this builder. */ + $if( + this: T, + value: V, + ifTrue: (self: T, v: Exclude) => R | void, + ifFalse?: (self: T, v: Extract) => R | void, + ): R | T { + if (value) { + const result = ifTrue( + this, + value as Exclude, + ); + return result ?? this; + } + if (ifFalse) { + const result = ifFalse( + this, + value as Extract, + ); + return result ?? this; + } + return this; + } + + protected $node(input: I): NodeOfMaybe { + if (input === undefined) { + return undefined as NodeOfMaybe; + } + if (typeof input === 'string') { + return this.$expr(input) as NodeOfMaybe; + } + if (input instanceof Array) { + return input.map((item) => this._render(item)) as NodeOfMaybe; + } + return this._render(input as any) as NodeOfMaybe; + } + + protected $stmt( + input: + | MaybeTsDsl> + | ReadonlyArray>>, + ): ReadonlyArray { + const arr = input instanceof Array ? input : [input]; + return arr.map((item) => { + const node = + typeof item === 'string' + ? ts.factory.createIdentifier(item) + : this._render(item as any); + return ts.isExpression(node) + ? ts.factory.createExpressionStatement(node) + : (node as ts.Statement); + }); + } + + protected $type(type: I): TypeOfMaybe { + if (type === undefined) { + return undefined as TypeOfMaybe; + } + if (typeof type === 'string') { + return ts.factory.createTypeReferenceNode( + type, + ) as unknown as TypeOfMaybe; + } + if (typeof type === 'boolean') { + const literal = type ? ts.factory.createTrue() : ts.factory.createFalse(); + return ts.factory.createLiteralTypeNode(literal) as TypeOfMaybe; + } + return this._render(type as any) as TypeOfMaybe; + } + + private _render(value: MaybeTsDsl): T { + return (value instanceof TsDsl ? value.$render() : value) as T; + } +} + +type NodeOfMaybe = undefined extends I + ? NodeOf> | undefined + : NodeOf; + +type NodeOf = + I extends ReadonlyArray + ? ReadonlyArray ? N : U> + : I extends string + ? ts.Expression + : I extends TsDsl + ? N + : I extends ts.Node + ? I + : never; + +type TypeOfMaybe = undefined extends I + ? TypeOf> | undefined + : TypeOf; + +type TypeOf = I extends string + ? ts.TypeNode + : I extends boolean + ? ts.LiteralTypeNode + : I extends TsDsl + ? N + : I extends ts.TypeNode + ? I + : never; + +export type MaybeTsDsl = + // if T includes string in the union + string extends T + ? Exclude extends ts.Node + ? string | Exclude | TsDsl> + : string + : // otherwise only node or DSL + T extends ts.Node + ? T | TsDsl + : never; diff --git a/packages/openapi-ts/src/ts-dsl/binary.ts b/packages/openapi-ts/src/ts-dsl/binary.ts new file mode 100644 index 000000000..8fbddc449 --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/binary.ts @@ -0,0 +1,81 @@ +import ts from 'typescript'; + +import type { ExprInput, MaybeTsDsl } from './base'; +import { TsDsl } from './base'; + +type Operator = + | '!=' + | '!==' + | '&&' + | '*' + | '+' + | '-' + | '/' + | '<' + | '<=' + | '=' + | '==' + | '===' + | '>' + | '>=' + | '??' + | '||'; + +export class BinaryTsDsl extends TsDsl { + private left: MaybeTsDsl; + private operator: Operator | ts.BinaryOperator; + private right: MaybeTsDsl; + + constructor( + left: MaybeTsDsl, + operator: Operator | ts.BinaryOperator, + right: MaybeTsDsl, + ) { + super(); + this.left = left; + this.operator = operator; + this.right = right; + } + + $render(): ts.BinaryExpression { + const leftNode = this.$node(this.left); + const rightNode = this.$node(this.right); + const operatorToken = + typeof this.operator === 'string' + ? this.mapOperator(this.operator) + : this.operator; + return ts.factory.createBinaryExpression( + leftNode, + operatorToken, + rightNode, + ); + } + + private mapOperator( + operator: Operator, + ): ts.BinaryOperator | ts.BinaryOperatorToken { + const tokenMap: Record = { + '!=': ts.SyntaxKind.ExclamationEqualsToken, + '!==': ts.SyntaxKind.ExclamationEqualsEqualsToken, + '&&': ts.SyntaxKind.AmpersandAmpersandToken, + '*': ts.SyntaxKind.AsteriskToken, + '+': ts.SyntaxKind.PlusToken, + '-': ts.SyntaxKind.MinusToken, + '/': ts.SyntaxKind.SlashToken, + '<': ts.SyntaxKind.LessThanToken, + '<=': ts.SyntaxKind.LessThanEqualsToken, + '=': ts.SyntaxKind.EqualsToken, + '==': ts.SyntaxKind.EqualsEqualsToken, + '===': ts.SyntaxKind.EqualsEqualsEqualsToken, + '>': ts.SyntaxKind.GreaterThanToken, + '>=': ts.SyntaxKind.GreaterThanEqualsToken, + '??': ts.SyntaxKind.QuestionQuestionToken, + '||': ts.SyntaxKind.BarBarToken, + }; + const token = tokenMap[operator]; + if (!token) { + throw new Error(`Unsupported operator: ${operator}`); + } + return token; + } +} diff --git a/packages/openapi-ts/src/ts-dsl/call.ts b/packages/openapi-ts/src/ts-dsl/call.ts new file mode 100644 index 000000000..b1732fbfe --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/call.ts @@ -0,0 +1,30 @@ +import ts from 'typescript'; + +import type { ExprInput, MaybeTsDsl } from './base'; +import { TsDsl } from './base'; + +export class CallTsDsl extends TsDsl { + private callee: MaybeTsDsl; + private callArgs: ReadonlyArray> = []; + + constructor( + callee: MaybeTsDsl, + ...args: ReadonlyArray> + ) { + super(); + this.callee = callee; + if (args.length) this.callArgs = args; + } + + /** Adds one or more arguments to the call expression. */ + args(...args: ReadonlyArray>): this { + this.callArgs = args; + return this; + } + + $render(): ts.CallExpression { + const calleeNode = this.$node(this.callee); + const argsNodes = this.$node(this.callArgs).map((arg) => this.$expr(arg)); + return ts.factory.createCallExpression(calleeNode, undefined, argsNodes); + } +} diff --git a/packages/openapi-ts/src/ts-dsl/class.ts b/packages/openapi-ts/src/ts-dsl/class.ts new file mode 100644 index 000000000..6f8c3b6a3 --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/class.ts @@ -0,0 +1,108 @@ +/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */ +import ts from 'typescript'; + +import type { ExprInput, MaybeTsDsl } from './base'; +import { TsDsl } from './base'; +import { FieldTsDsl } from './field'; +import { InitTsDsl } from './init'; +import { MethodTsDsl } from './method'; +import { mixin } from './mixins/apply'; +import { DecoratorMixin } from './mixins/decorator'; +import { DescribeMixin } from './mixins/describe'; +import { GenericsMixin } from './mixins/generics'; +import { + AbstractMixin, + createModifierAccessor, + DefaultMixin, + ExportMixin, +} from './mixins/modifiers'; +import { NewlineTsDsl } from './newline'; + +export class ClassTsDsl extends TsDsl { + private heritageClauses: Array = []; + private body: Array | NewlineTsDsl> = []; + private modifiers = createModifierAccessor(this); + private name: string; + + constructor(name: string) { + super(); + this.name = name; + } + + /** Adds a class constructor. */ + init(fn?: (i: InitTsDsl) => void): this { + const i = new InitTsDsl(fn); + this.body.push(i); + return this; + } + + /** Adds a base class to extend from. */ + extends(base?: ExprInput | false | null): this { + if (!base) return this; + this.heritageClauses.push( + ts.factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [ + ts.factory.createExpressionWithTypeArguments( + this.$expr(base), + undefined, + ), + ]), + ); + return this; + } + + /** Adds a class field. */ + field(name: string, fn?: (f: FieldTsDsl) => void): this { + const f = new FieldTsDsl(name, fn); + this.body.push(f); + return this; + } + + /** Adds a class method. */ + method(name: string, fn?: (m: MethodTsDsl) => void): this { + const m = new MethodTsDsl(name, fn); + this.body.push(m); + return this; + } + + /** Adds one or more class members (fields, methods, etc.). */ + do(...items: ReadonlyArray>): this { + // @ts-expect-error --- IGNORE --- + this.body.push(...items); + return this; + } + + /** Inserts an empty line between members for formatting. */ + newline(): this { + this.body.push(new NewlineTsDsl()); + return this; + } + + /** Builds the `ClassDeclaration` node. */ + $render(): ts.ClassDeclaration { + const builtBody = this.$node(this.body) as ReadonlyArray; + return ts.factory.createClassDeclaration( + [...(this.decorators ?? []), ...this.modifiers.list()], + ts.factory.createIdentifier(this.name), + this.$generics(), + this.heritageClauses, + builtBody, + ); + } +} + +export interface ClassTsDsl + extends AbstractMixin, + DecoratorMixin, + DescribeMixin, + DefaultMixin, + ExportMixin, + GenericsMixin {} +mixin( + ClassTsDsl, + AbstractMixin, + DecoratorMixin, + [DescribeMixin, { overrideRender: true }], + DefaultMixin, + ExportMixin, + GenericsMixin, +); diff --git a/packages/openapi-ts/src/ts-dsl/const.ts b/packages/openapi-ts/src/ts-dsl/const.ts new file mode 100644 index 000000000..ce55f6120 --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/const.ts @@ -0,0 +1,52 @@ +/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */ +import ts from 'typescript'; + +import { TsDsl } from './base'; +import { mixin } from './mixins/apply'; +import { DescribeMixin } from './mixins/describe'; +import { + createModifierAccessor, + DefaultMixin, + ExportMixin, +} from './mixins/modifiers'; +import { ValueMixin } from './mixins/value'; + +export class ConstTsDsl extends TsDsl { + private modifiers = createModifierAccessor(this); + private name: string; + + constructor(name: string) { + super(); + this.name = name; + } + + $render(): ts.VariableStatement { + return ts.factory.createVariableStatement( + this.modifiers.list(), + ts.factory.createVariableDeclarationList( + [ + ts.factory.createVariableDeclaration( + ts.factory.createIdentifier(this.name), + undefined, + undefined, + this.$node(this.initializer), + ), + ], + ts.NodeFlags.Const, + ), + ); + } +} + +export interface ConstTsDsl + extends DefaultMixin, + DescribeMixin, + ExportMixin, + ValueMixin {} +mixin( + ConstTsDsl, + DefaultMixin, + [DescribeMixin, { overrideRender: true }], + ExportMixin, + ValueMixin, +); diff --git a/packages/openapi-ts/src/ts-dsl/describe.ts b/packages/openapi-ts/src/ts-dsl/describe.ts new file mode 100644 index 000000000..ad45940b6 --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/describe.ts @@ -0,0 +1,72 @@ +import ts from 'typescript'; + +import { TsDsl } from './base'; + +export class DescribeTsDsl extends TsDsl { + private _lines: Array = []; + + constructor( + lines?: string | ReadonlyArray, + fn?: (d: DescribeTsDsl) => void, + ) { + super(); + if (lines) { + if (typeof lines === 'string') { + this.add(lines); + } else { + this.add(...lines); + } + } + if (fn) fn(this); + } + + add(...lines: ReadonlyArray): this { + this._lines.push(...lines); + return this; + } + + apply(node: T): T { + const lines = this._lines.filter((line) => Boolean(line) || line === ''); + if (!lines.length) return node; + + const jsdocTexts = lines.map((line, index) => { + let text = line; + if (index !== lines.length) { + text = `${text}\n`; + } + return ts.factory.createJSDocText(text); + }); + + const jsdoc = ts.factory.createJSDocComment( + ts.factory.createNodeArray(jsdocTexts), + undefined, + ); + + const cleanedJsdoc = ts + .createPrinter() + .printNode( + ts.EmitHint.Unspecified, + jsdoc, + node.getSourceFile?.() ?? + ts.createSourceFile('', '', ts.ScriptTarget.Latest), + ) + .replace('/*', '') + .replace('* */', ''); + + ts.addSyntheticLeadingComment( + node, + ts.SyntaxKind.MultiLineCommentTrivia, + cleanedJsdoc, + true, + ); + + return node; + } + + $render(): ts.Node { + // this class does not build a standalone node; + // it modifies other nodes via `apply()`. + // Return a dummy comment node for compliance. + return ts.factory.createIdentifier(''); + } +} diff --git a/packages/openapi-ts/src/ts-dsl/expr.ts b/packages/openapi-ts/src/ts-dsl/expr.ts new file mode 100644 index 000000000..77e35e8cd --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/expr.ts @@ -0,0 +1,24 @@ +/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */ +import type ts from 'typescript'; + +import type { ExprInput, MaybeTsDsl } from './base'; +import { TsDsl } from './base'; +import { AccessMixin } from './mixins/access'; +import { mixin } from './mixins/apply'; +import { OperatorMixin } from './mixins/operator'; + +export class ExprTsDsl extends TsDsl { + private input: MaybeTsDsl; + + constructor(id: MaybeTsDsl) { + super(); + this.input = id; + } + + $render(): ts.Expression { + return this.$node(this.input); + } +} + +export interface ExprTsDsl extends AccessMixin, OperatorMixin {} +mixin(ExprTsDsl, AccessMixin, OperatorMixin); diff --git a/packages/openapi-ts/src/ts-dsl/field.ts b/packages/openapi-ts/src/ts-dsl/field.ts new file mode 100644 index 000000000..6c934e890 --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/field.ts @@ -0,0 +1,64 @@ +/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */ +import ts from 'typescript'; + +import { TsDsl } from './base'; +import { mixin } from './mixins/apply'; +import { DecoratorMixin } from './mixins/decorator'; +import { DescribeMixin } from './mixins/describe'; +import { + createModifierAccessor, + PrivateMixin, + ProtectedMixin, + PublicMixin, + ReadonlyMixin, + StaticMixin, +} from './mixins/modifiers'; +import { createTypeAccessor } from './mixins/type'; +import { ValueMixin } from './mixins/value'; + +export class FieldTsDsl extends TsDsl { + private modifiers = createModifierAccessor(this); + private name: string; + private _type = createTypeAccessor(this); + + constructor(name: string, fn?: (f: FieldTsDsl) => void) { + super(); + this.name = name; + if (fn) fn(this); + } + + /** Sets the property's type. */ + type = this._type.method; + + /** Builds the `PropertyDeclaration` node. */ + $render(): ts.PropertyDeclaration { + return ts.factory.createPropertyDeclaration( + [...(this.decorators ?? []), ...this.modifiers.list()], + ts.factory.createIdentifier(this.name), + undefined, + this._type.$render(), + this.$node(this.initializer), + ); + } +} + +export interface FieldTsDsl + extends DecoratorMixin, + DescribeMixin, + PrivateMixin, + ProtectedMixin, + PublicMixin, + ReadonlyMixin, + StaticMixin, + ValueMixin {} +mixin( + FieldTsDsl, + DecoratorMixin, + [DescribeMixin, { overrideRender: true }], + PrivateMixin, + ProtectedMixin, + PublicMixin, + ReadonlyMixin, + StaticMixin, + ValueMixin, +); diff --git a/packages/openapi-ts/src/ts-dsl/getter.ts b/packages/openapi-ts/src/ts-dsl/getter.ts new file mode 100644 index 000000000..3317b8e1e --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/getter.ts @@ -0,0 +1,70 @@ +/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */ +import ts from 'typescript'; + +import type { MaybeTsDsl } from './base'; +import { TsDsl } from './base'; +import { mixin } from './mixins/apply'; +import { DecoratorMixin } from './mixins/decorator'; +import { DescribeMixin } from './mixins/describe'; +import type { AsyncMixin } from './mixins/modifiers'; +import { + AbstractMixin, + createModifierAccessor, + PrivateMixin, + ProtectedMixin, + PublicMixin, + StaticMixin, +} from './mixins/modifiers'; +import { ParamMixin } from './mixins/param'; + +export class GetterTsDsl extends TsDsl { + private body: Array> = []; + private modifiers = createModifierAccessor(this); + private name: string; + + constructor(name: string, fn?: (g: GetterTsDsl) => void) { + super(); + this.name = name; + if (fn) fn(this); + } + + /** Adds one or more expressions to the getter body. */ + do(...items: ReadonlyArray>): this { + this.body.push(...items); + return this; + } + + $render(): ts.GetAccessorDeclaration { + const builtParams = this.$node(this._params ?? []); + const builtBody = this.$stmt(this.body); + return ts.factory.createGetAccessorDeclaration( + [...(this.decorators ?? []), ...this.modifiers.list()], + this.name, + builtParams, + undefined, + ts.factory.createBlock(builtBody, true), + ); + } +} + +export interface GetterTsDsl + extends AbstractMixin, + AsyncMixin, + DecoratorMixin, + DescribeMixin, + ParamMixin, + PrivateMixin, + ProtectedMixin, + PublicMixin, + StaticMixin {} +mixin( + GetterTsDsl, + AbstractMixin, + DecoratorMixin, + [DescribeMixin, { overrideRender: true }], + ParamMixin, + PrivateMixin, + ProtectedMixin, + PublicMixin, + StaticMixin, +); diff --git a/packages/openapi-ts/src/ts-dsl/if.ts b/packages/openapi-ts/src/ts-dsl/if.ts new file mode 100644 index 000000000..f4958be74 --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/if.ts @@ -0,0 +1,60 @@ +import ts from 'typescript'; + +import type { ExprInput, MaybeTsDsl } from './base'; +import { TsDsl } from './base'; + +export class IfTsDsl extends TsDsl { + private conditionInput?: MaybeTsDsl; + private thenInput?: ReadonlyArray>; + private elseInput?: ReadonlyArray>; + + constructor(condition?: MaybeTsDsl) { + super(); + if (condition) this.condition(condition); + } + + condition(condition: MaybeTsDsl): this { + this.conditionInput = condition; + return this; + } + + do(...items: ReadonlyArray>): this { + this.thenInput = items; + return this; + } + + otherwise(...statements: ReadonlyArray>): this { + this.elseInput = statements; + return this; + } + + $render(): ts.IfStatement { + if (!this.conditionInput) throw new Error('Missing condition in if'); + if (!this.thenInput) throw new Error('Missing then block in if'); + + const condition = this.$node(this.conditionInput); + + const thenStmts = this.$node(this.thenInput); + const thenBlock = + thenStmts.length === 1 + ? thenStmts[0]! + : ts.factory.createBlock(thenStmts, true); + const thenNode = ts.isBlock(thenBlock) + ? thenBlock + : ts.factory.createBlock([thenBlock], true); + + let elseNode: ts.Statement | undefined; + if (this.elseInput) { + const elseStmts = this.$node(this.elseInput); + const elseBlock = + elseStmts.length === 1 + ? elseStmts[0]! + : ts.factory.createBlock(elseStmts, true); + elseNode = ts.isBlock(elseBlock) + ? elseBlock + : ts.factory.createBlock([elseBlock], true); + } + + return ts.factory.createIfStatement(condition, thenNode, elseNode); + } +} diff --git a/packages/openapi-ts/src/ts-dsl/index.ts b/packages/openapi-ts/src/ts-dsl/index.ts new file mode 100644 index 000000000..270e3a4b4 --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/index.ts @@ -0,0 +1,77 @@ +import { AttrTsDsl } from './attr'; +import { BinaryTsDsl } from './binary'; +import { CallTsDsl } from './call'; +import { ClassTsDsl } from './class'; +import { ConstTsDsl } from './const'; +import { DescribeTsDsl } from './describe'; +import { ExprTsDsl } from './expr'; +import { FieldTsDsl } from './field'; +import { GetterTsDsl } from './getter'; +import { IfTsDsl } from './if'; +import { InitTsDsl } from './init'; +import { LiteralTsDsl } from './literal'; +import { MethodTsDsl } from './method'; +import { NewTsDsl } from './new'; +import { NewlineTsDsl } from './newline'; +import { NotTsDsl } from './not'; +import { ObjectTsDsl } from './object'; +import { ParamTsDsl } from './param'; +import { ReturnTsDsl } from './return'; +import { SetterTsDsl } from './setter'; +import { TemplateTsDsl } from './template'; +import { ThrowTsDsl } from './throw'; +import { TypeTsDsl } from './type'; + +const base = { + attr: (...args: ConstructorParameters) => + new AttrTsDsl(...args), + binary: (...args: ConstructorParameters) => + new BinaryTsDsl(...args), + call: (...args: ConstructorParameters) => + new CallTsDsl(...args), + class: (...args: ConstructorParameters) => + new ClassTsDsl(...args), + const: (...args: ConstructorParameters) => + new ConstTsDsl(...args), + describe: (...args: ConstructorParameters) => + new DescribeTsDsl(...args), + expr: (...args: ConstructorParameters) => + new ExprTsDsl(...args), + field: (...args: ConstructorParameters) => + new FieldTsDsl(...args), + getter: (...args: ConstructorParameters) => + new GetterTsDsl(...args), + if: (...args: ConstructorParameters) => new IfTsDsl(...args), + init: (...args: ConstructorParameters) => + new InitTsDsl(...args), + literal: (...args: ConstructorParameters) => + new LiteralTsDsl(...args), + method: (...args: ConstructorParameters) => + new MethodTsDsl(...args), + new: (...args: ConstructorParameters) => + new NewTsDsl(...args), + newline: (...args: ConstructorParameters) => + new NewlineTsDsl(...args), + not: (...args: ConstructorParameters) => + new NotTsDsl(...args), + object: (...args: ConstructorParameters) => + new ObjectTsDsl(...args), + param: (...args: ConstructorParameters) => + new ParamTsDsl(...args), + return: (...args: ConstructorParameters) => + new ReturnTsDsl(...args), + setter: (...args: ConstructorParameters) => + new SetterTsDsl(...args), + template: (...args: ConstructorParameters) => + new TemplateTsDsl(...args), + throw: (...args: ConstructorParameters) => + new ThrowTsDsl(...args), + type: TypeTsDsl, +}; + +export const $ = Object.assign( + (...args: ConstructorParameters) => new ExprTsDsl(...args), + base, +); + +export type { TsDsl } from './base'; diff --git a/packages/openapi-ts/src/ts-dsl/init.ts b/packages/openapi-ts/src/ts-dsl/init.ts new file mode 100644 index 000000000..ad53bf0f4 --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/init.ts @@ -0,0 +1,59 @@ +/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */ +import ts from 'typescript'; + +import type { MaybeTsDsl } from './base'; +import { TsDsl } from './base'; +import { mixin } from './mixins/apply'; +import { DecoratorMixin } from './mixins/decorator'; +import { DescribeMixin } from './mixins/describe'; +import { + createModifierAccessor, + PrivateMixin, + ProtectedMixin, + PublicMixin, +} from './mixins/modifiers'; +import { ParamMixin } from './mixins/param'; + +export class InitTsDsl extends TsDsl { + private body: Array> = []; + private modifiers = createModifierAccessor(this); + + constructor(fn?: (i: InitTsDsl) => void) { + super(); + if (fn) fn(this); + } + + /** Adds one or more statements or expressions to the constructor body. */ + do(...items: ReadonlyArray>): this { + this.body.push(...items); + return this; + } + + /** Builds the `ConstructorDeclaration` node. */ + $render(): ts.ConstructorDeclaration { + const builtParams = this.$node(this._params ?? []); + const builtBody = this.$stmt(this.body); + return ts.factory.createConstructorDeclaration( + [...(this.decorators ?? []), ...this.modifiers.list()], + builtParams, + ts.factory.createBlock(builtBody, true), + ); + } +} + +export interface InitTsDsl + extends DecoratorMixin, + DescribeMixin, + ParamMixin, + PrivateMixin, + ProtectedMixin, + PublicMixin {} +mixin( + InitTsDsl, + DecoratorMixin, + [DescribeMixin, { overrideRender: true }], + ParamMixin, + PrivateMixin, + ProtectedMixin, + PublicMixin, +); diff --git a/packages/openapi-ts/src/ts-dsl/literal.ts b/packages/openapi-ts/src/ts-dsl/literal.ts new file mode 100644 index 000000000..986e2c017 --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/literal.ts @@ -0,0 +1,25 @@ +import ts from 'typescript'; + +import { TsDsl } from './base'; + +export class LiteralTsDsl extends TsDsl { + private value: string | number | boolean; + + constructor(value: string | number | boolean) { + super(); + this.value = value; + } + + $render(): ts.LiteralTypeNode['literal'] { + switch (typeof this.value) { + case 'boolean': + return this.value ? ts.factory.createTrue() : ts.factory.createFalse(); + case 'number': + return ts.factory.createNumericLiteral(this.value); + case 'string': + return ts.factory.createStringLiteral(this.value); + default: + throw new Error(`Unsupported literal: ${String(this.value)}`); + } + } +} diff --git a/packages/openapi-ts/src/ts-dsl/method.ts b/packages/openapi-ts/src/ts-dsl/method.ts new file mode 100644 index 000000000..516e13170 --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/method.ts @@ -0,0 +1,86 @@ +/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */ +import ts from 'typescript'; + +import type { MaybeTsDsl } from './base'; +import { TsDsl } from './base'; +import { mixin } from './mixins/apply'; +import { DecoratorMixin } from './mixins/decorator'; +import { DescribeMixin } from './mixins/describe'; +import { GenericsMixin } from './mixins/generics'; +import { + AbstractMixin, + AsyncMixin, + createModifierAccessor, + PrivateMixin, + ProtectedMixin, + PublicMixin, + StaticMixin, +} from './mixins/modifiers'; +import { OptionalMixin } from './mixins/optional'; +import { ParamMixin } from './mixins/param'; +import { createTypeAccessor } from './mixins/type'; + +export class MethodTsDsl extends TsDsl { + private body: Array> = []; + private modifiers = createModifierAccessor(this); + private name: string; + private _returns = createTypeAccessor(this); + + constructor(name: string, fn?: (m: MethodTsDsl) => void) { + super(); + this.name = name; + if (fn) fn(this); + } + + /** Sets the return type. */ + returns = this._returns.method; + + /** Adds one or more statements or expressions to the method body. */ + do(...items: ReadonlyArray>): this { + this.body.push(...items); + return this; + } + + /** Builds the `MethodDeclaration` node. */ + $render(): ts.MethodDeclaration { + const builtParams = this.$node(this._params ?? []); + const builtBody = this.$stmt(this.body); + return ts.factory.createMethodDeclaration( + [...(this.decorators ?? []), ...this.modifiers.list()], + undefined, + ts.factory.createIdentifier(this.name), + this.questionToken, + this.$generics(), + builtParams, + this._returns.$render(), + ts.factory.createBlock(builtBody, true), + ); + } +} + +export interface MethodTsDsl + extends AbstractMixin, + AsyncMixin, + DecoratorMixin, + DescribeMixin, + GenericsMixin, + OptionalMixin, + ParamMixin, + PrivateMixin, + ProtectedMixin, + PublicMixin, + StaticMixin {} +mixin( + MethodTsDsl, + AbstractMixin, + AsyncMixin, + DecoratorMixin, + [DescribeMixin, { overrideRender: true }], + GenericsMixin, + OptionalMixin, + ParamMixin, + PrivateMixin, + ProtectedMixin, + PublicMixin, + StaticMixin, +); diff --git a/packages/openapi-ts/src/ts-dsl/mixins/access.ts b/packages/openapi-ts/src/ts-dsl/mixins/access.ts new file mode 100644 index 000000000..b8b76b6b5 --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/mixins/access.ts @@ -0,0 +1,19 @@ +import type ts from 'typescript'; + +import { AttrTsDsl } from '../attr'; +import type { ExprInput, MaybeTsDsl, TsDsl } from '../base'; +import { CallTsDsl } from '../call'; + +export class AccessMixin { + /** Accesses a property on the current expression (e.g. `this.foo`). */ + attr(this: TsDsl, name: string): AttrTsDsl { + return new AttrTsDsl(this, name); + } + /** Calls the current expression as a function (e.g. `fn(arg1, arg2)`). */ + call( + this: TsDsl, + ...args: ReadonlyArray> + ): CallTsDsl { + return new CallTsDsl(this, ...args); + } +} diff --git a/packages/openapi-ts/src/ts-dsl/mixins/apply.ts b/packages/openapi-ts/src/ts-dsl/mixins/apply.ts new file mode 100644 index 000000000..f974cb38a --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/mixins/apply.ts @@ -0,0 +1,30 @@ +/* eslint-disable @typescript-eslint/no-unsafe-function-type */ +export function mixin( + target: Function, + ...sources: ReadonlyArray +) { + const targetProto = target.prototype; + for (const src of sources) { + const [source, options] = src instanceof Array ? src : [src]; + let resolvedSource = source; + if (typeof source === 'function') { + try { + const candidate = source(target); + if (candidate?.prototype) { + resolvedSource = candidate; + } + } catch { + // noop + } + } + const sourceProto = resolvedSource.prototype; + if (!sourceProto) continue; + for (const [key, descriptor] of Object.entries( + Object.getOwnPropertyDescriptors(sourceProto), + )) { + if (key === 'constructor') continue; + if (key === '$render' && !options?.overrideRender) continue; + Object.defineProperty(targetProto, key, descriptor); + } + } +} diff --git a/packages/openapi-ts/src/ts-dsl/mixins/assignment.ts b/packages/openapi-ts/src/ts-dsl/mixins/assignment.ts new file mode 100644 index 000000000..dc36c5518 --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/mixins/assignment.ts @@ -0,0 +1,11 @@ +import type ts from 'typescript'; + +import type { ExprInput, MaybeTsDsl, TsDsl } from '../base'; +import { BinaryTsDsl } from '../binary'; + +export class AssignmentMixin { + /** Creates an assignment expression (e.g. `this = expr`). */ + assign(this: TsDsl, expr: MaybeTsDsl): BinaryTsDsl { + return new BinaryTsDsl(this, '=', expr); + } +} diff --git a/packages/openapi-ts/src/ts-dsl/mixins/decorator.ts b/packages/openapi-ts/src/ts-dsl/mixins/decorator.ts new file mode 100644 index 000000000..756db5c17 --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/mixins/decorator.ts @@ -0,0 +1,34 @@ +import ts from 'typescript'; + +import type { ExprInput } from '../base'; +import { TsDsl } from '../base'; +import { ObjectTsDsl } from '../object'; + +export class DecoratorMixin extends TsDsl { + protected decorators?: Array; + + /** Adds a decorator (e.g. `@sealed({ in: 'root' })`). */ + decorator( + this: T, + name: ExprInput | false | null, + fn?: (o: ObjectTsDsl) => void, + ): T { + if (!name) return this; + + const expr = this.$expr(name); + let call: ts.Expression = expr; + + // if callback provided, build object argument + if (fn) { + const obj = new ObjectTsDsl(fn); + call = ts.factory.createCallExpression(expr, undefined, [obj.$render()]); + } + + (this.decorators ??= []).push(ts.factory.createDecorator(call)); + return this; + } + + $render(): ts.Node { + throw new Error('noop'); + } +} diff --git a/packages/openapi-ts/src/ts-dsl/mixins/describe.ts b/packages/openapi-ts/src/ts-dsl/mixins/describe.ts new file mode 100644 index 000000000..210cc403c --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/mixins/describe.ts @@ -0,0 +1,29 @@ +import type { ITsDsl } from '../base'; +import { DescribeTsDsl } from '../describe'; + +export function DescribeMixin< + TBase extends new (...args: ReadonlyArray) => ITsDsl, +>(Base: TBase) { + const Mixin = class extends Base { + protected _desc?: DescribeTsDsl; + + describe( + lines?: string | ReadonlyArray, + fn?: (d: DescribeTsDsl) => void, + ): this { + this._desc = new DescribeTsDsl(lines, fn); + return this; + } + }; + + const originalFn = Base.prototype.$render; + + Mixin.prototype.$render = function (...args: Parameters) { + const node = originalFn.apply(this, args); + return this._desc ? this._desc.apply(node) : node; + }; + + return Mixin; +} + +export type DescribeMixin = InstanceType>; diff --git a/packages/openapi-ts/src/ts-dsl/mixins/generics.ts b/packages/openapi-ts/src/ts-dsl/mixins/generics.ts new file mode 100644 index 000000000..cf82a5d9d --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/mixins/generics.ts @@ -0,0 +1,44 @@ +import ts from 'typescript'; + +import { type MaybeTsDsl, TsDsl } from '../base'; +import { TypeParamTsDsl } from '../type'; + +export class GenericsMixin extends TsDsl { + protected _generics?: Array>; + + /** Adds a single generic type argument (e.g. `T` in `Array`). */ + generic(name: string, fn?: (t: TypeParamTsDsl) => void): this { + const g = new TypeParamTsDsl(name, fn); + if (!this._generics) this._generics = []; + this._generics.push(g); + return this; + } + + /** Adds generic type arguments (e.g. `Map`). */ + generics( + ...args: ReadonlyArray> + ): this { + this._generics = [...args]; + return this; + } + + protected $generics(): + | ReadonlyArray + | undefined { + return this._generics?.map((g) => { + if (typeof g === 'string') { + return ts.factory.createTypeParameterDeclaration( + undefined, + ts.factory.createIdentifier(g), + undefined, + undefined, + ); + } + return this.$node(g); + }); + } + + $render(): ts.Node { + throw new Error('noop'); + } +} diff --git a/packages/openapi-ts/src/ts-dsl/mixins/modifiers.ts b/packages/openapi-ts/src/ts-dsl/mixins/modifiers.ts new file mode 100644 index 000000000..23801f59b --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/mixins/modifiers.ts @@ -0,0 +1,71 @@ +import ts from 'typescript'; + +import type { TsDsl } from '../base'; + +export function createModifierAccessor(parent: Parent) { + const modifiers: Array = []; + + function _m(kind: ts.ModifierSyntaxKind, condition = true): Parent { + if (condition) { + modifiers.push(ts.factory.createModifier(kind)); + } + return parent; + } + + Object.assign(parent, { _m }); // attaches to parent + + function list() { + return modifiers; + } + + return { list }; +} + +type Target = object & { + _m?(kind: ts.ModifierSyntaxKind, condition?: boolean): unknown; +}; +export class AbstractMixin { + abstract(this: T, condition: boolean = true): T { + return this._m!(ts.SyntaxKind.AbstractKeyword, condition) as T; + } +} +export class AsyncMixin { + async(this: T, condition: boolean = true): T { + return this._m!(ts.SyntaxKind.AsyncKeyword, condition) as T; + } +} +export class DefaultMixin { + default(this: T, condition: boolean = true): T { + return this._m!(ts.SyntaxKind.DefaultKeyword, condition) as T; + } +} +export class ExportMixin { + export(this: T, condition: boolean = true): T { + return this._m!(ts.SyntaxKind.ExportKeyword, condition) as T; + } +} +export class PrivateMixin { + private(this: T, condition: boolean = true): T { + return this._m!(ts.SyntaxKind.PrivateKeyword, condition) as T; + } +} +export class ProtectedMixin { + protected(this: T, condition: boolean = true): T { + return this._m!(ts.SyntaxKind.ProtectedKeyword, condition) as T; + } +} +export class PublicMixin { + public(this: T, condition: boolean = true): T { + return this._m!(ts.SyntaxKind.PublicKeyword, condition) as T; + } +} +export class ReadonlyMixin { + readonly(this: T, condition: boolean = true): T { + return this._m!(ts.SyntaxKind.ReadonlyKeyword, condition) as T; + } +} +export class StaticMixin { + static(this: T, condition: boolean = true): T { + return this._m!(ts.SyntaxKind.StaticKeyword, condition) as T; + } +} diff --git a/packages/openapi-ts/src/ts-dsl/mixins/operator.ts b/packages/openapi-ts/src/ts-dsl/mixins/operator.ts new file mode 100644 index 000000000..e995411c3 --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/mixins/operator.ts @@ -0,0 +1,67 @@ +import type ts from 'typescript'; + +import type { ExprInput, MaybeTsDsl, TsDsl } from '../base'; +import { BinaryTsDsl } from '../binary'; + +export class OperatorMixin { + /** Logical AND — `this && expr` */ + and(this: TsDsl, expr: MaybeTsDsl) { + return new BinaryTsDsl(this, '&&', expr); + } + /** Nullish coalescing — `this ?? expr` */ + coalesce(this: TsDsl, expr: MaybeTsDsl) { + return new BinaryTsDsl(this, '??', expr); + } + /** Division — `this / expr` */ + div(this: TsDsl, expr: MaybeTsDsl) { + return new BinaryTsDsl(this, '/', expr); + } + /** Strict equality — `this === expr` */ + eq(this: TsDsl, expr: MaybeTsDsl) { + return new BinaryTsDsl(this, '===', expr); + } + /** Greater than — `this > expr` */ + gt(this: TsDsl, expr: MaybeTsDsl) { + return new BinaryTsDsl(this, '>', expr); + } + /** Greater than or equal — `this >= expr` */ + gte(this: TsDsl, expr: MaybeTsDsl) { + return new BinaryTsDsl(this, '>=', expr); + } + /** Loose equality — `this == expr` */ + looseEq(this: TsDsl, expr: MaybeTsDsl) { + return new BinaryTsDsl(this, '==', expr); + } + /** Loose inequality — `this != expr` */ + looseNeq(this: TsDsl, expr: MaybeTsDsl) { + return new BinaryTsDsl(this, '!=', expr); + } + /** Less than — `this < expr` */ + lt(this: TsDsl, expr: MaybeTsDsl) { + return new BinaryTsDsl(this, '<', expr); + } + /** Less than or equal — `this <= expr` */ + lte(this: TsDsl, expr: MaybeTsDsl) { + return new BinaryTsDsl(this, '<=', expr); + } + /** Subtraction — `this - expr` */ + minus(this: TsDsl, expr: MaybeTsDsl) { + return new BinaryTsDsl(this, '-', expr); + } + /** Strict inequality — `this !== expr` */ + neq(this: TsDsl, expr: MaybeTsDsl) { + return new BinaryTsDsl(this, '!==', expr); + } + /** Logical OR — `this || expr` */ + or(this: TsDsl, expr: MaybeTsDsl) { + return new BinaryTsDsl(this, '||', expr); + } + /** Addition — `this + expr` */ + plus(this: TsDsl, expr: MaybeTsDsl) { + return new BinaryTsDsl(this, '+', expr); + } + /** Multiplication — `this * expr` */ + times(this: TsDsl, expr: MaybeTsDsl) { + return new BinaryTsDsl(this, '*', expr); + } +} diff --git a/packages/openapi-ts/src/ts-dsl/mixins/optional.ts b/packages/openapi-ts/src/ts-dsl/mixins/optional.ts new file mode 100644 index 000000000..1006dc234 --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/mixins/optional.ts @@ -0,0 +1,14 @@ +import ts from 'typescript'; + +export class OptionalMixin { + protected isOptional?: boolean; + protected questionToken?: ts.PunctuationToken; + + optional(this: T, condition = true): T { + if (condition) { + this.isOptional = true; + this.questionToken = ts.factory.createToken(ts.SyntaxKind.QuestionToken); + } + return this; + } +} diff --git a/packages/openapi-ts/src/ts-dsl/mixins/param.ts b/packages/openapi-ts/src/ts-dsl/mixins/param.ts new file mode 100644 index 000000000..e5e21f5cf --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/mixins/param.ts @@ -0,0 +1,23 @@ +import type ts from 'typescript'; + +import type { MaybeTsDsl } from '../base'; +import { ParamTsDsl } from '../param'; + +export class ParamMixin { + protected _params?: Array>; + + /** Adds a parameter. */ + param(name: string, fn?: (p: ParamTsDsl) => void): this { + const p = new ParamTsDsl(name, fn); + if (!this._params) this._params = []; + this._params.push(p); + return this; + } + + /** Adds multiple parameters. */ + params(...params: ReadonlyArray>): this { + if (!this._params) this._params = []; + this._params.push(...params); + return this; + } +} diff --git a/packages/openapi-ts/src/ts-dsl/mixins/type.ts b/packages/openapi-ts/src/ts-dsl/mixins/type.ts new file mode 100644 index 000000000..44b688bd5 --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/mixins/type.ts @@ -0,0 +1,36 @@ +import type ts from 'typescript'; + +import type { TypeInput } from '../base'; +import type { TsDsl } from '../base'; +import { TypeTsDsl } from '../type'; + +/** Provides `.type()`-like access with internal state management. */ +export function createTypeAccessor(parent: Parent) { + const $type = parent['$type'].bind(parent); + + let _type: ReturnType | undefined; + let input: TypeInput | undefined; + + function $render(): ts.TypeNode | undefined { + if (_type) { + return _type.$render(); + } + return $type(input); + } + + function method(): ReturnType; + function method(type: TypeInput): Parent; + function method(type?: TypeInput): ReturnType | Parent { + if (type === undefined) { + if (!_type) _type = TypeTsDsl(); + return _type; + } + input = type; + return parent; + } + + return { + $render, + method, + }; +} diff --git a/packages/openapi-ts/src/ts-dsl/mixins/value.ts b/packages/openapi-ts/src/ts-dsl/mixins/value.ts new file mode 100644 index 000000000..76f2df82e --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/mixins/value.ts @@ -0,0 +1,11 @@ +import type { ExprInput, MaybeTsDsl } from '../base'; + +export class ValueMixin { + protected initializer?: MaybeTsDsl; + + /** Sets the initializer expression (e.g. `= expr`). */ + assign(this: T, expr: MaybeTsDsl): T { + this.initializer = expr; + return this; + } +} diff --git a/packages/openapi-ts/src/ts-dsl/new.ts b/packages/openapi-ts/src/ts-dsl/new.ts new file mode 100644 index 000000000..394f0abeb --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/new.ts @@ -0,0 +1,43 @@ +/* eslint-disable @typescript-eslint/no-empty-object-type, @typescript-eslint/no-unsafe-declaration-merging */ +import ts from 'typescript'; + +import type { ExprInput, MaybeTsDsl } from './base'; +import { TsDsl } from './base'; +import { mixin } from './mixins/apply'; +import { GenericsMixin } from './mixins/generics'; + +export class NewTsDsl extends TsDsl { + private classExpr: MaybeTsDsl; + private argList: Array> = []; + + constructor( + classExpr: MaybeTsDsl, + ...args: ReadonlyArray> + ) { + super(); + this.classExpr = classExpr; + if (args.length) this.argList = [...args]; + } + + /** Adds constructor arguments. */ + args(...args: ReadonlyArray>): this { + this.argList = [...args]; + return this; + } + + /** Builds the `NewExpression` node. */ + $render(): ts.NewExpression { + const classExprNode = this.$node(this.classExpr); + const argListNodes = this.$node(this.argList).map((arg) => this.$expr(arg)); + const builtTypes = this._generics?.map((arg) => this.$type(arg)); + return ts.factory.createNewExpression( + classExprNode, + // @ts-expect-error --- generics are not officially supported on 'new' expressions yet + builtTypes, + argListNodes, + ); + } +} + +export interface NewTsDsl extends GenericsMixin {} +mixin(NewTsDsl, GenericsMixin); diff --git a/packages/openapi-ts/src/ts-dsl/newline.ts b/packages/openapi-ts/src/ts-dsl/newline.ts new file mode 100644 index 000000000..4c7f1f8fb --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/newline.ts @@ -0,0 +1,9 @@ +import ts from 'typescript'; + +import { TsDsl } from './base'; + +export class NewlineTsDsl extends TsDsl { + $render(): ts.Identifier { + return ts.factory.createIdentifier('\n'); + } +} diff --git a/packages/openapi-ts/src/ts-dsl/not.ts b/packages/openapi-ts/src/ts-dsl/not.ts new file mode 100644 index 000000000..8d05c6adc --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/not.ts @@ -0,0 +1,21 @@ +import ts from 'typescript'; + +import type { ExprInput, MaybeTsDsl } from './base'; +import { TsDsl } from './base'; + +export class NotTsDsl extends TsDsl { + private exprInput: MaybeTsDsl; + + constructor(expr: MaybeTsDsl) { + super(); + this.exprInput = expr; + } + + $render(): ts.PrefixUnaryExpression { + const expression = this.$node(this.exprInput); + return ts.factory.createPrefixUnaryExpression( + ts.SyntaxKind.ExclamationToken, + expression, + ); + } +} diff --git a/packages/openapi-ts/src/ts-dsl/object.ts b/packages/openapi-ts/src/ts-dsl/object.ts new file mode 100644 index 000000000..724305605 --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/object.ts @@ -0,0 +1,56 @@ +import ts from 'typescript'; + +import type { ExprInput } from './base'; +import { TsDsl } from './base'; +import { ExprTsDsl } from './expr'; + +export class ObjectTsDsl extends TsDsl { + private props: Array<{ expr: TsDsl; name: string }> = []; + private layout: boolean | number = 3; + + constructor(fn?: (o: ObjectTsDsl) => void) { + super(); + if (fn) fn(this); + } + + /** Sets automatic line output with optional threshold (default: 3). */ + auto(threshold: number = 3): this { + this.layout = threshold; + return this; + } + + /** Sets single line output. */ + inline(): this { + this.layout = false; + return this; + } + + /** Sets multi line output. */ + pretty(): this { + this.layout = true; + return this; + } + + /** Adds a property assignment using a callback builder. */ + prop( + name: string, + fn: (p: (expr: ExprInput) => ExprTsDsl) => TsDsl, + ): this { + const result = fn((expr: ExprInput) => new ExprTsDsl(expr)); + this.props.push({ expr: result, name }); + return this; + } + + $render(): ts.ObjectLiteralExpression { + const props = this.props.map(({ expr, name }) => + ts.factory.createPropertyAssignment(name, expr.$render()), + ); + + const multiLine = + typeof this.layout === 'number' + ? this.props.length >= this.layout + : this.layout; + + return ts.factory.createObjectLiteralExpression(props, multiLine); + } +} diff --git a/packages/openapi-ts/src/ts-dsl/param.ts b/packages/openapi-ts/src/ts-dsl/param.ts new file mode 100644 index 000000000..a5de4ab29 --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/param.ts @@ -0,0 +1,37 @@ +/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */ +import ts from 'typescript'; + +import { TsDsl } from './base'; +import { mixin } from './mixins/apply'; +import { DecoratorMixin } from './mixins/decorator'; +import { OptionalMixin } from './mixins/optional'; +import { createTypeAccessor } from './mixins/type'; +import { ValueMixin } from './mixins/value'; + +export class ParamTsDsl extends TsDsl { + private name: string; + private _type = createTypeAccessor(this); + + constructor(name: string, fn?: (p: ParamTsDsl) => void) { + super(); + this.name = name; + if (fn) fn(this); + } + + /** Sets the parameter's type. */ + type = this._type.method; + + $render(): ts.ParameterDeclaration { + return ts.factory.createParameterDeclaration( + this.decorators, + undefined, + ts.factory.createIdentifier(this.name), + this.questionToken, + this._type.$render(), + this.$node(this.initializer), + ); + } +} + +export interface ParamTsDsl extends DecoratorMixin, OptionalMixin, ValueMixin {} +mixin(ParamTsDsl, DecoratorMixin, OptionalMixin, ValueMixin); diff --git a/packages/openapi-ts/src/ts-dsl/return.ts b/packages/openapi-ts/src/ts-dsl/return.ts new file mode 100644 index 000000000..5a4373e7f --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/return.ts @@ -0,0 +1,18 @@ +import ts from 'typescript'; + +import type { ExprInput, MaybeTsDsl } from './base'; +import { TsDsl } from './base'; + +export class ReturnTsDsl extends TsDsl { + private expr?: MaybeTsDsl; + + constructor(expr?: MaybeTsDsl) { + super(); + this.expr = expr; + } + + $render(): ts.ReturnStatement { + const exprNode = this.$node(this.expr); + return ts.factory.createReturnStatement(exprNode); + } +} diff --git a/packages/openapi-ts/src/ts-dsl/setter.ts b/packages/openapi-ts/src/ts-dsl/setter.ts new file mode 100644 index 000000000..208988a5a --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/setter.ts @@ -0,0 +1,69 @@ +/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */ +import ts from 'typescript'; + +import type { MaybeTsDsl } from './base'; +import { TsDsl } from './base'; +import { mixin } from './mixins/apply'; +import { DecoratorMixin } from './mixins/decorator'; +import { DescribeMixin } from './mixins/describe'; +import type { AsyncMixin } from './mixins/modifiers'; +import { + AbstractMixin, + createModifierAccessor, + PrivateMixin, + ProtectedMixin, + PublicMixin, + StaticMixin, +} from './mixins/modifiers'; +import { ParamMixin } from './mixins/param'; + +export class SetterTsDsl extends TsDsl { + private body: Array> = []; + private modifiers = createModifierAccessor(this); + private name: string; + + constructor(name: string, fn?: (s: SetterTsDsl) => void) { + super(); + this.name = name; + if (fn) fn(this); + } + + /** Adds one or more expressions/statements to the setter body. */ + do(...items: ReadonlyArray>): this { + this.body.push(...items); + return this; + } + + $render(): ts.SetAccessorDeclaration { + const builtParams = this.$node(this._params ?? []); + const builtBody = this.$stmt(this.body); + return ts.factory.createSetAccessorDeclaration( + [...(this.decorators ?? []), ...this.modifiers.list()], + this.name, + builtParams, + ts.factory.createBlock(builtBody, true), + ); + } +} + +export interface SetterTsDsl + extends AbstractMixin, + AsyncMixin, + DecoratorMixin, + DescribeMixin, + ParamMixin, + PrivateMixin, + ProtectedMixin, + PublicMixin, + StaticMixin {} +mixin( + SetterTsDsl, + AbstractMixin, + DecoratorMixin, + [DescribeMixin, { overrideRender: true }], + ParamMixin, + PrivateMixin, + ProtectedMixin, + PublicMixin, + StaticMixin, +); diff --git a/packages/openapi-ts/src/ts-dsl/template.ts b/packages/openapi-ts/src/ts-dsl/template.ts new file mode 100644 index 000000000..56e07c75f --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/template.ts @@ -0,0 +1,87 @@ +import ts from 'typescript'; + +import type { ExprInput, MaybeTsDsl } from './base'; +import { TsDsl } from './base'; + +export class TemplateTsDsl extends TsDsl< + ts.TemplateExpression | ts.NoSubstitutionTemplateLiteral +> { + private parts: Array> = []; + + constructor(value?: MaybeTsDsl) { + super(); + if (value !== undefined) this.add(value); + } + + add(value: MaybeTsDsl): this { + this.parts.push(value); + return this; + } + + $render(): ts.TemplateExpression | ts.NoSubstitutionTemplateLiteral { + const parts = this.$node(this.parts); + + const normalized: Array = []; + // merge consecutive string parts + for (let index = 0; index < parts.length; index++) { + const current = parts[index]!; + if (typeof current === 'string') { + let merged = current; + while ( + index + 1 < parts.length && + typeof parts[index + 1] === 'string' + ) { + merged += parts[index + 1]; + index++; + } + normalized.push(merged); + } else { + normalized.push(current); + } + } + + if (normalized.length === 0 || typeof normalized[0] !== 'string') { + normalized.unshift(''); + } + + if (normalized.length === 1 && typeof normalized[0] === 'string') { + return ts.factory.createNoSubstitutionTemplateLiteral(normalized[0]); + } + + if ( + normalized.length === 2 && + typeof normalized[0] === 'string' && + typeof normalized[1] !== 'string' + ) { + return ts.factory.createTemplateExpression( + ts.factory.createTemplateHead(normalized[0]), + [ + ts.factory.createTemplateSpan( + normalized[1]!, + ts.factory.createTemplateTail(''), + ), + ], + ); + } + + const head = ts.factory.createTemplateHead(normalized.shift() as string); + const spans: Array = []; + + while (normalized.length) { + const expr = normalized.shift() as ts.Expression; + const next = + typeof normalized[0] === 'string' ? (normalized.shift() as string) : ''; + const isLast = normalized.length === 0; + spans.push( + ts.factory.createTemplateSpan( + expr, + isLast + ? ts.factory.createTemplateTail(next) + : ts.factory.createTemplateMiddle(next), + ), + ); + } + + return ts.factory.createTemplateExpression(head, spans); + } +} diff --git a/packages/openapi-ts/src/ts-dsl/throw.ts b/packages/openapi-ts/src/ts-dsl/throw.ts new file mode 100644 index 000000000..d8a178108 --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/throw.ts @@ -0,0 +1,37 @@ +import ts from 'typescript'; + +import type { ExprInput, MaybeTsDsl } from './base'; +import { TsDsl } from './base'; + +export class ThrowTsDsl extends TsDsl { + private error: MaybeTsDsl; + private msg?: MaybeTsDsl; + private useNew: boolean; + + constructor(error: MaybeTsDsl, useNew = true) { + super(); + this.error = error; + this.useNew = useNew; + } + + message(value: MaybeTsDsl): this { + this.msg = value; + return this; + } + + $render(): ts.ThrowStatement { + const errorNode = this.$node(this.error); + const messageNode = this.$node(this.msg ? [this.msg] : []).map((expr) => + typeof expr === 'string' ? ts.factory.createStringLiteral(expr) : expr, + ); + if (this.useNew) { + return ts.factory.createThrowStatement( + ts.factory.createNewExpression(errorNode, undefined, messageNode), + ); + } + const args = messageNode.length + ? [ts.factory.createCallExpression(errorNode, undefined, messageNode)] + : [errorNode]; + return ts.factory.createThrowStatement(args[0]!); + } +} diff --git a/packages/openapi-ts/src/ts-dsl/type.ts b/packages/openapi-ts/src/ts-dsl/type.ts new file mode 100644 index 000000000..ce4dc4948 --- /dev/null +++ b/packages/openapi-ts/src/ts-dsl/type.ts @@ -0,0 +1,171 @@ +/* eslint-disable @typescript-eslint/no-empty-object-type, @typescript-eslint/no-unsafe-declaration-merging */ +import ts from 'typescript'; + +import type { ExprInput, TypeInput } from './base'; +import { TsDsl } from './base'; +import { LiteralTsDsl } from './literal'; +import { mixin } from './mixins/apply'; +import { GenericsMixin } from './mixins/generics'; +import { OptionalMixin } from './mixins/optional'; + +export abstract class BaseTypeTsDsl< + T extends ts.TypeNode | ts.TypeParameterDeclaration, +> extends TsDsl { + protected base?: ts.EntityName; + protected constraint?: TypeInput; + protected defaultValue?: TypeInput; + + constructor(base?: ExprInput) { + super(); + if (base) this.base = this.$expr(base); + } + + default(value: TypeInput): this { + this.defaultValue = value; + return this; + } + + extends(constraint: TypeInput): this { + this.constraint = constraint; + return this; + } +} + +export class TypeReferenceTsDsl extends BaseTypeTsDsl { + private objectBuilder?: TypeObjectTsDsl; + + constructor( + name?: ExprInput, + fn?: (base: TypeReferenceTsDsl) => void, + ) { + super(name); + if (fn) fn(this); + } + + /** Starts an object type literal (e.g. `{ foo: string }`). */ + object(fn: (o: TypeObjectTsDsl) => void): this { + this.objectBuilder = new TypeObjectTsDsl(fn); + return this; + } + + $render(): ts.TypeNode { + if (this.objectBuilder) { + return ts.factory.createTypeLiteralNode(this.objectBuilder.$render()); + } + if (!this.base) throw new Error('Missing base type'); + const builtTypes = this._generics?.map((arg) => this.$type(arg)); + return ts.factory.createTypeReferenceNode( + this.base, + // @ts-expect-error --- generics are not officially supported on type references yet + builtTypes, + ); + } +} +export interface TypeReferenceTsDsl extends GenericsMixin {} +mixin(TypeReferenceTsDsl, GenericsMixin); + +export class TypeParamTsDsl extends BaseTypeTsDsl { + constructor( + name?: ExprInput, + fn?: (base: TypeParamTsDsl) => void, + ) { + super(name); + if (fn) fn(this); + } + + $render(): ts.TypeParameterDeclaration { + if (!this.base) throw new Error('Missing type name'); + return ts.factory.createTypeParameterDeclaration( + undefined, + this.base as ts.Identifier, + this.$type(this.constraint), + this.$type(this.defaultValue), + ); + } +} +export interface TypeParamTsDsl extends GenericsMixin {} +mixin(TypeParamTsDsl, GenericsMixin); + +export class TypeLiteralTsDsl extends TsDsl { + private literal: LiteralTsDsl; + + constructor(value: string | number | boolean) { + super(); + this.literal = new LiteralTsDsl(value); + } + + $render(): ts.LiteralTypeNode { + const expr = this.literal.$render(); + return ts.factory.createLiteralTypeNode(expr); + } +} + +export class TypeObjectTsDsl { + private props: Array = []; + + constructor(fn: (o: TypeObjectTsDsl) => void) { + fn(this); + } + + /** Adds a property signature (returns property builder). */ + prop(name: string, fn: (p: TypePropTsDsl) => void): this { + const propTsDsl = new TypePropTsDsl(name, fn); + this.props.push(propTsDsl); + return this; + } + + $render(): ReadonlyArray { + return this.props.map((p) => p.$render()); + } +} + +export class TypePropTsDsl { + private name: string; + private typeInput?: TypeInput; + + constructor(name: string, fn: (p: TypePropTsDsl) => void) { + this.name = name; + fn(this); + } + + /** Sets the property type. */ + type(type: TypeInput): this { + this.typeInput = type; + return this; + } + + /** Builds and returns the property signature. */ + $render(): ts.TypeElement { + if (!this.typeInput) { + throw new Error(`Type not specified for property '${this.name}'`); + } + const typeNode = + typeof this.typeInput === 'string' + ? ts.factory.createTypeReferenceNode(this.typeInput) + : (this.typeInput as ts.TypeNode); + return ts.factory.createPropertySignature( + undefined, + ts.factory.createIdentifier(this.name), + this.questionToken, + typeNode, + ); + } +} + +export interface TypePropTsDsl extends OptionalMixin {} +mixin(TypePropTsDsl, OptionalMixin); + +export const TypeTsDsl = Object.assign( + (...args: ConstructorParameters) => + new TypeReferenceTsDsl(...args), + { + literal: (...args: ConstructorParameters) => + new TypeLiteralTsDsl(...args), + object: (...args: ConstructorParameters) => + new TypeObjectTsDsl(...args), + param: (...args: ConstructorParameters) => + new TypeParamTsDsl(...args), + ref: (...args: ConstructorParameters) => + new TypeReferenceTsDsl(...args), + }, +); diff --git a/packages/openapi-ts/src/tsc/classes.ts b/packages/openapi-ts/src/tsc/classes.ts index ffb8a0abc..9c9c71147 100644 --- a/packages/openapi-ts/src/tsc/classes.ts +++ b/packages/openapi-ts/src/tsc/classes.ts @@ -132,6 +132,7 @@ export const createClassDeclaration = ({ extendedClasses, name, nodes, + typeParameters, }: { /** * Class decorator. @@ -153,6 +154,7 @@ export const createClassDeclaration = ({ * Class elements. */ nodes: ReadonlyArray; + typeParameters?: ReadonlyArray; }): ts.ClassDeclaration => { const modifiers: Array = []; @@ -191,7 +193,7 @@ export const createClassDeclaration = ({ return ts.factory.createClassDeclaration( modifiers, createIdentifier({ text: name }), - undefined, + typeParameters, heritageClauses, nodes, ); diff --git a/packages/openapi-ts/src/tsc/index.ts b/packages/openapi-ts/src/tsc/index.ts index 916a571a3..1a9729f29 100644 --- a/packages/openapi-ts/src/tsc/index.ts +++ b/packages/openapi-ts/src/tsc/index.ts @@ -48,6 +48,7 @@ export const tsc = { objectExpression: types.createObjectType, ots: utils.ots, parameterDeclaration: types.createParameterDeclaration, + prefixUnaryExpression: utils.createPrefixUnaryExpression, propertyAccessExpression: types.createPropertyAccessExpression, propertyAccessExpressions: transform.createPropertyAccessExpressions, propertyAssignment: types.createPropertyAssignment, diff --git a/packages/openapi-ts/src/tsc/utils.ts b/packages/openapi-ts/src/tsc/utils.ts index 188b1ddb5..94bc143c8 100644 --- a/packages/openapi-ts/src/tsc/utils.ts +++ b/packages/openapi-ts/src/tsc/utils.ts @@ -72,8 +72,35 @@ export function tsNodeToString({ } } -export const createIdentifier = ({ text }: { text: string }): ts.Identifier => - ts.factory.createIdentifier(text); +export const createIdentifier = ( + args: string | { text: string }, +): ts.Identifier => + ts.factory.createIdentifier(typeof args === 'string' ? args : args.text); + +type Prefix = '!' | '-'; + +const prefixToOperator = (prefix: Prefix): ts.PrefixUnaryOperator => { + switch (prefix) { + case '!': + return ts.SyntaxKind.ExclamationToken; + case '-': + return ts.SyntaxKind.MinusToken; + } +}; + +export const createPrefixUnaryExpression = ({ + expression, + prefix, +}: { + expression: string | ts.Expression; + prefix: Prefix | ts.PrefixUnaryOperator; +}): ts.PrefixUnaryExpression => { + const operand = + typeof expression === 'string' ? createIdentifier(expression) : expression; + const operator = + typeof prefix === 'string' ? prefixToOperator(prefix) : prefix; + return ts.factory.createPrefixUnaryExpression(operator, operand); +}; export const createThis = (): ts.ThisExpression => ts.factory.createThis(); @@ -86,23 +113,23 @@ export const createModifier = ({ keyword }: { keyword: Modifier }) => { export const createPropertyDeclaration = ({ initializer, - modifier, + modifiers, name, type, }: { initializer?: ts.Expression; - modifier?: Modifier; + modifiers?: Modifier | ReadonlyArray; name: string | ts.PropertyName; type?: ts.TypeNode; }) => { - const node = ts.factory.createPropertyDeclaration( - modifier ? [createModifier({ keyword: modifier })] : undefined, + const mods = Array.isArray(modifiers) ? modifiers : [modifiers]; + return ts.factory.createPropertyDeclaration( + modifiers ? mods.map((keyword) => createModifier({ keyword })) : undefined, name, undefined, type, initializer, ); - return node; }; /** @@ -116,17 +143,17 @@ export const ots = { boolean: (value: boolean) => value ? ts.factory.createTrue() : ts.factory.createFalse(), export: ({ alias, asType = false, name }: ImportExportItemObject) => { - const nameNode = createIdentifier({ text: name! }); + const nameNode = createIdentifier(name!); if (alias) { - const aliasNode = createIdentifier({ text: alias }); + const aliasNode = createIdentifier(alias); return ts.factory.createExportSpecifier(asType, nameNode, aliasNode); } return ts.factory.createExportSpecifier(asType, undefined, nameNode); }, import: ({ alias, asType = false, name }: ImportExportItemObject) => { - const nameNode = createIdentifier({ text: name! }); + const nameNode = createIdentifier(name!); if (alias) { - const aliasNode = createIdentifier({ text: alias }); + const aliasNode = createIdentifier(alias); return ts.factory.createImportSpecifier(asType, nameNode, aliasNode); } return ts.factory.createImportSpecifier(asType, undefined, nameNode); @@ -136,10 +163,10 @@ export const ots = { */ number: (value: number) => { if (value < 0) { - return ts.factory.createPrefixUnaryExpression( - ts.SyntaxKind.MinusToken, - ts.factory.createNumericLiteral(Math.abs(value)), - ); + return createPrefixUnaryExpression({ + expression: ts.factory.createNumericLiteral(Math.abs(value)), + prefix: '-', + }); } return ts.factory.createNumericLiteral(value); }, @@ -162,7 +189,7 @@ export const ots = { text = `\`${text.replace(/(?=16'} hasBin: true + swr@2.3.6: + resolution: {integrity: sha512-wfHRmHWk/isGNMwlLGlZX5Gzz/uTgo0o2IRuTMcf4CPuPFJZlq0rDaKUx+ozB5nBOReNV1kiOyzMfj+MBMikLw==} + peerDependencies: + react: ^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + symbol-observable@4.0.0: resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==} engines: {node: '>=0.10'} @@ -14233,7 +14241,7 @@ snapshots: dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.1902.0(chokidar@4.0.3) - '@angular-devkit/build-webpack': 0.1902.0(chokidar@4.0.3)(webpack-dev-server@5.2.0(webpack@5.98.0(esbuild@0.25.0)))(webpack@5.98.0(esbuild@0.25.0)) + '@angular-devkit/build-webpack': 0.1902.0(chokidar@4.0.3)(webpack-dev-server@5.2.0(webpack@5.98.0))(webpack@5.98.0(esbuild@0.25.0)) '@angular-devkit/core': 19.2.0(chokidar@4.0.3) '@angular/build': 19.2.0(@angular/compiler-cli@19.2.0(@angular/compiler@19.2.0(@angular/core@19.2.0(rxjs@7.8.2)(zone.js@0.15.1)))(typescript@5.8.3))(@angular/compiler@19.2.0(@angular/core@19.2.0(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/platform-server@19.2.0(@angular/common@19.2.0(@angular/core@19.2.0(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@19.2.0(@angular/core@19.2.0(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/core@19.2.0(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@19.2.0(@angular/animations@19.2.0(@angular/core@19.2.0(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@19.2.0(@angular/core@19.2.0(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@19.2.0(rxjs@7.8.2)(zone.js@0.15.1))))(@angular/ssr@19.2.15(5c03da8199d2fcdf9ff93b70f9349edd))(@types/node@22.10.5)(chokidar@4.0.3)(jiti@2.6.1)(karma@6.4.4)(less@4.2.2)(postcss@8.5.2)(tailwindcss@3.4.14(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.8.3)))(terser@5.39.0)(typescript@5.8.3)(yaml@2.8.1) '@angular/compiler-cli': 19.2.0(@angular/compiler@19.2.0(@angular/core@19.2.0(rxjs@7.8.2)(zone.js@0.15.1)))(typescript@5.8.3) @@ -14284,8 +14292,8 @@ snapshots: tslib: 2.8.1 typescript: 5.8.3 webpack: 5.98.0(esbuild@0.25.0) - webpack-dev-middleware: 7.4.2(webpack@5.98.0(esbuild@0.25.0)) - webpack-dev-server: 5.2.0(webpack@5.98.0(esbuild@0.25.0)) + webpack-dev-middleware: 7.4.2(webpack@5.98.0) + webpack-dev-server: 5.2.0(webpack@5.98.0) webpack-merge: 6.0.1 webpack-subresource-integrity: 5.1.0(webpack@5.98.0) optionalDependencies: @@ -14321,7 +14329,7 @@ snapshots: dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.1902.0(chokidar@4.0.3) - '@angular-devkit/build-webpack': 0.1902.0(chokidar@4.0.3)(webpack-dev-server@5.2.0(webpack@5.98.0(esbuild@0.25.0)))(webpack@5.98.0(esbuild@0.25.0)) + '@angular-devkit/build-webpack': 0.1902.0(chokidar@4.0.3)(webpack-dev-server@5.2.0(webpack@5.98.0))(webpack@5.98.0(esbuild@0.25.0)) '@angular-devkit/core': 19.2.0(chokidar@4.0.3) '@angular/build': 19.2.0(@angular/compiler-cli@19.2.0(@angular/compiler@19.2.0(@angular/core@19.2.0(rxjs@7.8.2)(zone.js@0.15.1)))(typescript@5.8.3))(@angular/compiler@19.2.0(@angular/core@19.2.0(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/platform-server@19.2.0(@angular/common@19.2.0(@angular/core@19.2.0(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@19.2.0(@angular/core@19.2.0(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/core@19.2.0(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@19.2.0(@angular/animations@19.2.0(@angular/core@19.2.0(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@19.2.0(@angular/core@19.2.0(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@19.2.0(rxjs@7.8.2)(zone.js@0.15.1))))(@angular/ssr@19.2.15(5c03da8199d2fcdf9ff93b70f9349edd))(@types/node@22.10.5)(chokidar@4.0.3)(jiti@2.6.1)(karma@6.4.4)(less@4.2.2)(postcss@8.5.2)(tailwindcss@3.4.14(ts-node@10.9.2(@types/node@22.10.5)(typescript@5.8.3)))(terser@5.39.0)(typescript@5.8.3)(yaml@2.8.1) '@angular/compiler-cli': 19.2.0(@angular/compiler@19.2.0(@angular/core@19.2.0(rxjs@7.8.2)(zone.js@0.15.1)))(typescript@5.8.3) @@ -14372,8 +14380,8 @@ snapshots: tslib: 2.8.1 typescript: 5.8.3 webpack: 5.98.0(esbuild@0.25.0) - webpack-dev-middleware: 7.4.2(webpack@5.98.0(esbuild@0.25.0)) - webpack-dev-server: 5.2.0(webpack@5.98.0(esbuild@0.25.0)) + webpack-dev-middleware: 7.4.2(webpack@5.98.0) + webpack-dev-server: 5.2.0(webpack@5.98.0) webpack-merge: 6.0.1 webpack-subresource-integrity: 5.1.0(webpack@5.98.0) optionalDependencies: @@ -14460,7 +14468,7 @@ snapshots: tslib: 2.8.1 typescript: 5.8.3 webpack: 5.98.0(esbuild@0.25.4) - webpack-dev-middleware: 7.4.2(webpack@5.98.0(esbuild@0.25.0)) + webpack-dev-middleware: 7.4.2(webpack@5.98.0) webpack-dev-server: 5.2.2(webpack@5.98.0) webpack-merge: 6.0.1 webpack-subresource-integrity: 5.1.0(webpack@5.98.0) @@ -14548,7 +14556,7 @@ snapshots: tslib: 2.8.1 typescript: 5.9.3 webpack: 5.98.0(esbuild@0.25.4) - webpack-dev-middleware: 7.4.2(webpack@5.98.0(esbuild@0.25.0)) + webpack-dev-middleware: 7.4.2(webpack@5.98.0) webpack-dev-server: 5.2.2(webpack@5.98.0) webpack-merge: 6.0.1 webpack-subresource-integrity: 5.1.0(webpack@5.98.0) @@ -14580,12 +14588,12 @@ snapshots: - webpack-cli - yaml - '@angular-devkit/build-webpack@0.1902.0(chokidar@4.0.3)(webpack-dev-server@5.2.0(webpack@5.98.0(esbuild@0.25.0)))(webpack@5.98.0(esbuild@0.25.0))': + '@angular-devkit/build-webpack@0.1902.0(chokidar@4.0.3)(webpack-dev-server@5.2.0(webpack@5.98.0))(webpack@5.98.0(esbuild@0.25.0))': dependencies: '@angular-devkit/architect': 0.1902.0(chokidar@4.0.3) rxjs: 7.8.1 webpack: 5.98.0(esbuild@0.25.0) - webpack-dev-server: 5.2.0(webpack@5.98.0(esbuild@0.25.0)) + webpack-dev-server: 5.2.0(webpack@5.98.0) transitivePeerDependencies: - chokidar @@ -18106,32 +18114,32 @@ snapshots: '@nuxt/devalue@2.0.2': {} - '@nuxt/devtools-kit@1.7.0(magicast@0.3.5)(vite@7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1))': + '@nuxt/devtools-kit@1.7.0(magicast@0.3.5)(vite@5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.43.1))': dependencies: '@nuxt/kit': 3.15.4(magicast@0.3.5) '@nuxt/schema': 3.16.2 execa: 7.2.0 - vite: 7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1) + vite: 5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.43.1) transitivePeerDependencies: - magicast - supports-color - '@nuxt/devtools-kit@1.7.0(magicast@0.3.5)(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.1))': + '@nuxt/devtools-kit@1.7.0(magicast@0.3.5)(vite@7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1))': dependencies: '@nuxt/kit': 3.15.4(magicast@0.3.5) '@nuxt/schema': 3.16.2 execa: 7.2.0 - vite: 7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.1) + vite: 7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1) transitivePeerDependencies: - magicast - supports-color - '@nuxt/devtools-kit@1.7.0(magicast@0.3.5)(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.0))': + '@nuxt/devtools-kit@1.7.0(magicast@0.3.5)(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.1))': dependencies: '@nuxt/kit': 3.15.4(magicast@0.3.5) '@nuxt/schema': 3.16.2 execa: 7.2.0 - vite: 7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.0) + vite: 7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.1) transitivePeerDependencies: - magicast - supports-color @@ -18196,13 +18204,13 @@ snapshots: - utf-8-validate - vue - '@nuxt/devtools@1.7.0(rollup@4.50.0)(vite@7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1))(vue@3.5.13(typescript@5.9.3))': + '@nuxt/devtools@1.7.0(rollup@4.50.0)(vite@5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.43.1))(vue@3.5.13(typescript@5.9.3))': dependencies: '@antfu/utils': 0.7.10 - '@nuxt/devtools-kit': 1.7.0(magicast@0.3.5)(vite@7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1)) + '@nuxt/devtools-kit': 1.7.0(magicast@0.3.5)(vite@5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)) '@nuxt/devtools-wizard': 1.7.0 '@nuxt/kit': 3.15.4(magicast@0.3.5) - '@vue/devtools-core': 7.6.8(vite@7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1))(vue@3.5.13(typescript@5.9.3)) + '@vue/devtools-core': 7.6.8(vite@5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.43.1))(vue@3.5.13(typescript@5.9.3)) '@vue/devtools-kit': 7.6.8 birpc: 0.2.19 consola: 3.4.2 @@ -18231,9 +18239,9 @@ snapshots: sirv: 3.0.2 tinyglobby: 0.2.15 unimport: 3.14.6(rollup@4.50.0) - vite: 7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1) - vite-plugin-inspect: 0.8.9(@nuxt/kit@3.15.4(magicast@0.3.5))(rollup@4.50.0)(vite@7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1)) - vite-plugin-vue-inspector: 5.3.2(vite@7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1)) + vite: 5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.43.1) + vite-plugin-inspect: 0.8.9(@nuxt/kit@3.15.4(magicast@0.3.5))(rollup@4.50.0)(vite@5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)) + vite-plugin-vue-inspector: 5.3.2(vite@5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)) which: 3.0.1 ws: 8.18.3 transitivePeerDependencies: @@ -18243,13 +18251,13 @@ snapshots: - utf-8-validate - vue - '@nuxt/devtools@1.7.0(rollup@4.50.0)(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.1))(vue@3.5.13(typescript@5.9.3))': + '@nuxt/devtools@1.7.0(rollup@4.50.0)(vite@7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1))(vue@3.5.13(typescript@5.9.3))': dependencies: '@antfu/utils': 0.7.10 - '@nuxt/devtools-kit': 1.7.0(magicast@0.3.5)(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.1)) + '@nuxt/devtools-kit': 1.7.0(magicast@0.3.5)(vite@7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1)) '@nuxt/devtools-wizard': 1.7.0 '@nuxt/kit': 3.15.4(magicast@0.3.5) - '@vue/devtools-core': 7.6.8(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.1))(vue@3.5.13(typescript@5.9.3)) + '@vue/devtools-core': 7.6.8(vite@7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1))(vue@3.5.13(typescript@5.9.3)) '@vue/devtools-kit': 7.6.8 birpc: 0.2.19 consola: 3.4.2 @@ -18278,9 +18286,9 @@ snapshots: sirv: 3.0.2 tinyglobby: 0.2.15 unimport: 3.14.6(rollup@4.50.0) - vite: 7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.1) - vite-plugin-inspect: 0.8.9(@nuxt/kit@3.15.4(magicast@0.3.5))(rollup@4.50.0)(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.1)) - vite-plugin-vue-inspector: 5.3.2(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.1)) + vite: 7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1) + vite-plugin-inspect: 0.8.9(@nuxt/kit@3.15.4(magicast@0.3.5))(rollup@4.50.0)(vite@7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1)) + vite-plugin-vue-inspector: 5.3.2(vite@7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1)) which: 3.0.1 ws: 8.18.3 transitivePeerDependencies: @@ -18290,13 +18298,13 @@ snapshots: - utf-8-validate - vue - '@nuxt/devtools@1.7.0(rollup@4.50.0)(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.13(typescript@5.9.3))': + '@nuxt/devtools@1.7.0(rollup@4.50.0)(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.1))(vue@3.5.13(typescript@5.9.3))': dependencies: '@antfu/utils': 0.7.10 - '@nuxt/devtools-kit': 1.7.0(magicast@0.3.5)(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.0)) + '@nuxt/devtools-kit': 1.7.0(magicast@0.3.5)(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.1)) '@nuxt/devtools-wizard': 1.7.0 '@nuxt/kit': 3.15.4(magicast@0.3.5) - '@vue/devtools-core': 7.6.8(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.13(typescript@5.9.3)) + '@vue/devtools-core': 7.6.8(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.1))(vue@3.5.13(typescript@5.9.3)) '@vue/devtools-kit': 7.6.8 birpc: 0.2.19 consola: 3.4.2 @@ -18325,9 +18333,9 @@ snapshots: sirv: 3.0.2 tinyglobby: 0.2.15 unimport: 3.14.6(rollup@4.50.0) - vite: 7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.0) - vite-plugin-inspect: 0.8.9(@nuxt/kit@3.15.4(magicast@0.3.5))(rollup@4.50.0)(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.0)) - vite-plugin-vue-inspector: 5.3.2(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.0)) + vite: 7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.1) + vite-plugin-inspect: 0.8.9(@nuxt/kit@3.15.4(magicast@0.3.5))(rollup@4.50.0)(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.1)) + vite-plugin-vue-inspector: 5.3.2(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.1)) which: 3.0.1 ws: 8.18.3 transitivePeerDependencies: @@ -21089,38 +21097,38 @@ snapshots: dependencies: '@vue/devtools-kit': 8.0.3 - '@vue/devtools-core@7.6.8(vite@7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1))(vue@3.5.13(typescript@5.9.3))': + '@vue/devtools-core@7.6.8(vite@5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.43.1))(vue@3.5.13(typescript@5.9.3))': dependencies: '@vue/devtools-kit': 7.7.7 '@vue/devtools-shared': 7.7.7 mitt: 3.0.1 nanoid: 5.1.5 pathe: 1.1.2 - vite-hot-client: 0.2.4(vite@7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1)) + vite-hot-client: 0.2.4(vite@5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)) vue: 3.5.13(typescript@5.9.3) transitivePeerDependencies: - vite - '@vue/devtools-core@7.6.8(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.1))(vue@3.5.13(typescript@5.9.3))': + '@vue/devtools-core@7.6.8(vite@7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1))(vue@3.5.13(typescript@5.9.3))': dependencies: '@vue/devtools-kit': 7.7.7 '@vue/devtools-shared': 7.7.7 mitt: 3.0.1 nanoid: 5.1.5 pathe: 1.1.2 - vite-hot-client: 0.2.4(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.1)) + vite-hot-client: 0.2.4(vite@7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1)) vue: 3.5.13(typescript@5.9.3) transitivePeerDependencies: - vite - '@vue/devtools-core@7.6.8(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.13(typescript@5.9.3))': + '@vue/devtools-core@7.6.8(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.1))(vue@3.5.13(typescript@5.9.3))': dependencies: '@vue/devtools-kit': 7.7.7 '@vue/devtools-shared': 7.7.7 mitt: 3.0.1 nanoid: 5.1.5 pathe: 1.1.2 - vite-hot-client: 0.2.4(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.0)) + vite-hot-client: 0.2.4(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.1)) vue: 3.5.13(typescript@5.9.3) transitivePeerDependencies: - vite @@ -23197,8 +23205,8 @@ snapshots: '@typescript-eslint/parser': 8.29.1(eslint@9.17.0(jiti@2.6.1))(typescript@5.8.3) eslint: 9.17.0(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.8.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.8.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.8.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-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(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.8.3))(eslint-import-resolver-typescript@3.10.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)) @@ -23225,7 +23233,7 @@ 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.8.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)(eslint@9.17.0(jiti@2.6.1)): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.1 @@ -23236,22 +23244,22 @@ snapshots: tinyglobby: 0.2.14 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.8.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.8.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.17.0(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.17.0(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.8.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.8.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.17.0(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.17.0(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.8.3) eslint: 9.17.0(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.8.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)(eslint@9.17.0(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.8.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.8.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.17.0(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.17.0(jiti@2.6.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -23262,7 +23270,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.17.0(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.8.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.8.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.17.0(jiti@2.6.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.17.0(jiti@2.6.1)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -26244,10 +26252,10 @@ snapshots: - vue-tsc - xml2js - nuxt@3.14.1592(@netlify/blobs@9.1.2)(@parcel/watcher@2.5.1)(@types/node@22.10.5)(db0@0.3.2)(encoding@0.1.13)(eslint@9.17.0(jiti@2.6.1))(ioredis@5.7.0)(less@4.2.2)(magicast@0.3.5)(optionator@0.9.4)(rolldown@1.0.0-beta.45)(rollup@4.50.0)(sass@1.85.0)(terser@5.43.1)(typescript@5.9.3)(vite@7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1)): + nuxt@3.14.1592(@netlify/blobs@9.1.2)(@parcel/watcher@2.5.1)(@types/node@22.10.5)(db0@0.3.2)(encoding@0.1.13)(eslint@9.17.0(jiti@2.6.1))(ioredis@5.7.0)(less@4.2.2)(magicast@0.3.5)(optionator@0.9.4)(rolldown@1.0.0-beta.45)(rollup@4.50.0)(sass@1.85.0)(terser@5.43.1)(typescript@5.9.3)(vite@5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)): dependencies: '@nuxt/devalue': 2.0.2 - '@nuxt/devtools': 1.7.0(rollup@4.50.0)(vite@7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1))(vue@3.5.13(typescript@5.9.3)) + '@nuxt/devtools': 1.7.0(rollup@4.50.0)(vite@5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.43.1))(vue@3.5.13(typescript@5.9.3)) '@nuxt/kit': 3.14.1592(magicast@0.3.5)(rollup@4.50.0) '@nuxt/schema': 3.14.1592(magicast@0.3.5)(rollup@4.50.0) '@nuxt/telemetry': 2.6.6(magicast@0.3.5) @@ -26365,10 +26373,10 @@ snapshots: - vue-tsc - xml2js - nuxt@3.14.1592(@netlify/blobs@9.1.2)(@parcel/watcher@2.5.1)(@types/node@22.10.5)(db0@0.3.2)(encoding@0.1.13)(eslint@9.17.0(jiti@2.6.1))(ioredis@5.7.0)(less@4.2.2)(magicast@0.3.5)(optionator@0.9.4)(rolldown@1.0.0-beta.45)(rollup@4.50.0)(sass@1.85.0)(terser@5.43.1)(typescript@5.9.3)(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.0)): + nuxt@3.14.1592(@netlify/blobs@9.1.2)(@parcel/watcher@2.5.1)(@types/node@22.10.5)(db0@0.3.2)(encoding@0.1.13)(eslint@9.17.0(jiti@2.6.1))(ioredis@5.7.0)(less@4.2.2)(magicast@0.3.5)(optionator@0.9.4)(rolldown@1.0.0-beta.45)(rollup@4.50.0)(sass@1.85.0)(terser@5.43.1)(typescript@5.9.3)(vite@7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1)): dependencies: '@nuxt/devalue': 2.0.2 - '@nuxt/devtools': 1.7.0(rollup@4.50.0)(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.0))(vue@3.5.13(typescript@5.9.3)) + '@nuxt/devtools': 1.7.0(rollup@4.50.0)(vite@7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1))(vue@3.5.13(typescript@5.9.3)) '@nuxt/kit': 3.14.1592(magicast@0.3.5)(rollup@4.50.0) '@nuxt/schema': 3.14.1592(magicast@0.3.5)(rollup@4.50.0) '@nuxt/telemetry': 2.6.6(magicast@0.3.5) @@ -28526,6 +28534,12 @@ snapshots: picocolors: 1.1.1 sax: 1.4.1 + swr@2.3.6(react@19.0.0): + dependencies: + dequal: 2.0.3 + react: 19.0.0 + use-sync-external-store: 1.5.0(react@19.0.0) + symbol-observable@4.0.0: {} symbol-tree@3.2.4: {} @@ -29463,6 +29477,10 @@ snapshots: vite: 7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1) vite-hot-client: 2.1.0(vite@7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1)) + vite-hot-client@0.2.4(vite@5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)): + dependencies: + vite: 5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.43.1) + vite-hot-client@0.2.4(vite@7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1)): dependencies: vite: 7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1) @@ -29471,10 +29489,6 @@ snapshots: dependencies: vite: 7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.1) - vite-hot-client@0.2.4(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.0)): - dependencies: - vite: 7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.0) - vite-hot-client@2.1.0(vite@7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1)): dependencies: vite: 7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1) @@ -29619,7 +29633,7 @@ snapshots: - rollup - supports-color - vite-plugin-inspect@0.8.9(@nuxt/kit@3.15.4(magicast@0.3.5))(rollup@4.50.0)(vite@7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1)): + vite-plugin-inspect@0.8.9(@nuxt/kit@3.15.4(magicast@0.3.5))(rollup@4.50.0)(vite@5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)): dependencies: '@antfu/utils': 0.7.10 '@rollup/pluginutils': 5.2.0(rollup@4.50.0) @@ -29630,14 +29644,14 @@ snapshots: perfect-debounce: 1.0.0 picocolors: 1.1.1 sirv: 3.0.2 - vite: 7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1) + vite: 5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.43.1) optionalDependencies: '@nuxt/kit': 3.15.4(magicast@0.3.5) transitivePeerDependencies: - rollup - supports-color - vite-plugin-inspect@0.8.9(@nuxt/kit@3.15.4(magicast@0.3.5))(rollup@4.50.0)(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.1)): + vite-plugin-inspect@0.8.9(@nuxt/kit@3.15.4(magicast@0.3.5))(rollup@4.50.0)(vite@7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1)): dependencies: '@antfu/utils': 0.7.10 '@rollup/pluginutils': 5.2.0(rollup@4.50.0) @@ -29648,14 +29662,14 @@ snapshots: perfect-debounce: 1.0.0 picocolors: 1.1.1 sirv: 3.0.2 - vite: 7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.1) + vite: 7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1) optionalDependencies: '@nuxt/kit': 3.15.4(magicast@0.3.5) transitivePeerDependencies: - rollup - supports-color - vite-plugin-inspect@0.8.9(@nuxt/kit@3.15.4(magicast@0.3.5))(rollup@4.50.0)(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.0)): + vite-plugin-inspect@0.8.9(@nuxt/kit@3.15.4(magicast@0.3.5))(rollup@4.50.0)(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.1)): dependencies: '@antfu/utils': 0.7.10 '@rollup/pluginutils': 5.2.0(rollup@4.50.0) @@ -29666,7 +29680,7 @@ snapshots: perfect-debounce: 1.0.0 picocolors: 1.1.1 sirv: 3.0.2 - vite: 7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.0) + vite: 7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.1) optionalDependencies: '@nuxt/kit': 3.15.4(magicast@0.3.5) transitivePeerDependencies: @@ -29703,7 +29717,7 @@ snapshots: - supports-color - vue - vite-plugin-vue-inspector@5.3.2(vite@7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1)): + vite-plugin-vue-inspector@5.3.2(vite@5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)): dependencies: '@babel/core': 7.28.3 '@babel/plugin-proposal-decorators': 7.28.0(@babel/core@7.28.3) @@ -29714,11 +29728,11 @@ snapshots: '@vue/compiler-dom': 3.5.21 kolorist: 1.8.0 magic-string: 0.30.18 - vite: 7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1) + vite: 5.4.19(@types/node@22.10.5)(less@4.2.2)(sass@1.85.0)(terser@5.43.1) transitivePeerDependencies: - supports-color - vite-plugin-vue-inspector@5.3.2(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.1)): + vite-plugin-vue-inspector@5.3.2(vite@7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1)): dependencies: '@babel/core': 7.28.3 '@babel/plugin-proposal-decorators': 7.28.0(@babel/core@7.28.3) @@ -29729,11 +29743,11 @@ snapshots: '@vue/compiler-dom': 3.5.21 kolorist: 1.8.0 magic-string: 0.30.18 - vite: 7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.1) + vite: 7.1.2(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1) transitivePeerDependencies: - supports-color - vite-plugin-vue-inspector@5.3.2(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.0)): + vite-plugin-vue-inspector@5.3.2(vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.1)): dependencies: '@babel/core': 7.28.3 '@babel/plugin-proposal-decorators': 7.28.0(@babel/core@7.28.3) @@ -29744,7 +29758,7 @@ snapshots: '@vue/compiler-dom': 3.5.21 kolorist: 1.8.0 magic-string: 0.30.18 - vite: 7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.0) + vite: 7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.39.0)(yaml@2.8.1) transitivePeerDependencies: - supports-color @@ -29868,23 +29882,6 @@ snapshots: terser: 5.39.0 yaml: 2.8.1 - vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.0): - dependencies: - esbuild: 0.25.9 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.50.0 - tinyglobby: 0.2.15 - optionalDependencies: - '@types/node': 22.10.5 - fsevents: 2.3.3 - jiti: 2.6.1 - less: 4.2.2 - sass: 1.85.0 - terser: 5.43.1 - yaml: 2.8.0 - vite@7.1.5(@types/node@22.10.5)(jiti@2.6.1)(less@4.2.2)(sass@1.85.0)(terser@5.43.1)(yaml@2.8.1): dependencies: esbuild: 0.25.9 @@ -30224,7 +30221,7 @@ snapshots: webidl-conversions@7.0.0: {} - webpack-dev-middleware@7.4.2(webpack@5.98.0(esbuild@0.25.0)): + webpack-dev-middleware@7.4.2(webpack@5.98.0): dependencies: colorette: 2.0.20 memfs: 4.38.2 @@ -30235,7 +30232,7 @@ snapshots: optionalDependencies: webpack: 5.98.0(esbuild@0.25.0) - webpack-dev-server@5.2.0(webpack@5.98.0(esbuild@0.25.0)): + webpack-dev-server@5.2.0(webpack@5.98.0): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 @@ -30262,7 +30259,7 @@ snapshots: serve-index: 1.9.1 sockjs: 0.3.24 spdy: 4.0.2 - webpack-dev-middleware: 7.4.2(webpack@5.98.0(esbuild@0.25.0)) + webpack-dev-middleware: 7.4.2(webpack@5.98.0) ws: 8.18.3 optionalDependencies: webpack: 5.98.0(esbuild@0.25.0) @@ -30300,7 +30297,7 @@ snapshots: serve-index: 1.9.1 sockjs: 0.3.24 spdy: 4.0.2 - webpack-dev-middleware: 7.4.2(webpack@5.98.0(esbuild@0.25.0)) + webpack-dev-middleware: 7.4.2(webpack@5.98.0) ws: 8.18.3 optionalDependencies: webpack: 5.98.0(esbuild@0.25.0)