diff --git a/src/generators/generate/generateQueries.ts b/src/generators/generate/generateQueries.ts index a703726..a2cb674 100644 --- a/src/generators/generate/generateQueries.ts +++ b/src/generators/generate/generateQueries.ts @@ -937,10 +937,40 @@ function renderMutation({ ? `${endpointParams}${endpointParams ? "; " : ""}abortController?: AbortController; onUploadProgress?: (progress: { loaded: number; total: number }) => void` : endpointParams; + const isPost = endpoint.method === "post"; + const scopeEnabled = !!resolver.options.mutationScope && !isPost; + const scopePathParams = scopeEnabled + ? mapEndpointParamsToFunctionParams(resolver, endpoint, {}).filter((p) => p.paramType === "Path") + : []; + const isScoped = scopePathParams.length > 0; + + const nonPathEndpointParams = isScoped + ? renderEndpointParams(resolver, endpoint, { + includeFileParam: true, + optionalPathParams: resolver.options.workspaceContext, + modelNamespaceTag: tag, + excludePathParams: true, + }) + : endpointParams; + const nonPathMutationVariablesType = isScoped + ? endpoint.mediaUpload + ? `${nonPathEndpointParams}${nonPathEndpointParams ? "; " : ""}abortController?: AbortController; onUploadProgress?: (progress: { loaded: number; total: number }) => void` + : nonPathEndpointParams + : mutationVariablesType; + + const pathParamFirstArg = isScoped + ? `{ ${scopePathParams.map((p) => p.name).join(", ")} }: { ${scopePathParams.map((p) => `${p.name}: ${p.type}`).join("; ")} }, ` + : ""; + const mutationOptionsTypeArg = isScoped + ? nonPathMutationVariablesType + ? `, { ${nonPathMutationVariablesType} }` + : "" + : `, { ${mutationVariablesType} }`; + const lines: string[] = []; lines.push(renderQueryJsDocs({ resolver, endpoint, mode: "mutation", tag })); lines.push( - `export const ${getQueryName(endpoint, true)} = (options?: AppMutationOptions${hasMutationEffects ? ` & ${MUTATION_EFFECTS.optionsType}` : ""}${hasAxiosRequestConfig ? `, ${AXIOS_REQUEST_CONFIG_NAME}?: ${AXIOS_REQUEST_CONFIG_TYPE}` : ""}) => {`, + `export const ${getQueryName(endpoint, true)} = (${pathParamFirstArg}options?: AppMutationOptions${hasMutationEffects ? ` & ${MUTATION_EFFECTS.optionsType}` : ""}${hasAxiosRequestConfig ? `, ${AXIOS_REQUEST_CONFIG_NAME}?: ${AXIOS_REQUEST_CONFIG_TYPE}` : ""}) => {`, ); if (hasMutationDefaultOnError) { lines.push(" const queryConfig = OpenApiQueryConfig.useConfig();"); @@ -963,9 +993,15 @@ function renderMutation({ lines.push(""); lines.push(` return ${QUERY_HOOKS.mutation}({`); - const mutationFnArg = endpointParams - ? `{ ${destructuredMutationArgs}${endpoint.mediaUpload ? `${destructuredMutationArgs ? ", " : ""}abortController, onUploadProgress` : ""} }` - : ""; + const nonPathDestructuredArgs = isScoped + ? renderEndpointArgs(resolver, endpoint, { includeFileParam: true, excludePathParams: true }) + : destructuredMutationArgs; + const effectiveParams = isScoped ? nonPathEndpointParams : endpointParams; + const effectiveArgs = isScoped ? nonPathDestructuredArgs : destructuredMutationArgs; + const mutationFnArg = + effectiveParams || endpoint.mediaUpload + ? `{ ${effectiveArgs}${endpoint.mediaUpload ? `${effectiveArgs ? ", " : ""}abortController, onUploadProgress` : ""} }` + : ""; lines.push( ` mutationFn: ${endpoint.mediaUpload ? "async " : ""}(${mutationFnArg}) => ${hasMutationFnBody ? "{ " : ""}`, ); @@ -1015,6 +1051,10 @@ function renderMutation({ lines.push(","); } + if (isScoped) { + const scopePathParamInterpolations = scopePathParams.map((p) => `:\${${p.name}}`).join(""); + lines.push(` scope: { id: \`${getEndpointName(endpoint)}${scopePathParamInterpolations}\` },`); + } lines.push(" ...options,"); if (hasMutationDefaultOnError) { lines.push(" onError: options?.onError ?? queryConfig.onError,"); @@ -1022,8 +1062,10 @@ function renderMutation({ if (hasMutationEffects) { lines.push(" onSuccess: async (resData, variables, onMutateResult, context) => {"); if (updateQueryEndpoints.length > 0) { - if (destructuredVariables.length > 0) { - lines.push(` const { ${destructuredVariables.join(", ")} } = variables;`); + const scopedPathParamNames = new Set(scopePathParams.map((p) => p.name)); + const variablesDestructure = destructuredVariables.filter((v) => !scopedPathParamNames.has(v)); + if (variablesDestructure.length > 0) { + lines.push(` const { ${variablesDestructure.join(", ")} } = variables;`); } lines.push(...renderWorkspaceParamCoalescing({ replacements: workspaceParamReplacements, indent: " " })); lines.push( diff --git a/src/generators/generateCodeFromOpenAPIDoc.test.ts b/src/generators/generateCodeFromOpenAPIDoc.test.ts index 5477eee..11e3e4d 100644 --- a/src/generators/generateCodeFromOpenAPIDoc.test.ts +++ b/src/generators/generateCodeFromOpenAPIDoc.test.ts @@ -167,29 +167,34 @@ describe("generateCodeFromOpenAPIDoc", () => { const queries = files.find(({ fileName }) => fileName === "output/documents/documents.queries.ts")?.content; expect(queries).toBeDefined(); + + // PUT with path params + body: path params become first arg, body stays in mutationFn, scope added expect(queries).toContain( - "export const useUpdate = ({ userId, documentId }: { userId: string; documentId: string; }, options?: AppMutationOptions) => {", + "export const useUpdate = ({ userId, documentId }: { userId: string; documentId: string }, options?: AppMutationOptions) => {", ); - expect(queries).toContain("mutationFn: ( { data } ) =>"); + expect(queries).toContain("mutationFn: ({ data }) =>"); expect(queries).toContain("DocumentsApi.update(userId, documentId, data)"); expect(queries).toContain("scope: { id: `update:${userId}:${documentId}` }"); + // DELETE with only path params: path params become first arg, mutationFn has no args, no TVariables type arg expect(queries).toContain( - "export const useDeleteDocument = ({ userId, documentId }: { userId: string; documentId: string; }, options?: AppMutationOptions) => {", + "export const useDeleteDocument = ({ userId, documentId }: { userId: string; documentId: string }, options?: AppMutationOptions) => {", ); expect(queries).toContain("mutationFn: () =>"); expect(queries).toContain("DocumentsApi.deleteDocument(userId, documentId)"); expect(queries).toContain("scope: { id: `deleteDocument:${userId}:${documentId}` }"); + // POST without path params: no scope, no API change expect(queries).toContain( - "export const useCreate = (options?: AppMutationOptions) => {", + "export const useCreate = (options?: AppMutationOptions) => {", ); expect(queries).not.toContain("scope: { id: `create"); + // POST with path params + media upload: POST is excluded from scoping, no API change expect(queries).toContain( - "export const useUploadAvatar = (options?: AppMutationOptions void }>) => {", + "export const useUploadAvatar = (options?: AppMutationOptions"); + expect(queries).toContain("mutationFn: async ({ userId, data, file, abortController, onUploadProgress }) => {"); expect(queries).toContain("DocumentsApi.uploadAvatar(userId, data)"); expect(queries).not.toContain("scope: { id: `uploadAvatar:${userId}` }"); }); diff --git a/src/generators/templates/partials/query-use-infinite-query.hbs b/src/generators/templates/partials/query-use-infinite-query.hbs deleted file mode 100644 index e9fad55..0000000 --- a/src/generators/templates/partials/query-use-infinite-query.hbs +++ /dev/null @@ -1,23 +0,0 @@ -{{! Js docs }} -{{{genQueryJsDocs endpoint infiniteQuery=true}}} -{{! Infinite query definition}} -export const {{infiniteQueryName endpoint}} = ({{#if (endpointParams endpoint)}}{{#if (endpointParamsAllOptional endpoint excludePageParam=true)}}params: { {{{genEndpointParams endpoint excludePageParam=true}}} } = {}{{else}}{ {{{endpointArgs endpoint excludePageParam=true}}} }: { {{{genEndpointParams endpoint excludePageParam=true}}} }{{/if}}, {{/if}}options?: AppInfiniteQueryOptions{{#if hasAxiosRequestConfig}}, {{axiosRequestConfigName}}?: {{axiosRequestConfigType}}{{/if}}) => { - {{! Use acl check }} - {{#if hasAclCheck}}const { checkAcl } = {{aclCheckHook}}();{{/if}} - {{#if (endpointParams endpoint)}}{{#if (endpointParamsAllOptional endpoint excludePageParam=true)}}const { {{{endpointArgs endpoint excludePageParam=true}}} } = params;{{/if}}{{/if}} - - return {{infiniteQueryHook}}({ - queryKey: keys.{{endpointName endpoint}}Infinite({{#if (endpointParams endpoint)}}{{{endpointArgs endpoint excludePageParam=true}}}{{/if}}), - queryFn: ({ pageParam }) => {{#if hasQueryFnBody}}{ {{/if}} - {{#if hasAclCheck}}{{{genAclCheckCall endpoint}}}{{/if}} - {{#if hasQueryFnBody}}return {{/if}}{{importedEndpointName endpoint}}({{{endpointArgs endpoint replacePageParam=true}}}{{#if hasAxiosRequestConfig}}, {{axiosRequestConfigName}}{{/if}}) - {{#if hasQueryFnBody}} }{{/if}}, - initialPageParam: 1, - getNextPageParam: (response) => { - const pageParam = (response.{{pageParamName}} ?? 1); - const limitParam = response.{{limitParamName}}; - return pageParam * limitParam < response.{{totalItemsName}} ? pageParam + 1 : null; - }, - ...options, - }); -}; diff --git a/src/generators/templates/partials/query-use-mutation.hbs b/src/generators/templates/partials/query-use-mutation.hbs deleted file mode 100644 index 3d22b85..0000000 --- a/src/generators/templates/partials/query-use-mutation.hbs +++ /dev/null @@ -1,55 +0,0 @@ -{{! Js docs }} -{{{genQueryJsDocs endpoint mutation=true}}} -{{! Mutation definition}} -export const {{queryName endpoint mutation=true}} = ({{#if hasMutationScope}}{ {{#each mutationScopePathParams}}{{this.name}}{{#unless @last}}, {{/unless}}{{/each}} }: { {{#each mutationScopePathParams}}{{this.name}}: {{this.type}}; {{/each}} }, {{/if}}options?: AppMutationOptions void{{/if}} }{{/if}}>{{#if hasMutationEffects}} & {{mutationEffectsType}}{{/if}}{{#if hasAxiosRequestConfig}}, {{axiosRequestConfigName}}?: {{axiosRequestConfigType}}{{/if}}) => { - {{! Use acl check }} - {{#if hasAclCheck}}const { checkAcl } = {{aclCheckHook}}();{{/if}} - {{! Use mutation effects }} - {{#if hasMutationEffects}}const { runMutationEffects } = useMutationEffects({ currentModule: {{queriesModuleName}} });{{/if}} - - return {{queryHook}}({ - mutationFn: {{#if endpoint.mediaUpload}}async {{/if}}({{#if hasMutationVariables}} { {{#if hasMutationScope}}{{{endpointArgs endpoint excludePathParams=true includeFileParam=true}}}{{else}}{{{endpointArgs endpoint includeFileParam=true}}}{{/if}}{{#if endpoint.mediaUpload}}, abortController, onUploadProgress{{/if}} } {{/if}}) => {{#if hasMutationFnBody}} { {{/if}} - {{#if hasAclCheck}}{{{genAclCheckCall endpoint}}}{{/if}} - {{#if endpoint.mediaUpload}}const uploadInstructions = await {{importedEndpointName endpoint}}({{{endpointArgs endpoint}}}{{#if hasAxiosRequestConfig}}{{#if (endpointArgs endpoint)}}, {{/if}}{{axiosRequestConfigName}}{{/if}}); - - if (file && uploadInstructions.url) { - const method = (data?.method?.toLowerCase() ?? "put") as 'put' | 'post'; - let dataToSend: File | FormData = file; - if (method === "post") { - dataToSend = new FormData(); - if (uploadInstructions.fields) { - for (const [key, value] of uploadInstructions.fields) { - dataToSend.append(key, value); - } - } - dataToSend.append('file', file); - } - await axios[method](uploadInstructions.url, dataToSend, { - headers: { - "Content-Type": file.type, - }, - signal: abortController?.signal, - onUploadProgress: onUploadProgress - ? (progressEvent) => onUploadProgress({ loaded: progressEvent.loaded, total: progressEvent.total ?? 0 }) - : undefined, - }); - } - - return uploadInstructions; - {{else}} - {{#if hasMutationFnBody}}return {{/if}}{{importedEndpointName endpoint}}({{{endpointArgs endpoint}}}{{#if hasAxiosRequestConfig}}{{#if (endpointArgs endpoint)}}, {{/if}}{{axiosRequestConfigName}}{{/if}}) - {{/if}} - {{#if hasMutationFnBody}} }{{/if}}, - {{#if hasMutationScope}}scope: { id: {{{mutationScopeExpression}}} }, - {{/if}}...options, {{#if hasMutationEffects}} - onSuccess: async (resData, variables, onMutateResult, context) => { - {{! Mutation effects }} - {{#if updateQueryEndpoints}} - {{#if destructuredVariables}}const { {{commaSeparated destructuredVariables }} } = variables;{{/if}} - const updateKeys = [{{#each updateQueryEndpoints as | endpoint |}}keys.{{endpointName endpoint}}({{{endpointArgs endpoint includeOnlyRequiredParams=true}}}), {{/each}}]; - {{/if}} - await runMutationEffects(resData, variables, options{{#if updateQueryEndpoints}}, updateKeys{{/if}}); - options?.onSuccess?.(resData, variables, onMutateResult, context); - },{{/if}} - }); -}; diff --git a/src/generators/templates/partials/query-use-query.hbs b/src/generators/templates/partials/query-use-query.hbs deleted file mode 100644 index 96394f4..0000000 --- a/src/generators/templates/partials/query-use-query.hbs +++ /dev/null @@ -1,17 +0,0 @@ -{{! Js docs }} -{{{genQueryJsDocs endpoint query=true}}} -{{! Query definition}} -export const {{queryName endpoint}} = ({{#if (endpointParams endpoint)}}{{#if (endpointParamsAllOptional endpoint)}}params: { {{{genEndpointParams endpoint}}} } = {}{{else}}{ {{{endpointArgs endpoint}}} }: { {{{genEndpointParams endpoint}}} }{{/if}}, {{/if}}options?: AppQueryOptions{{#if hasAxiosRequestConfig}}, {{axiosRequestConfigName}}?: {{axiosRequestConfigType}}{{/if}}) => { - {{! Use acl check }} - {{#if hasAclCheck}}const { checkAcl } = {{aclCheckHook}}();{{/if}} - {{#if (endpointParams endpoint)}}{{#if (endpointParamsAllOptional endpoint)}}const { {{{endpointArgs endpoint}}} } = params;{{/if}}{{/if}} - - return {{queryHook}}({ - queryKey: keys.{{endpointName endpoint}}({{#if (endpointParams endpoint)}}{{{endpointArgs endpoint}}}{{/if}}), - queryFn: {{#if hasQueryFn}}() => {{#if hasQueryFnBody}}{ {{/if}} - {{#if hasAclCheck}}{{{genAclCheckCall endpoint}}}{{/if}} - {{#if hasQueryFnBody}}return {{/if}}{{importedEndpointName endpoint}}({{{endpointArgs endpoint}}}{{#if hasAxiosRequestConfig}}{{#if (endpointArgs endpoint)}}, {{/if}}{{axiosRequestConfigName}}{{/if}}){{else}}{{importedEndpointName endpoint}}{{/if}} - {{#if hasQueryFnBody}} }{{/if}}, - ...options, - }); -}; diff --git a/src/generators/utils/hbs/hbs.endpoints.utils.ts b/src/generators/utils/hbs/hbs.endpoints.utils.ts deleted file mode 100644 index aa14fac..0000000 --- a/src/generators/utils/hbs/hbs.endpoints.utils.ts +++ /dev/null @@ -1,124 +0,0 @@ -import Handlebars from "handlebars"; -import { OpenAPIV3 } from "openapi-types"; - -import { SchemaResolver } from "@/generators/core/SchemaResolver.class"; -import { Endpoint } from "@/generators/types/endpoint"; -import { GenerateOptions } from "@/generators/types/options"; -import { - endpointParamsAllOptional, - getEndpointBody, - getEndpointName, - getEndpointPath, - getImportedEndpointName, - mapEndpointParamsToFunctionParams, -} from "@/generators/utils/generate/generate.endpoints.utils"; -import { getSchemaDescriptions } from "@/generators/utils/generate/generate.openapi.utils"; -import { isSchemaObject } from "@/generators/utils/openapi-schema.utils"; -import { isParamMediaTypeAllowed } from "@/generators/utils/openapi.utils"; - -enum EndpointsHelpers { - EndpointName = "endpointName", - ImportedEndpointName = "importedEndpointName", - EndpointParams = "endpointParams", - EndpointPath = "endpointPath", - EndpointBody = "endpointBody", - EndpointArgs = "endpointArgs", - EndpointParamDescription = "endpointParamDescription", - EndpointParamsAllOptional = "endpointParamsAllOptional", -} - -export function registerEndpointsHbsHelpers(resolver: SchemaResolver) { - registerEndpointNameHelper(); - registerImportedEndpointNameHelper(resolver.options); - registerEndpointParamsHelper(resolver); - registerEndpointPathHelper(); - registerEndpointBodyHelper(); - registerEndpointArgsHelper(resolver); - registerEndpointParamDescriptionHelper(); - registerEndpointParamsAllOptionalHelper(resolver); -} - -function registerEndpointNameHelper() { - Handlebars.registerHelper(EndpointsHelpers.EndpointName, getEndpointName); -} - -function registerImportedEndpointNameHelper(options: GenerateOptions) { - Handlebars.registerHelper(EndpointsHelpers.ImportedEndpointName, (endpoint: Endpoint) => - getImportedEndpointName(endpoint, options), - ); -} - -function registerEndpointPathHelper() { - Handlebars.registerHelper(EndpointsHelpers.EndpointPath, getEndpointPath); -} - -function registerEndpointBodyHelper() { - Handlebars.registerHelper(EndpointsHelpers.EndpointBody, getEndpointBody); -} - -function registerEndpointParamsHelper(resolver: SchemaResolver) { - Handlebars.registerHelper( - EndpointsHelpers.EndpointParams, - (endpoint: Endpoint, options: { hash: Parameters[2] }) => - mapEndpointParamsToFunctionParams(resolver, endpoint, options.hash), - ); -} - -function registerEndpointArgsHelper(resolver: SchemaResolver) { - Handlebars.registerHelper( - EndpointsHelpers.EndpointArgs, - (endpoint: Endpoint, options: { hash: Parameters[2] }) => - mapEndpointParamsToFunctionParams(resolver, endpoint, options.hash) - .map((param) => param.name) - .join(", "), - ); -} - -function registerEndpointParamsAllOptionalHelper(resolver: SchemaResolver) { - Handlebars.registerHelper( - EndpointsHelpers.EndpointParamsAllOptional, - (endpoint: Endpoint, options: { hash: Parameters[2] }) => - endpointParamsAllOptional(resolver, endpoint, options.hash), - ); -} - -function registerEndpointParamDescriptionHelper() { - Handlebars.registerHelper( - EndpointsHelpers.EndpointParamDescription, - (endpointParam: ReturnType[0]) => { - const strs = [`${endpointParam.paramType} parameter`]; - - const description = endpointParam.parameterObject?.description || endpointParam.bodyObject?.description; - if (description) { - strs.push(description); - } - - let schema: OpenAPIV3.SchemaObject | undefined = undefined; - let mediaTypeObject: OpenAPIV3.MediaTypeObject | undefined = undefined; - if (endpointParam.parameterObject?.schema && isSchemaObject(endpointParam.parameterObject.schema)) { - schema = endpointParam.parameterObject?.schema; - } - if (endpointParam.bodyObject?.content) { - const mediaTypes = Object.keys(endpointParam.bodyObject.content ?? {}); - const matchingMediaType = mediaTypes.find(isParamMediaTypeAllowed); - if (matchingMediaType) { - mediaTypeObject = endpointParam.bodyObject.content[matchingMediaType]; - if (mediaTypeObject.schema && isSchemaObject(mediaTypeObject.schema)) { - schema = mediaTypeObject.schema; - } - } - } - - if (schema) { - const schemaDescriptions = getSchemaDescriptions(schema); - strs.push(...schemaDescriptions); - } - - if (mediaTypeObject?.example) { - strs.push(`Example: \`${mediaTypeObject.example}\``); - } - - return strs.join(". "); - }, - ); -} diff --git a/src/generators/utils/hbs/hbs.partials.utils.ts b/src/generators/utils/hbs/hbs.partials.utils.ts deleted file mode 100644 index e00deb4..0000000 --- a/src/generators/utils/hbs/hbs.partials.utils.ts +++ /dev/null @@ -1,310 +0,0 @@ -import Handlebars from "handlebars"; -import { OpenAPIV3 } from "openapi-types"; - -import { ACL_CHECK_HOOK, CASL_ABILITY_BINDING } from "@/generators/const/acl.const"; -import { MUTATION_EFFECTS, ZOD_EXTENDED } from "@/generators/const/deps.const"; -import { AXIOS_REQUEST_CONFIG_NAME, AXIOS_REQUEST_CONFIG_TYPE } from "@/generators/const/endpoints.const"; -import { QUERIES_MODULE_NAME, QUERY_HOOKS } from "@/generators/const/queries.const"; -import { BLOB_SCHEMA } from "@/generators/const/zod.const"; -import { SchemaResolver } from "@/generators/core/SchemaResolver.class"; -import { DynamicColumnsConfig, DynamicInputsConfig } from "@/generators/types/builder-config"; -import { Endpoint, EndpointParameter } from "@/generators/types/endpoint"; -import { GenerateZodSchemaData, Import } from "@/generators/types/generate"; -import { getAbilityConditionsTypes, hasAbilityConditions } from "@/generators/utils/generate/generate.acl.utils"; -import { - getEndpointBody, - getEndpointConfig, - getEndpointName, - getUpdateQueryEndpoints, - hasEndpointConfig, - mapEndpointParamsToFunctionParams, - requiresBody, -} from "@/generators/utils/generate/generate.endpoints.utils"; -import { getHbsPartialTemplateDelegate } from "@/generators/utils/hbs/hbs-template.utils"; -import { getDestructuredVariables, isInfiniteQuery, isMutation, isQuery } from "@/generators/utils/query.utils"; -import { isNamedZodSchema } from "@/generators/utils/zod-schema.utils"; - -enum PartialsHelpers { - ModelJsDocs = "genModelJsDocs", - Import = "genImport", - EndpointParams = "genEndpointParams", - HasUndefinedEndpointBody = "hasUndefinedEndpointBody", - EndpointConfig = "genEndpointConfig", - EndpointParamParse = "genEndpointParamParse", - QueryKeys = "genQueryKeys", - Query = "genQuery", - Mutation = "genMutation", - InfiniteQuery = "genInfiniteQuery", - QueryJsDocs = "genQueryJsDocs", - CaslAbilityType = "genCaslAbilityType", - CaslAbilityFunction = "genCaslAbilityFunction", - CaslAbilityQuery = "genCaslAbilityQuery", - AclCheckCall = "genAclCheckCall", - InputsConfig = "genInputsConfig", - ColumnsConfig = "genColumnsConfig", -} - -export function registerPartialsHbsHelpers(resolver: SchemaResolver) { - registerGenerateModelJsDocsHelper(); - registerImportHelper(); - registerGenerateEndpointParamsHelper(); - registerHasUndefinedEndpointBodyHelper(resolver); - registerGenerateEndpointConfigHelper(resolver); - registerGenerateEndpointParamParseHelper(); - registerGenerateQueryKeysHelper(resolver); - registerGenerateQueryHelper(resolver); - registerGenerateMutationHelper(resolver); - registerGenerateInfiniteQueryHelper(resolver); - registerGenerateQueryJsDocsHelper(resolver); - registerGenerateCaslAbilityTypeHelper(); - registerGenerateCaslAbilityFunctionHelper(); - registerGenerateCaslAbilityQueryHelper(); - registerGenerateAclCheckCallHelper(); - registerGenerateInputsConfigHelper(); - registerGenerateColumnsConfigHelper(); -} - -function registerGenerateModelJsDocsHelper() { - Handlebars.registerHelper( - PartialsHelpers.ModelJsDocs, - (name: string, zodSchema: GenerateZodSchemaData, tag: string) => - getHbsPartialTemplateDelegate("model-js-docs")({ name, zodSchema, tag }), - ); -} - -function registerImportHelper() { - Handlebars.registerHelper(PartialsHelpers.Import, (genImport: Import) => - getHbsPartialTemplateDelegate("import")({ import: genImport }), - ); -} - -function registerGenerateEndpointParamsHelper() { - Handlebars.registerHelper( - PartialsHelpers.EndpointParams, - (endpoint: Endpoint, options: { hash: Parameters[2] }) => - getHbsPartialTemplateDelegate("endpoint-params")({ endpoint, options }), - ); -} - -function registerHasUndefinedEndpointBodyHelper(resolver: SchemaResolver) { - Handlebars.registerHelper( - PartialsHelpers.HasUndefinedEndpointBody, - (endpoint: Endpoint) => - requiresBody(endpoint) && !getEndpointBody(endpoint) && hasEndpointConfig(endpoint, resolver), - ); -} - -function registerGenerateEndpointConfigHelper(resolver: SchemaResolver) { - Handlebars.registerHelper(PartialsHelpers.EndpointConfig, (endpoint: Endpoint) => { - const endpointConfig = getEndpointConfig(endpoint); - const hasAxiosRequestConfig = resolver.options.axiosRequestConfig; - if (Object.keys(endpointConfig).length === 0) { - return hasAxiosRequestConfig ? AXIOS_REQUEST_CONFIG_NAME : ""; - } - - return getHbsPartialTemplateDelegate("endpoint-config")({ - endpointConfig, - hasAxiosRequestConfig, - hasBlobResponse: endpoint.response === BLOB_SCHEMA, - hasFileDownload: endpoint.mediaDownload, - axiosRequestConfigName: AXIOS_REQUEST_CONFIG_NAME, - generateParse: resolver.options.parseRequestParams, - }); - }); -} - -function registerGenerateEndpointParamParseHelper() { - Handlebars.registerHelper(PartialsHelpers.EndpointParamParse, (param: EndpointParameter, paramName: string) => - getHbsPartialTemplateDelegate("endpoint-param-parse")({ - param, - paramName, - isQuery: param.type === "Query", - zodExtendedNamespace: ZOD_EXTENDED.namespace, - parse: ZOD_EXTENDED.exports.parse, - sortExp: ZOD_EXTENDED.exports.sortExp, - addOptional: - !(param.parameterObject ?? param.bodyObject)?.required && - (param.parameterSortingEnumSchemaName || isNamedZodSchema(param.zodSchema)), - }), - ); -} - -function registerGenerateQueryKeysHelper(resolver: SchemaResolver) { - Handlebars.registerHelper(PartialsHelpers.QueryKeys, (queryEndpoints: Endpoint[]) => { - if (queryEndpoints.length === 0) { - return ""; - } - - return getHbsPartialTemplateDelegate("query-keys")({ - queryEndpoints, - queriesModuleName: QUERIES_MODULE_NAME, - generateInfiniteQueries: resolver.options.infiniteQueries, - }); - }); -} - -function registerGenerateQueryHelper(resolver: SchemaResolver) { - Handlebars.registerHelper(PartialsHelpers.Query, (endpoint: Endpoint) => { - if (!isQuery(endpoint)) { - return; - } - - const hasAxiosRequestConfig = resolver.options.axiosRequestConfig; - const hasAclCheck = resolver.options.checkAcl && endpoint.acl; - - return getHbsPartialTemplateDelegate("query-use-query")({ - endpoint, - queryHook: QUERY_HOOKS.query, - hasQueryFn: - mapEndpointParamsToFunctionParams(resolver, endpoint).length > 0 || hasAxiosRequestConfig || hasAclCheck, - hasQueryFnBody: hasAclCheck, - hasAxiosRequestConfig, - axiosRequestConfigName: AXIOS_REQUEST_CONFIG_NAME, - axiosRequestConfigType: AXIOS_REQUEST_CONFIG_TYPE, - hasAclCheck, - aclCheckHook: ACL_CHECK_HOOK, - }); - }); -} - -function registerGenerateMutationHelper(resolver: SchemaResolver) { - Handlebars.registerHelper(PartialsHelpers.Mutation, (endpoint: Endpoint, queryEndpoints: Endpoint[]) => { - if (!isMutation(endpoint)) { - return; - } - - const updateQueryEndpoints = getUpdateQueryEndpoints(endpoint, queryEndpoints); - const hasAclCheck = resolver.options.checkAcl && endpoint.acl; - - const pathFuncParams = mapEndpointParamsToFunctionParams(resolver, endpoint).filter( - (param) => param.paramType === "Path", - ); - const hasMutationScope = - resolver.options.mutationScope === true && - pathFuncParams.length > 0 && - endpoint.method !== OpenAPIV3.HttpMethods.POST; - const mutationScopePathParams = hasMutationScope ? pathFuncParams.map(({ name, type }) => ({ name, type })) : []; - const mutationScopeExpression = hasMutationScope - ? getMutationScopeExpression(getEndpointName(endpoint), mutationScopePathParams.map(({ name }) => name)) - : undefined; - const mutationVariablesParams = mapEndpointParamsToFunctionParams(resolver, endpoint, { - excludePathParams: hasMutationScope, - includeFileParam: true, - }); - - const allDestructuredVariables = getDestructuredVariables(resolver, endpoint, updateQueryEndpoints); - const pathParamNames = new Set(pathFuncParams.map(({ name }) => name)); - const destructuredVariables = hasMutationScope - ? allDestructuredVariables.filter((name) => !pathParamNames.has(name)) - : allDestructuredVariables; - - return getHbsPartialTemplateDelegate("query-use-mutation")({ - endpoint, - queryHook: QUERY_HOOKS.mutation, - queriesModuleName: QUERIES_MODULE_NAME, - hasAxiosRequestConfig: resolver.options.axiosRequestConfig, - hasMutationFnBody: endpoint.mediaUpload || hasAclCheck, - axiosRequestConfigName: AXIOS_REQUEST_CONFIG_NAME, - axiosRequestConfigType: AXIOS_REQUEST_CONFIG_TYPE, - hasMutationEffects: resolver.options.mutationEffects, - mutationEffectsType: MUTATION_EFFECTS.optionsType, - updateQueryEndpoints, - destructuredVariables, - hasAclCheck, - aclCheckHook: ACL_CHECK_HOOK, - hasMutationScope, - mutationScopeExpression, - mutationScopePathParams, - hasMutationVariables: mutationVariablesParams.length > 0, - }); - }); -} - -function getMutationScopeExpression(endpointName: string, pathParamNames: string[]) { - return `\`${[endpointName, ...pathParamNames.map((name) => `\${${name}}`)].join(":")}\``; -} - -function registerGenerateInfiniteQueryHelper(resolver: SchemaResolver) { - Handlebars.registerHelper(PartialsHelpers.InfiniteQuery, (endpoint: Endpoint) => { - if (!resolver.options.infiniteQueries || !isInfiniteQuery(endpoint, resolver.options)) { - return; - } - - const hasAclCheck = resolver.options.checkAcl && endpoint.acl; - - return getHbsPartialTemplateDelegate("query-use-infinite-query")({ - endpoint, - infiniteQueryHook: QUERY_HOOKS.infiniteQuery, - hasQueryFnBody: hasAclCheck, - pageParamName: resolver.options.infiniteQueryResponseParamNames.page, - totalItemsName: resolver.options.infiniteQueryResponseParamNames.totalItems, - limitParamName: resolver.options.infiniteQueryResponseParamNames.limit, - hasAxiosRequestConfig: resolver.options.axiosRequestConfig, - axiosRequestConfigName: AXIOS_REQUEST_CONFIG_NAME, - axiosRequestConfigType: AXIOS_REQUEST_CONFIG_TYPE, - hasAclCheck, - aclCheckHook: ACL_CHECK_HOOK, - }); - }); -} - -function registerGenerateQueryJsDocsHelper(resolver: SchemaResolver) { - Handlebars.registerHelper( - PartialsHelpers.QueryJsDocs, - (endpoint: Endpoint, options: { hash: { query?: boolean; mutation?: boolean; infiniteQuery?: boolean } }) => - getHbsPartialTemplateDelegate("query-js-docs")({ - endpoint, - query: options.hash.query, - mutation: options.hash.mutation, - infiniteQuery: options.hash.infiniteQuery, - hasMutationEffects: resolver.options.mutationEffects, - mutationEffectsType: MUTATION_EFFECTS.optionsType, - }), - ); -} - -function registerGenerateCaslAbilityTypeHelper() { - Handlebars.registerHelper(PartialsHelpers.CaslAbilityType, (endpoint: Endpoint) => - getHbsPartialTemplateDelegate("casl-ability-type")({ - endpoint, - abilityTuple: CASL_ABILITY_BINDING.abilityTuple, - }), - ); -} - -function registerGenerateCaslAbilityFunctionHelper() { - Handlebars.registerHelper(PartialsHelpers.CaslAbilityFunction, (endpoint: Endpoint) => - getHbsPartialTemplateDelegate("casl-ability-function")({ endpoint }), - ); -} - -function registerGenerateCaslAbilityQueryHelper() { - Handlebars.registerHelper(PartialsHelpers.CaslAbilityQuery, (endpoint: Endpoint) => - getHbsPartialTemplateDelegate("casl-ability-query")({ endpoint }), - ); -} - -function registerGenerateAclCheckCallHelper() { - Handlebars.registerHelper(PartialsHelpers.AclCheckCall, (endpoint: Endpoint) => { - const checkParams = getAbilityConditionsTypes(endpoint)?.map((condition) => condition.name); - const params = new Set(endpoint.parameters.map((param) => param.name)); - const hasAllCheckParams = checkParams?.every((param) => params.has(param)); - - return getHbsPartialTemplateDelegate("acl-check-call")({ - endpoint, - generateAclCheckParams: hasAbilityConditions(endpoint) && hasAllCheckParams, - }); - }); -} - -function registerGenerateInputsConfigHelper() { - Handlebars.registerHelper(PartialsHelpers.InputsConfig, (inputsConfig: DynamicInputsConfig) => - getHbsPartialTemplateDelegate("inputs-config")({ inputsConfig }), - ); -} - -function registerGenerateColumnsConfigHelper() { - Handlebars.registerHelper(PartialsHelpers.ColumnsConfig, (columnsConfig: DynamicColumnsConfig) => - getHbsPartialTemplateDelegate("columns-config")({ columnsConfig }), - ); -}