@7nohe/openapi-react-query-codegen 1.5.1 → 1.6.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.
package/README.md CHANGED
@@ -42,23 +42,25 @@ Usage: openapi-rq [options]
42
42
  Generate React Query code based on OpenAPI
43
43
 
44
44
  Options:
45
- -V, --version output the version number
46
- -i, --input <value> OpenAPI specification, can be a path, url or string content (required)
47
- -o, --output <value> Output directory (default: "openapi")
48
- -c, --client <value> HTTP client to generate (choices: "angular", "axios", "fetch", "node", "xhr", default: "fetch")
49
- --request <value> Path to custom request file
50
- --format <value> Process output folder with formatter? (choices: "biome", "prettier")
51
- --lint <value> Process output folder with linter? (choices: "biome", "eslint")
52
- --operationId Use operation ID to generate operation names?
53
- --serviceResponse <value> Define shape of returned value from service calls (choices: "body", "response", default: "body")
54
- --base <value> Manually set base in OpenAPI config instead of inferring from server value
55
- --enums <value> Generate JavaScript objects from enum definitions? (choices: "javascript", "typescript")
56
- --useDateType Use Date type instead of string for date types for models, this will not convert the data to a Date object
57
- --debug Run in debug mode?
58
- --noSchemas Disable generating JSON schemas
59
- --schemaType <value> Type of JSON schema [Default: 'json'] (choices: "form", "json")
60
- --pageParam <value> Name of the query parameter used for pagination (default: "page")
61
- --nextPageParam <value> Name of the response parameter used for next page (default: "nextPage")
45
+ -V, --version output the version number
46
+ -i, --input <value> OpenAPI specification, can be a path, url or string content (required)
47
+ -o, --output <value> Output directory (default: "openapi")
48
+ -c, --client <value> HTTP client to generate (choices: "angular", "axios", "fetch", "node", "xhr", default: "fetch")
49
+ --request <value> Path to custom request file
50
+ --format <value> Process output folder with formatter? (choices: "biome", "prettier")
51
+ --lint <value> Process output folder with linter? (choices: "biome", "eslint")
52
+ --operationId Use operation ID to generate operation names?
53
+ --serviceResponse <value> Define shape of returned value from service calls (choices: "body", "response", default: "body")
54
+ --base <value> Manually set base in OpenAPI config instead of inferring from server value
55
+ --enums <value> Generate JavaScript objects from enum definitions? ['javascript', 'typescript', 'typescript+namespace']
56
+ --enums <value> Generate JavaScript objects from enum definitions? (choices: "javascript", "typescript")
57
+ --useDateType Use Date type instead of string for date types for models, this will not convert the data to a Date object
58
+ --debug Run in debug mode?
59
+ --noSchemas Disable generating JSON schemas
60
+ --schemaType <value> Type of JSON schema [Default: 'json'] (choices: "form", "json")
61
+ --pageParam <value> Name of the query parameter used for pagination (default: "page")
62
+ --nextPageParam <value> Name of the response parameter used for next page (default: "nextPage")
63
+ --initialPageParam <value> Initial value for the pagination parameter (default: "1")
62
64
  -h, --help display help for command
63
65
  ```
64
66
 
@@ -240,6 +242,8 @@ export default App;
240
242
 
241
243
  This feature will generate a function in infiniteQueries.ts when the name specified by the `pageParam` option exists in the query parameters and the name specified by the `nextPageParam` option exists in the response.
242
244
 
245
+ The `initialPageParam` option can be specified to set the intial page to load, defaults to 1. The `nextPageParam` supports dot notation for nested values (i.e. `meta.next`).
246
+
243
247
  Example Schema:
244
248
 
245
249
  ```yml
package/dist/cli.mjs CHANGED
@@ -29,13 +29,14 @@ async function setupProgram() {
29
29
  .choices(["body", "response"])
30
30
  .default("body"))
31
31
  .option("--base <value>", "Manually set base in OpenAPI config instead of inferring from server value")
32
- .addOption(new Option("--enums <value>", "Generate JavaScript objects from enum definitions?").choices(["javascript", "typescript"]))
32
+ .addOption(new Option("--enums <value>", "Generate JavaScript objects from enum definitions?").choices(["javascript", "typescript", "typescript+namespace"]))
33
33
  .option("--useDateType", "Use Date type instead of string for date types for models, this will not convert the data to a Date object")
