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

Configure Feed

Select the types of activity you want to include in your feed.

feat: inline useQuery in generated hooks to preserve type inference

+144 -38
+14
packages/openapi-ts-tests/main/test/plugins.test.ts
··· 66 66 }, 67 67 { 68 68 config: createConfig({ 69 + output: 'useQuery-disabled', 70 + plugins: [ 71 + { 72 + name: '@tanstack/react-query', 73 + useQuery: false, 74 + }, 75 + '@hey-api/client-fetch', 76 + ], 77 + }), 78 + description: 79 + 'generate Fetch API client with TanStack React Query plugin with useQuery disabled', 80 + }, 81 + { 82 + config: createConfig({ 69 83 output: 'fetch', 70 84 plugins: ['@tanstack/solid-query', '@hey-api/client-fetch'], 71 85 }),
+1 -1
packages/openapi-ts/src/plugins/@tanstack/preact-query/config.ts
··· 85 85 plugin.config.useQuery = context.valueToObject({ 86 86 defaultValue: { 87 87 case: plugin.config.case ?? 'camelCase', 88 - enabled: false, 88 + enabled: true, 89 89 name: 'use{{name}}Query', 90 90 }, 91 91 mappers: {
+1 -1
packages/openapi-ts/src/plugins/@tanstack/preact-query/types.ts
··· 339 339 * - `string` or `function`: Shorthand for `{ name: string | function }` 340 340 * - `object`: Full configuration object 341 341 * 342 - * @default false 342 + * @default true 343 343 */ 344 344 useQuery?: 345 345 | boolean
+26 -8
packages/openapi-ts/src/plugins/@tanstack/query-core/v5/infiniteQueryOptions.ts
··· 139 139 const typeData = useTypeData({ operation, plugin }); 140 140 const typeResponse = useTypeResponse({ operation, plugin }); 141 141 142 + const symbolSkipToken = $(plugin.external(`${plugin.name}.skipToken`)); 143 + 144 + const optsName = 'opts'; 145 + 142 146 const symbolQueryKeyType = plugin.referenceSymbol({ 143 147 category: 'type', 144 148 resource: 'QueryKey', ··· 180 184 ) 181 185 .call( 182 186 $.object() 183 - .spread('options') 187 + .spread(optsName) 184 188 .spread('params') 185 189 .prop('signal', $('signal')) 186 190 .prop('throwOnError', $.literal(true)), ··· 216 220 statements.push($.const().object('data').assign(awaitSdkFn), $.return('data')); 217 221 } 218 222 223 + const asyncQueryFn = $.func() 224 + .async() 225 + .param((p) => p.object('pageParam', 'queryKey', 'signal')) 226 + .do(...statements); 227 + 228 + const paramType = $.type.or(typeData, $.type.query(symbolSkipToken)); 229 + 219 230 const symbolInfiniteQueryOptionsFn = plugin.symbol( 220 231 applyNaming(operation.id, plugin.config.infiniteQueryOptions), 221 232 ); ··· 224 235 .$if(plugin.config.comments && createOperationComment(operation), (c, v) => c.doc(v)) 225 236 .assign( 226 237 $.func() 227 - .param('options', (p) => p.required(isRequiredOptions).type(typeData)) 238 + .param('options', (p) => p.required(isRequiredOptions).type(paramType)) 228 239 .do( 240 + $.const(optsName).assign( 241 + $.ternary($('options').neq(symbolSkipToken)).do($('options')).otherwise($('undefined')), 242 + ), 229 243 $.return( 230 244 $(symbolInfiniteQueryOptions) 231 245 .call( 232 246 $.object() 233 247 .pretty() 234 - .hint('@ts-ignore') 235 248 .prop( 236 249 'queryFn', 237 - $.func() 238 - .async() 239 - .param((p) => p.object('pageParam', 'queryKey', 'signal')) 240 - .do(...statements), 250 + $.ternary($('options').eq(symbolSkipToken)) 251 + .do(symbolSkipToken) 252 + .otherwise(asyncQueryFn), 253 + ) 254 + .prop( 255 + 'queryKey', 256 + $(symbolInfiniteQueryKey).call( 257 + isRequiredOptions ? $(optsName).as(typeData) : $(optsName), 258 + ), 241 259 ) 242 - .prop('queryKey', $(symbolInfiniteQueryKey).call('options')) 243 260 .$if(handleMeta(plugin, operation, 'infiniteQueryOptions'), (o, v) => 244 261 o.prop('meta', v), 245 262 ), 246 263 ) 264 + .hint('@ts-ignore') 247 265 .generics( 248 266 typeResponse, 249 267 useTypeError({ operation, plugin }),
+30 -8
packages/openapi-ts/src/plugins/@tanstack/query-core/v5/plugin.ts
··· 1 - import type { PluginHandler } from '../types'; 1 + import type { PluginHandler, PluginInstance } from '../types'; 2 2 import { createInfiniteQueryOptions } from './infiniteQueryOptions'; 3 3 import { createMutationOptions } from './mutationOptions'; 4 4 import { createQueryOptions } from './queryOptions'; 5 5 import { createUseMutation } from './useMutation'; 6 6 import { createUseQuery } from './useQuery'; 7 7 8 + const createQueryStyleNames = new Set<PluginInstance['name']>([ 9 + '@tanstack/angular-query-experimental', 10 + '@tanstack/solid-query', 11 + '@tanstack/svelte-query', 12 + ]); 13 + 14 + const getMutationOptionsType = (name: PluginInstance['name']) => 15 + createQueryStyleNames.has(name) ? 'MutationOptions' : 'UseMutationOptions'; 16 + 17 + const getQueryOptionsType = (name: PluginInstance['name']) => 18 + createQueryStyleNames.has(name) ? 'CreateQueryOptions' : 'UseQueryOptions'; 19 + 8 20 export const handlerV5: PluginHandler = ({ plugin }) => { 9 21 plugin.symbol('DefaultError', { 10 22 external: plugin.name, ··· 14 26 external: plugin.name, 15 27 kind: 'type', 16 28 }); 17 - const mutationsType = 18 - plugin.name === '@tanstack/angular-query-experimental' || 19 - plugin.name === '@tanstack/svelte-query' || 20 - plugin.name === '@tanstack/solid-query' 21 - ? 'MutationOptions' 22 - : 'UseMutationOptions'; 23 - plugin.symbol(mutationsType, { 29 + plugin.symbol(getMutationOptionsType(plugin.name), { 24 30 external: plugin.name, 25 31 kind: 'type', 26 32 meta: { ··· 39 45 plugin.symbol('useQuery', { 40 46 external: plugin.name, 41 47 }); 48 + plugin.symbol(getQueryOptionsType(plugin.name), { 49 + external: plugin.name, 50 + kind: 'type', 51 + meta: { 52 + category: 'external', 53 + resource: `${plugin.name}.QueryObserverOptions`, 54 + }, 55 + }); 56 + plugin.symbol('skipToken', { 57 + external: plugin.name, 58 + meta: { 59 + category: 'external', 60 + resource: `${plugin.name}.skipToken`, 61 + }, 62 + }); 63 + 42 64 plugin.symbol('AxiosError', { 43 65 external: 'axios', 44 66 kind: 'type',
+25 -9
packages/openapi-ts/src/plugins/@tanstack/query-core/v5/queryOptions.ts
··· 55 55 56 56 const typeResponse = useTypeResponse({ operation, plugin }); 57 57 58 + const symbolSkipToken = $(plugin.external(`${plugin.name}.skipToken`)); 59 + 60 + const optsName = 'opts'; 61 + 58 62 const awaitSdkFn = $.lazy((ctx) => 59 63 ctx 60 64 .access( ··· 66 70 ) 67 71 .call( 68 72 $.object() 69 - .spread(optionsParamName) 73 + .spread(optsName) 70 74 .spread($('queryKey').attr(0)) 71 75 .prop('signal', $('signal')) 72 76 .prop('throwOnError', $.literal(true)), ··· 81 85 statements.push($.const().object('data').assign(awaitSdkFn), $.return('data')); 82 86 } 83 87 88 + const asyncQueryFn = $.func() 89 + .async() 90 + .param((p) => p.object('queryKey', 'signal')) 91 + .do(...statements); 92 + 93 + const typeData = useTypeData({ operation, plugin }); 94 + 95 + const optsForQueryKey = isRequiredOptions ? $(optsName).as(typeData) : $(optsName); 96 + 84 97 const queryOptionsObj = $.object() 85 98 .pretty() 86 99 .prop( 87 100 'queryFn', 88 - $.func() 89 - .async() 90 - .param((p) => p.object('queryKey', 'signal')) 91 - .do(...statements), 101 + $.ternary($(optionsParamName).eq(symbolSkipToken)) 102 + .do(symbolSkipToken) 103 + .otherwise(asyncQueryFn), 92 104 ) 93 - .prop('queryKey', $(symbolQueryKey).call(optionsParamName)) 105 + .prop('queryKey', $(symbolQueryKey).call(optsForQueryKey)) 94 106 .$if(handleMeta(plugin, operation, 'queryOptions'), (o, v) => o.prop('meta', v)); 107 + const paramType = $.type.or(typeData, $.type.query(symbolSkipToken)); 95 108 96 109 const symbolQueryOptionsFn = plugin.symbol( 97 110 applyNaming(operation.id, plugin.config.queryOptions), ··· 112 125 .$if(plugin.config.comments && createOperationComment(operation), (c, v) => c.doc(v)) 113 126 .assign( 114 127 $.func() 115 - .param(optionsParamName, (p) => 116 - p.required(isRequiredOptions).type(useTypeData({ operation, plugin })), 117 - ) 128 + .param(optionsParamName, (p) => p.required(isRequiredOptions).type(paramType)) 118 129 .do( 130 + $.const(optsName).assign( 131 + $.ternary($(optionsParamName).neq(symbolSkipToken)) 132 + .do($(optionsParamName)) 133 + .otherwise($('undefined')), 134 + ), 119 135 $(symbolQueryOptions) 120 136 .call(queryOptionsObj) 121 137 .generics(
+39 -7
packages/openapi-ts/src/plugins/@tanstack/query-core/v5/useQuery.ts
··· 11 11 import type { PluginInstance } from '../types'; 12 12 13 13 const optionsParamName = 'options'; 14 + const queryOptionsKey = 'queryOptions'; 15 + const sdkOptionsName = 'sdkOptions'; 14 16 15 17 export const createUseQuery = ({ 16 18 operation, ··· 27 29 return; 28 30 } 29 31 32 + const symbolUseQuery = plugin.external(`${plugin.name}.useQuery`); 30 33 const symbolUseQueryFn = plugin.symbol(applyNaming(operation.id, plugin.config.useQuery)); 31 - 32 - const symbolUseQuery = plugin.external(`${plugin.name}.useQuery`); 33 34 34 35 const isRequiredOptions = isOperationOptionsRequired({ 35 36 context: plugin.context, ··· 37 38 }); 38 39 const typeData = useTypeData({ operation, plugin }); 39 40 41 + const symbolSkipToken = $(plugin.external(`${plugin.name}.skipToken`)); 42 + const sdkParamType = $.type.or(typeData, $.type.query(symbolSkipToken)); 43 + 40 44 const symbolQueryOptionsFn = plugin.referenceSymbol({ 41 45 category: 'hook', 42 46 resource: 'operation', ··· 44 48 role: 'queryOptions', 45 49 tool: plugin.name, 46 50 }); 51 + 52 + const queryOptionsType = $.type('Partial').generic( 53 + $.type('Omit', (t) => 54 + t.generics( 55 + $(symbolQueryOptionsFn).returnType(), 56 + $.type.or($.type.literal('queryKey'), $.type.literal('queryFn')), 57 + ), 58 + ), 59 + ); 60 + 61 + const mergedParamType = $.type.and( 62 + sdkParamType, 63 + $.type.object().prop(queryOptionsKey, (p) => p.optional().type(queryOptionsType)), 64 + ); 65 + 66 + const func = $.func().param(optionsParamName, (p) => 67 + p.required(isRequiredOptions).type(mergedParamType), 68 + ); 69 + 70 + func.do( 71 + $.if($(optionsParamName).eq(symbolSkipToken)).do( 72 + $(symbolUseQuery).call($(symbolQueryOptionsFn).call(optionsParamName)).return(), 73 + ), 74 + $.const() 75 + .object(queryOptionsKey) 76 + .spread(sdkOptionsName) 77 + .assign(isRequiredOptions ? $(optionsParamName) : $(optionsParamName).coalesce($.object())), 78 + $(symbolUseQuery) 79 + .call($.object().spread($(symbolQueryOptionsFn).call(sdkOptionsName)).spread(queryOptionsKey)) 80 + .return(), 81 + ); 82 + 47 83 const statement = $.const(symbolUseQueryFn) 48 84 .export() 49 85 .$if(plugin.config.comments && createOperationComment(operation), (c, v) => c.doc(v)) 50 - .assign( 51 - $.func() 52 - .param(optionsParamName, (p) => p.required(isRequiredOptions).type(typeData)) 53 - .do($(symbolUseQuery).call($(symbolQueryOptionsFn).call(optionsParamName)).return()), 54 - ); 86 + .assign(func); 55 87 plugin.node(statement); 56 88 };
+1 -1
packages/openapi-ts/src/plugins/@tanstack/react-query/config.ts
··· 85 85 plugin.config.useQuery = context.valueToObject({ 86 86 defaultValue: { 87 87 case: plugin.config.case ?? 'camelCase', 88 - enabled: false, 88 + enabled: true, 89 89 name: 'use{{name}}Query', 90 90 }, 91 91 mappers: {
+1 -1
packages/openapi-ts/src/plugins/@tanstack/react-query/types.ts
··· 339 339 * - `string` or `function`: Shorthand for `{ name: string | function }` 340 340 * - `object`: Full configuration object 341 341 * 342 - * @default false 342 + * @default true 343 343 */ 344 344 useQuery?: 345 345 | boolean
+6 -2
packages/openapi-ts/src/ts-dsl/expr/call.ts
··· 7 7 import { ArgsMixin } from '../mixins/args'; 8 8 import { AsMixin } from '../mixins/as'; 9 9 import { ExprMixin } from '../mixins/expr'; 10 + import { HintMixin } from '../mixins/hint'; 10 11 import { SpreadMixin } from '../mixins/spread'; 11 12 import { TypeArgsMixin } from '../mixins/type-args'; 12 13 import { f } from '../utils/factories'; ··· 15 16 export type CallCallee = NodeName | MaybeTsDsl<ts.Expression>; 16 17 export type CallCtor = (callee: CallCallee, ...args: CallArgs) => CallTsDsl; 17 18 18 - const Mixed = ArgsMixin(AsMixin(ExprMixin(SpreadMixin(TypeArgsMixin(TsDsl<ts.CallExpression>))))); 19 + const Mixed = ArgsMixin( 20 + AsMixin(ExprMixin(HintMixin(SpreadMixin(TypeArgsMixin(TsDsl<ts.CallExpression>))))), 21 + ); 19 22 20 23 export class CallTsDsl extends Mixed { 21 24 readonly '~dsl' = 'CallTsDsl'; ··· 34 37 } 35 38 36 39 override toAst() { 37 - return ts.factory.createCallExpression( 40 + const node = ts.factory.createCallExpression( 38 41 this.$node(this._callee), 39 42 this.$generics(), 40 43 this.$args(), 41 44 ); 45 + return this.$hint(node); 42 46 } 43 47 } 44 48