@7nohe/openapi-react-query-codegen 1.6.1 → 2.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,11 @@
1
1
  import { posix } from "node:path";
2
2
  import ts from "typescript";
3
- import { modalsFileName, serviceFileName } from "./constants.mjs";
3
+ import { modelsFileName, serviceFileName } from "./constants.mjs";
4
4
  const { join } = posix;
5
- export const createImports = ({ serviceEndName, project, }) => {
5
+ export const createImports = ({ project, client, }) => {
6
6
  const modelsFile = project
7
7
  .getSourceFiles()
8
- .find((sourceFile) => sourceFile.getFilePath().includes(modalsFileName));
8
+ .find((sourceFile) => sourceFile.getFilePath().includes(modelsFileName));
9
9
  const serviceFile = project.getSourceFileOrThrow(`${serviceFileName}.ts`);
10
10
  if (!modelsFile) {
11
11
  console.warn(`
@@ -16,7 +16,7 @@ export const createImports = ({ serviceEndName, project, }) => {
16
16
  ? Array.from(modelsFile.getExportedDeclarations().keys())
17
17
  : [];
18
18
  const serviceExports = Array.from(serviceFile.getExportedDeclarations().keys());
19
- const serviceNames = serviceExports.filter((name) => name.endsWith(serviceEndName));
19
+ const serviceNames = serviceExports;
20
20
  const imports = [
21
21
  ts.factory.createImportDeclaration(undefined, ts.factory.createImportClause(false, undefined, ts.factory.createNamedImports([
22
22
  ts.factory.createImportSpecifier(true, undefined, ts.factory.createIdentifier("QueryClient")),
@@ -37,7 +37,12 @@ export const createImports = ({ serviceEndName, project, }) => {
37
37
  // import all the models by name
38
38
  imports.push(ts.factory.createImportDeclaration(undefined, ts.factory.createImportClause(false, undefined, ts.factory.createNamedImports([
39
39
  ...modelNames.map((modelName) => ts.factory.createImportSpecifier(false, undefined, ts.factory.createIdentifier(modelName))),
40
- ])), ts.factory.createStringLiteral(join("../requests/", modalsFileName)), undefined));
40
+ ])), ts.factory.createStringLiteral(join("../requests/", modelsFileName)), undefined));
41
+ }
42
+ if (client === "@hey-api/client-axios") {
43
+ imports.push(ts.factory.createImportDeclaration(undefined, ts.factory.createImportClause(false, undefined, ts.factory.createNamedImports([
44
+ ts.factory.createImportSpecifier(false, undefined, ts.factory.createIdentifier("AxiosError")),
45
+ ])), ts.factory.createStringLiteral("axios")));
41
46
  }
42
47
  return imports;
43
48
  };
@@ -0,0 +1,56 @@
1
+ import ts from "typescript";
2
+ import { BuildCommonTypeName, EqualsOrGreaterThanToken, getNameFromVariable, getQueryKeyFnName, getRequestParamFromMethod, getVariableArrowFunctionParameters, } from "./common.mjs";
3
+ import { createQueryKeyFromMethod, hookNameFromMethod, } from "./createUseQuery.mjs";
4
+ import { addJSDocToNode } from "./util.mjs";
5
+ /**
6
+ * Creates a prefetch/ensure function for a query
7
+ */
8
+ function createPrefetchOrEnsureHook({ requestParams, method, functionType, }) {
9
+ const methodName = getNameFromVariable(method);
10
+ const queryName = hookNameFromMethod({ method });
11
+ let customHookName = `prefetch${queryName.charAt(0).toUpperCase() + queryName.slice(1)}`;
12
+ if (functionType === "ensure") {
13
+ customHookName = `ensure${queryName.charAt(0).toUpperCase() + queryName.slice(1)}Data`;
14
+ }
15
+ const queryKey = createQueryKeyFromMethod({ method });
16
+ // const
17
+ const hookExport = ts.factory.createVariableStatement(
18
+ // export
19
+ [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], ts.factory.createVariableDeclarationList([
20
+ ts.factory.createVariableDeclaration(ts.factory.createIdentifier(customHookName), undefined, undefined, ts.factory.createArrowFunction(undefined, undefined, [
21
+ ts.factory.createParameterDeclaration(undefined, undefined, "queryClient", undefined, ts.factory.createTypeReferenceNode(ts.factory.createIdentifier("QueryClient"))),
22
+ ...requestParams,
23
+ ], undefined, EqualsOrGreaterThanToken, ts.factory.createCallExpression(ts.factory.createIdentifier(`queryClient.${functionType === "prefetch" ? "prefetchQuery" : "ensureQueryData"}`), undefined, [
24
+ ts.factory.createObjectLiteralExpression([
25
+ ts.factory.createPropertyAssignment(ts.factory.createIdentifier("queryKey"), ts.factory.createCallExpression(BuildCommonTypeName(getQueryKeyFnName(queryKey)), undefined, [ts.factory.createIdentifier("clientOptions")])),
26
+ ts.factory.createPropertyAssignment(ts.factory.createIdentifier("queryFn"), ts.factory.createArrowFunction(undefined, undefined, [], undefined, EqualsOrGreaterThanToken, ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createCallExpression(ts.factory.createIdentifier(methodName), undefined,
27
+ // { ...clientOptions }
28
+ getVariableArrowFunctionParameters(method).length
29
+ ? [
30
+ ts.factory.createObjectLiteralExpression([
31
+ ts.factory.createSpreadAssignment(ts.factory.createIdentifier("clientOptions")),
32
+ ]),
33
+ ]
34
+ : undefined), ts.factory.createIdentifier("then")), undefined, [
35
+ ts.factory.createArrowFunction(undefined, undefined, [
36
+ ts.factory.createParameterDeclaration(undefined, undefined, ts.factory.createIdentifier("response"), undefined, undefined, undefined),
37
+ ], undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("response"), ts.factory.createIdentifier("data"))),
38
+ ]))),
39
+ ]),
40
+ ]))),
41
+ ], ts.NodeFlags.Const));
42
+ return hookExport;
43
+ }
44
+ export const createPrefetchOrEnsure = ({ method, jsDoc, functionType, modelNames, }) => {
45
+ const requestParam = getRequestParamFromMethod(method, undefined, modelNames);
46
+ const requestParams = requestParam ? [requestParam] : [];
47
+ const prefetchOrEnsureHook = createPrefetchOrEnsureHook({
48
+ requestParams,
49
+ method,
50
+ functionType,
51
+ });
52
+ const hookWithJsDoc = addJSDocToNode(prefetchOrEnsureHook, jsDoc);
53
+ return {
54
+ hook: hookWithJsDoc,
55
+ };
56
+ };
@@ -5,7 +5,7 @@ import { OpenApiRqFiles } from "./constants.mjs";
5
5
  import { createExports } from "./createExports.mjs";
6
6
  import { createImports } from "./createImports.mjs";
7
7
  import { getServices } from "./service.mjs";
8
- const createSourceFile = async (outputPath, serviceEndName, pageParam, nextPageParam, initialPageParam) => {
8
+ const createSourceFile = async ({ outputPath, client, pageParam, nextPageParam, initialPageParam, }) => {
9
9
  const project = new Project({
10
10
  // Optionally specify compiler options, tsconfig.json, in-memory file system, and more here.
11
11
  // If you initialize with a tsconfig.json, then it will automatically populate the project
@@ -17,10 +17,17 @@ const createSourceFile = async (outputPath, serviceEndName, pageParam, nextPageP
17
17
  project.addSourceFilesAtPaths(`${sourceFiles}/**/*`);
18
18
  const service = await getServices(project);
19
19
  const imports = createImports({
20
- serviceEndName,
21
20
  project,
21
+ client,
22
+ });
23
+ const exports = createExports({
24
+ service,
25
+ client,
26
+ project,
27
+ pageParam,
28
+ nextPageParam,
29
+ initialPageParam,
22
30
  });
23
- const exports = createExports(service, pageParam, nextPageParam, initialPageParam);
24
31
  const commonSource = ts.factory.createSourceFile([...imports, ...exports.allCommon], ts.factory.createToken(ts.SyntaxKind.EndOfFileToken), ts.NodeFlags.None);
25
32
  const commonImport = ts.factory.createImportDeclaration(undefined, ts.factory.createImportClause(false, ts.factory.createIdentifier("* as Common"), undefined), ts.factory.createStringLiteral(`./${OpenApiRqFiles.common}`), undefined);
26
33
  const commonExport = ts.factory.createExportDeclaration(undefined, false, undefined, ts.factory.createStringLiteral(`./${OpenApiRqFiles.common}`), undefined);
@@ -30,6 +37,7 @@ const createSourceFile = async (outputPath, serviceEndName, pageParam, nextPageP
30
37
  const suspenseSource = ts.factory.createSourceFile([commonImport, ...imports, ...exports.suspenseExports], ts.factory.createToken(ts.SyntaxKind.EndOfFileToken), ts.NodeFlags.None);
31
38
  const indexSource = ts.factory.createSourceFile([commonExport, queriesExport], ts.factory.createToken(ts.SyntaxKind.EndOfFileToken), ts.NodeFlags.None);
32
39
  const prefetchSource = ts.factory.createSourceFile([commonImport, ...imports, ...exports.allPrefetchExports], ts.factory.createToken(ts.SyntaxKind.EndOfFileToken), ts.NodeFlags.None);
40
+ const ensureSource = ts.factory.createSourceFile([commonImport, ...imports, ...exports.allEnsures], ts.factory.createToken(ts.SyntaxKind.EndOfFileToken), ts.NodeFlags.None);
33
41
  return {
34
42
  commonSource,
35
43
  infiniteQueriesSource,
@@ -37,20 +45,28 @@ const createSourceFile = async (outputPath, serviceEndName, pageParam, nextPageP
37
45
  suspenseSource,
38
46
  indexSource,
39
47
  prefetchSource,
48
+ ensureSource,
40
49
  };
41
50
  };
42
- export const createSource = async ({ outputPath, version, serviceEndName, pageParam, nextPageParam, initialPageParam, }) => {
51
+ export const createSource = async ({ outputPath, client, version, pageParam, nextPageParam, initialPageParam, }) => {
43
52
  const queriesFile = ts.createSourceFile(`${OpenApiRqFiles.queries}.ts`, "", ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
44
53
  const infiniteQueriesFile = ts.createSourceFile(`${OpenApiRqFiles.infiniteQueries}.ts`, "", ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
45
54
  const commonFile = ts.createSourceFile(`${OpenApiRqFiles.common}.ts`, "", ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
46
55
  const suspenseFile = ts.createSourceFile(`${OpenApiRqFiles.suspense}.ts`, "", ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
47
56
  const indexFile = ts.createSourceFile(`${OpenApiRqFiles.index}.ts`, "", ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
48
57
  const prefetchFile = ts.createSourceFile(`${OpenApiRqFiles.prefetch}.ts`, "", ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
58
+ const ensureQueryDataFile = ts.createSourceFile(`${OpenApiRqFiles.ensureQueryData}.ts`, "", ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
49
59
  const printer = ts.createPrinter({
50
60
  newLine: ts.NewLineKind.LineFeed,
51
61
  removeComments: false,
52
62
  });
53
- const { commonSource, mainSource, infiniteQueriesSource, suspenseSource, indexSource, prefetchSource, } = await createSourceFile(outputPath, serviceEndName, pageParam, nextPageParam, initialPageParam);
63
+ const { commonSource, mainSource, infiniteQueriesSource, suspenseSource, indexSource, prefetchSource, ensureSource, } = await createSourceFile({
64
+ outputPath,
65
+ client,
66
+ pageParam,
67
+ nextPageParam,
68
+ initialPageParam,
69
+ });
54
70
  const comment = `// generated with @7nohe/openapi-react-query-codegen@${version} \n\n`;
55
71
  const commonResult = comment +
56
72
  printer.printNode(ts.EmitHint.Unspecified, commonSource, commonFile);
@@ -64,6 +80,8 @@ export const createSource = async ({ outputPath, version, serviceEndName, pagePa
64
80
  printer.printNode(ts.EmitHint.Unspecified, indexSource, indexFile);
65
81
  const prefetchResult = comment +
66
82
  printer.printNode(ts.EmitHint.Unspecified, prefetchSource, prefetchFile);
83
+ const enqureResult = comment +
84
+ printer.printNode(ts.EmitHint.Unspecified, ensureSource, ensureQueryDataFile);
67
85
  return [
68
86
  {
69
87
  name: `${OpenApiRqFiles.index}.ts`,
@@ -89,5 +107,9 @@ export const createSource = async ({ outputPath, version, serviceEndName, pagePa
89
107
  name: `${OpenApiRqFiles.prefetch}.ts`,
90
108
  content: prefetchResult,
91
109
  },
110
+ {
111
+ name: `${OpenApiRqFiles.ensureQueryData}.ts`,
112
+ content: enqureResult,
113
+ },
92
114
  ];
93
115
  };
@@ -1,38 +1,49 @@
1
1
  import ts from "typescript";
2
- import { BuildCommonTypeName, TContext, TData, TError, capitalizeFirstLetter, extractPropertiesFromObjectParam, getNameFromMethod, getShortType, } from "./common.mjs";
2
+ import { BuildCommonTypeName, EqualsOrGreaterThanToken, TContext, TData, TError, capitalizeFirstLetter, createQueryKeyExport, createQueryKeyFnExport, getNameFromVariable, getQueryKeyFnName, getVariableArrowFunctionParameters, queryKeyConstraint, queryKeyGenericType, } from "./common.mjs";
3
+ import { createQueryKeyFromMethod } from "./createUseQuery.mjs";
3
4
  import { addJSDocToNode } from "./util.mjs";
4
5
  /**
5
6
  * Awaited<ReturnType<typeof myClass.myMethod>>
6
7
  */
7
- function generateAwaitedReturnType({ className, methodName, }) {
8
+ function generateAwaitedReturnType({ methodName }) {
8
9
  return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier("Awaited"), [
9
10
  ts.factory.createTypeReferenceNode(ts.factory.createIdentifier("ReturnType"), [
10
- ts.factory.createTypeQueryNode(ts.factory.createQualifiedName(ts.factory.createIdentifier(className), ts.factory.createIdentifier(methodName)), undefined),
11
+ ts.factory.createTypeQueryNode(ts.factory.createIdentifier(methodName), undefined),
11
12
  ]),
12
13
  ]);
13
14
  }
14
- export const createUseMutation = ({ className, method, jsDoc, }) => {
15
- const methodName = getNameFromMethod(method);
15
+ export const createUseMutation = ({ functionDescription: { method, jsDoc }, modelNames, client, }) => {
16
+ const methodName = getNameFromVariable(method);
17
+ const mutationKey = createQueryKeyFromMethod({ method });
16
18
  const awaitedResponseDataType = generateAwaitedReturnType({
17
- className,
18
19
  methodName,
19
20
  });
20
- const mutationResult = ts.factory.createTypeAliasDeclaration([ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], ts.factory.createIdentifier(`${className}${capitalizeFirstLetter(methodName)}MutationResult`), undefined, awaitedResponseDataType);
21
+ const mutationResult = ts.factory.createTypeAliasDeclaration([ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], ts.factory.createIdentifier(`${capitalizeFirstLetter(methodName)}MutationResult`), undefined, awaitedResponseDataType);
22
+ // `TData = Common.AddPetMutationResult`
21
23
  const responseDataType = ts.factory.createTypeParameterDeclaration(undefined, TData, undefined, ts.factory.createTypeReferenceNode(BuildCommonTypeName(mutationResult.name)));
22
- const methodParameters = method.getParameters().length !== 0
23
- ? ts.factory.createTypeLiteralNode(method.getParameters().flatMap((param) => {
24
- const paramNodes = extractPropertiesFromObjectParam(param);
25
- return paramNodes.map((refParam) => ts.factory.createPropertySignature(undefined, ts.factory.createIdentifier(refParam.name), refParam.optional
26
- ? ts.factory.createToken(ts.SyntaxKind.QuestionToken)
27
- : undefined, ts.factory.createTypeReferenceNode(getShortType(refParam.type?.getText(param) ?? ""))));
28
- }))
24
+ // @hey-api/client-axios -> `TError = AxiosError<AddPetError>`
25
+ // @hey-api/client-fetch -> `TError = AddPetError`
26
+ const responseErrorType = ts.factory.createTypeParameterDeclaration(undefined, TError, undefined, client === "@hey-api/client-axios"
27
+ ? ts.factory.createTypeReferenceNode(ts.factory.createIdentifier("AxiosError"), [
28
+ ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(`${capitalizeFirstLetter(methodName)}Error`)),
29
+ ])
30
+ : ts.factory.createTypeReferenceNode(`${capitalizeFirstLetter(methodName)}Error`));
31
+ const methodParameters = getVariableArrowFunctionParameters(method).length !== 0
32
+ ? ts.factory.createTypeReferenceNode(ts.factory.createIdentifier("Options"), [
33
+ ts.factory.createTypeReferenceNode(modelNames.includes(`${capitalizeFirstLetter(methodName)}Data`)
34
+ ? `${capitalizeFirstLetter(methodName)}Data`
35
+ : "unknown"),
36
+ ts.factory.createLiteralTypeNode(ts.factory.createTrue()),
37
+ ])
29
38
  : ts.factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword);
30
39
  const exportHook = ts.factory.createVariableStatement([ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], ts.factory.createVariableDeclarationList([
31
- ts.factory.createVariableDeclaration(ts.factory.createIdentifier(`use${className}${capitalizeFirstLetter(methodName)}`), undefined, undefined, ts.factory.createArrowFunction(undefined, ts.factory.createNodeArray([
40
+ ts.factory.createVariableDeclaration(ts.factory.createIdentifier(`use${capitalizeFirstLetter(methodName)}`), undefined, undefined, ts.factory.createArrowFunction(undefined, ts.factory.createNodeArray([
32
41
  responseDataType,
33
- ts.factory.createTypeParameterDeclaration(undefined, TError, undefined, ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword)),
42
+ responseErrorType,
43
+ ts.factory.createTypeParameterDeclaration(undefined, "TQueryKey", queryKeyConstraint, ts.factory.createArrayTypeNode(ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword))),
34
44
  ts.factory.createTypeParameterDeclaration(undefined, TContext, undefined, ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword)),
35
45
  ]), [
46
+ ts.factory.createParameterDeclaration(undefined, undefined, ts.factory.createIdentifier("mutationKey"), ts.factory.createToken(ts.SyntaxKind.QuestionToken), queryKeyGenericType),
36
47
  ts.factory.createParameterDeclaration(undefined, undefined, ts.factory.createIdentifier("options"), ts.factory.createToken(ts.SyntaxKind.QuestionToken), ts.factory.createTypeReferenceNode(ts.factory.createIdentifier("Omit"), [
37
48
  ts.factory.createTypeReferenceNode(ts.factory.createIdentifier("UseMutationOptions"), [
38
49
  ts.factory.createTypeReferenceNode(TData),
@@ -40,7 +51,10 @@ export const createUseMutation = ({ className, method, jsDoc, }) => {
40
51
  methodParameters,
41
52
  ts.factory.createTypeReferenceNode(TContext),
42
53
  ]),
43
- ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral("mutationFn")),
54
+ ts.factory.createUnionTypeNode([
55
+ ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral("mutationKey")),
56
+ ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral("mutationFn")),
57
+ ]),
44
58
  ]), undefined),
45
59
  ], undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), ts.factory.createCallExpression(ts.factory.createIdentifier("useMutation"), [
46
60
  ts.factory.createTypeReferenceNode(TData),
@@ -49,28 +63,29 @@ export const createUseMutation = ({ className, method, jsDoc, }) => {
49
63
  ts.factory.createTypeReferenceNode(TContext),
50
64
  ], [
51
65
  ts.factory.createObjectLiteralExpression([
52
- ts.factory.createPropertyAssignment(ts.factory.createIdentifier("mutationFn"), ts.factory.createArrowFunction(undefined, undefined, method.getParameters().length !== 0
53
- ? [
54
- ts.factory.createParameterDeclaration(undefined, undefined, ts.factory.createObjectBindingPattern(method.getParameters().flatMap((param) => {
55
- const paramNodes = extractPropertiesFromObjectParam(param);
56
- return paramNodes.map((refParam) => ts.factory.createBindingElement(undefined, undefined, ts.factory.createIdentifier(refParam.name), undefined));
57
- })), undefined, undefined, undefined),
58
- ]
59
- : [], undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), ts.factory.createAsExpression(ts.factory.createAsExpression(ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(className), ts.factory.createIdentifier(methodName)), undefined, method.getParameters().length !== 0
60
- ? [
61
- ts.factory.createObjectLiteralExpression(method.getParameters().flatMap((params) => {
62
- const paramNodes = extractPropertiesFromObjectParam(params);
63
- return paramNodes.map((refParam) => ts.factory.createShorthandPropertyAssignment(refParam.name));
64
- })),
65
- ]
66
- : []), ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword)), ts.factory.createTypeReferenceNode(ts.factory.createIdentifier("Promise"), [ts.factory.createTypeReferenceNode(TData)])))),
66
+ ts.factory.createPropertyAssignment(ts.factory.createIdentifier("mutationKey"), ts.factory.createCallExpression(BuildCommonTypeName(getQueryKeyFnName(mutationKey)), undefined, [ts.factory.createIdentifier("mutationKey")])),
67
+ ts.factory.createPropertyAssignment(ts.factory.createIdentifier("mutationFn"),
68
+ // (clientOptions) => addPet(clientOptions).then(response => response.data as TData) as unknown as Promise<TData>
69
+ ts.factory.createArrowFunction(undefined, undefined, [
70
+ ts.factory.createParameterDeclaration(undefined, undefined, ts.factory.createIdentifier("clientOptions"), undefined, undefined, undefined),
71
+ ], undefined, EqualsOrGreaterThanToken, ts.factory.createAsExpression(ts.factory.createAsExpression(ts.factory.createCallExpression(ts.factory.createIdentifier(methodName), undefined, getVariableArrowFunctionParameters(method).length >
72
+ 0
73
+ ? [ts.factory.createIdentifier("clientOptions")]
74
+ : undefined), ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword)), ts.factory.createTypeReferenceNode(ts.factory.createIdentifier("Promise"), [ts.factory.createTypeReferenceNode(TData)])))),
67
75
  ts.factory.createSpreadAssignment(ts.factory.createIdentifier("options")),
68
76
  ]),
69
77
  ]))),
70
78
  ], ts.NodeFlags.Const));
71
79
  const hookWithJsDoc = addJSDocToNode(exportHook, jsDoc);
80
+ const mutationKeyExport = createQueryKeyExport({
81
+ methodName,
82
+ queryKey: mutationKey,
83
+ });
84
+ const mutationKeyFn = createQueryKeyFnExport(mutationKey, method, "mutation");
72
85
  return {
73
86
  mutationResult,
87
+ key: mutationKeyExport,
74
88
  mutationHook: hookWithJsDoc,
89
+ mutationKeyFn,
75
90
  };
76
91
  };