34
34
  .option("--debug", "Run in debug mode?")
35
35
  .option("--noSchemas", "Disable generating JSON schemas")
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", "initialPageParam")
39
40
  .parse();
40
41
  const options = program.opts();
41
42
  await generate(options, version);
@@ -1,7 +1,7 @@
1
1
  import { createPrefetch } from "./createPrefetch.mjs";
2
2
  import { createUseMutation } from "./createUseMutation.mjs";
3
3
  import { createUseQuery } from "./createUseQuery.mjs";
4
- export const createExports = (service, pageParam, nextPageParam) => {
4
+ export const createExports = (service, pageParam, nextPageParam, initialPageParam) => {
5
5
  const { klasses } = service;
6
6
  const methods = klasses.flatMap((k) => k.methods);
7
7
  const allGet = methods.filter((m) => m.httpMethodName.toUpperCase().includes("GET"));
@@ -9,7 +9,7 @@ export const createExports = (service, pageParam, nextPageParam) => {
9
9
  const allPut = methods.filter((m) => m.httpMethodName.toUpperCase().includes("PUT"));
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
- const allGetQueries = allGet.map((m) => createUseQuery(m, pageParam, nextPageParam));
12
+ const allGetQueries = allGet.map((m) => createUseQuery(m, pageParam, nextPageParam, initialPageParam));
13
13
  const allPrefetchQueries = allGet.map((m) => createPrefetch(m));
14
14
  const allPostMutations = allPost.map((m) => createUseMutation(m));
15
15
  const allPutMutations = allPut.map((m) => createUseMutation(m));
@@ -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) => {
8
+ const createSourceFile = async (outputPath, serviceEndName, 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
@@ -20,7 +20,7 @@ const createSourceFile = async (outputPath, serviceEndName, pageParam, nextPageP
20
20
  serviceEndName,
21
21
  project,
22
22
  });
23
- const exports = createExports(service, pageParam, nextPageParam);
23
+ const exports = createExports(service, pageParam, nextPageParam, initialPageParam);
24
24
  const commonSource = ts.factory.createSourceFile([...imports, ...exports.allCommon], ts.factory.createToken(ts.SyntaxKind.EndOfFileToken), ts.NodeFlags.None);
25
25
  const commonImport = ts.factory.createImportDeclaration(undefined, ts.factory.createImportClause(false, ts.factory.createIdentifier("* as Common"), undefined), ts.factory.createStringLiteral(`./${OpenApiRqFiles.common}`), undefined);
26
26
  const commonExport = ts.factory.createExportDeclaration(undefined, false, undefined, ts.factory.createStringLiteral(`./${OpenApiRqFiles.common}`), undefined);
@@ -39,7 +39,7 @@ const createSourceFile = async (outputPath, serviceEndName, pageParam, nextPageP
39
39
  prefetchSource,
40
40
  };
41
41
  };
42
- export const createSource = async ({ outputPath, version, serviceEndName, pageParam, nextPageParam, }) => {
42
+ export const createSource = async ({ outputPath, version, serviceEndName, pageParam, nextPageParam, initialPageParam, }) => {
43
43
  const queriesFile = ts.createSourceFile(`${OpenApiRqFiles.queries}.ts`, "", ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
44
44
  const infiniteQueriesFile = ts.createSourceFile(`${OpenApiRqFiles.infiniteQueries}.ts`, "", ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
45
45
  const commonFile = ts.createSourceFile(`${OpenApiRqFiles.common}.ts`, "", ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
@@ -50,7 +50,7 @@ export const createSource = async ({ outputPath, version, serviceEndName, pagePa
50
50
  newLine: ts.NewLineKind.LineFeed,
51
51
  removeComments: false,
52
52
  });
53
- const { commonSource, mainSource, infiniteQueriesSource, suspenseSource, indexSource, prefetchSource, } = await createSourceFile(outputPath, serviceEndName, pageParam, nextPageParam);
53
+ const { commonSource, mainSource, infiniteQueriesSource, suspenseSource, indexSource, prefetchSource, } = await createSourceFile(outputPath, serviceEndName, pageParam, nextPageParam, initialPageParam);
54
54
  const comment = `// generated with @7nohe/openapi-react-query-codegen@${version} \n\n`;
55
55
  const commonResult = comment +
56
56
  printer.printNode(ts.EmitHint.Unspecified, commonSource, commonFile);
@@ -24,7 +24,7 @@ export const createUseMutation = ({ className, method, jsDoc, }) => {
24
24
  const paramNodes = extractPropertiesFromObjectParam(param);
25
25
  return paramNodes.map((refParam) => ts.factory.createPropertySignature(undefined, ts.factory.createIdentifier(refParam.name), refParam.optional
26
26
  ? ts.factory.createToken(ts.SyntaxKind.QuestionToken)
27
- : undefined, ts.factory.createTypeReferenceNode(getShortType(refParam.type.getText(param)))));
27
+ : undefined, ts.factory.createTypeReferenceNode(getShortType(refParam.type?.getText(param) ?? ""))));
28
28
  }))
29
29
  : ts.factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword);
30
30
  const exportHook = ts.factory.createVariableStatement([ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], ts.factory.createVariableDeclarationList([
@@ -38,7 +38,7 @@ export function getRequestParamFromMethod(method, pageParam) {
38
38
  .filter((p) => p.name !== pageParam)
39
39
  .map((refParam) => ({
40
40
  name: refParam.name,
41
- typeName: getShortType(refParam.type.getText()),
41
+ typeName: getShortType(refParam.type?.getText() ?? ""),
42
42
  optional: refParam.optional,
43
43
  }));
44
44
  });
@@ -90,7 +90,7 @@ export function createQueryKeyFromMethod({ method, className, }) {
90
90
  * @param queryString The type of query to use from react-query
91
91
  * @param suffix The suffix to append to the hook name
92
92
  */
93
- export function createQueryHook({ queryString, suffix, responseDataType, requestParams, method, className, pageParam, nextPageParam, }) {
93
+ export function createQueryHook({ queryString, suffix, responseDataType, requestParams, method, className, pageParam, nextPageParam, initialPageParam, }) {
94
94
  const methodName = getNameFromMethod(method);
95
95
  const customHookName = hookNameFromMethod({ method, className });
96
96
  const queryKey = createQueryKeyFromMethod({ method, className });
@@ -155,14 +155,14 @@ export function createQueryHook({ queryString, suffix, responseDataType, request
155
155
  : ts.factory.createShorthandPropertyAssignment(ts.factory.createIdentifier(p.name))))),
156
156
  ]
157
157
  : undefined), ts.factory.createTypeReferenceNode(TData)))),
158
- ...createInfiniteQueryParams(pageParam, nextPageParam),
158
+ ...createInfiniteQueryParams(pageParam, nextPageParam, initialPageParam),
159
159
  ts.factory.createSpreadAssignment(ts.factory.createIdentifier("options")),
160
160
  ]),
