@kollors/react-codegen 2.0.0-alpha.4 → 2.0.0-alpha.6
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 +193 -49
- package/README.ru.md +193 -49
- package/dist/{cli.js → cli/index.js} +6 -11
- package/dist/cli/index.js.map +1 -0
- package/dist/core/auth.d.ts +7 -0
- package/dist/core/auth.js +2 -0
- package/dist/core/auth.js.map +1 -0
- package/dist/core/config.d.ts +2 -0
- package/dist/core/config.js +67 -0
- package/dist/core/config.js.map +1 -0
- package/dist/{generate.d.ts → core/generate.d.ts} +0 -1
- package/dist/core/generate.js +47 -0
- package/dist/core/generate.js.map +1 -0
- package/dist/core/names.d.ts +5 -0
- package/dist/core/names.js +16 -0
- package/dist/core/names.js.map +1 -0
- package/dist/core/output.d.ts +5 -0
- package/dist/core/output.js +39 -0
- package/dist/core/output.js.map +1 -0
- package/dist/core/paths.d.ts +4 -0
- package/dist/core/paths.js +12 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/{types.d.ts → core/types.d.ts} +2 -2
- package/dist/core/types.js.map +1 -0
- package/dist/graphql/document.d.ts +8 -0
- package/dist/graphql/document.js +118 -0
- package/dist/graphql/document.js.map +1 -0
- package/dist/graphql/fetcher.d.ts +5 -0
- package/dist/graphql/fetcher.js +4 -0
- package/dist/graphql/fetcher.js.map +1 -0
- package/dist/graphql/generate.d.ts +3 -0
- package/dist/graphql/generate.js +59 -0
- package/dist/graphql/generate.js.map +1 -0
- package/dist/graphql/operations.d.ts +13 -0
- package/dist/graphql/operations.js +139 -0
- package/dist/graphql/operations.js.map +1 -0
- package/dist/{graphql-fetcher.d.ts → graphql/runtime.d.ts} +4 -3
- package/dist/{graphql-fetcher.js → graphql/runtime.js} +12 -6
- package/dist/graphql/runtime.js.map +1 -0
- package/dist/graphql/runtime.source +140 -0
- package/dist/graphql/selections.d.ts +12 -0
- package/dist/graphql/selections.js +120 -0
- package/dist/graphql/selections.js.map +1 -0
- package/dist/graphql/types.d.ts +15 -0
- package/dist/graphql/types.js +110 -0
- package/dist/graphql/types.js.map +1 -0
- package/dist/index.d.ts +6 -6
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/openapi/fetcher.d.ts +3 -0
- package/dist/openapi/fetcher.js +4 -0
- package/dist/openapi/fetcher.js.map +1 -0
- package/dist/openapi/generate.d.ts +1 -1
- package/dist/openapi/generate.js +2 -1
- package/dist/openapi/generate.js.map +1 -1
- package/dist/openapi/names.d.ts +1 -5
- package/dist/openapi/names.js +1 -15
- package/dist/openapi/names.js.map +1 -1
- package/dist/openapi/operations.d.ts +0 -1
- package/dist/openapi/operations.js +35 -45
- package/dist/openapi/operations.js.map +1 -1
- package/dist/{openapi-runtime.d.ts → openapi/runtime.d.ts} +5 -7
- package/dist/{openapi-runtime.js → openapi/runtime.js} +38 -25
- package/dist/openapi/runtime.js.map +1 -0
- package/dist/{openapi-runtime.source → openapi/runtime.source} +43 -21
- package/dist/openapi/schema.d.ts +4 -0
- package/dist/openapi/schema.js +83 -77
- package/dist/openapi/schema.js.map +1 -1
- package/dist/openapi/type-expression.d.ts +38 -0
- package/dist/openapi/type-expression.js +166 -0
- package/dist/openapi/type-expression.js.map +1 -0
- package/docs/migration.md +21 -0
- package/docs/migration.ru.md +21 -0
- package/package.json +10 -15
- package/dist/cli.js.map +0 -1
- package/dist/generate.js +0 -197
- package/dist/generate.js.map +0 -1
- package/dist/graphql-fetcher.js.map +0 -1
- package/dist/openapi-fetcher.d.ts +0 -3
- package/dist/openapi-fetcher.js +0 -4
- package/dist/openapi-fetcher.js.map +0 -1
- package/dist/openapi-runtime.js.map +0 -1
- package/dist/path-utils.d.ts +0 -2
- package/dist/path-utils.js +0 -5
- package/dist/path-utils.js.map +0 -1
- package/dist/types.js.map +0 -1
- package/templates/graphql.template +0 -23
- /package/dist/{cli.d.ts → cli/index.d.ts} +0 -0
- /package/dist/{types.js → core/types.js} +0 -0
package/README.md
CHANGED
|
@@ -2,27 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
[Русский](README.ru.md)
|
|
4
4
|
|
|
5
|
-
Generate
|
|
6
|
-
|
|
7
|
-
Requires Node.js 22 or newer and TanStack Query 5 in the consuming application.
|
|
5
|
+
Generate TypeScript types, request functions, and React hooks for TanStack Query from OpenAPI and GraphQL. Each configured schema produces a separate `.ts` file.
|
|
8
6
|
|
|
9
7
|
## Install
|
|
10
8
|
|
|
9
|
+
Requires Node.js 22 or newer. The application using the generated hooks must have TanStack Query 5 installed and a `QueryClientProvider` configured.
|
|
10
|
+
|
|
11
11
|
```sh
|
|
12
12
|
npm install -D @kollors/react-codegen@alpha
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
The generated files include the code that sends requests. They use TanStack Query and do not require React Codegen in the application at runtime.
|
|
16
|
+
|
|
17
|
+
## Configuration and generation
|
|
16
18
|
|
|
17
19
|
Create `codegen.config.js`:
|
|
18
20
|
|
|
19
21
|
```js
|
|
20
22
|
export default {
|
|
21
23
|
auth: {
|
|
22
|
-
storage: 'localStorage',
|
|
24
|
+
storage: 'localStorage',
|
|
23
25
|
key: 'accessToken',
|
|
24
|
-
scheme: 'Bearer',
|
|
25
|
-
credentials: 'same-origin',
|
|
26
|
+
scheme: 'Bearer',
|
|
27
|
+
credentials: 'same-origin',
|
|
26
28
|
},
|
|
27
29
|
openapi: {
|
|
28
30
|
schema: './openapi.yaml',
|
|
@@ -38,53 +40,168 @@ export default {
|
|
|
38
40
|
};
|
|
39
41
|
```
|
|
40
42
|
|
|
41
|
-
Run
|
|
43
|
+
Run:
|
|
42
44
|
|
|
43
45
|
```sh
|
|
44
46
|
npx react-codegen codegen.config.js
|
|
45
47
|
```
|
|
46
48
|
|
|
47
|
-
|
|
49
|
+
This example creates `src/api/openapi.ts` and `src/api/graphql.ts`. Include `openapi`, `graphql`, or both; at least one is required. Output directories are created automatically, and the two outputs must use different filenames.
|
|
50
|
+
|
|
51
|
+
File paths resolve relative to the config file. The config uses an ES module default export; in a CommonJS project, use `codegen.config.mjs` and pass that filename to the command.
|
|
52
|
+
|
|
53
|
+
| Setting | Required | Description or default |
|
|
54
|
+
| --- | --- | --- |
|
|
55
|
+
| `openapi.schema` | Yes | OpenAPI 3.0.x or 3.1.x in YAML/JSON: file path or HTTP URL |
|
|
56
|
+
| `openapi.output` | Yes | Path to the generated `.ts` file |
|
|
57
|
+
| `openapi.baseUrl` | No | URL prefix for requests; paths stay relative when omitted |
|
|
58
|
+
| `graphql.schema` | Yes | GraphQL SDL or introspection JSON: file path or HTTP URL |
|
|
59
|
+
| `graphql.documents` | Yes | Directory containing named queries, mutations, and fragments in `.graphql` files; subdirectories are included |
|
|
60
|
+
| `graphql.output` | Yes | Path to the generated `.ts` file |
|
|
61
|
+
| `graphql.endpoint` | No | Request endpoint; defaults to `/api/graphql` |
|
|
62
|
+
| `auth` | No | Shared [authentication settings](#authentication) |
|
|
63
|
+
| `openapi.auth`, `graphql.auth` | No | Replace shared authentication settings for that client |
|
|
64
|
+
|
|
65
|
+
GraphQL introspection JSON can contain `__schema` or `data.__schema`. A GraphQL HTTP endpoint can also be used as `schema`: the generator requests its schema through introspection.
|
|
66
|
+
|
|
67
|
+
## Using the generated code
|
|
68
|
+
|
|
69
|
+
### Queries
|
|
70
|
+
|
|
71
|
+
For an OpenAPI GET operation with `operationId: getPet`, use the hook inside a component or another hook:
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
import { useGetPet } from './api/openapi';
|
|
75
|
+
|
|
76
|
+
export function usePetName(id: string) {
|
|
77
|
+
return useGetPet({ pathParams: { id } }, { select: pet => pet.name });
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
For a GraphQL query named `MovieDetailsQuery` that selects `movie.title`:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
import { useMovieDetailsQuery } from './api/graphql';
|
|
85
|
+
|
|
86
|
+
export function useMovieTitle(id: string) {
|
|
87
|
+
return useMovieDetailsQuery({ id }, { select: data => data.movie?.title });
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Both generators provide the following helpers for queries:
|
|
92
|
+
|
|
93
|
+
| Purpose | OpenAPI `getPet` | GraphQL `MovieDetailsQuery` |
|
|
94
|
+
| --- | --- | --- |
|
|
95
|
+
| Query hook | `useGetPet` | `useMovieDetailsQuery` |
|
|
96
|
+
| Suspense hook | `useSuspenseGetPet` | `useSuspenseMovieDetailsQuery` |
|
|
97
|
+
| Options for `QueryClient` | `getPetQuery` | `movieDetailsQuery` |
|
|
98
|
+
| Cache key | `getPetQueryKey` | `movieDetailsQueryKey` |
|
|
99
|
+
| Direct request | `fetchGetPet` | `fetchMovieDetailsQuery` |
|
|
100
|
+
|
|
101
|
+
OpenAPI names come from `operationId`, or from the HTTP method and path when it is absent. GraphQL names come from the operation name. GraphQL also exports the selected result type, variable type, and document string, such as `MovieDetailsQuery`, `MovieDetailsQueryVariables`, and `MovieDetailsQueryDocument`.
|
|
102
|
+
|
|
103
|
+
### Mutations
|
|
104
|
+
|
|
105
|
+
OpenAPI methods other than GET and GraphQL mutations generate mutation hooks. For an OpenAPI operation with `operationId: createPet`:
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
import { useCreatePet, type CreatePetRequestBody } from './api/openapi';
|
|
109
|
+
|
|
110
|
+
export function useSavePet() {
|
|
111
|
+
const mutation = useCreatePet();
|
|
112
|
+
return (body: CreatePetRequestBody) => mutation.mutate({ body });
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
OpenAPI arguments are grouped into `pathParams`, `queryParams`, `headers`, and `body`. GraphQL arguments are the operation's variables. Required arguments follow the schema; GraphQL variables marked `!` are required unless they have a default.
|
|
117
|
+
|
|
118
|
+
If no arguments are required, hooks and request functions can be called without them. Mutation hooks also allow `mutate()` and `mutateAsync()` in that case.
|
|
119
|
+
|
|
120
|
+
### Skipping a query
|
|
121
|
+
|
|
122
|
+
Regular query hooks accept `skipToken`:
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
import { skipToken } from '@tanstack/react-query';
|
|
126
|
+
import { useGetPet } from './api/openapi';
|
|
127
|
+
|
|
128
|
+
export function useOptionalPet(id?: string) {
|
|
129
|
+
return useGetPet(id ? { pathParams: { id } } : skipToken);
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Suspense hooks do not accept `skipToken`. Their arguments can be omitted when the operation has no required arguments.
|
|
134
|
+
|
|
135
|
+
### Requests and cache keys
|
|
48
136
|
|
|
49
|
-
|
|
137
|
+
Load data through TanStack Query:
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
import { QueryClient } from '@tanstack/react-query';
|
|
141
|
+
import { getPetQuery } from './api/openapi';
|
|
50
142
|
|
|
51
|
-
|
|
143
|
+
const queryClient = new QueryClient();
|
|
144
|
+
const pet = await queryClient.fetchQuery(getPetQuery({ pathParams: { id: '42' } }));
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
To refresh cached data in the application, use its `QueryClient`:
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
151
|
+
import { getPetQueryKey } from './api/openapi';
|
|
52
152
|
|
|
53
|
-
|
|
153
|
+
export function useRefreshPet(id: string) {
|
|
154
|
+
const queryClient = useQueryClient();
|
|
155
|
+
return () => queryClient.invalidateQueries({ queryKey: getPetQueryKey({ pathParams: { id } }) });
|
|
156
|
+
}
|
|
157
|
+
```
|
|
54
158
|
|
|
55
|
-
|
|
159
|
+
To send a request directly, without TanStack Query:
|
|
56
160
|
|
|
57
161
|
```ts
|
|
58
|
-
import {
|
|
162
|
+
import { fetchGetPet } from './api/openapi';
|
|
59
163
|
|
|
60
|
-
const
|
|
61
|
-
const
|
|
62
|
-
await queryClient.fetchQuery(getPetQuery(variables));
|
|
63
|
-
await queryClient.invalidateQueries({ queryKey: getPetQueryKey(variables) });
|
|
64
|
-
await fetchGetPet(variables, abortController.signal);
|
|
164
|
+
const controller = new AbortController();
|
|
165
|
+
const pet = await fetchGetPet({ pathParams: { id: '42' } }, controller.signal);
|
|
65
166
|
```
|
|
66
167
|
|
|
67
|
-
|
|
168
|
+
Calling `controller.abort()` cancels the direct request. Query hooks receive TanStack Query's cancellation signal automatically. The GraphQL request functions and helpers work the same way.
|
|
169
|
+
|
|
170
|
+
Use the generated key helpers for cache operations. Keys include the endpoint or base URL and request arguments; OpenAPI keys also include request headers. Tokens read from storage and browser cookies are excluded, so clear the relevant cache when the signed-in user changes.
|
|
171
|
+
|
|
172
|
+
## Authentication
|
|
68
173
|
|
|
69
|
-
|
|
174
|
+
Top-level `auth` applies to both clients. `openapi.auth` or `graphql.auth` replaces the whole shared section for that client.
|
|
70
175
|
|
|
71
|
-
|
|
176
|
+
Without `auth`, the generated client does not add an `Authorization` header.
|
|
72
177
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
178
|
+
| Option | Required | Behavior |
|
|
179
|
+
| --- | --- | --- |
|
|
180
|
+
| `storage` | When `auth` is configured | Where to read the token; see below |
|
|
181
|
+
| `key` | Unless `storage` is `none` | Name of the storage entry or cookie |
|
|
182
|
+
| `scheme` | No | Header prefix; defaults to `Bearer`. Set `false` to send the token unchanged |
|
|
183
|
+
| `credentials` | No | Browser cookie policy; defaults to `same-origin` |
|
|
78
184
|
|
|
79
|
-
|
|
185
|
+
| `storage` | Token source |
|
|
186
|
+
| --- | --- |
|
|
187
|
+
| `localStorage` | `localStorage.getItem(key)` |
|
|
188
|
+
| `sessionStorage` | `sessionStorage.getItem(key)` |
|
|
189
|
+
| `cookie` | Cookie named `key`, read through `document.cookie` |
|
|
190
|
+
| `none` | No token is read; no authorization header is added |
|
|
80
191
|
|
|
81
|
-
|
|
192
|
+
| `credentials` | Browser cookies |
|
|
193
|
+
| --- | --- |
|
|
194
|
+
| `omit` | Do not send |
|
|
195
|
+
| `same-origin` | Allow for requests to the same origin |
|
|
196
|
+
| `include` | Also allow for requests to another origin |
|
|
82
197
|
|
|
83
|
-
|
|
198
|
+
If the token is missing or empty, no authorization header is added. For `HttpOnly` cookies, which JavaScript cannot read, let the browser send them:
|
|
84
199
|
|
|
85
|
-
|
|
200
|
+
```js
|
|
201
|
+
auth: { storage: 'none', credentials: 'include' }
|
|
202
|
+
```
|
|
86
203
|
|
|
87
|
-
|
|
204
|
+
Browser cookie and CORS rules still apply. When calling `createOpenapiFetcher` or `createGraphqlFetcher` directly, `getToken` can return the complete `Authorization` header value. This option belongs to the fetcher factories, not the codegen config.
|
|
88
205
|
|
|
89
206
|
## Programmatic API
|
|
90
207
|
|
|
@@ -92,33 +209,53 @@ Regenerate the client. Usual camelCase operation names and grouped variables rem
|
|
|
92
209
|
import { generate, type CodegenConfig } from '@kollors/react-codegen';
|
|
93
210
|
|
|
94
211
|
const config: CodegenConfig = {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
},
|
|
99
|
-
graphql: {
|
|
100
|
-
schema: './schema.graphql',
|
|
101
|
-
documents: './src/graphql',
|
|
102
|
-
output: './src/api/graphql.ts',
|
|
103
|
-
endpoint: '/graphql',
|
|
212
|
+
openapi: {
|
|
213
|
+
schema: './openapi.yaml',
|
|
214
|
+
output: './src/api/openapi.ts',
|
|
104
215
|
},
|
|
105
216
|
};
|
|
106
217
|
|
|
107
|
-
const
|
|
108
|
-
console.log(
|
|
218
|
+
const { outputs } = await generate(config);
|
|
219
|
+
console.log(outputs);
|
|
109
220
|
```
|
|
110
221
|
|
|
111
|
-
|
|
222
|
+
The settings are the same as in the CLI config. Relative paths resolve from the current working directory. `generate` returns the paths of the generated files.
|
|
223
|
+
|
|
224
|
+
## Supported schemas and limits
|
|
225
|
+
|
|
226
|
+
Both generators create types from the schema. They do not validate server response data at runtime. A generation error leaves the existing output files in place.
|
|
112
227
|
|
|
113
|
-
|
|
228
|
+
### OpenAPI
|
|
114
229
|
|
|
115
|
-
|
|
230
|
+
- Supports OpenAPI 3.0.x and 3.1.x; Swagger 2.0 is not supported.
|
|
231
|
+
- Supports objects, arrays, dictionaries, enums, internal `$ref`, recursive components, `allOf`, `oneOf`, and `anyOf`. OpenAPI 3.1 also supports `const`, boolean schemas, and type arrays.
|
|
232
|
+
- `required` controls required fields; `null` is included where the schema allows it. `readOnly` fields are excluded from request types, and `writeOnly` fields from response types. Dates remain strings.
|
|
233
|
+
- Supports JSON, `+json`, text/XML strings, binary data as `Blob`, multipart, and URL-encoded bodies. For multiple request formats, priority is JSON, `+json`, URL-encoded, multipart, then other supported formats alphabetically.
|
|
234
|
+
- Supports path/header `simple` and query `form` parameters, flat `deepObject` with `explode: true`, and `spaceDelimited`/`pipeDelimited` arrays with `explode: false`. Nested parameter objects and arrays are not supported.
|
|
116
235
|
|
|
117
|
-
|
|
236
|
+
External `$ref` must be bundled into one document before generation. Callbacks, webhooks, cookie parameters, parameter `content`, `allowReserved`, `label`/`matrix` path styles, and custom form encoding are not supported. Advanced JSON Schema constraints such as conditions, `not`, `dependentRequired`, `patternProperties`, and `unevaluatedProperties` cause an error with the schema location.
|
|
118
237
|
|
|
119
|
-
|
|
238
|
+
Typed `additionalProperties` combined with named properties are not supported; put the dictionary in a separate property. Numeric bounds, patterns, and lengths are not checked at runtime. `oneOf` becomes a TypeScript union without checking that exactly one branch matches; describe the discriminator field and its values in the schema.
|
|
120
239
|
|
|
121
|
-
|
|
240
|
+
Use `baseUrl` and `auth` to configure requests; schema `servers` and `security` are not applied. GET responses must declare a body. Empty mutation responses return `undefined` with type `void`; a missing body where one is declared causes a request error. GET/HEAD request bodies, TRACE, and path segments `.` or `..` are rejected. Response headers are not returned separately.
|
|
241
|
+
|
|
242
|
+
### GraphQL
|
|
243
|
+
|
|
244
|
+
Supports named queries and mutations, fragments, aliases, interfaces, and unions. Result types describe selected fields. Select `__typename` when you need to distinguish union members.
|
|
245
|
+
|
|
246
|
+
Nullable fields use `T | null`; conditional selections with `@skip` or `@include` can be optional. Lists preserve element nullability. Non-null input fields and variables with defaults can be omitted but cannot be `null`. `@oneOf` inputs require exactly one non-null field. Custom scalars use `unknown`.
|
|
247
|
+
|
|
248
|
+
Subscriptions and `@defer`/`@stream` are not supported. Schema downloads do not use `auth`; use a local schema export if the schema URL requires authentication.
|
|
249
|
+
|
|
250
|
+
### Request errors
|
|
251
|
+
|
|
252
|
+
| Error | Details |
|
|
253
|
+
| --- | --- |
|
|
254
|
+
| `OpenapiHttpError` | HTTP status and response data in `data` |
|
|
255
|
+
| `GraphqlHttpError` | HTTP status and response body in `body` |
|
|
256
|
+
| `GraphqlResponseError` | GraphQL execution errors in `errors` and partial response data in `data` |
|
|
257
|
+
|
|
258
|
+
When updating existing generated clients, see the [migration guide](docs/migration.md).
|
|
122
259
|
|
|
123
260
|
## Development
|
|
124
261
|
|
|
@@ -127,6 +264,13 @@ npm ci
|
|
|
127
264
|
npm run verify
|
|
128
265
|
```
|
|
129
266
|
|
|
267
|
+
| Directory | Contents |
|
|
268
|
+
| --- | --- |
|
|
269
|
+
| `src/cli/` | CLI command |
|
|
270
|
+
| `src/core/` | Configuration, generation entry point, file writing, and shared utilities |
|
|
271
|
+
| `src/openapi/` | OpenAPI generator and request code |
|
|
272
|
+
| `src/graphql/` | GraphQL generator and request code |
|
|
273
|
+
|
|
130
274
|
## License
|
|
131
275
|
|
|
132
276
|
[MIT](LICENSE)
|