fork of hey-api/openapi-ts because I need some additional things

chore: generate CreateClientConfig type with ClientOptions

Lubos ccc7ae40 bb6d46ae

+184 -33
+2 -2
packages/client-axios/src/utils.ts
··· 281 281 }; 282 282 283 283 export const createConfig = <T extends ClientOptions = ClientOptions>( 284 - override: Config<ClientOptions & T> = {}, 285 - ): Config<Required<ClientOptions> & T> => ({ 284 + override: Config<Omit<ClientOptions, keyof T> & T> = {}, 285 + ): Config<Omit<ClientOptions, keyof T> & T> => ({ 286 286 ...override, 287 287 });
+2 -2
packages/client-fetch/src/utils.ts
··· 393 393 }; 394 394 395 395 export const createConfig = <T extends ClientOptions = ClientOptions>( 396 - override: Config<ClientOptions & T> = {}, 397 - ): Config<Required<ClientOptions> & T> => ({ 396 + override: Config<Omit<ClientOptions, keyof T> & T> = {}, 397 + ): Config<Omit<ClientOptions, keyof T> & T> => ({ 398 398 ...jsonBodySerializer, 399 399 headers: defaultHeaders, 400 400 parseAs: 'auto',
+2 -2
packages/client-next/src/utils.ts
··· 382 382 }; 383 383 384 384 export const createConfig = <T extends ClientOptions = ClientOptions>( 385 - override: Config<ClientOptions & T> = {}, 386 - ): Config<Required<ClientOptions> & T> => ({ 385 + override: Config<Omit<ClientOptions, keyof T> & T> = {}, 386 + ): Config<Omit<ClientOptions, keyof T> & T> => ({ 387 387 ...jsonBodySerializer, 388 388 headers: defaultHeaders, 389 389 parseAs: 'auto',
+2 -2
packages/client-nuxt/src/utils.ts
··· 303 303 }; 304 304 305 305 export const createConfig = <T extends ClientOptions = ClientOptions>( 306 - override: Config<ClientOptions & T> = {}, 307 - ): Config<Required<ClientOptions> & T> => ({ 306 + override: Config<Omit<ClientOptions, keyof T> & T> = {}, 307 + ): Config<Omit<ClientOptions, keyof T> & T> => ({ 308 308 ...jsonBodySerializer, 309 309 headers: defaultHeaders, 310 310 querySerializer: defaultQuerySerializer,
+1
packages/openapi-ts/src/plugins/@hey-api/client-axios/config.ts
··· 3 3 import type { Config } from './types'; 4 4 5 5 export const defaultConfig: Plugin.Config<Config> = { 6 + _dependencies: ['@hey-api/typescript'], 6 7 _handler: handler, 7 8 _handlerLegacy: () => {}, 8 9 _tags: ['client'],
+95 -2
packages/openapi-ts/src/plugins/@hey-api/client-core/plugin.ts
··· 1 1 import { compiler } from '../../../compiler'; 2 2 import { clientModulePath } from '../../../generate/client'; 3 + import type { IR } from '../../../ir/types'; 3 4 import { clientId } from '../client-core/utils'; 5 + import { typesId } from '../typescript/ref'; 4 6 import type { PluginHandler } from './types'; 5 7 8 + const createClientConfigType = ({ context }: { context: IR.Context }) => { 9 + const file = context.file({ id: clientId })!; 10 + 11 + const clientModule = clientModulePath({ 12 + config: context.config, 13 + sourceOutput: file.nameWithoutExtension(), 14 + }); 15 + const clientOptions = file.import({ 16 + asType: true, 17 + module: file.relativePathToFile({ context, id: typesId }), 18 + name: 'ClientOptions', 19 + }); 20 + const configType = file.import({ 21 + asType: true, 22 + module: clientModule, 23 + name: 'Config', 24 + }); 25 + const defaultClientOptions = file.import({ 26 + alias: 'DefaultClientOptions', 27 + asType: true, 28 + module: clientModule, 29 + name: 'ClientOptions', 30 + }); 31 + 32 + const defaultClientOptionsType = compiler.typeReferenceNode({ 33 + typeName: defaultClientOptions.name, 34 + }); 35 + const tType = compiler.typeReferenceNode({ typeName: 'T' }); 36 + 37 + const typeCreateClientConfig = compiler.typeAliasDeclaration({ 38 + comment: [ 39 + 'The `createClientConfig()` function will be called on client initialization', 40 + "and the returned object will become the client's initial configuration.", 41 + '', 42 + 'You may want to initialize your client this way instead of calling', 43 + "`setConfig()`. This is useful for example if you're using Next.js", 44 + 'to ensure your client always has the correct values.', 45 + ], 46 + exportType: true, 47 + name: 'CreateClientConfig', 48 + type: compiler.functionTypeNode({ 49 + parameters: [ 50 + compiler.parameterDeclaration({ 51 + name: 'override', 52 + required: false, 53 + type: compiler.typeReferenceNode({ 54 + typeArguments: [ 55 + compiler.typeIntersectionNode({ 56 + types: [defaultClientOptionsType, tType], 57 + }), 58 + ], 59 + typeName: configType.name, 60 + }), 61 + }), 62 + ], 63 + returnType: compiler.typeReferenceNode({ 64 + typeArguments: [ 65 + compiler.typeIntersectionNode({ 66 + types: [ 67 + compiler.typeReferenceNode({ 68 + typeArguments: [defaultClientOptionsType], 69 + typeName: 'Required', 70 + }), 71 + tType, 72 + ], 73 + }), 74 + ], 75 + typeName: configType.name, 76 + }), 77 + }), 78 + typeParameters: [ 79 + { 80 + default: compiler.typeReferenceNode({ typeName: clientOptions.name }), 81 + extends: defaultClientOptionsType, 82 + name: 'T', 83 + }, 84 + ], 85 + }); 86 + 87 + file.add(typeCreateClientConfig); 88 + }; 89 + 6 90 export const handler: PluginHandler = ({ context, plugin }) => { 7 91 const file = context.createFile({ 8 92 exportFromIndex: plugin.exportFromIndex, 9 93 id: clientId, 10 94 path: plugin.output, 11 95 }); 12 - const clientOutput = file.nameWithoutExtension(); 13 96 14 97 const clientModule = clientModulePath({ 15 98 config: context.config, 16 - sourceOutput: clientOutput, 99 + sourceOutput: file.nameWithoutExtension(), 17 100 }); 18 101 const createClient = file.import({ 19 102 module: clientModule, ··· 22 105 const createConfig = file.import({ 23 106 module: clientModule, 24 107 name: 'createConfig', 108 + }); 109 + const clientOptions = file.import({ 110 + asType: true, 111 + module: file.relativePathToFile({ context, id: typesId }), 112 + name: 'ClientOptions', 25 113 }); 26 114 27 115 const createClientConfig = plugin.runtimeConfigPath ··· 49 137 }) 50 138 : undefined, 51 139 ], 140 + types: [compiler.typeReferenceNode({ typeName: clientOptions.name })], 52 141 }), 53 142 ]; 143 + 144 + createClientConfigType({ 145 + context, 146 + }); 54 147 55 148 const statement = compiler.constVariable({ 56 149 exportConst: true,
+11
packages/openapi-ts/src/plugins/@hey-api/client-core/utils.ts
··· 5 5 6 6 type Plugins = Required<Config>['plugins']; 7 7 8 + export const getClientBaseUrlKey = (config: Config) => { 9 + const client = getClientPlugin(config); 10 + if ( 11 + client.name === '@hey-api/client-axios' || 12 + client.name === '@hey-api/client-nuxt' 13 + ) { 14 + return 'baseURL'; 15 + } 16 + return 'baseUrl'; 17 + }; 18 + 8 19 export const getClientPlugin = ( 9 20 config: Config, 10 21 ): Required<Plugins>[PluginClientNames] => {
+1
packages/openapi-ts/src/plugins/@hey-api/client-fetch/config.ts
··· 3 3 import type { Config } from './types'; 4 4 5 5 export const defaultConfig: Plugin.Config<Config> = { 6 + _dependencies: ['@hey-api/typescript'], 6 7 _handler: handler, 7 8 _handlerLegacy: () => {}, 8 9 _tags: ['client'],
+1
packages/openapi-ts/src/plugins/@hey-api/client-next/config.ts
··· 3 3 import type { Config } from './types'; 4 4 5 5 export const defaultConfig: Plugin.Config<Config> = { 6 + _dependencies: ['@hey-api/typescript'], 6 7 _handler: handler, 7 8 _handlerLegacy: () => {}, 8 9 _tags: ['client'],
+1
packages/openapi-ts/src/plugins/@hey-api/client-nuxt/config.ts
··· 3 3 import type { Config } from './types'; 4 4 5 5 export const defaultConfig: Plugin.Config<Config> = { 6 + _dependencies: ['@hey-api/typescript'], 6 7 _handler: handler, 7 8 _handlerLegacy: () => {}, 8 9 _tags: ['client'],
+55
packages/openapi-ts/src/plugins/@hey-api/typescript/plugin.ts
··· 12 12 import { fieldName } from '../../shared/utils/case'; 13 13 import { operationIrRef } from '../../shared/utils/ref'; 14 14 import type { Plugin } from '../../types'; 15 + import { getClientBaseUrlKey } from '../client-core/utils'; 15 16 import { typesId } from './ref'; 16 17 import type { Config } from './types'; 17 18 ··· 1019 1020 return type; 1020 1021 }; 1021 1022 1023 + const createClientOptions = ({ 1024 + context, 1025 + }: { 1026 + context: IR.Context; 1027 + plugin: Plugin.Instance<Config>; 1028 + }) => { 1029 + const file = context.file({ id: typesId })!; 1030 + 1031 + const clientOptions = file.identifier({ 1032 + $ref: 'ClientOptions', 1033 + create: true, 1034 + namespace: 'type', 1035 + }); 1036 + 1037 + if (!clientOptions.name) { 1038 + return; 1039 + } 1040 + 1041 + const typeClientOptions = compiler.typeAliasDeclaration({ 1042 + exportType: true, 1043 + name: clientOptions.name, 1044 + type: compiler.typeInterfaceNode({ 1045 + properties: [ 1046 + { 1047 + name: getClientBaseUrlKey(context.config), 1048 + type: compiler.typeUnionNode({ 1049 + types: [ 1050 + compiler.literalTypeNode({ 1051 + literal: compiler.stringLiteral({ text: '/' }), 1052 + }), 1053 + compiler.typeIntersectionNode({ 1054 + types: [ 1055 + compiler.keywordTypeNode({ keyword: 'string' }), 1056 + ts.factory.createTypeLiteralNode([]), 1057 + ], 1058 + }), 1059 + ], 1060 + }), 1061 + }, 1062 + ], 1063 + useLegacyResolution: false, 1064 + }), 1065 + }); 1066 + 1067 + file.add(typeClientOptions); 1068 + }; 1069 + 1022 1070 export const handler: Plugin.Handler<Config> = ({ context, plugin }) => { 1023 1071 context.createFile({ 1024 1072 exportFromIndex: plugin.exportFromIndex, 1025 1073 id: typesId, 1026 1074 identifierCase: plugin.identifierCase, 1027 1075 path: plugin.output, 1076 + }); 1077 + 1078 + context.subscribe('before', () => { 1079 + createClientOptions({ 1080 + context, 1081 + plugin, 1082 + }); 1028 1083 }); 1029 1084 1030 1085 context.subscribe('schema', ({ $ref, schema }) => {
-9
packages/openapi-ts/src/plugins/@tanstack/query-core/client.ts
··· 1 - import { getConfig } from '../../../utils/config'; 2 - import { getClientPlugin } from '../../@hey-api/client-core/utils'; 3 - 4 - // TODO: this function could be moved so other plugins can reuse it 5 - export const getClientBaseUrlKey = () => { 6 - const config = getConfig(); 7 - const client = getClientPlugin(config); 8 - return client.name === '@hey-api/client-axios' ? 'baseURL' : 'baseUrl'; 9 - };
+7 -10
packages/openapi-ts/src/plugins/@tanstack/query-core/plugin-legacy.ts
··· 20 20 import type { Files } from '../../../types/utils'; 21 21 import { getConfig, isLegacyClient } from '../../../utils/config'; 22 22 import { transformServiceName } from '../../../utils/transform'; 23 - import { getClientPlugin } from '../../@hey-api/client-core/utils'; 23 + import { 24 + getClientBaseUrlKey, 25 + getClientPlugin, 26 + } from '../../@hey-api/client-core/utils'; 24 27 import { 25 28 generateImport, 26 29 operationDataTypeName, ··· 101 104 const queryOptionsFn = 'queryOptions'; 102 105 const TOptionsType = 'TOptions'; 103 106 104 - const getClientBaseUrlKey = () => { 105 - const config = getConfig(); 106 - const clientPlugin = getClientPlugin(config); 107 - return clientPlugin.name === '@hey-api/client-axios' ? 'baseURL' : 'baseUrl'; 108 - }; 109 - 110 107 const createInfiniteParamsFunction = ({ 111 108 file, 112 109 }: { ··· 329 326 value: compiler.identifier({ text: 'id' }), 330 327 }, 331 328 { 332 - key: getClientBaseUrlKey(), 329 + key: getClientBaseUrlKey(getConfig()), 333 330 value: compiler.identifier({ 334 - text: `(options?.client ?? _heyApiClient).getConfig().${getClientBaseUrlKey()}`, 331 + text: `(options?.client ?? _heyApiClient).getConfig().${getClientBaseUrlKey(getConfig())}`, 335 332 }), 336 333 }, 337 334 ], ··· 491 488 compiler.typeIntersectionNode({ 492 489 types: [ 493 490 compiler.typeReferenceNode({ 494 - typeName: `Pick<${TOptionsType}, '${getClientBaseUrlKey()}' | 'body' | 'headers' | 'path' | 'query'>`, 491 + typeName: `Pick<${TOptionsType}, '${getClientBaseUrlKey(getConfig())}' | 'body' | 'headers' | 'path' | 'query'>`, 495 492 }), 496 493 compiler.typeInterfaceNode({ 497 494 properties,
+4 -4
packages/openapi-ts/src/plugins/@tanstack/query-core/queryKey.ts
··· 2 2 import { clientApi } from '../../../generate/client'; 3 3 import { hasOperationDataRequired } from '../../../ir/operation'; 4 4 import type { IR } from '../../../ir/types'; 5 + import { getClientBaseUrlKey } from '../../@hey-api/client-core/utils'; 5 6 import { serviceFunctionIdentifier } from '../../@hey-api/sdk/plugin-legacy'; 6 - import { getClientBaseUrlKey } from './client'; 7 7 import type { PluginInstance } from './types'; 8 8 import { useTypeData } from './useType'; 9 9 ··· 69 69 value: compiler.identifier({ text: 'id' }), 70 70 }, 71 71 { 72 - key: getClientBaseUrlKey(), 72 + key: getClientBaseUrlKey(context.config), 73 73 value: compiler.identifier({ 74 - text: `(options?.client ?? _heyApiClient).getConfig().${getClientBaseUrlKey()}`, 74 + text: `(options?.client ?? _heyApiClient).getConfig().${getClientBaseUrlKey(context.config)}`, 75 75 }), 76 76 }, 77 77 ], ··· 271 271 compiler.typeIntersectionNode({ 272 272 types: [ 273 273 compiler.typeReferenceNode({ 274 - typeName: `Pick<${TOptionsType}, '${getClientBaseUrlKey()}' | 'body' | 'headers' | 'path' | 'query'>`, 274 + typeName: `Pick<${TOptionsType}, '${getClientBaseUrlKey(context.config)}' | 'body' | 'headers' | 'path' | 'query'>`, 275 275 }), 276 276 compiler.typeInterfaceNode({ 277 277 properties,