Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
f6fc823
docs: add AI assistant guidelines (CLAUDE.md, AGENTS.md)
7nohe Dec 7, 2025
606ec44
refactor: migrate code generation to a ts-morph pipeline
7nohe Dec 14, 2025
8a866af
docs: add TanStack Router integration guide using ensureQueryData (#190)
7nohe Dec 16, 2025
41e1b26
feat: upgrade hey-api generator to v0.73
7nohe Mar 8, 2026
0093987
Merge main (v2.2.0): hey-api/openapi-ts 0.99.x and TypeScript 6.0.x s…
7nohe Jul 10, 2026
07ed7a2
fix: adapt ts-morph pipeline to hey-api 0.92+ SDK semantics
7nohe Jul 10, 2026
adab060
fix: restore v2-compatible Options type and operation JSDoc in genera…
7nohe Jul 10, 2026
bcf2c1a
chore: release v3.0.0-beta.1
7nohe Jul 10, 2026
8486a9f
feat: generate queryOptions/infiniteQueryOptions factories and dedica…
7nohe Jul 10, 2026
24bd4dd
chore: release v3.0.0-beta.2
7nohe Jul 10, 2026
a631ad1
docs: add v2 to v3 migration guide
7nohe Jul 10, 2026
f778c1c
chore: update dev dependencies (biome 2, vitest 4, commander 15, rimr…
7nohe Jul 18, 2026
43e0fc8
feat: declare @tanstack/react-query as a peer dependency and widen co…
7nohe Jul 18, 2026
a85f3b1
feat: make initialPageParam and getNextPageParam overridable in infin…
7nohe Jul 18, 2026
e2163b2
feat!: hierarchical infinite query keys for granular invalidation
7nohe Jul 18, 2026
36202b2
feat: complete the infinite query family and surface SDK errors
7nohe Jul 18, 2026
383c241
docs: positioning README, hey-api version policy, IR boundary guardra…
7nohe Jul 18, 2026
5e01438
refactor: extract shared infinite-query builders and align generated …
7nohe Jul 18, 2026
96fb045
docs: polish the v3 migration guide for release
7nohe Jul 18, 2026
975e25b
test: verify generated code at runtime against a live HTTP server
7nohe Jul 18, 2026
25798ca
chore: release v3.0.0-beta.3
7nohe Jul 18, 2026
853d69d
docs(examples): showcase SSR infinite prefetch and drop obsolete thro…
7nohe Jul 18, 2026
fab6733
fix: preserve blank initial page parameter
7nohe Jul 19, 2026
dc2720d
chore: drop unused StructureKind import
7nohe Jul 19, 2026
f6014eb
feat: add --omitInitialPageParam to send no initial page param
7nohe Jul 19, 2026
09d3a33
chore: release v3.0.0-beta.4
7nohe Jul 19, 2026
e65134d
fix(examples): correct client config key and error typing in react-app
7nohe Jul 19, 2026
5362ab5
Revert "fix(examples): correct client config key and error typing in …
7nohe Jul 19, 2026
058c6d0
fix: emit package declaration files
7nohe Jul 20, 2026
08f76f2
fix: improve generated request handling
7nohe Jul 20, 2026
dbab2e5
docs(examples): demonstrate abortable mutations
7nohe Jul 20, 2026
fb268ab
Merge pull request #200 from 7nohe/codex/address-recommended-issues
7nohe Jul 20, 2026
e8970e2
chore: release v3.0.0-beta.5
7nohe Jul 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,14 @@ jobs:

- name: Publish release
if: ${{ github.event_name == 'push' }}
run: pnpm publish --no-git-checks
# Prerelease versions (e.g. 3.0.0-beta.1) go to the beta dist-tag so
# they never override latest
run: |
if node -e "process.exit(require('./package.json').version.includes('-') ? 0 : 1)"; then
pnpm publish --no-git-checks --tag beta
else
pnpm publish --no-git-checks
fi

- name: Publish prerelease
if: ${{ github.event_name == 'issue_comment' }}
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,5 @@ dist-ssr
openapi
*.tsbuildinfo
coverage

.agents
1 change: 1 addition & 0 deletions .serena/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/cache
3 changes: 3 additions & 0 deletions .serena/memories/project_purpose.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Project purpose
- Library: `@7nohe/openapi-react-query-codegen` generates React Query (TanStack Query) hooks, prefetch/ensure helpers, and TS clients from an OpenAPI schema by leveraging `@hey-api/openapi-ts`.
- Outputs React Query wrappers around the generated request client, supporting useQuery/useSuspenseQuery/useMutation/useInfiniteQuery and query key functions.
5 changes: 5 additions & 0 deletions .serena/memories/style_and_conventions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Style and conventions
- Code: TypeScript strict, NodeNext modules, ESNext target. Imports organized; prefer named imports. Uses ts-morph/TypeScript factory for AST-based codegen.
- Formatting/lint: Biome enforced (formatter + linter). 2-space indent, spaces not tabs. Import organization enabled. Biome ignores build artifacts (dist, docs/.astro, examples outputs).
- Generated output: Comments include generator version header. Use double quotes and trailing commas (ts-morph manipulation settings). Keep code ASCII unless needed.
- Tests: Vitest. Coverage flag enabled in test script.
10 changes: 10 additions & 0 deletions .serena/memories/suggested_commands.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Suggested commands
- Install deps: `pnpm install`
- Build generator: `pnpm build`
- Lint (Biome): `pnpm lint`
- Fix lint/format: `pnpm lint:fix`
- Tests (Vitest + coverage): `pnpm test`
- Update snapshots: `pnpm snapshot`
- Preview example generation (build then generate in sample app): `pnpm preview:react`, `pnpm preview:nextjs`, `pnpm preview:tanstack-router`
- Release (bumpp + git-ensure): `pnpm release`
- Docs (Astro) lives under docs/; run from that workspace if needed.
5 changes: 5 additions & 0 deletions .serena/memories/task_completion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# What to run before finishing a task
- Run `pnpm lint` (Biome) to ensure style/lint compliance.
- Run `pnpm test` for Vitest with coverage (or `pnpm snapshot` if snapshots changed intentionally).
- Run `pnpm build` to confirm the generator compiles to dist.
- If touching example outputs, rerun the relevant `preview:*` command to verify generation still works.
5 changes: 5 additions & 0 deletions .serena/memories/tech_stack_and_structure.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Tech stack and structure
- Runtime/tooling: Node (>=14), pnpm (>=9), TypeScript (strict, NodeNext). Uses ts-morph and TypeScript factory APIs for codegen. Tests: Vitest. Lint/format: Biome. Bundling/CLI output in `dist/` via `tsc`.
- Source layout: `src/` contains CLI/generator pieces (generate.mts, createSource.mts, createImports.mts, createExports.mts, format.mts, service.mts, etc.). `tests/` holds Vitest suites. `examples/` has sample apps per framework; `docs/` uses Astro for docs site. Built artifacts land in `dist/`.
- Config: `tsconfig.json` sets strict + ESNext + DOM libs, NodeNext module resolution. `biome.json` enables formatter/linter with 2-space indent and import organization; ignores dist/examples build outputs.
- Scripts of interest (package.json): build via `pnpm build` (rimraf dist && tsc), lint via `pnpm lint` (biome check), tests via `pnpm test` (vitest --coverage.enabled true), preview generators under examples (preview:*), release uses bumpp/git-ensure.
84 changes: 84 additions & 0 deletions .serena/project.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# list of languages for which language servers are started; choose from:
# al bash clojure cpp csharp csharp_omnisharp
# dart elixir elm erlang fortran go
# haskell java julia kotlin lua markdown
# nix perl php python python_jedi r
# rego ruby ruby_solargraph rust scala swift
# terraform typescript typescript_vts yaml zig
# Note:
# - For C, use cpp
# - For JavaScript, use typescript
# Special requirements:
# - csharp: Requires the presence of a .sln file in the project folder.
# When using multiple languages, the first language server that supports a given file will be used for that file.
# The first language is the default language and the respective language server will be used as a fallback.
# Note that when using the JetBrains backend, language servers are not used and this list is correspondingly ignored.
languages:
- typescript

# the encoding used by text files in the project
# For a list of possible encodings, see https://docs.python.org/3.11/library/codecs.html#standard-encodings
encoding: "utf-8"

# whether to use the project's gitignore file to ignore files
# Added on 2025-04-07
ignore_all_files_in_gitignore: true

# list of additional paths to ignore
# same syntax as gitignore, so you can use * and **
# Was previously called `ignored_dirs`, please update your config if you are using that.
# Added (renamed) on 2025-04-07
ignored_paths: []

# whether the project is in read-only mode
# If set to true, all editing tools will be disabled and attempts to use them will result in an error
# Added on 2025-04-18
read_only: false

# list of tool names to exclude. We recommend not excluding any tools, see the readme for more details.
# Below is the complete list of tools for convenience.
# To make sure you have the latest list of tools, and to view their descriptions,
# execute `uv run scripts/print_tool_overview.py`.
#
# * `activate_project`: Activates a project by name.
# * `check_onboarding_performed`: Checks whether project onboarding was already performed.
# * `create_text_file`: Creates/overwrites a file in the project directory.
# * `delete_lines`: Deletes a range of lines within a file.
# * `delete_memory`: Deletes a memory from Serena's project-specific memory store.
# * `execute_shell_command`: Executes a shell command.
# * `find_referencing_code_snippets`: Finds code snippets in which the symbol at the given location is referenced.
# * `find_referencing_symbols`: Finds symbols that reference the symbol at the given location (optionally filtered by type).
# * `find_symbol`: Performs a global (or local) search for symbols with/containing a given name/substring (optionally filtered by type).
# * `get_current_config`: Prints the current configuration of the agent, including the active and available projects, tools, contexts, and modes.
# * `get_symbols_overview`: Gets an overview of the top-level symbols defined in a given file.
# * `initial_instructions`: Gets the initial instructions for the current project.
# Should only be used in settings where the system prompt cannot be set,
# e.g. in clients you have no control over, like Claude Desktop.
# * `insert_after_symbol`: Inserts content after the end of the definition of a given symbol.
# * `insert_at_line`: Inserts content at a given line in a file.
# * `insert_before_symbol`: Inserts content before the beginning of the definition of a given symbol.
# * `list_dir`: Lists files and directories in the given directory (optionally with recursion).
# * `list_memories`: Lists memories in Serena's project-specific memory store.
# * `onboarding`: Performs onboarding (identifying the project structure and essential tasks, e.g. for testing or building).
# * `prepare_for_new_conversation`: Provides instructions for preparing for a new conversation (in order to continue with the necessary context).
# * `read_file`: Reads a file within the project directory.
# * `read_memory`: Reads the memory with the given name from Serena's project-specific memory store.
# * `remove_project`: Removes a project from the Serena configuration.
# * `replace_lines`: Replaces a range of lines within a file with new content.
# * `replace_symbol_body`: Replaces the full definition of a symbol.
# * `restart_language_server`: Restarts the language server, may be necessary when edits not through Serena happen.
# * `search_for_pattern`: Performs a search for a pattern in the project.
# * `summarize_changes`: Provides instructions for summarizing the changes made to the codebase.
# * `switch_modes`: Activates modes by providing a list of their names
# * `think_about_collected_information`: Thinking tool for pondering the completeness of collected information.
# * `think_about_task_adherence`: Thinking tool for determining whether the agent is still on track with the current task.
# * `think_about_whether_you_are_done`: Thinking tool for determining whether the task is truly completed.
# * `write_memory`: Writes a named memory (for future reference) to Serena's project-specific memory store.
excluded_tools: []

# initial prompt for the project. It will always be given to the LLM upon activating the project
# (contrary to the memories, which are loaded on demand).
initial_prompt: ""

project_name: "openapi-react-query-codegen"
included_optional_tools: []
43 changes: 43 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Repository Guidelines

## Project Structure & Module Organization
- Source code lives in `src/` (CLI entry `cli.mts`, generator pipeline `generate.mts`, codegen helpers like `createSource.mts`, `createImports.mts`, `createExports.mts`, `service.mts`, formatting in `format.mts`).
- Tests reside in `tests/` (Vitest).
- Example apps under `examples/` (React/Next.js/TanStack Router) consume the generated client.
- Docs site in `docs/` (Astro). Build artifacts output to `dist/`.

## Build, Test, and Development Commands
- Install: `pnpm install`
- Build generator: `pnpm build` (cleans `dist/`, runs `tsc`).
- Lint/format check: `pnpm lint` (Biome). Auto-fix: `pnpm lint:fix`.
- Tests: `pnpm test` (Vitest with coverage). Snapshots: `pnpm snapshot`.
- Preview generation into examples: `pnpm preview:react`, `pnpm preview:nextjs`, `pnpm preview:tanstack-router`.

## Coding Style & Naming Conventions
- Language: TypeScript (strict, ESNext, NodeNext). Keep code in modules (`.mts`), output compiled to `dist/`.
- Formatting/linting via Biome: 2-space indent, double quotes, trailing commas, organized imports. Run formatters before committing.
- Generated outputs include a header comment with package version; preserve this when modifying generation.
- Prefer descriptive function names and explicit types; avoid implicit `any`.

## Testing Guidelines
- Framework: Vitest. Coverage enabled by default.
- Place tests in `tests/`; mirror generator behavior with snapshot tests where helpful.
- After generator changes, run tests and consider regenerating example outputs to manually diff.

## Commit & Pull Request Guidelines
- Commits: clear, descriptive messages (e.g., `fix: align imports for generated queries`, `chore: update ts-morph config`). Avoid bundling unrelated changes.
- Pull requests: include summary of changes, affected areas (e.g., codegen output, docs, examples), and test commands run. Link issues when applicable. Add before/after notes or sample generated snippets if behavior changes.

## Architecture: IR Boundary (Backend Portability)
- The generation pipeline is split by an intermediate representation (IR): `OperationInfo` and `GenerationContext` in `src/types.mts`.
- hey-api-specific knowledge must stay confined to the parsing side: the `createClient` invocation in `src/generate.mts` and the `sdk.gen`/`types.gen` parsing in `src/service.mts` / `src/createSource.mts`.
- Generation-side modules (`src/tsmorph/build*.mts`, `generateFiles.mts`) should consume only the IR. Do not add new hey-api-specific parsing or imports there; extend the IR instead.
- This boundary is what keeps the generator portable to a different SDK backend without rewriting the generation layer. Treat leaks across it as review findings.

## hey-api Version Policy
- `@hey-api/openapi-ts` is pinned to an exact version and patched via `pnpm.patchedDependencies` when needed (see `patches/`).
- Upgrades: bump the pin, run the full snapshot suite, regenerate an example app and type-check it, then release as a minor version. Breaking changes in hey-api are absorbed here — they must not leak into the generated API surface outside a major version.

## Agent-Specific Notes
- Use AST-aware paths (ts-morph/TypeScript factory) when editing generators to keep output structurally valid.
- Respect ignore patterns in `biome.json` and avoid checking in `dist/` or example-generated artifacts unless explicitly intended.
73 changes: 73 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

OpenAPI React Query Codegen generates React Query (TanStack Query) hooks from OpenAPI specifications. It uses `@hey-api/openapi-ts` to generate TypeScript clients and then creates additional query/mutation hooks on top.

## Commands

```bash
# Build
npm run build

# Run tests with coverage
npm test

# Run a single test file
npx vitest tests/generate.test.ts

# Update snapshots
npm run snapshot

# Lint
npm run lint
npm run lint:fix

# Preview generated output in example apps
npm run preview:react
npm run preview:nextjs
npm run preview:tanstack-router
```

## Architecture

### Code Generation Pipeline

1. **CLI Entry** (`src/cli.mts`): Parses command-line options using Commander
2. **Generate** (`src/generate.mts`): Orchestrates the generation process:
- Calls `@hey-api/openapi-ts` to generate base TypeScript client in `openapi/requests/`
- Calls `createSource()` to generate React Query hooks in `openapi/queries/`
3. **Service Parsing** (`src/service.mts`): Uses ts-morph to parse the generated `services.gen.ts` file and extract function descriptions (method name, HTTP method, JSDoc, etc.)
4. **Export Creation** (`src/createExports.mts`): Routes methods to appropriate generators based on HTTP method:
- GET methods → `createUseQuery()` (queries, suspense queries, infinite queries)
- POST/PUT/PATCH/DELETE → `createUseMutation()`
5. **Hook Generators**:
- `src/createUseQuery.mts`: Generates `useQuery`, `useSuspenseQuery`, and `useInfiniteQuery` hooks
- `src/createUseMutation.mts`: Generates `useMutation` hooks
- `src/createPrefetchOrEnsure.mts`: Generates `prefetchQuery` and `ensureQueryData` functions
6. **Print** (`src/print.mts`): Writes generated TypeScript to files

### Generated Output Structure

The tool generates files in `openapi/queries/`:
- `common.ts`: Shared types, query keys, and key functions
- `queries.ts`: `useQuery` and `useMutation` hooks
- `suspense.ts`: `useSuspenseQuery` hooks
- `infiniteQueries.ts`: `useInfiniteQuery` hooks
- `prefetch.ts`: `prefetchQuery` functions
- `ensureQueryData.ts`: `ensureQueryData` functions
- `index.ts`: Re-exports

### Key Dependencies

- **ts-morph**: AST manipulation for reading the generated service file
- **typescript**: AST creation for generating new TypeScript code
- **@hey-api/openapi-ts**: Base OpenAPI to TypeScript client generator

## Testing

Tests use Vitest with snapshot testing. Test files in `tests/` correspond to source modules. The `tests/utils.ts` file provides a shared `project` fixture using `examples/petstore.yaml`.

Coverage thresholds: 95% lines/functions/statements, 90% branches.
60 changes: 55 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,62 @@
# OpenAPI React Query Codegen

> Code generator for creating [React Query (also known as TanStack Query)](https://tanstack.com/query) hooks based on your OpenAPI schema.
> Code generator for [TanStack Query (React Query)](https://tanstack.com/query) based on your OpenAPI schema — `queryOptions` factories following the official TanStack Query v5 pattern, plus ready-to-use hooks, prefetch, ensure, suspense, and infinite query helpers.

[![npm version](https://badge.fury.io/js/%407nohe%2Fopenapi-react-query-codegen.svg)](https://badge.fury.io/js/%407nohe%2Fopenapi-react-query-codegen)

📖 **[Documentation](https://openapi-react-query-codegen.vercel.app)** · [Migrating to v3](https://openapi-react-query-codegen.vercel.app/guides/migrating-to-v3/)

## Features

- Generates custom react hooks that use React Query's `useQuery`, `useSuspenseQuery`, `useMutation` and `useInfiniteQuery` hooks
- Generates custom functions that use React Query's `ensureQueryData` and `prefetchQuery` functions
- Generates query keys and functions for query caching
- Generates pure TypeScript clients generated by [@hey-api/openapi-ts](https://github.com/hey-api/openapi-ts)
- **`queryOptions` / `infiniteQueryOptions` factories** for every GET operation — the [TanStack Query v5 recommended pattern](https://tanstack.com/query/latest/docs/framework/react/guides/query-options), composable with `useQuery`, `useQueries`, `useSuspenseQuery`, `prefetchQuery`, `ensureQueryData`, and `setQueryData` with full type safety
- **Custom hooks**: `useQuery`, `useSuspenseQuery`, `useMutation`, `useInfiniteQuery`, and `useSuspenseInfiniteQuery` variants per operation
- **SSR helpers**: `prefetchQuery`, `prefetchInfiniteQuery`, and `ensureQueryData` functions per operation — ready for Next.js App Router hydration
- **Hierarchical query keys** with exported key constants and functions: invalidate one exact query, all infinite pages of an operation, or every cache entry of an operation with a single prefix
- **Pure TypeScript clients** generated by [@hey-api/openapi-ts](https://github.com/hey-api/openapi-ts) (fetch and axios)

## Quick start

```bash
npm install -D @7nohe/openapi-react-query-codegen
npx openapi-rq -i ./petstore.yaml
```

```tsx
import { useQuery } from "@tanstack/react-query";
import { findPetsOptions } from "./openapi/queries";

function Pets() {
const { data } = useQuery(findPetsOptions({ query: { limit: 10 } }));
// ...or use the generated hook directly: useFindPets({ query: { limit: 10 } })
}
```

See the [documentation](https://openapi-react-query-codegen.vercel.app) for CLI options, SSR recipes, and infinite query usage.

## How it compares

| | This library | @hey-api tanstack-query plugin | Orval |
|---|---|---|---|
| `queryOptions` / `infiniteQueryOptions` factories (TanStack v5 pattern) | ✅ | ✅ | ❌ |
| Ready-to-use hooks (`useQuery` / suspense / infinite variants) | ✅ | ❌ (options only) | ✅ |
| SSR helpers (`prefetchQuery` / `prefetchInfiniteQuery` / `ensureQueryData`) | ✅ | ❌ | Partial (`usePrefetch`) |
| Hierarchical query keys for granular invalidation | ✅ | ✅ (tags) | Partial |
| Stable release line | ✅ SemVer | pre-1.0, frequent breaking changes | ✅ |
| MSW mock generation | ❌ (out of scope) | ❌ | ✅ |
| Vue / Solid / Svelte / Angular | ❌ React-focused | ✅ | ✅ |

**Scope**: this library is deliberately React-focused and does not generate API mocks — use Orval if MSW mocks are your priority, or hey-api's own plugin if you need non-React frameworks.

## Stability policy

This library builds on [@hey-api/openapi-ts](https://github.com/hey-api/openapi-ts), which is pre-1.0 and moves fast. We **pin the exact hey-api version** and absorb its breaking changes for you: hey-api upgrades land here only after our full snapshot-test suite passes, and are released as minor versions. Your generated API surface follows SemVer — breaking output changes only happen in major versions, with a migration guide.

## Requirements

- Node.js 22.18+
- `@tanstack/react-query` 5.x (peer dependency)
- `typescript` 5.x or 6.x, `ts-morph` 28.x, `commander` 12–15 (peer dependencies)

## License

MIT
Loading
Loading