@@ -1,18 +1,23 @@
1
1
  import ts from "typescript";
2
- import { BuildCommonTypeName, EqualsOrGreaterThanToken, QuestionToken, TData, TError, capitalizeFirstLetter, extractPropertiesFromObjectParam, getNameFromMethod, getShortType, queryKeyConstraint, queryKeyGenericType, } from "./common.mjs";
2
+ import { BuildCommonTypeName, EqualsOrGreaterThanToken, TData, TError, capitalizeFirstLetter, createQueryKeyExport, createQueryKeyFnExport, getNameFromVariable, getQueryKeyFnName, getRequestParamFromMethod, getVariableArrowFunctionParameters, queryKeyConstraint, queryKeyGenericType, } from "./common.mjs";
3
3
  import { addJSDocToNode } from "./util.mjs";
4
- export const createApiResponseType = ({ className, methodName, }) => {
4
+ const createApiResponseType = ({ methodName, client, }) => {
5
5
  /** Awaited<ReturnType<typeof myClass.myMethod>> */
6
- const awaitedResponseDataType = ts.factory.createTypeReferenceNode(ts.factory.createIdentifier("Awaited"), [
6
+ const awaitedResponseDataType = ts.factory.createIndexedAccessTypeNode(ts.factory.createTypeReferenceNode(ts.factory.createIdentifier("Awaited"), [
7
7
  ts.factory.createTypeReferenceNode(ts.factory.createIdentifier("ReturnType"), [
8
- ts.factory.createTypeQueryNode(ts.factory.createQualifiedName(ts.factory.createIdentifier(className), ts.factory.createIdentifier(methodName)), undefined),
8
+ ts.factory.createTypeQueryNode(ts.factory.createIdentifier(methodName), undefined),
9
9
  ]),
10
- ]);
10
+ ]), ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral("data")));
11
11
  /** DefaultResponseDataType
12
12
  * export type MyClassMethodDefaultResponse = Awaited<ReturnType<typeof myClass.myMethod>>
13
13
  */
14
- const apiResponse = ts.factory.createTypeAliasDeclaration([ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], ts.factory.createIdentifier(`${capitalizeFirstLetter(className)}${capitalizeFirstLetter(methodName)}DefaultResponse`), undefined, awaitedResponseDataType);
14
+ const apiResponse = ts.factory.createTypeAliasDeclaration([ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], ts.factory.createIdentifier(`${capitalizeFirstLetter(methodName)}DefaultResponse`), undefined, awaitedResponseDataType);
15
15
  const responseDataType = ts.factory.createTypeParameterDeclaration(undefined, TData.text, undefined, ts.factory.createTypeReferenceNode(BuildCommonTypeName(apiResponse.name)));
16
+ const responseErrorType = ts.factory.createTypeParameterDeclaration(undefined, TError.text, undefined, client === "@hey-api/client-axios"
17
+ ? ts.factory.createTypeReferenceNode(ts.factory.createIdentifier("AxiosError"), [
18
+ ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(`${capitalizeFirstLetter(methodName)}Error`)),
19
+ ])
20
+ : ts.factory.createTypeReferenceNode(`${capitalizeFirstLetter(methodName)}Error`));
16
21
  return {
17
22
  /**
18
23
  * DefaultResponseDataType
@@ -26,41 +31,21 @@ export const createApiResponseType = ({ className, methodName, }) => {
26
31
  * MyClassMethodDefaultResponse
27
32
  */
28
33
  responseDataType,
34
+ /**
35
+ * ErrorDataType
36
+ *
37
+ * MyClassMethodError
38
+ */
39
+ responseErrorType,
29
40
  };
