Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,6 @@ dist
.pnp.*

lib/

# AI Assistant Configuration
CLAUDE.md
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ coverage
node_modules

lib

README.md
75 changes: 75 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

- **New query/mutation/infinite options exports** for React Query v5 compatibility
- `{methodName}QueryOptions` functions that return `queryOptions` for use with `useQuery`/`useSuspenseQuery`
- `{methodName}MutationOptions` functions that return `mutationOptions` for use with `useMutation`
- `{methodName}InfiniteQueryOptions` functions that return `infiniteQueryOptions` for use with `useInfiniteQuery`/`useSuspenseInfiniteQuery`
- These exports enable better tree-shaking and composability
- Full TypeScript support with proper generic types
- **Service getter functions** for non-React contexts
- `get{ServiceName}Service()` functions that return service instances without React hooks
- Enables use of API clients outside React components (e.g., in server-side code, scripts, tests)
- **Query key builder utility** (`query-key-builder.ts`) for type-safe cache operations
- `matchQueryKey()` function for building type-safe query keys
- `QueryKeyMap`, `ServiceKeys`, `OperationKeys`, and `OperationParams` types for full type safety
- Enables precise cache invalidation and query matching

### Changed

- **Query key structure completely redesigned** for simplicity and consistency
- Changed from complex URL-based patterns (e.g., `` `/widgets/${id}` ``) to simple arrays: `['serviceName', 'methodName', params || {}, metadata?]`
- Infinite queries now differentiated by metadata (`{infinite: true}`) instead of key structure
- All queries for an interface can now be invalidated with just `['interfaceName']`
- Removed `buildResourceKey()`, `isCacheParam()`, and complex path parsing logic
- **Mutations now invalidate at the interface level** instead of specific resource paths
- Simplified from invalidating multiple specific query keys to just `queryClient.invalidateQueries({ queryKey: ['interfaceName'] })`
- More predictable cache invalidation behavior
- **Refactored naming system** from class-based to function-based
- Replaced `NameFactory` class with standalone functions in `name-helpers.ts`
- Functions: `buildHookName()`, `buildQueryOptionsName()`, `buildMutationOptionsName()`, `buildInfiniteQueryOptionsName()`, `buildServiceName()`, `buildServiceHookName()`, `buildServiceGetterName()`, `buildContextName()`, `buildProviderName()`
- `buildHookName()` now requires `service` parameter for proper context
- **Context file enhanced** with new capabilities
- Added `currentContext` variable for non-hook access to context
- Service getter functions exported alongside hooks for flexibility
- Interfaces sorted alphabetically for consistent output
- Props interface now extends options type with optional fetch
- **Error handling improved** with `QueryError` type
- Changed from `CompositeError` throws to structured `QueryError<Error[]>` type
- Enables better error discrimination in error handlers

### Fixed

- **TypeScript compilation errors** in generated code
- Fixed `isRequired()` parameter access in `query-key-builder.ts` (accessing `p.value` instead of `p`)
- Removed unused `includeRelayParams` parameter that was being passed but ignored
- Fixed duplicate imports and missing function exports
- **Test and snapshot generation issues**
- Updated test utilities to use `@basketry/ir` parser instead of inline JSON parsing
- Fixed snapshot file generation that was silently failing
- Cleaned up debug `console.log` statements from test utilities

### Deprecated

- **All wrapped hook exports** are now marked as `@deprecated`
- `use{MethodName}()` - query hooks
- `useSuspense{MethodName}()` - suspense query hooks
- `useInfinite{MethodName}()` - infinite query hooks
- `useSuspenseInfinite{MethodName}()` - suspense infinite query hooks
- Hooks remain functional for backward compatibility but display deprecation warnings
- Each deprecation notice includes migration guidance to the new pattern
- Will be removed in the next major version (v1.0.0)

### Internal

- Added `xxxx()` method in `hook-file.ts` that needs renaming (analyzes return types for select function generation)
- Removed complex relay parameter handling from query key generation
- Simplified infinite query differentiation using metadata instead of key manipulation
184 changes: 175 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,195 @@

# React Query

