@7nohe/openapi-react-query-codegen 1.6.1 → 1.6.2
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.
- package/README.md +3 -1
- package/dist/cli.mjs +1 -1
- package/dist/constants.mjs +1 -0
- package/dist/createExports.mjs +9 -5
- package/dist/{createPrefetch.mjs → createPrefetchOrEnsure.mjs} +12 -8
- package/dist/createSource.mjs +10 -1
- package/dist/createUseQuery.mjs +39 -4
- package/dist/generate.mjs +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
9
|
- Generates custom react hooks that use React Query's `useQuery`, `useSuspenseQuery`, `useMutation` and `useInfiniteQuery` hooks
|
|
10
|
+
- Generates custom functions that use React Query's `ensureQueryData` and `prefetchQuery` functions
|
|
10
11
|
- Generates query keys and functions for query caching
|
|
11
12
|
- Generates pure TypeScript clients generated by [@hey-api/openapi-ts](https://github.com/hey-api/openapi-ts)
|
|
12
13
|
|
|
@@ -79,9 +80,10 @@ $ openapi-rq -i ./petstore.yaml
|
|
|
79
80
|
- queries
|
|
80
81
|
- index.ts <- main file that exports common types, variables, and queries. Does not export suspense or prefetch hooks
|
|
81
82
|
- common.ts <- common types
|
|
83
|
+
- ensureQueryData.ts <- generated ensureQueryData functions
|
|
82
84
|
- queries.ts <- generated query hooks
|
|
83
85
|
- suspenses.ts <- generated suspense hooks
|
|
84
|
-
- prefetch.ts <- generated prefetch
|
|
86
|
+
- prefetch.ts <- generated prefetch functions learn more about prefetching in in link below
|
|
85
87
|
- requests <- output code generated by @hey-api/openapi-ts
|
|
86
88
|
```
|
|
87
89
|
|
package/dist/cli.mjs
CHANGED
|
@@ -36,7 +36,7 @@ async function setupProgram() {
|
|
|
36
36
|
.addOption(new Option("--schemaType <value>", "Type of JSON schema [Default: 'json']").choices(["form", "json"]))
|
|
37
37
|
.option("--pageParam <value>", "Name of the query parameter used for pagination", "page")
|
|
38
38
|
.option("--nextPageParam <value>", "Name of the response parameter used for next page", "nextPage")
|
|
39
|
-
.option("--initialPageParam <value>", "Initial page value to query", "
|
|
39
|
+
.option("--initialPageParam <value>", "Initial page value to query", "1")
|
|
40
40
|
.parse();
|
|
41
41
|
const options = program.opts();
|
|
42
42
|
await generate(options, version);
|
package/dist/constants.mjs
CHANGED
package/dist/createExports.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createPrefetchOrEnsure } from "./createPrefetchOrEnsure.mjs";
|
|
2
2
|
import { createUseMutation } from "./createUseMutation.mjs";
|
|
3
3
|
import { createUseQuery } from "./createUseQuery.mjs";
|
|
4
4
|
export const createExports = (service, pageParam, nextPageParam, initialPageParam) => {
|
|
@@ -10,7 +10,8 @@ export const createExports = (service, pageParam, nextPageParam, initialPagePara
|
|
|
10
10
|
const allPatch = methods.filter((m) => m.httpMethodName.toUpperCase().includes("PATCH"));
|
|
11
11
|
const allDelete = methods.filter((m) => m.httpMethodName.toUpperCase().includes("DELETE"));
|
|
12
12
|
const allGetQueries = allGet.map((m) => createUseQuery(m, pageParam, nextPageParam, initialPageParam));
|
|
13
|
-
const allPrefetchQueries = allGet.map((m) =>
|
|
13
|
+
const allPrefetchQueries = allGet.map((m) => createPrefetchOrEnsure({ ...m, functionType: "prefetch" }));
|
|
14
|
+
const allEnsureQueries = allGet.map((m) => createPrefetchOrEnsure({ ...m, functionType: "ensure" }));
|
|
14
15
|
const allPostMutations = allPost.map((m) => createUseMutation(m));
|
|
15
16
|
const allPutMutations = allPut.map((m) => createUseMutation(m));
|
|
16
17
|
const allPatchMutations = allPatch.map((m) => createUseMutation(m));
|
|
@@ -44,9 +45,8 @@ export const createExports = (service, pageParam, nextPageParam, initialPagePara
|
|
|
44
45
|
suspenseQueryHook,
|
|
45
46
|
]);
|
|
46
47
|
const suspenseExports = [...suspenseQueries];
|
|
47
|
-
const allPrefetches = allPrefetchQueries.flatMap(({
|
|
48
|
-
|
|
49
|
-
]);
|
|
48
|
+
const allPrefetches = allPrefetchQueries.flatMap(({ hook }) => [hook]);
|
|
49
|
+
const allEnsures = allEnsureQueries.flatMap(({ hook }) => [hook]);
|
|
50
50
|
const allPrefetchExports = [...allPrefetches];
|
|
51
51
|
return {
|
|
52
52
|
/**
|
|
@@ -69,5 +69,9 @@ export const createExports = (service, pageParam, nextPageParam, initialPagePara
|
|
|
69
69
|
* Prefetch exports are the hooks that are used in the prefetch components
|
|
70
70
|
*/
|
|
71
71
|
allPrefetchExports,
|
|
72
|
+
/**
|
|
73
|
+
* Ensure exports are the hooks that are used in the loader components
|
|
74
|
+
*/
|
|
75
|
+
allEnsures,
|
|
72
76
|
};
|
|
73
77
|
};
|
|
@@ -3,12 +3,15 @@ import { BuildCommonTypeName, extractPropertiesFromObjectParam, getNameFromMetho
|
|
|
3
3
|
import { createQueryKeyFromMethod, getQueryKeyFnName, getRequestParamFromMethod, hookNameFromMethod, } from "./createUseQuery.mjs";
|
|
4
4
|
import { addJSDocToNode } from "./util.mjs";
|
|
5
5
|
/**
|
|
6
|
-
* Creates a prefetch function for a query
|
|
6
|
+
* Creates a prefetch/ensure function for a query
|
|
7
7
|
*/
|
|
8
|
-
function
|
|
8
|
+
function createPrefetchOrEnsureHook({ requestParams, method, className, functionType, }) {
|
|
9
9
|
const methodName = getNameFromMethod(method);
|
|
10
10
|
const queryName = hookNameFromMethod({ method, className });
|
|
11
|
-
|
|
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
|
+
}
|
|
12
15
|
const queryKey = createQueryKeyFromMethod({ method, className });
|
|
13
16
|
// const
|
|
14
17
|
const hookExport = ts.factory.createVariableStatement(
|
|
@@ -17,7 +20,7 @@ function createPrefetchHook({ requestParams, method, className, }) {
|
|
|
17
20
|
ts.factory.createVariableDeclaration(ts.factory.createIdentifier(customHookName), undefined, undefined, ts.factory.createArrowFunction(undefined, undefined, [
|
|
18
21
|
ts.factory.createParameterDeclaration(undefined, undefined, "queryClient", undefined, ts.factory.createTypeReferenceNode(ts.factory.createIdentifier("QueryClient"))),
|
|
19
22
|
...requestParams,
|
|
20
|
-
], undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), ts.factory.createCallExpression(ts.factory.createIdentifier("
|
|
23
|
+
], undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), ts.factory.createCallExpression(ts.factory.createIdentifier(`queryClient.${functionType === "prefetch" ? "prefetchQuery" : "ensureQueryData"}`), undefined, [
|
|
21
24
|
ts.factory.createObjectLiteralExpression([
|
|
22
25
|
ts.factory.createPropertyAssignment(ts.factory.createIdentifier("queryKey"), ts.factory.createCallExpression(BuildCommonTypeName(getQueryKeyFnName(queryKey)), undefined, method.getParameters().length
|
|
23
26
|
? [
|
|
@@ -38,16 +41,17 @@ function createPrefetchHook({ requestParams, method, className, }) {
|
|
|
38
41
|
], ts.NodeFlags.Const));
|
|
39
42
|
return hookExport;
|
|
40
43
|
}
|
|
41
|
-
export const
|
|
44
|
+
export const createPrefetchOrEnsure = ({ className, method, jsDoc, functionType, }) => {
|
|
42
45
|
const requestParam = getRequestParamFromMethod(method);
|
|
43
46
|
const requestParams = requestParam ? [requestParam] : [];
|
|
44
|
-
const
|
|
47
|
+
const prefetchOrEnsureHook = createPrefetchOrEnsureHook({
|
|
45
48
|
requestParams,
|
|
46
49
|
method,
|
|
47
50
|
className,
|
|
51
|
+
functionType,
|
|
48
52
|
});
|
|
49
|
-
const hookWithJsDoc = addJSDocToNode(
|
|
53
|
+
const hookWithJsDoc = addJSDocToNode(prefetchOrEnsureHook, jsDoc);
|
|
50
54
|
return {
|
|
51
|
-
|
|
55
|
+
hook: hookWithJsDoc,
|
|
52
56
|
};
|
|
53
57
|
};
|
package/dist/createSource.mjs
CHANGED
|
@@ -30,6 +30,7 @@ const createSourceFile = async (outputPath, serviceEndName, pageParam, nextPageP
|
|
|
30
30
|
const suspenseSource = ts.factory.createSourceFile([commonImport, ...imports, ...exports.suspenseExports], ts.factory.createToken(ts.SyntaxKind.EndOfFileToken), ts.NodeFlags.None);
|
|
31
31
|
const indexSource = ts.factory.createSourceFile([commonExport, queriesExport], ts.factory.createToken(ts.SyntaxKind.EndOfFileToken), ts.NodeFlags.None);
|
|
32
32
|
const prefetchSource = ts.factory.createSourceFile([commonImport, ...imports, ...exports.allPrefetchExports], ts.factory.createToken(ts.SyntaxKind.EndOfFileToken), ts.NodeFlags.None);
|
|
33
|
+
const ensureSource = ts.factory.createSourceFile([commonImport, ...imports, ...exports.allEnsures], ts.factory.createToken(ts.SyntaxKind.EndOfFileToken), ts.NodeFlags.None);
|
|
33
34
|
return {
|
|
34
35
|
commonSource,
|
|
35
36
|
infiniteQueriesSource,
|
|
@@ -37,6 +38,7 @@ const createSourceFile = async (outputPath, serviceEndName, pageParam, nextPageP
|
|
|
37
38
|
suspenseSource,
|
|
38
39
|
indexSource,
|
|
39
40
|
prefetchSource,
|
|
41
|
+
ensureSource,
|
|
40
42
|
};
|
|
41
43
|
};
|
|
42
44
|
export const createSource = async ({ outputPath, version, serviceEndName, pageParam, nextPageParam, initialPageParam, }) => {
|
|
@@ -46,11 +48,12 @@ export const createSource = async ({ outputPath, version, serviceEndName, pagePa
|
|
|
46
48
|
const suspenseFile = ts.createSourceFile(`${OpenApiRqFiles.suspense}.ts`, "", ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
|
|
47
49
|
const indexFile = ts.createSourceFile(`${OpenApiRqFiles.index}.ts`, "", ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
|
|
48
50
|
const prefetchFile = ts.createSourceFile(`${OpenApiRqFiles.prefetch}.ts`, "", ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
|
|
51
|
+
const ensureQueryDataFile = ts.createSourceFile(`${OpenApiRqFiles.ensureQueryData}.ts`, "", ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
|
|
49
52
|
const printer = ts.createPrinter({
|
|
50
53
|
newLine: ts.NewLineKind.LineFeed,
|
|
51
54
|
removeComments: false,
|
|
52
55
|
});
|
|
53
|
-
const { commonSource, mainSource, infiniteQueriesSource, suspenseSource, indexSource, prefetchSource, } = await createSourceFile(outputPath, serviceEndName, pageParam, nextPageParam, initialPageParam);
|
|
56
|
+
const { commonSource, mainSource, infiniteQueriesSource, suspenseSource, indexSource, prefetchSource, ensureSource, } = await createSourceFile(outputPath, serviceEndName, pageParam, nextPageParam, initialPageParam);
|
|
54
57
|
const comment = `// generated with @7nohe/openapi-react-query-codegen@${version} \n\n`;
|
|
55
58
|
const commonResult = comment +
|
|
56
59
|
printer.printNode(ts.EmitHint.Unspecified, commonSource, commonFile);
|
|
@@ -64,6 +67,8 @@ export const createSource = async ({ outputPath, version, serviceEndName, pagePa
|
|
|
64
67
|
printer.printNode(ts.EmitHint.Unspecified, indexSource, indexFile);
|
|
65
68
|
const prefetchResult = comment +
|
|
66
69
|
printer.printNode(ts.EmitHint.Unspecified, prefetchSource, prefetchFile);
|
|
70
|
+
const enqureResult = comment +
|
|
71
|
+
printer.printNode(ts.EmitHint.Unspecified, ensureSource, ensureQueryDataFile);
|
|
67
72
|
return [
|
|
68
73
|
{
|
|
69
74
|
name: `${OpenApiRqFiles.index}.ts`,
|
|
@@ -89,5 +94,9 @@ export const createSource = async ({ outputPath, version, serviceEndName, pagePa
|
|
|
89
94
|
name: `${OpenApiRqFiles.prefetch}.ts`,
|
|
90
95
|
content: prefetchResult,
|
|
91
96
|
},
|
|
97
|
+
{
|
|
98
|
+
name: `${OpenApiRqFiles.ensureQueryData}.ts`,
|
|
99
|
+
content: enqureResult,
|
|
100
|
+
},
|
|
92
101
|
];
|
|
93
102
|
};
|
package/dist/createUseQuery.mjs
CHANGED
|
@@ -85,6 +85,30 @@ export function createQueryKeyFromMethod({ method, className, }) {
|
|
|
85
85
|
const queryKey = `${customHookName}Key`;
|
|
86
86
|
return queryKey;
|
|
87
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* Extracts the type of the next page parameter from the given properties.
|
|
90
|
+
*
|
|
91
|
+
* @param properties The properties to search through.
|
|
92
|
+
* @param nextPageParam The name of the next page parameter.
|
|
93
|
+
* @returns The type of the next page parameter, if found.
|
|
94
|
+
*/
|
|
95
|
+
function findNextPageParamType(properties, nextPageParam) {
|
|
96
|
+
if (!properties)
|
|
97
|
+
return undefined;
|
|
98
|
+
for (const property of properties) {
|
|
99
|
+
if (property.getName() === nextPageParam) {
|
|
100
|
+
return property?.getDeclarations()?.at(0)?.getType()?.getText();
|
|
101
|
+
}
|
|
102
|
+
const type = property.getDeclarations().at(0)?.getType();
|
|
103
|
+
const nestedProperties = type?.getProperties();
|
|
104
|
+
if (!type?.isObject() || type.isArray())
|
|
105
|
+
continue;
|
|
106
|
+
const result = findNextPageParamType(nestedProperties, nextPageParam);
|
|
107
|
+
if (result)
|
|
108
|
+
return result;
|
|
109
|
+
}
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
88
112
|
/**
|
|
89
113
|
* Creates a custom hook for a query
|
|
90
114
|
* @param queryString The type of query to use from react-query
|
|
@@ -101,6 +125,11 @@ export function createQueryHook({ queryString, suffix, responseDataType, request
|
|
|
101
125
|
const isInfiniteQuery = queryString === "useInfiniteQuery";
|
|
102
126
|
const responseDataTypeRef = responseDataType.default;
|
|
103
127
|
const responseDataTypeIdentifier = responseDataTypeRef.typeName;
|
|
128
|
+
const arg = method.getReturnType().getTypeArguments().at(0);
|
|
129
|
+
const nextPageParamTypePropetires = arg?.getProperties();
|
|
130
|
+
const nextPageParamType = arg?.isObject() && nextPageParam
|
|
131
|
+
? findNextPageParamType(nextPageParamTypePropetires, nextPageParam.split(".").at(-1) ?? "")
|
|
132
|
+
: undefined;
|
|
104
133
|
const hookExport = ts.factory.createVariableStatement([ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], ts.factory.createVariableDeclarationList([
|
|
105
134
|
ts.factory.createVariableDeclaration(ts.factory.createIdentifier(`${customHookName}${suffix}`), undefined, undefined, ts.factory.createArrowFunction(undefined, ts.factory.createNodeArray([
|
|
106
135
|
isInfiniteQuery
|
|
@@ -151,11 +180,15 @@ export function createQueryHook({ queryString, suffix, responseDataType, request
|
|
|
151
180
|
ts.factory.createObjectLiteralExpression(method
|
|
152
181
|
.getParameters()
|
|
153
182
|
.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(
|
|
183
|
+
? ts.factory.createPropertyAssignment(ts.factory.createIdentifier(p.name), ts.factory.createAsExpression(ts.factory.createIdentifier("pageParam"), ts.factory.createKeywordTypeNode(p.type?.getText() === "number"
|
|
184
|
+
? ts.SyntaxKind
|
|
185
|
+
.NumberKeyword
|
|
186
|
+
: ts.SyntaxKind
|
|
187
|
+
.StringKeyword)))
|
|
155
188
|
: ts.factory.createShorthandPropertyAssignment(ts.factory.createIdentifier(p.name))))),
|
|
156
189
|
]
|
|
157
190
|
: undefined), ts.factory.createTypeReferenceNode(TData)))),
|
|
158
|
-
...createInfiniteQueryParams(pageParam, nextPageParam, initialPageParam),
|
|
191
|
+
...createInfiniteQueryParams(pageParam, nextPageParam, initialPageParam, nextPageParamType),
|
|
159
192
|
ts.factory.createSpreadAssignment(ts.factory.createIdentifier("options")),
|
|
160
193
|
]),
|
|
161
194
|
]))),
|
|
@@ -258,7 +291,7 @@ function queryKeyFn(queryKey, method) {
|
|
|
258
291
|
: ts.factory.createArrayLiteralExpression([])))),
|
|
259
292
|
], false);
|
|
260
293
|
}
|
|
261
|
-
function createInfiniteQueryParams(pageParam, nextPageParam, initialPageParam = "1") {
|
|
294
|
+
function createInfiniteQueryParams(pageParam, nextPageParam, initialPageParam = "1", type) {
|
|
262
295
|
if (pageParam === undefined || nextPageParam === undefined) {
|
|
263
296
|
return [];
|
|
264
297
|
}
|
|
@@ -272,6 +305,8 @@ function createInfiniteQueryParams(pageParam, nextPageParam, initialPageParam =
|
|
|
272
305
|
return ts.factory.createTypeLiteralNode([
|
|
273
306
|
ts.factory.createPropertySignature(undefined, ts.factory.createIdentifier(segment), undefined, acc),
|
|
274
307
|
]);
|
|
275
|
-
}, ts.factory.createKeywordTypeNode(
|
|
308
|
+
}, ts.factory.createKeywordTypeNode(type === "number"
|
|
309
|
+
? ts.SyntaxKind.NumberKeyword
|
|
310
|
+
: ts.SyntaxKind.StringKeyword)))), ts.factory.createIdentifier(nextPageParam)))),
|
|
276
311
|
];
|
|
277
312
|
}
|
package/dist/generate.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@7nohe/openapi-react-query-codegen",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.2",
|
|
4
4
|
"description": "OpenAPI React Query Codegen",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"codegen",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"lint": "biome check .",
|
|
62
62
|
"lint:fix": "biome check --write .",
|
|
63
63
|
"preview": "npm run build && npm -C examples/react-app run generate:api",
|
|
64
|
-
"release": "npx git-ensure -a && npx bumpp --commit --tag --push",
|
|
64
|
+
"release": "npx git-ensure -a -b v1 && npx bumpp --commit --tag --push",
|
|
65
65
|
"snapshot": "vitest --update",
|
|
66
66
|
"test": "vitest --coverage.enabled true"
|
|
67
67
|
}
|