@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.
package/dist/format.mjs CHANGED
@@ -1,3 +1,4 @@
1
+ import { sync } from "cross-spawn";
1
2
  import { IndentationText, NewLineKind, Project, QuoteKind } from "ts-morph";
2
3
  export const formatOutput = async (outputPath) => {
3
4
  const project = new Project({
@@ -19,3 +20,48 @@ export const formatOutput = async (outputPath) => {
19
20
  });
20
21
  await Promise.all(tasks);
21
22
  };
23
+ const formatters = {
24
+ biome: {
25
+ args: (path) => ["format", "--write", path],
26
+ command: "biome",
27
+ name: "Biome (Format)",
28
+ },
29
+ prettier: {
30
+ args: (path) => [
31
+ "--ignore-unknown",
32
+ path,
33
+ "--write",
34
+ "--ignore-path",
35
+ "./.prettierignore",
36
+ ],
37
+ command: "prettier",
38
+ name: "Prettier",
39
+ },
40
+ };
41
+ /**
42
+ * Map of supported linters
43
+ */
44
+ const linters = {
45
+ biome: {
46
+ args: (path) => ["lint", "--write", path],
47
+ command: "biome",
48
+ name: "Biome (Lint)",
49
+ },
50
+ eslint: {
51
+ args: (path) => [path, "--fix"],
52
+ command: "eslint",
53
+ name: "ESLint",
54
+ },
55
+ };
56
+ export const processOutput = async ({ output, format, lint, }) => {
57
+ if (format) {
58
+ const module = formatters[format];
59
+ console.log(`✨ Running ${module.name} on queries`);
60
+ sync(module.command, module.args(output));
61
+ }
62
+ if (lint) {
63
+ const module = linters[lint];
64
+ console.log(`✨ Running ${module.name} on queries`);
65
+ sync(module.command, module.args(output));
66
+ }
67
+ };
package/dist/generate.mjs CHANGED
@@ -1,13 +1,12 @@
1
1
  import { createClient } from "@hey-api/openapi-ts";
2
2
  import { buildQueriesOutputPath, buildRequestsOutputPath, formatOptions, } from "./common.mjs";
3
3
  import { createSource } from "./createSource.mjs";
4
- import { formatOutput } from "./format.mjs";
4
+ import { formatOutput, processOutput } from "./format.mjs";
5
5
  import { print } from "./print.mjs";
6
6
  export async function generate(options, version) {
7
7
  const openApiOutputPath = buildRequestsOutputPath(options.output);
8
8
  const formattedOptions = formatOptions(options);
9
9
  const config = {
10
- base: formattedOptions.base,
11
10
  client: formattedOptions.client,
12
11
  debug: formattedOptions.debug,
13
12
  dryRun: false,
@@ -18,15 +17,16 @@ export async function generate(options, version) {
18
17
  path: openApiOutputPath,
19
18
  },
20
19
  input: formattedOptions.input,
21
- request: formattedOptions.request,
22
20
  schemas: {
23
21
  export: !formattedOptions.noSchemas,
24
22
  type: formattedOptions.schemaType,
25
23
  },
26
24
  services: {
27
25
  export: true,
28
- response: formattedOptions.serviceResponse,
29
- asClass: true,
26
+ asClass: false,
27
+ operationId: formattedOptions.operationId !== undefined
28
+ ? formattedOptions.operationId
29
+ : true,
30
30
  },
31
31
  types: {
32
32
  dates: formattedOptions.useDateType,
@@ -38,8 +38,8 @@ export async function generate(options, version) {
38
38
  await createClient(config);
39
39
  const source = await createSource({
40
40
  outputPath: openApiOutputPath,
41
+ client: formattedOptions.client,
41
42
  version,
42
- serviceEndName: "Service", // we are hard coding this because changing the service end name was depreciated in @hey-api/openapi-ts
43
43
  pageParam: formattedOptions.pageParam,
44
44
  nextPageParam: formattedOptions.nextPageParam,
45
45
  initialPageParam: formattedOptions.initialPageParam.toString(),
@@ -47,4 +47,9 @@ export async function generate(options, version) {
47
47
  await print(source, formattedOptions);
48
48
  const queriesOutputPath = buildQueriesOutputPath(options.output);
49
49
  await formatOutput(queriesOutputPath);
50
+ await processOutput({
51
+ output: queriesOutputPath,
52
+ format: formattedOptions.format,
53
+ lint: formattedOptions.lint,
54
+ });
50
55
  }
package/dist/service.mjs CHANGED
@@ -1,5 +1,4 @@
1
1
  import ts from "typescript";
2
- import { getClassNameFromClassNode, getClassesFromService, } from "./common.mjs";
3
2
  import { serviceFileName } from "./constants.mjs";
4
3
  export async function getServices(project) {
5
4
  const node = project
@@ -8,72 +7,73 @@ export async function getServices(project) {
8
7
  if (!node) {
9
8
  throw new Error("No service node found");
10
9
  }
11
- const klasses = getClassesFromService(node);
10
+ const methods = getMethodsFromService(node);
12
11
  return {
13
- klasses: klasses.map(({ klass, className }) => ({
14
- className,
15
- klass,
16
- methods: getMethodsFromService(node, klass),
17
- })),
12
+ methods,
18
13
  node,
19
14
  };
20
15
  }
21
- function getMethodsFromService(node, klass) {
22
- const methods = klass.getMethods();
23
- if (!methods.length) {
24
- throw new Error("No methods found");
25
- }
26
- return methods.map((method) => {
27
- const methodBlockNode = method.compilerNode
28
- .getChildren(node.compilerNode)
29
- .find((child) => child.kind === ts.SyntaxKind.Block);
30
- if (!methodBlockNode) {
31
- throw new Error("Method block not found");
32
- }
33
- const methodBlock = methodBlockNode;
34
- const foundReturnStatement = methodBlock.statements.find((s) => s.kind === ts.SyntaxKind.ReturnStatement);
35
- if (!foundReturnStatement) {
36
- throw new Error("Return statement not found");
37
- }
38
- const returnStatement = foundReturnStatement;
39
- const foundCallExpression = returnStatement.expression;
40
- if (!foundCallExpression) {
41
- throw new Error("Call expression not found");
42
- }
43
- const callExpression = foundCallExpression;
44
- const properties = callExpression.arguments[1].properties;
45
- const httpMethodName = properties
46
- .find((p) => p.name?.getText(node.compilerNode) === "method")
47
- ?.initializer?.getText(node.compilerNode);
48
- if (!httpMethodName) {
49
- throw new Error("httpMethodName not found");
50
- }
51
- const getAllChildren = (tsNode) => {
52
- const childItems = tsNode.getChildren(node.compilerNode);
53
- if (childItems.length) {
54
- const allChildren = childItems.map(getAllChildren);
55
- return [tsNode].concat(allChildren.flat());
16
+ export function getMethodsFromService(node) {
17
+ const variableStatements = node.getVariableStatements();
18
+ // The first variable statement is `const client = createClient(createConfig())`, so we skip it
19
+ return variableStatements.splice(1).flatMap((variableStatement) => {
20
+ const declarations = variableStatement.getDeclarations();
21
+ return declarations.map((declaration) => {
22
+ if (!ts.isVariableDeclaration(declaration.compilerNode)) {
23
+ throw new Error("Variable declaration not found");
24
+ }
25
+ const initializer = declaration.getInitializer();
26
+ if (!initializer) {
27
+ throw new Error("Initializer not found");
28
+ }
29
+ if (!ts.isArrowFunction(initializer.compilerNode)) {
30
+ throw new Error("Arrow function not found");
31
+ }
32
+ const methodBlockNode = initializer.compilerNode.body;
33
+ if (!methodBlockNode || !ts.isBlock(methodBlockNode)) {
34
+ throw new Error("Method block not found");
35
+ }
36
+ const foundReturnStatement = methodBlockNode.statements.find((s) => s.kind === ts.SyntaxKind.ReturnStatement);
37
+ if (!foundReturnStatement) {
38
+ throw new Error("Return statement not found");
39
+ }
40
+ const returnStatement = foundReturnStatement;
41
+ const foundCallExpression = returnStatement.expression;
42
+ if (!foundCallExpression) {
43
+ throw new Error("Call expression not found");
44
+ }
45
+ const callExpression = foundCallExpression;
46
+ const propertyAccessExpression = callExpression.expression;
47
+ const httpMethodName = propertyAccessExpression.name.getText();
48
+ if (!httpMethodName) {
49
+ throw new Error("httpMethodName not found");
56
50
  }
57
- return [tsNode];
58
- };
59
- const children = getAllChildren(method.compilerNode);
60
- // get all JSDoc comments
61
- // this should be an array of 1 or 0
62
- const jsDocs = children
63
- .filter((c) => c.kind === ts.SyntaxKind.JSDoc)
64
- .map((c) => c.getText(node.compilerNode));
65
- // get the first JSDoc comment
66
- const jsDoc = jsDocs?.[0];
67
- const isDeprecated = children.some((c) => c.kind === ts.SyntaxKind.JSDocDeprecatedTag);
68
- const className = getClassNameFromClassNode(klass);
69
- return {
70
- className,
71
- node,
72
- method,
73
- methodBlock,
74
- httpMethodName,
75
- jsDoc,
76
- isDeprecated,
77
- };
51
+ const getAllChildren = (tsNode) => {
52
+ const childItems = tsNode.getChildren(node.compilerNode);
53
+ if (childItems.length) {
54
+ const allChildren = childItems.map(getAllChildren);
55
+ return [tsNode].concat(allChildren.flat());
56
+ }
57
+ return [tsNode];
58
+ };
59
+ const children = getAllChildren(initializer.compilerNode);
60
+ // get all JSDoc comments
61
+ // this should be an array of 1 or 0
62
+ const jsDocs = children
63
+ .filter((c) => c.kind === ts.SyntaxKind.JSDoc)
64
+ .map((c) => c.getText(node.compilerNode));
65
+ // get the first JSDoc comment
66
+ const jsDoc = jsDocs?.[0];
67
+ const isDeprecated = children.some((c) => c.kind === ts.SyntaxKind.JSDocDeprecatedTag);
68
+ const methodDescription = {
69
+ node,
70
+ method: declaration,
71
+ methodBlock: methodBlockNode,
72
+ httpMethodName,
73
+ jsDoc,
74
+ isDeprecated,
75
+ };
76
+ return methodDescription;
77
+ });
78
78
  });
79
79
  }
package/package.json CHANGED
@@ -1,7 +1,31 @@
1
1
  {
2
2
  "name": "@7nohe/openapi-react-query-codegen",
3
- "version": "1.6.1",
3
+ "version": "2.0.0-beta.1",
4
4
  "description": "OpenAPI React Query Codegen",
5
+ "bin": {
6
+ "openapi-rq": "dist/cli.mjs"
7
+ },
8
+ "private": false,
9
+ "type": "module",
10
+ "workspaces": [
11
+ "examples/*"
12
+ ],
13
+ "exports": [
14
+ {
15
+ "import": "./dist/generate.mjs",
16
+ "require": "./dist/generate.mjs",
17
+ "types": "./dist/generate.d.mts"
18
+ }
19
+ ],
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/7nohe/openapi-react-query-codegen.git"
23
+ },
24
+ "homepage": "https://github.com/7nohe/openapi-react-query-codegen",
25
+ "bugs": "https://github.com/7nohe/openapi-react-query-codegen/issues",
26
+ "files": [
27
+ "dist"
28
+ ],
5
29
  "keywords": [
6
30
  "codegen",
7
31
  "react-query",
@@ -12,44 +36,28 @@
12
36
  "openapi-typescript-codegen",
13
37
  "@hey-api/openapi-ts"
14
38
  ],
15
- "homepage": "https://github.com/7nohe/openapi-react-query-codegen",
16
- "bugs": "https://github.com/7nohe/openapi-react-query-codegen/issues",
17
- "repository": {
18
- "type": "git",
19
- "url": "git+https://github.com/7nohe/openapi-react-query-codegen.git"
20
- },
21
39
  "license": "MIT",
22
40
  "author": "Daiki Urata (@7nohe)",
23
- "type": "module",
24
- "bin": {
25
- "openapi-rq": "dist/cli.mjs"
26
- },
27
- "files": [
28
- "dist"
29
- ],
30
- "workspaces": [
31
- "examples/*"
32
- ],
33
41
  "dependencies": {
34
- "@hey-api/openapi-ts": "0.52.0"
42
+ "@hey-api/client-fetch": "0.4.0",
43
+ "@hey-api/openapi-ts": "0.53.8",
44
+ "cross-spawn": "^7.0.3"
35
45
  },
36
46
  "devDependencies": {
37
- "@biomejs/biome": "^1.7.2",
38
- "@types/node": "^20.10.6",
47
+ "@biomejs/biome": "^1.9.3",
48
+ "@types/cross-spawn": "^6.0.6",
49
+ "@types/node": "^22.7.4",
39
50
  "@vitest/coverage-v8": "^1.5.0",
40
51
  "commander": "^12.0.0",
41
- "glob": "^10.3.10",
42
52
  "lefthook": "^1.6.10",
43
53
  "rimraf": "^5.0.5",
44
54
  "ts-morph": "^23.0.0",
45
- "ts-node": "^10.9.2",
46
55
  "typescript": "^5.5.4",
47
56
  "vitest": "^1.5.0"
48
57
  },
49
58
  "peerDependencies": {
50
59
  "commander": "12.x",
51
- "glob": "10.x",
52
- "ts-morph": "22.x",
60
+ "ts-morph": "23.x",
53
61
  "typescript": "5.x"
54
62
  },
55
63
  "engines": {
@@ -60,9 +68,11 @@
60
68
  "build": "rimraf dist && tsc -p tsconfig.json",
61
69
  "lint": "biome check .",
62
70
  "lint:fix": "biome check --write .",
63
- "preview": "npm run build && npm -C examples/react-app run generate:api",
71
+ "preview:react": "npm run build && npm -C examples/react-app run generate:api",
72
+ "preview:nextjs": "npm run build && npm -C examples/nextjs-app run generate:api",
73
+ "preview:tanstack-router": "npm run build && npm -C examples/tanstack-router-app run generate:api",
64
74
  "release": "npx git-ensure -a && npx bumpp --commit --tag --push",
65
- "snapshot": "vitest --update",
66
- "test": "vitest --coverage.enabled true"
75
+ "test": "vitest --coverage.enabled true",
76
+ "snapshot": "vitest --update"
67
77
  }
68
78
  }
@@ -1,53 +0,0 @@
1
- import ts from "typescript";
2
- import { BuildCommonTypeName, extractPropertiesFromObjectParam, getNameFromMethod, } from "./common.mjs";
3
- import { createQueryKeyFromMethod, getQueryKeyFnName, getRequestParamFromMethod, hookNameFromMethod, } from "./createUseQuery.mjs";
4
- import { addJSDocToNode } from "./util.mjs";
5
- /**
6
- * Creates a prefetch function for a query
7
- */
8
- function createPrefetchHook({ requestParams, method, className, }) {
9
- const methodName = getNameFromMethod(method);
10
- const queryName = hookNameFromMethod({ method, className });
11
- const customHookName = `prefetch${queryName.charAt(0).toUpperCase() + queryName.slice(1)}`;
12
- const queryKey = createQueryKeyFromMethod({ method, className });
13
- // const
14
- const hookExport = ts.factory.createVariableStatement(
15
- // export
16
- [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], ts.factory.createVariableDeclarationList([
17
- ts.factory.createVariableDeclaration(ts.factory.createIdentifier(customHookName), undefined, undefined, ts.factory.createArrowFunction(undefined, undefined, [
18
- ts.factory.createParameterDeclaration(undefined, undefined, "queryClient", undefined, ts.factory.createTypeReferenceNode(ts.factory.createIdentifier("QueryClient"))),
19
- ...requestParams,
20
- ], undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), ts.factory.createCallExpression(ts.factory.createIdentifier("queryClient.prefetchQuery"), undefined, [
21
- ts.factory.createObjectLiteralExpression([
22
- ts.factory.createPropertyAssignment(ts.factory.createIdentifier("queryKey"), ts.factory.createCallExpression(BuildCommonTypeName(getQueryKeyFnName(queryKey)), undefined, method.getParameters().length
23
- ? [
24
- ts.factory.createObjectLiteralExpression(method
25
- .getParameters()
26
- .flatMap((param) => extractPropertiesFromObjectParam(param).map((p) => ts.factory.createShorthandPropertyAssignment(ts.factory.createIdentifier(p.name))))),
27
- ]
28
- : [])),
29
- ts.factory.createPropertyAssignment(ts.factory.createIdentifier("queryFn"), ts.factory.createArrowFunction(undefined, undefined, [], undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(className), ts.factory.createIdentifier(methodName)), undefined, method.getParameters().length
30
- ? [
31
- ts.factory.createObjectLiteralExpression(method
32
- .getParameters()
33
- .flatMap((param) => extractPropertiesFromObjectParam(param).map((p) => ts.factory.createShorthandPropertyAssignment(ts.factory.createIdentifier(p.name))))),
34
- ]
35
- : undefined))),
36
- ]),
37
- ]))),
38
- ], ts.NodeFlags.Const));
39
- return hookExport;
40
- }
41
- export const createPrefetch = ({ className, method, jsDoc, }) => {
42
- const requestParam = getRequestParamFromMethod(method);
43
- const requestParams = requestParam ? [requestParam] : [];
44
- const prefetchHook = createPrefetchHook({
45
- requestParams,
46
- method,
47
- className,
48
- });
49
- const hookWithJsDoc = addJSDocToNode(prefetchHook, jsDoc);
50
- return {
51
- prefetchHook: hookWithJsDoc,
52
- };
53
- };