30
41
  };
31
- export function getRequestParamFromMethod(method, pageParam) {
32
- if (!method.getParameters().length) {
33
- return null;
34
- }
35
- const params = method.getParameters().flatMap((param) => {
36
- const paramNodes = extractPropertiesFromObjectParam(param);
37
- return paramNodes
38
- .filter((p) => p.name !== pageParam)
39
- .map((refParam) => ({
40
- name: refParam.name,
41
- typeName: getShortType(refParam.type?.getText() ?? ""),
42
- optional: refParam.optional,
43
- }));
44
- });
45
- const areAllPropertiesOptional = params.every((param) => param.optional);
46
- return ts.factory.createParameterDeclaration(undefined, undefined, ts.factory.createObjectBindingPattern(params.map((refParam) => ts.factory.createBindingElement(undefined, undefined, ts.factory.createIdentifier(refParam.name), undefined))), undefined, ts.factory.createTypeLiteralNode(params.map((refParam) => {
47
- return ts.factory.createPropertySignature(undefined, ts.factory.createIdentifier(refParam.name), refParam.optional
48
- ? ts.factory.createToken(ts.SyntaxKind.QuestionToken)
49
- : undefined, ts.factory.createTypeReferenceNode(refParam.typeName));
50
- })),
51
- // if all params are optional, we create an empty object literal
52
- // so the hook can be called without any parameters
53
- areAllPropertiesOptional
54
- ? ts.factory.createObjectLiteralExpression()
55
- : undefined);
56
- }
57
42
  /**
58
43
  * Return Type
59
44
  *
60
45
  * export const classNameMethodNameQueryResult<TData = MyClassMethodDefaultResponse, TError = unknown> = UseQueryResult<TData, TError>;
61
46
  */