161
161
  ]))),
162
162
  ], ts.NodeFlags.Const));
163
163
  return hookExport;
164
164
  }
165
- export const createUseQuery = ({ className, method, jsDoc }, pageParam, nextPageParam) => {
165
+ export const createUseQuery = ({ className, method, jsDoc }, pageParam, nextPageParam, initialPageParam) => {
166
166
  const methodName = getNameFromMethod(method);
167
167
  const queryKey = createQueryKeyFromMethod({ method, className });
168
168
  const { apiResponse: defaultApiResponse, responseDataType } = createApiResponseType({
@@ -206,6 +206,7 @@ export const createUseQuery = ({ className, method, jsDoc }, pageParam, nextPage
206
206
  className,
207
207
  pageParam,
208
208
  nextPageParam,
209
+ initialPageParam,
209
210
  })
210
211
  : undefined;
211
212
  const hookWithJsDoc = addJSDocToNode(queryHook, jsDoc);
@@ -257,16 +258,20 @@ function queryKeyFn(queryKey, method) {
257
258
  : ts.factory.createArrayLiteralExpression([])))),
258
259
  ], false);
259
260
  }
260
- function createInfiniteQueryParams(pageParam, nextPageParam) {
261
+ function createInfiniteQueryParams(pageParam, nextPageParam, initialPageParam = "1") {
261
262
  if (pageParam === undefined || nextPageParam === undefined) {
262
263
  return [];
263
264
  }
264
265
  return [
265
- ts.factory.createPropertyAssignment(ts.factory.createIdentifier("initialPageParam"), ts.factory.createNumericLiteral(1)),
266
+ ts.factory.createPropertyAssignment(ts.factory.createIdentifier("initialPageParam"), ts.factory.createStringLiteral(initialPageParam)),
266
267
  ts.factory.createPropertyAssignment(ts.factory.createIdentifier("getNextPageParam"),
267
268
  // (response) => (response as { nextPage: number }).nextPage,
268
269
  ts.factory.createArrowFunction(undefined, undefined, [
269
270
  ts.factory.createParameterDeclaration(undefined, undefined, ts.factory.createIdentifier("response"), undefined, undefined),
270
- ], undefined, EqualsOrGreaterThanToken, ts.factory.createPropertyAccessExpression(ts.factory.createParenthesizedExpression(ts.factory.createAsExpression(ts.factory.createIdentifier("response"), ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(`{ ${nextPageParam}: number }`)))), ts.factory.createIdentifier(nextPageParam)))),
271
+ ], undefined, EqualsOrGreaterThanToken, ts.factory.createPropertyAccessExpression(ts.factory.createParenthesizedExpression(ts.factory.createAsExpression(ts.factory.createIdentifier("response"), nextPageParam.split(".").reduceRight((acc, segment) => {
272
+ return ts.factory.createTypeLiteralNode([
273
+ ts.factory.createPropertySignature(undefined, ts.factory.createIdentifier(segment), undefined, acc),
274
+ ]);
275
+ }, ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword)))), ts.factory.createIdentifier(nextPageParam)))),
271
276
  ];