[Basketry generator](https://github.com/basketry/basketry) for generating React Query hooks. This parser can be coupled with any Basketry parser.
[Basketry generator](https://basketry.io) for generating React Query queryOptions and hooks. This generator can be coupled with any Basketry parser.

## Quick Start

// TODO
### Installation

```bash
npm install @basketry/react-query
```

### Getting Started

1. **Create a Basketry configuration file** (`basketry.config.json`):

```json
{
"source": "openapi.json",
"parser": "@basketry/openapi-3",
"generators": ["@basketry/react-query"],
"output": "./src/generated/react-query",
"options": {
"basketry": {
"command": "npx basketry"
},
"typescript": {
"includeVersion": false
},
"reactQuery": {
"typesModule": "@your-api/types", // Path to generated TypeScript types
"clientModule": "@your-api/http-client-sdk" // Path to generated HTTP client
}
}
}
```

2. **Run Basketry** to generate the React Query hooks:

```bash
npx basketry
```

3. **Set up your React Query provider** in your app:

```typescript
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
// Name of provider will depend on the name of the API service in your OpenAPI spec.
import { BasketryExampleProvider } from './src/generated/context';

const queryClient = new QueryClient();
const httpClient = fetch; // or your custom fetch implementation

function App() {
return (
<QueryClientProvider client={queryClient}>
<BasketryExampleProvider httpClient={httpClient}>
{/* Your app components */}
</BasketryExampleProvider>
</QueryClientProvider>
);
}
```

4. **Use the generated hooks** in your components:

```typescript
import { useQuery } from '@tanstack/react-query';
import { getWidgetsQueryOptions } from './src/generated';

function WidgetList() {
const { data, isLoading } = useQuery(getWidgetsQueryOptions());

if (isLoading) return <div>Loading...</div>;
return <div>{data?.map(widget => <div key={widget.id}>{widget.name}</div>)}</div>;
}
```

### Basic Usage

This generator produces React Query compatible code with queryOptions functions that provide maximum flexibility:

```typescript
// Using query options with React Query hooks
import { useQuery, useSuspenseQuery } from '@tanstack/react-query';
import { getWidgetsQueryOptions } from './petstore'; // generated code

function WidgetList() {
// Basic usage
const { data } = useQuery(getWidgetsQueryOptions());

// With parameters
const { data: filtered } = useQuery(
getWidgetsQueryOptions({ status: 'active' })
);

// With custom options
const { data: cached } = useQuery({
...getWidgetsQueryOptions(),
staleTime: 5 * 60 * 1000, // 5 minutes
});

return <div>{/* render widgets */}</div>;
}
```

### Mutations

```typescript
import { useMutation } from '@tanstack/react-query';
import { createWidgetMutationOptions } from './petstore'; // generated code

function CreateWidget() {
const mutation = useMutation(createWidgetMutationOptions());

const handleSubmit = (data: CreateWidgetInput) => {
mutation.mutate(data, {
onSuccess: (widget) => {
console.log('Created widget:', widget);
},
});
};

return <form>{/* form fields */}</form>;
}
```

### Infinite Queries (Pagination)

For services with Relay-style pagination:

```typescript
import { useInfiniteQuery } from '@tanstack/react-query';
import { getWidgetsInfiniteQueryOptions } from './petstore'; // generated code

function InfiniteWidgetList() {
const {
data,
fetchNextPage,
hasNextPage,
} = useInfiniteQuery(getWidgetsInfiniteQueryOptions());

return (
<div>
{data?.pages.map(page =>
page.edges.map(({ node }) => (
<Widget key={node.id} data={node} />
))
)}
<button onClick={() => fetchNextPage()} disabled={!hasNextPage}>
Load More
</button>
</div>
);
}
```

## Configuration

Add to your `basketry.config.json`:

```json
```

## Features

- **React Query Compatible**: Generates queryOptions and mutationOptions functions
- **Type-Safe**: Full TypeScript support with proper type inference
- **Flexible**: Use with any React Query hook (useQuery, useSuspenseQuery, etc.)
- **SSR Ready**: Service getters work outside React components
- **Backward Compatible**: Legacy hooks are deprecated but still available
- **Relay Pagination**: Built-in support for cursor-based pagination
- **Error Handling**: Automatic error aggregation with CompositeError

---

## For contributors:
## For contributors

### Run this project

1. Install packages: `npm ci`
1. Build the code: `npm run build`
1. Run it! `npm start`
1. Install packages: `npm ci`
1. Build the code: `npm run build`
1. Run it! `npm start`

Note that the `lint` script is run prior to `build`. Auto-fixable linting or formatting errors may be fixed by running `npm run fix`.

### Create and run tests

1. Add tests by creating files with the `.test.ts` suffix
1. Run the tests: `npm t`
1. Test coverage can be viewed at `/coverage/lcov-report/index.html`
1. Add tests by creating files with the `.test.ts` suffix
1. Run the tests: `npm test`
1. Test coverage can be viewed at `/coverage/lcov-report/index.html`

### Publish a new package version

Expand Down
7 changes: 5 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@basketry/react-query",
"version": "0.2.1",
"description": "Basketry generator for generating Typescript interfaces",
"version": "0.3.0-alpha.0",
"description": "Basketry generator for generating React Query hooks",
"main": "./lib/index.js",
"bin": {
"basketry-react-query": "./lib/rpc.js"
Expand Down
Loading