62
- export function createReturnTypeExport({ className, methodName, defaultApiResponse, }) {
63
- return ts.factory.createTypeAliasDeclaration([ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], ts.factory.createIdentifier(`${capitalizeFirstLetter(className)}${capitalizeFirstLetter(methodName)}QueryResult`), [
47
+ function createReturnTypeExport({ methodName, defaultApiResponse, }) {
48
+ return ts.factory.createTypeAliasDeclaration([ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], ts.factory.createIdentifier(`${capitalizeFirstLetter(methodName)}QueryResult`), [
64
49
  ts.factory.createTypeParameterDeclaration(undefined, TData, undefined, ts.factory.createTypeReferenceNode(defaultApiResponse.name)),
65
50
  ts.factory.createTypeParameterDeclaration(undefined, TError, undefined, ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword)),
66
51
  ], ts.factory.createTypeReferenceNode(ts.factory.createIdentifier("UseQueryResult"), [
@@ -68,20 +53,12 @@ export function createReturnTypeExport({ className, methodName, defaultApiRespon
68
53
  ts.factory.createTypeReferenceNode(TError),
69
54
  ]));
70
55
  }
71
- /**
72
- * QueryKey
73
- */
74
- export function createQueryKeyExport({ className, methodName, queryKey, }) {
75
- return ts.factory.createVariableStatement([ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], ts.factory.createVariableDeclarationList([
76
- ts.factory.createVariableDeclaration(ts.factory.createIdentifier(queryKey), undefined, undefined, ts.factory.createStringLiteral(`${className}${capitalizeFirstLetter(methodName)}`)),
77
- ], ts.NodeFlags.Const));
78
- }
79
- export function hookNameFromMethod({ method, className, }) {
80
- const methodName = getNameFromMethod(method);
81
- return `use${className}${capitalizeFirstLetter(methodName)}`;
56
+ export function hookNameFromMethod({ method, }) {
57
+ const methodName = getNameFromVariable(method);
58
+ return `use${capitalizeFirstLetter(methodName)}`;
82
59
  }
83
- export function createQueryKeyFromMethod({ method, className, }) {
84
- const customHookName = hookNameFromMethod({ method, className });
60
+ export function createQueryKeyFromMethod({ method, }) {
61
+ const customHookName = hookNameFromMethod({ method });
85
62
  const queryKey = `${customHookName}Key`;
86
63
  return queryKey;
87
64
  }
@@ -90,10 +67,10 @@ export function createQueryKeyFromMethod({ method, className, }) {
90
67
  * @param queryString The type of query to use from react-query
91
68
  * @param suffix The suffix to append to the hook name
92
69
  */
93
- export function createQueryHook({ queryString, suffix, responseDataType, requestParams, method, className, pageParam, nextPageParam, initialPageParam, }) {
94
- const methodName = getNameFromMethod(method);
95
- const customHookName = hookNameFromMethod({ method, className });
96
- const queryKey = createQueryKeyFromMethod({ method, className });
70
+ function createQueryHook({ queryString, suffix, responseDataType, responseErrorType, requestParams, method, pageParam, nextPageParam, initialPageParam, }) {
71
+ const methodName = getNameFromVariable(method);
72
+ const customHookName = hookNameFromMethod({ method });
73
+ const queryKey = createQueryKeyFromMethod({ method });
97
74
  if (queryString === "useInfiniteQuery" &&
98
75
  (pageParam === undefined || nextPageParam === undefined)) {
99
76
  throw new Error("pageParam and nextPageParam are required for infinite queries");
@@ -108,7 +85,7 @@ export function createQueryHook({ queryString, suffix, responseDataType, request
108
85
  ts.factory.createTypeReferenceNode(responseDataTypeIdentifier),
109
86
  ]))
110
87
  : responseDataType,
111
- ts.factory.createTypeParameterDeclaration(undefined, TError, undefined, ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword)),
88
+ responseErrorType,
112
89
  ts.factory.createTypeParameterDeclaration(undefined, "TQueryKey", queryKeyConstraint, ts.factory.createArrayTypeNode(ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword))),
113
90
  ]), [
114
91
  ...requestParams,
@@ -132,29 +109,40 @@ export function createQueryHook({ queryString, suffix, responseDataType, request
132
109
  ts.factory.createTypeReferenceNode(TError),
133
110
  ], [
134
111
  ts.factory.createObjectLiteralExpression([
135
- ts.factory.createPropertyAssignment(ts.factory.createIdentifier("queryKey"), ts.factory.createCallExpression(BuildCommonTypeName(getQueryKeyFnName(queryKey)), undefined, method.getParameters().length
136
- ? [
137
- ts.factory.createObjectLiteralExpression(method.getParameters().flatMap((param) => extractPropertiesFromObjectParam(param)
138
- .filter((p) => p.name !== pageParam)
139
- .map((p) => ts.factory.createShorthandPropertyAssignment(ts.factory.createIdentifier(p.name))))),
140
- ts.factory.createIdentifier("queryKey"),
141
- ]
142
- : [ts.factory.createIdentifier("queryKey")])),
112
+ ts.factory.createPropertyAssignment(ts.factory.createIdentifier("queryKey"), ts.factory.createCallExpression(BuildCommonTypeName(getQueryKeyFnName(queryKey)), undefined, [
113
+ ts.factory.createIdentifier("clientOptions"),
114
+ ts.factory.createIdentifier("queryKey"),
115
+ ])),
143
116
  ts.factory.createPropertyAssignment(ts.factory.createIdentifier("queryFn"), ts.factory.createArrowFunction(undefined, undefined, isInfiniteQuery
144
117
  ? [
145
118
  ts.factory.createParameterDeclaration(undefined, undefined, ts.factory.createObjectBindingPattern([
146
119
  ts.factory.createBindingElement(undefined, undefined, ts.factory.createIdentifier("pageParam"), undefined),
147
120
  ]), undefined, undefined),
148
121
  ]
149
- : [], undefined, EqualsOrGreaterThanToken, ts.factory.createAsExpression(ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(className), ts.factory.createIdentifier(methodName)), undefined, method.getParameters().length
122
+ : [], undefined, EqualsOrGreaterThanToken, ts.factory.createAsExpression(ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createCallExpression(ts.factory.createIdentifier(methodName), undefined, pageParam && isInfiniteQuery
150
123
  ? [
151
- ts.factory.createObjectLiteralExpression(method
152
- .getParameters()
153
- .flatMap((param) => extractPropertiesFromObjectParam(param).map((p) => p.name === pageParam
154
- ? ts.factory.createPropertyAssignment(ts.factory.createIdentifier(p.name), ts.factory.createAsExpression(ts.factory.createIdentifier("pageParam"), ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword)))
155
- : ts.factory.createShorthandPropertyAssignment(ts.factory.createIdentifier(p.name))))),
124
+ // { ...clientOptions, query: { ...clientOptions.query, page: pageParam as number } }
125
+ ts.factory.createObjectLiteralExpression([
126
+ ts.factory.createSpreadAssignment(ts.factory.createIdentifier("clientOptions")),
127
+ ts.factory.createPropertyAssignment(ts.factory.createIdentifier("query"), ts.factory.createObjectLiteralExpression([
128
+ ts.factory.createSpreadAssignment(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("clientOptions"), ts.factory.createIdentifier("query"))),
129
+ ts.factory.createPropertyAssignment(ts.factory.createIdentifier(pageParam), ts.factory.createAsExpression(ts.factory.createIdentifier("pageParam"), ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword))),
130
+ ])),
131
+ ]),
156
132
  ]
157
- : undefined), ts.factory.createTypeReferenceNode(TData)))),
133
+ : // { ...clientOptions }
134
+ getVariableArrowFunctionParameters(method)
135
+ .length > 0
136
+ ? [
137
+ ts.factory.createObjectLiteralExpression([
138
+ ts.factory.createSpreadAssignment(ts.factory.createIdentifier("clientOptions")),
139
+ ]),
140
+ ]
141
+ : undefined), ts.factory.createIdentifier("then")), undefined, [
142
+ ts.factory.createArrowFunction(undefined, undefined, [
143
+ ts.factory.createParameterDeclaration(undefined, undefined, ts.factory.createIdentifier("response"), undefined, undefined, undefined),
144
+ ], undefined, EqualsOrGreaterThanToken, ts.factory.createAsExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier("response"), ts.factory.createIdentifier("data")), ts.factory.createTypeReferenceNode(TData))),
145
+ ]), ts.factory.createTypeReferenceNode(TData)))),
158
146
  ...createInfiniteQueryParams(pageParam, nextPageParam, initialPageParam),