272
277
  }
package/dist/generate.mjs CHANGED
@@ -26,6 +26,7 @@ export async function generate(options, version) {
26
26
  services: {
27
27
  export: true,
28
28
  response: formattedOptions.serviceResponse,
29
+ asClass: true,
29
30
  },
30
31
  types: {
31
32
  dates: formattedOptions.useDateType,
@@ -41,6 +42,7 @@ export async function generate(options, version) {
41
42
  serviceEndName: "Service", // we are hard coding this because changing the service end name was depreciated in @hey-api/openapi-ts
42
43
  pageParam: formattedOptions.pageParam,
43
44
  nextPageParam: formattedOptions.nextPageParam,
45
+ initialPageParam: formattedOptions.initialPageParam.toString(),
44
46
  });
45
47
  await print(source, formattedOptions);
46
48
  const queriesOutputPath = buildQueriesOutputPath(options.output);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@7nohe/openapi-react-query-codegen",
3
- "version": "1.5.1",
3
+ "version": "1.6.1",
4
4
  "description": "OpenAPI React Query Codegen",
5
5
  "keywords": [
6
6
  "codegen",
@@ -31,7 +31,7 @@
31
31
  "examples/*"
32
32
  ],
33
33
  "dependencies": {
34
- "@hey-api/openapi-ts": "0.45.1"
34
+ "@hey-api/openapi-ts": "0.52.0"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@biomejs/biome": "^1.7.2",
@@ -41,9 +41,9 @@
41
41
  "glob": "^10.3.10",
42
42
  "lefthook": "^1.6.10",
43
43
  "rimraf": "^5.0.5",
44
- "ts-morph": "^22.0.0",
44
+ "ts-morph": "^23.0.0",
45
45
  "ts-node": "^10.9.2",
46
- "typescript": "^5.3.3",
46
+ "typescript": "^5.5.4",
47
47
  "vitest": "^1.5.0"
48
48
  },
49
49
  "peerDependencies": {
@@ -59,7 +59,7 @@
59
59
  "scripts": {
60
60
  "build": "rimraf dist && tsc -p tsconfig.json",
61
61
  "lint": "biome check .",
62
- "lint:fix": "biome check --apply .",
62
+ "lint:fix": "biome check --write .",
63
63
  "preview": "npm run build && npm -C examples/react-app run generate:api",
64
64
  "release": "npx git-ensure -a && npx bumpp --commit --tag --push",
65
65
  "snapshot": "vitest --update",