diff --git a/packages/core/src/utils/URLPath.ts b/packages/core/src/utils/URLPath.ts index 57dbd2a075..8fa69abf8a 100644 --- a/packages/core/src/utils/URLPath.ts +++ b/packages/core/src/utils/URLPath.ts @@ -1,6 +1,6 @@ import { camelCase, camelCaseTransformMerge } from 'change-case' -type URLObject = { +export type URLObject = { url: string params?: Record } diff --git a/packages/react-template/src/components/Function.test.tsx b/packages/react-template/src/components/Function.test.tsx index 9f155bcac9..5412c0083d 100644 --- a/packages/react-template/src/components/Function.test.tsx +++ b/packages/react-template/src/components/Function.test.tsx @@ -81,6 +81,19 @@ describe('', () => { `), ) }) + + test('render ArrowFunction SingleLine', async () => { + const Component = () => { + return ( + + 2; + + ) + } + const { output } = render() + + expect(await format(output)).toMatch(await format(`export const getData = async (): Promise => 2;`)) + }) // test('render Function ServerComponent(beta)', async () => { // const Component = async () => { // const data = await Promise.resolve('return 2;') diff --git a/packages/react-template/src/components/Function.tsx b/packages/react-template/src/components/Function.tsx index c43ad3e8a7..c5fa4cefad 100644 --- a/packages/react-template/src/components/Function.tsx +++ b/packages/react-template/src/components/Function.tsx @@ -56,7 +56,21 @@ export function Function({ name, export: canExport, async, generics, params, ret ) } -export function ArrowFunction({ name, export: canExport, async, generics, params, returnType, JSDoc, children }: Props): React.ReactNode { +type ArrowFunctionProps = Props & { + singleLine?: boolean +} + +export function ArrowFunction({ + name, + export: canExport, + async, + generics, + params, + returnType, + JSDoc, + singleLine, + children, +}: ArrowFunctionProps): React.ReactNode { return ( <> {JSDoc?.comments && ( @@ -84,11 +98,22 @@ export function ArrowFunction({ name, export: canExport, async, generics, params {'>'} )} - {' => {'} -
- {children} -
- {'};'} + {singleLine && ( + <> + {' => '} + {children} + + )} + + {!singleLine && ( + <> + {' => {'} +
+ {children} +
+ {'};'} + + )} ) } diff --git a/packages/swagger-client/package.json b/packages/swagger-client/package.json index b40c28dac7..5f3cc5fed0 100644 --- a/packages/swagger-client/package.json +++ b/packages/swagger-client/package.json @@ -80,7 +80,8 @@ "@kubb/swagger": "workspace:*", "@kubb/swagger-ts": "workspace:*", "@kubb/ts-codegen": "workspace:*", - "change-case": "^4.1.2" + "change-case": "^4.1.2", + "react": "^18.2.0" }, "devDependencies": { "@kubb/eslint-config": "workspace:*", @@ -93,13 +94,7 @@ "typescript": "^5.2.2" }, "peerDependencies": { - "axios": "^1.4.0", - "react": "^18.2.0" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - } + "axios": "^1.4.0" }, "packageManager": "pnpm@8.3.0", "engines": { diff --git a/packages/swagger-client/src/builders/ClientBuilder.tsx b/packages/swagger-client/src/builders/ClientBuilder.tsx index 9970a2ea1c..886f25841f 100644 --- a/packages/swagger-client/src/builders/ClientBuilder.tsx +++ b/packages/swagger-client/src/builders/ClientBuilder.tsx @@ -69,7 +69,7 @@ export class ClientBuilder extends OasBuilder { params={params} returnType={dataReturnType === 'data' ? `ResponseConfig<${clientGenerics[0]}>["data"]` : `ResponseConfig<${clientGenerics[0]}>`} method={method} - url={new URLPath(operation.path).template} + path={new URLPath(operation.path)} withParams={!!schemas.queryParams?.name} withData={!!schemas.request?.name} withHeaders={!!schemas.headerParams?.name} diff --git a/packages/swagger-client/src/components/ClientFunction.tsx b/packages/swagger-client/src/components/ClientFunction.tsx index 0984280d6a..a783d49ec1 100644 --- a/packages/swagger-client/src/components/ClientFunction.tsx +++ b/packages/swagger-client/src/components/ClientFunction.tsx @@ -2,24 +2,27 @@ import React from 'react' import { createIndent, Function } from '@kubb/react-template' +import type { URLPath } from '@kubb/core' import type { HttpMethod } from '@kubb/swagger' import type { ReactNode } from 'react' import type { Options as PluginOptions } from '../types' type Props = { name: string + params: string generics: string[] returnType: string - params: string + comments: string[] + children?: ReactNode + + // props Client method: HttpMethod - url: string + path: URLPath clientGenerics: string[] dataReturnType: PluginOptions['dataReturnType'] withParams?: boolean withData?: boolean withHeaders?: boolean - comments: string[] - children?: ReactNode } export function ClientFunction({ @@ -28,7 +31,7 @@ export function ClientFunction({ returnType, params, method, - url, + path, clientGenerics, withParams, withData, @@ -39,7 +42,7 @@ export function ClientFunction({ }: Props): React.ReactNode { const clientParams = [ `method: "${method}"`, - `url: ${url}`, + `url: ${path.template}`, withParams ? 'params' : undefined, withData ? 'data' : undefined, withHeaders ? 'headers: { ...headers, ...options.headers }' : undefined, @@ -48,21 +51,27 @@ export function ClientFunction({ const clientOptions = `${createIndent(4)}${clientParams.join(`,\n${createIndent(4)}`)}` + if (dataReturnType === 'full') { + return ( + + {` + return client<${clientGenerics.join(', ')}>({ + ${createIndent(4)}${clientParams.join(`,\n${createIndent(4)}`)} + });`} + {children} + + ) + } + return ( - {dataReturnType === 'data' && - ` + {` const { data: resData } = await client<${clientGenerics.join(', ')}>({ ${clientOptions} }); return resData;`} - {dataReturnType === 'full' && - ` -return client<${clientGenerics.join(', ')}>({ -${createIndent(4)}${clientParams.join(`,\n${createIndent(4)}`)} -});`} {children} ) diff --git a/packages/swagger-tanstack-query/package.json b/packages/swagger-tanstack-query/package.json index 0367a240dd..63a4a6923d 100644 --- a/packages/swagger-tanstack-query/package.json +++ b/packages/swagger-tanstack-query/package.json @@ -56,12 +56,15 @@ "@kubb/swagger-client": "workspace:*", "@kubb/swagger-ts": "workspace:*", "@kubb/ts-codegen": "workspace:*", - "change-case": "^4.1.2" + "change-case": "^4.1.2", + "@kubb/react-template": "workspace:*", + "react": "^18.2.0" }, "devDependencies": { "@kubb/eslint-config": "workspace:*", "@kubb/ts-config": "workspace:*", "@kubb/tsup-config": "workspace:*", + "@types/react": "^18.2.25", "eslint": "^8.51.0", "tsup": "^7.2.0", "typescript": "^5.2.2" diff --git a/packages/swagger-tanstack-query/src/builders/QueryBuilder.ts b/packages/swagger-tanstack-query/src/builders/QueryBuilder.tsx similarity index 94% rename from packages/swagger-tanstack-query/src/builders/QueryBuilder.ts rename to packages/swagger-tanstack-query/src/builders/QueryBuilder.tsx index 83718b2786..b3d3f1ff38 100644 --- a/packages/swagger-tanstack-query/src/builders/QueryBuilder.ts +++ b/packages/swagger-tanstack-query/src/builders/QueryBuilder.tsx @@ -1,13 +1,15 @@ /* eslint- @typescript-eslint/explicit-module-boundary-types */ import { combineCodes, createFunctionParams, createJSDocBlockText, URLPath } from '@kubb/core' +import { render } from '@kubb/react-template' import { getComments, getDataParams, getParams, OasBuilder } from '@kubb/swagger' import { camelCase, pascalCase } from 'change-case' +import { QueryKeyFunction } from '../components/index.ts' + import type { Import } from '@kubb/core' import type { Operation, OperationSchemas, Resolver } from '@kubb/swagger' -import type { Options as PluginOptions } from '../types' -import type { Framework, FrameworkImports } from '../types.ts' +import type { Framework, FrameworkImports, Options as PluginOptions } from '../types.ts' type BaseConfig = { dataReturnType: PluginOptions['dataReturnType'] @@ -27,7 +29,7 @@ type QueryConfig = BaseConfig & { type MutationConfig = BaseConfig type Config = QueryConfig | MutationConfig -type QueryResult = { code: string; name: string } +type QueryResult = { code: string; name: string; imports: Import[] } export class QueryBuilder extends OasBuilder { private get queryKey(): QueryResult { @@ -35,8 +37,7 @@ export class QueryBuilder extends OasBuilder { const codes: string[] = [] const name = camelCase(`${operation.getOperationId()}QueryKey`) - - const paramsData = [ + const params = createFunctionParams([ ...getDataParams(schemas.pathParams, { typed: true, override: framework === 'vue' ? (item) => ({ ...item, type: `MaybeRef<${item.type}>` }) : undefined, @@ -47,21 +48,22 @@ export class QueryBuilder extends OasBuilder { enabled: !!schemas.queryParams?.name, required: !!schemas.queryParams?.schema.required?.length, }, - ] - const params = createFunctionParams(paramsData) + ]) - const result = [ - new URLPath(operation.path).toObject({ - type: 'template', - stringify: true, - replacer: framework === 'vue' ? (pathParam) => `unref(${pathParam})` : undefined, - }), - schemas.queryParams?.name ? `...(params ? [params] : [])` : undefined, - ].filter(Boolean) + const FrameworkComponent = QueryKeyFunction[framework] + + const Component = () => { + return ( + <> + + + ) + } + const { output, imports } = render() - codes.push(`export const ${name} = (${params}) => [${result.join(',')}] as const;`) + codes.push(output) - return { code: combineCodes(codes), name } + return { code: combineCodes(codes), name, imports } } private get queryOptions(): QueryResult { @@ -142,7 +144,7 @@ export function ${name} <${generics.join(', ')}>(${params}): ${frameworkImports. }; `) - return { code: combineCodes(codes), name } + return { code: combineCodes(codes), name, imports: [] } } private get query(): QueryResult { @@ -229,7 +231,7 @@ export function ${name} <${generics.join(',')}>(${params}): ${frameworkImports.q }; `) - return { code: combineCodes(codes), name } + return { code: combineCodes(codes), name, imports: [] } } //infinite @@ -319,7 +321,7 @@ export function ${name} <${generics.join(', ')}>(${params}): ${frameworkImports. }; `) - return { code: combineCodes(codes), name } + return { code: combineCodes(codes), name, imports: [] } } private get queryInfinite(): QueryResult { @@ -408,7 +410,7 @@ export function ${name} <${generics.join(',')}>(${params}): ${frameworkImports.q }; `) - return { code: combineCodes(codes), name } + return { code: combineCodes(codes), name, imports: [] } } private get mutation(): QueryResult { @@ -492,7 +494,7 @@ export function ${name} <${generics.join(',')}>(${params}): ${frameworkImports.m }; `) - return { code: combineCodes(codes), name } + return { code: combineCodes(codes), name, imports: [] } } configure(config: Config): this { @@ -532,7 +534,7 @@ export function ${name} <${generics.join(',')}>(${params}): ${frameworkImports.m return codes.join('\n') } - imports(type: 'query' | 'mutation'): Import[] { - return [] + imports(): Import[] { + return [...this.queryKey.imports] } } diff --git a/packages/swagger-tanstack-query/src/builders/index.ts b/packages/swagger-tanstack-query/src/builders/index.ts index 8959d4866a..2973a0fd87 100644 --- a/packages/swagger-tanstack-query/src/builders/index.ts +++ b/packages/swagger-tanstack-query/src/builders/index.ts @@ -1 +1 @@ -export * from './QueryBuilder.ts' +export * from './QueryBuilder.tsx' diff --git a/packages/swagger-tanstack-query/src/components/QueryKeyFunction.tsx b/packages/swagger-tanstack-query/src/components/QueryKeyFunction.tsx new file mode 100644 index 0000000000..ee7d78b1fc --- /dev/null +++ b/packages/swagger-tanstack-query/src/components/QueryKeyFunction.tsx @@ -0,0 +1,58 @@ +import React from 'react' + +import { Function } from '@kubb/react-template' + +import type { URLObject, URLPath } from '@kubb/core' + +type Props = { + name: string + params: string + // generics: string[] + // returnType: string + // comments: string[] + children?: React.ReactNode + + // props QueryKey + path: URLPath + withParams: boolean +} + +function QueryKeyFunctionBase({ name, params, path, withParams, children }: Props): React.ReactNode { + const result = [ + path.toObject({ + type: 'template', + stringify: true, + }), + withParams ? `...(params ? [params] : [])` : undefined, + ].filter(Boolean) + + return ( + + {children ? children : `[${result.join(',')}] as const;`} + + ) +} + +function QueryKeyFunctionVue({ name, params, path, withParams }: Props): React.ReactNode { + const result = [ + path.toObject({ + type: 'template', + stringify: true, + replacer: (pathParam) => `unref(${pathParam})`, + }), + withParams ? `...(params ? [params] : [])` : undefined, + ].filter(Boolean) + + return ( + + {`[${result.join(',')}] as const;`} + + ) +} + +export const QueryKeyFunction = { + react: QueryKeyFunctionBase, + solid: QueryKeyFunctionBase, + svelte: QueryKeyFunctionBase, + vue: QueryKeyFunctionVue, +} as const diff --git a/packages/swagger-tanstack-query/src/components/index.ts b/packages/swagger-tanstack-query/src/components/index.ts new file mode 100644 index 0000000000..fda8ba44bc --- /dev/null +++ b/packages/swagger-tanstack-query/src/components/index.ts @@ -0,0 +1 @@ +export * from './QueryKeyFunction.tsx' diff --git a/packages/swagger-tanstack-query/src/generators/OperationGenerator.ts b/packages/swagger-tanstack-query/src/generators/OperationGenerator.ts index d33a2ebd77..1852b4244d 100644 --- a/packages/swagger-tanstack-query/src/generators/OperationGenerator.ts +++ b/packages/swagger-tanstack-query/src/generators/OperationGenerator.ts @@ -2,7 +2,7 @@ import { getRelativePath } from '@kubb/core' import { OperationGenerator as Generator } from '@kubb/swagger' import { pluginName as swaggerTypescriptPluginName } from '@kubb/swagger-ts' -import { QueryBuilder } from '../builders/QueryBuilder.ts' +import { QueryBuilder } from '../builders/QueryBuilder.tsx' import { pluginName } from '../plugin.ts' import type { File, OptionalPath, PluginContext } from '@kubb/core' @@ -293,13 +293,14 @@ export class OperationGenerator extends Generator { errors = this.resolveErrors(schemas.errors?.map((item) => item.statusCode && { operation, statusCode: item.statusCode }).filter(Boolean)) } - const source = new QueryBuilder(oas).configure({ errors, framework, frameworkImports, operation, schemas, infinite, dataReturnType }).print('query') + const queryBuilder = new QueryBuilder(oas).configure({ errors, framework, frameworkImports, operation, schemas, infinite, dataReturnType }) return { path: hook.filePath, fileName: hook.fileName, - source, + source: queryBuilder.print('query'), imports: [ + ...queryBuilder.imports(), ...this.getQueryImports('query'), { name: 'client', @@ -342,13 +343,14 @@ export class OperationGenerator extends Generator { errors = this.resolveErrors(schemas.errors?.map((item) => item.statusCode && { operation, statusCode: item.statusCode }).filter(Boolean)) } - const source = new QueryBuilder(oas).configure({ errors, framework, frameworkImports, operation, schemas, dataReturnType }).print('mutation') + const queryBuilder = new QueryBuilder(oas).configure({ errors, framework, frameworkImports, operation, schemas, dataReturnType }) return { path: hook.filePath, fileName: hook.fileName, - source, + source: queryBuilder.print('mutation'), imports: [ + ...queryBuilder.imports(), ...this.getQueryImports('mutate'), { name: 'client', diff --git a/packages/swagger-tanstack-query/src/index.ts b/packages/swagger-tanstack-query/src/index.ts index 05a5aa6893..a3d94e76bd 100644 --- a/packages/swagger-tanstack-query/src/index.ts +++ b/packages/swagger-tanstack-query/src/index.ts @@ -5,5 +5,6 @@ export * from './types.ts' export * from './generators/index.ts' export * from './builders/index.ts' +export * from './components/index.ts' export default definePlugin diff --git a/packages/swagger-tanstack-query/tsconfig.json b/packages/swagger-tanstack-query/tsconfig.json index afd28829e4..5047c58163 100644 --- a/packages/swagger-tanstack-query/tsconfig.json +++ b/packages/swagger-tanstack-query/tsconfig.json @@ -59,6 +59,9 @@ ], "@kubb/ts-codegen": [ "../ts-codegen/src/index.ts" + ], + "@kubb/react-template": [ + "../react-template/src/index.ts" ] } }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9ebfdee788..343fc617d7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1203,6 +1203,9 @@ importers: '@kubb/core': specifier: workspace:* version: link:../core + '@kubb/react-template': + specifier: workspace:* + version: link:../react-template '@kubb/swagger': specifier: workspace:* version: link:../swagger @@ -1218,6 +1221,9 @@ importers: change-case: specifier: ^4.1.2 version: 4.1.2 + react: + specifier: ^18.2.0 + version: 18.2.0 devDependencies: '@kubb/eslint-config': specifier: workspace:* @@ -1228,6 +1234,9 @@ importers: '@kubb/tsup-config': specifier: workspace:* version: link:../config/tsup-config + '@types/react': + specifier: ^18.2.25 + version: 18.2.25 eslint: specifier: ^8.51.0 version: 8.51.0