159
147
  ts.factory.createSpreadAssignment(ts.factory.createIdentifier("options")),
160
148
  ]),
@@ -162,48 +150,41 @@ export function createQueryHook({ queryString, suffix, responseDataType, request
162
150
  ], ts.NodeFlags.Const));
163
151
  return hookExport;
164
152
  }
165
- export const createUseQuery = ({ className, method, jsDoc }, pageParam, nextPageParam, initialPageParam) => {
166
- const methodName = getNameFromMethod(method);
167
- const queryKey = createQueryKeyFromMethod({ method, className });
168
- const { apiResponse: defaultApiResponse, responseDataType } = createApiResponseType({
169
- className,
153
+ export const createUseQuery = ({ functionDescription: { method, jsDoc }, client, pageParam, nextPageParam, initialPageParam, paginatableMethods, modelNames, }) => {
154
+ const methodName = getNameFromVariable(method);
155
+ const queryKey = createQueryKeyFromMethod({ method });
156
+ const { apiResponse: defaultApiResponse, responseDataType, responseErrorType, } = createApiResponseType({
170
157
  methodName,
158
+ client,
171
159
  });
172
- const requestParam = getRequestParamFromMethod(method);
173
- const infiniteRequestParam = getRequestParamFromMethod(method, pageParam);
160
+ const requestParam = getRequestParamFromMethod(method, undefined, modelNames);
161
+ const infiniteRequestParam = getRequestParamFromMethod(method, pageParam, modelNames);
174
162
  const requestParams = requestParam ? [requestParam] : [];
175
- const requestParamNames = requestParams
176
- .filter((p) => p.name.kind === ts.SyntaxKind.ObjectBindingPattern)
177
- .map((p) => p.name);
178
- const requestParamTexts = requestParamNames
179
- .at(0)
180
- ?.elements.filter((e) => e.name.kind === ts.SyntaxKind.Identifier)
181
- .map((e) => e.name.escapedText);
182
163
  const queryHook = createQueryHook({
183
164
  queryString: "useQuery",
184
165
  suffix: "",
185
166
  responseDataType,
167
+ responseErrorType,
186
168
  requestParams,
187
169
  method,
188
- className,
189
170
  });
190
171
  const suspenseQueryHook = createQueryHook({
191
172
  queryString: "useSuspenseQuery",
192
173
  suffix: "Suspense",
193
174
  responseDataType,
175
+ responseErrorType,
194
176
  requestParams,
195
177
  method,
196
- className,
197
178
  });
198
- const isInfiniteQuery = requestParamTexts?.includes(pageParam) ?? false;
179
+ const isInfiniteQuery = paginatableMethods.includes(methodName);
199
180
  const infiniteQueryHook = isInfiniteQuery
200
181
  ? createQueryHook({
201
182
  queryString: "useInfiniteQuery",
202
183
  suffix: "Infinite",
203
184
  responseDataType,
185
+ responseErrorType,
204
186
  requestParams: infiniteRequestParam ? [infiniteRequestParam] : [],
205
187
  method,
206
- className,
207
188
  pageParam,
208
189
  nextPageParam,
209
190
  initialPageParam,
@@ -215,12 +196,10 @@ export const createUseQuery = ({ className, method, jsDoc }, pageParam, nextPage
215
196
  ? addJSDocToNode(infiniteQueryHook, jsDoc)
216
197
  : undefined;
217
198
  const returnTypeExport = createReturnTypeExport({
218
- className,
219
199
  methodName,
220
200
  defaultApiResponse,
221
201
  });
222
202
  const queryKeyExport = createQueryKeyExport({
223
- className,
224
203
  methodName,
225
204
  queryKey,
226
205
  });
@@ -235,29 +214,6 @@ export const createUseQuery = ({ className, method, jsDoc }, pageParam, nextPage
235
214
  queryKeyFn,
236
215
  };
237
216
  };
238
- export function getQueryKeyFnName(queryKey) {
239
- return `${capitalizeFirstLetter(queryKey)}Fn`;
240
- }
241
- function createQueryKeyFnExport(queryKey, method) {
242
- const params = getRequestParamFromMethod(method);
243
- // override key is used to allow the user to override the the queryKey values
244
- const overrideKey = ts.factory.createParameterDeclaration(undefined, undefined, ts.factory.createIdentifier("queryKey"), QuestionToken, ts.factory.createTypeReferenceNode("Array<unknown>", []));
245
- return ts.factory.createVariableStatement([ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], ts.factory.createVariableDeclarationList([
246
- ts.factory.createVariableDeclaration(ts.factory.createIdentifier(getQueryKeyFnName(queryKey)), undefined, undefined, ts.factory.createArrowFunction(undefined, undefined, params ? [params, overrideKey] : [overrideKey], undefined, EqualsOrGreaterThanToken, queryKeyFn(queryKey, method))),
247
- ], ts.NodeFlags.Const));
248
- }
249
- function queryKeyFn(queryKey, method) {
250
- return ts.factory.createArrayLiteralExpression([
251
- ts.factory.createIdentifier(queryKey),
252
- ts.factory.createSpreadElement(ts.factory.createParenthesizedExpression(ts.factory.createBinaryExpression(ts.factory.createIdentifier("queryKey"), ts.factory.createToken(ts.SyntaxKind.QuestionQuestionToken), method.getParameters().length
253
- ? ts.factory.createArrayLiteralExpression([
254
- ts.factory.createObjectLiteralExpression(method
255
- .getParameters()
256
- .flatMap((param) => extractPropertiesFromObjectParam(param).map((p) => ts.factory.createShorthandPropertyAssignment(ts.factory.createIdentifier(p.name))))),
257
- ])
258
- : ts.factory.createArrayLiteralExpression([])))),
259
- ], false);
260
- }
261
217
  function createInfiniteQueryParams(pageParam, nextPageParam, initialPageParam = "1") {
262
218
  if (pageParam === undefined || nextPageParam === undefined) {
263
219
  return [];