@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.ru.md
CHANGED
|
@@ -2,27 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
[English](README.md)
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Требуются Node.js 22 или новее и TanStack Query 5 в подключающем приложении.
|
|
5
|
+
Генератор TypeScript-типов, функций запросов и React-хуков для TanStack Query из OpenAPI и GraphQL. Для каждой настроенной схемы создаётся отдельный `.ts`-файл.
|
|
8
6
|
|
|
9
7
|
## Установка
|
|
10
8
|
|
|
9
|
+
Нужна Node.js 22 или новее. В приложении, которое использует сгенерированные хуки, должен быть установлен TanStack Query 5 и настроен `QueryClientProvider`.
|
|
10
|
+
|
|
11
11
|
```sh
|
|
12
12
|
npm install -D @kollors/react-codegen@alpha
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
Сгенерированные файлы содержат код отправки запросов. Они используют TanStack Query; сам React Codegen нужен только для генерации.
|
|
16
|
+
|
|
17
|
+
## Конфигурация и запуск
|
|
16
18
|
|
|
17
19
|
Создайте `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
|
-
|
|
43
|
+
Запустите генерацию:
|
|
42
44
|
|
|
43
45
|
```sh
|
|
44
46
|
npx react-codegen codegen.config.js
|
|
45
47
|
```
|
|
46
48
|
|
|
47
|
-
|
|
49
|
+
Этот пример создаёт `src/api/openapi.ts` и `src/api/graphql.ts`. Укажите `openapi`, `graphql` или обе секции; нужна хотя бы одна. Каталоги создаются автоматически, а выходные файлы должны иметь разные имена.
|
|
50
|
+
|
|
51
|
+
Пути считаются от файла конфигурации. Конфиг использует `export default`; в проекте с CommonJS назовите его `codegen.config.mjs` и передайте это имя в команду.
|
|
52
|
+
|
|
53
|
+
| Настройка | Обязательна | Назначение или значение по умолчанию |
|
|
54
|
+
| --- | --- | --- |
|
|
55
|
+
| `openapi.schema` | Да | OpenAPI 3.0.x или 3.1.x в YAML/JSON: путь к файлу или HTTP URL |
|
|
56
|
+
| `openapi.output` | Да | Путь к создаваемому `.ts`-файлу |
|
|
57
|
+
| `openapi.baseUrl` | Нет | Начало URL для запросов; без настройки пути остаются относительными |
|
|
58
|
+
| `graphql.schema` | Да | GraphQL SDL или introspection JSON: путь к файлу или HTTP URL |
|
|
59
|
+
| `graphql.documents` | Да | Каталог с именованными запросами, мутациями и фрагментами в файлах `.graphql`; вложенные каталоги тоже читаются |
|
|
60
|
+
| `graphql.output` | Да | Путь к создаваемому `.ts`-файлу |
|
|
61
|
+
| `graphql.endpoint` | Нет | Адрес запросов; по умолчанию `/api/graphql` |
|
|
62
|
+
| `auth` | Нет | Общие [настройки авторизации](#авторизация) |
|
|
63
|
+
| `openapi.auth`, `graphql.auth` | Нет | Заменяют общие настройки авторизации для выбранного клиента |
|
|
64
|
+
|
|
65
|
+
GraphQL introspection JSON может содержать `__schema` или `data.__schema`. В `schema` также можно указать HTTP-адрес GraphQL API: генератор запросит его схему через introspection.
|
|
66
|
+
|
|
67
|
+
## Использование сгенерированного кода
|
|
68
|
+
|
|
69
|
+
### Запросы
|
|
70
|
+
|
|
71
|
+
Для OpenAPI GET-операции с `operationId: getPet` вызовите хук в компоненте или другом хуке:
|
|
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
|
+
Для GraphQL-запроса `MovieDetailsQuery`, который выбирает `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
|
+
Оба генератора создают следующие функции для запросов:
|
|
92
|
+
|
|
93
|
+
| Назначение | OpenAPI `getPet` | GraphQL `MovieDetailsQuery` |
|
|
94
|
+
| --- | --- | --- |
|
|
95
|
+
| Хук запроса | `useGetPet` | `useMovieDetailsQuery` |
|
|
96
|
+
| Хук с Suspense | `useSuspenseGetPet` | `useSuspenseMovieDetailsQuery` |
|
|
97
|
+
| Настройки для `QueryClient` | `getPetQuery` | `movieDetailsQuery` |
|
|
98
|
+
| Ключ кеша | `getPetQueryKey` | `movieDetailsQueryKey` |
|
|
99
|
+
| Прямой запрос | `fetchGetPet` | `fetchMovieDetailsQuery` |
|
|
100
|
+
|
|
101
|
+
В OpenAPI имена строятся из `operationId`, а при его отсутствии — из HTTP-метода и пути. В GraphQL — из имени операции. GraphQL также экспортирует тип выбранного результата, тип переменных и строку документа: например, `MovieDetailsQuery`, `MovieDetailsQueryVariables` и `MovieDetailsQueryDocument`.
|
|
102
|
+
|
|
103
|
+
### Мутации
|
|
104
|
+
|
|
105
|
+
Для OpenAPI-методов кроме GET и для GraphQL-мутаций создаются хуки мутаций. Пример для OpenAPI-операции с `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 аргументы сгруппированы в `pathParams`, `queryParams`, `headers` и `body`. В GraphQL передаются переменные операции. Обязательность задаёт схема; переменные GraphQL со знаком `!` обязательны, если у них нет значения по умолчанию.
|
|
117
|
+
|
|
118
|
+
Если обязательных аргументов нет, хуки и функции запросов можно вызывать без них. В этом случае для мутаций также доступны `mutate()` и `mutateAsync()` без аргументов.
|
|
119
|
+
|
|
120
|
+
### Пропуск запроса
|
|
121
|
+
|
|
122
|
+
Обычные хуки запросов принимают `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 не принимают `skipToken`. Аргументы для них можно опустить, если у операции нет обязательных аргументов.
|
|
134
|
+
|
|
135
|
+
### Запросы и ключи кеша
|
|
48
136
|
|
|
49
|
-
|
|
137
|
+
Загрузка данных через 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
|
+
Чтобы обновить кеш в приложении, используйте его `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
|
+
Прямой запрос без 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
|
+
Вызов `controller.abort()` отменяет прямой запрос. Хуки запросов получают сигнал отмены от TanStack Query автоматически. Функции запросов и вспомогательные функции GraphQL работают так же.
|
|
169
|
+
|
|
170
|
+
Для работы с кешем используйте сгенерированные функции ключей. Ключи учитывают адрес API и аргументы; в OpenAPI — также заголовки запроса. Токены из хранилища и браузерные cookie в ключ не входят, поэтому при смене пользователя очищайте соответствующий кеш.
|
|
171
|
+
|
|
172
|
+
## Авторизация
|
|
68
173
|
|
|
69
|
-
|
|
174
|
+
Общая секция `auth` применяется к обоим клиентам. `openapi.auth` или `graphql.auth` целиком заменяет её для выбранного клиента.
|
|
70
175
|
|
|
71
|
-
|
|
176
|
+
Без `auth` сгенерированный клиент не добавляет заголовок `Authorization`.
|
|
72
177
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
178
|
+
| Параметр | Обязателен | Поведение |
|
|
179
|
+
| --- | --- | --- |
|
|
180
|
+
| `storage` | Если указан `auth` | Откуда читать токен; варианты ниже |
|
|
181
|
+
| `key` | Если `storage` отличается от `none` | Имя записи в хранилище или cookie |
|
|
182
|
+
| `scheme` | Нет | Префикс заголовка; по умолчанию `Bearer`. Значение `false` отправляет токен без изменений |
|
|
183
|
+
| `credentials` | Нет | Правила отправки браузерных cookie; по умолчанию `same-origin` |
|
|
78
184
|
|
|
79
|
-
|
|
185
|
+
| `storage` | Источник токена |
|
|
186
|
+
| --- | --- |
|
|
187
|
+
| `localStorage` | `localStorage.getItem(key)` |
|
|
188
|
+
| `sessionStorage` | `sessionStorage.getItem(key)` |
|
|
189
|
+
| `cookie` | Cookie с именем `key`, прочитанная через `document.cookie` |
|
|
190
|
+
| `none` | Токен не читается, заголовок авторизации не добавляется |
|
|
80
191
|
|
|
81
|
-
|
|
192
|
+
| `credentials` | Браузерные cookie |
|
|
193
|
+
| --- | --- |
|
|
194
|
+
| `omit` | Не отправлять |
|
|
195
|
+
| `same-origin` | Разрешить для запросов к тому же origin |
|
|
196
|
+
| `include` | Разрешить также для запросов к другому origin |
|
|
82
197
|
|
|
83
|
-
|
|
198
|
+
Если токен отсутствует или пустой, заголовок авторизации не добавляется. Для cookie с флагом `HttpOnly`, которые JavaScript не может прочитать, настройте отправку браузером:
|
|
84
199
|
|
|
85
|
-
|
|
200
|
+
```js
|
|
201
|
+
auth: { storage: 'none', credentials: 'include' }
|
|
202
|
+
```
|
|
86
203
|
|
|
87
|
-
|
|
204
|
+
При этом действуют правила браузера для cookie и CORS. При прямом вызове `createOpenapiFetcher` или `createGraphqlFetcher` можно передать `getToken`, возвращающий полное значение заголовка `Authorization`. Этот параметр относится к функциям создания клиента, а не к конфигу генератора.
|
|
88
205
|
|
|
89
206
|
## Программный API
|
|
90
207
|
|
|
@@ -92,33 +209,53 @@ Fetch не позволяет отправлять тело с GET/HEAD и вы
|
|
|
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
|
+
Настройки совпадают с конфигом CLI. Относительные пути считаются от текущей рабочей директории. `generate` возвращает пути созданных файлов.
|
|
223
|
+
|
|
224
|
+
## Поддержка схем и ограничения
|
|
225
|
+
|
|
226
|
+
Оба генератора создают типы по схеме. Они не проверяют данные ответа сервера во время выполнения. Ошибка генерации сохраняет существующие выходные файлы.
|
|
112
227
|
|
|
113
|
-
|
|
228
|
+
### OpenAPI
|
|
114
229
|
|
|
115
|
-
|
|
230
|
+
- Поддерживаются OpenAPI 3.0.x и 3.1.x; Swagger 2.0 не поддерживается.
|
|
231
|
+
- Поддерживаются объекты, массивы, словари, enum, внутренние `$ref`, рекурсивные компоненты, `allOf`, `oneOf` и `anyOf`. В OpenAPI 3.1 — также `const`, булевы схемы и массивы типов.
|
|
232
|
+
- `required` определяет обязательные поля; `null` включается там, где разрешён схемой. Поля `readOnly` исключаются из типов запросов, `writeOnly` — из типов ответов. Даты остаются строками.
|
|
233
|
+
- Поддерживаются JSON, `+json`, текст/XML как строки, бинарные данные как `Blob`, multipart и URL-encoded тела. При нескольких форматах запроса приоритет такой: JSON, `+json`, URL-encoded, multipart, остальные поддерживаемые форматы по алфавиту.
|
|
234
|
+
- Поддерживаются параметры пути и заголовков `simple`, query-параметры `form`, плоский `deepObject` с `explode: true` и массивы `spaceDelimited`/`pipeDelimited` с `explode: false`. Вложенные объекты и массивы параметров не поддерживаются.
|
|
116
235
|
|
|
117
|
-
|
|
236
|
+
Внешние `$ref` нужно объединить в один документ перед генерацией. Не поддерживаются callbacks, webhooks, cookie-параметры, `content` у параметров, `allowReserved`, стили пути `label`/`matrix` и пользовательский encoding форм. Сложные ограничения JSON Schema, например условия, `not`, `dependentRequired`, `patternProperties` и `unevaluatedProperties`, вызывают ошибку с местом в схеме.
|
|
118
237
|
|
|
119
|
-
|
|
238
|
+
Типизированные `additionalProperties` вместе с именованными свойствами не поддерживаются; вынесите словарь в отдельное свойство. Числовые границы, паттерны и длины не проверяются во время выполнения. `oneOf` становится TypeScript-объединением без проверки, что подходит ровно один вариант; поле дискриминатора и его значения нужно описать в схеме.
|
|
120
239
|
|
|
121
|
-
|
|
240
|
+
Адрес и авторизация задаются через `baseUrl` и `auth`; `servers` и `security` из схемы не применяются. Для GET нужно описать тело ответа. Пустые ответы мутаций возвращают `undefined` с типом `void`; отсутствие объявленного тела ответа вызывает ошибку запроса. Тела GET/HEAD, метод TRACE и сегменты пути `.` или `..` отклоняются. Заголовки ответа отдельно не возвращаются.
|
|
241
|
+
|
|
242
|
+
### GraphQL
|
|
243
|
+
|
|
244
|
+
Поддерживаются именованные запросы и мутации, фрагменты, псевдонимы полей, интерфейсы и объединения. Тип результата описывает выбранные поля. Выбирайте `__typename`, если нужно различать варианты объединения.
|
|
245
|
+
|
|
246
|
+
Поля, допускающие `null`, имеют тип `T | null`; условные поля с `@skip` или `@include` могут быть необязательными. Списки сохраняют возможность `null` у элементов. Входные поля и переменные со знаком `!` и значением по умолчанию можно опустить, но нельзя передать `null`. Входные объекты с `@oneOf` требуют ровно одно поле со значением, отличным от `null`. Пользовательские скаляры имеют тип `unknown`.
|
|
247
|
+
|
|
248
|
+
Subscriptions и `@defer`/`@stream` не поддерживаются. Загрузка схемы не использует `auth`; если адрес схемы требует авторизации, используйте локальный экспорт схемы.
|
|
249
|
+
|
|
250
|
+
### Ошибки запросов
|
|
251
|
+
|
|
252
|
+
| Ошибка | Данные |
|
|
253
|
+
| --- | --- |
|
|
254
|
+
| `OpenapiHttpError` | HTTP-статус и данные ответа в `data` |
|
|
255
|
+
| `GraphqlHttpError` | HTTP-статус и тело ответа в `body` |
|
|
256
|
+
| `GraphqlResponseError` | Ошибки выполнения GraphQL в `errors` и частичные данные ответа в `data` |
|
|
257
|
+
|
|
258
|
+
При обновлении существующих клиентов смотрите [инструкцию по переходу](docs/migration.ru.md).
|
|
122
259
|
|
|
123
260
|
## Разработка
|
|
124
261
|
|
|
@@ -127,6 +264,13 @@ npm ci
|
|
|
127
264
|
npm run verify
|
|
128
265
|
```
|
|
129
266
|
|
|
267
|
+
| Каталог | Содержимое |
|
|
268
|
+
| --- | --- |
|
|
269
|
+
| `src/cli/` | Команда CLI |
|
|
270
|
+
| `src/core/` | Конфигурация, запуск генерации, запись файлов и общие утилиты |
|
|
271
|
+
| `src/openapi/` | Генератор OpenAPI и код отправки запросов |
|
|
272
|
+
| `src/graphql/` | Генератор GraphQL и код отправки запросов |
|
|
273
|
+
|
|
130
274
|
## Лицензия
|
|
131
275
|
|
|
132
276
|
[MIT](LICENSE)
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { readFile } from 'node:fs/promises';
|
|
3
|
-
import { dirname,
|
|
3
|
+
import { dirname, resolve } from 'node:path';
|
|
4
4
|
import { pathToFileURL } from 'node:url';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { validateCodegenConfig } from '../core/config.js';
|
|
6
|
+
import { generate } from '../core/generate.js';
|
|
7
|
+
import { resolvePath, resolveSchema } from '../core/paths.js';
|
|
7
8
|
const help = `Usage: react-codegen <codegen.config.js>
|
|
8
9
|
|
|
9
10
|
Generate configured OpenAPI and GraphQL clients.
|
|
@@ -12,19 +13,13 @@ Options:
|
|
|
12
13
|
-h, --help Show this help message
|
|
13
14
|
-v, --version Show version
|
|
14
15
|
`;
|
|
15
|
-
function resolvePath(value, directory) {
|
|
16
|
-
return isAbsolute(value) ? value : resolve(directory, value);
|
|
17
|
-
}
|
|
18
|
-
function resolveSchema(value, directory) {
|
|
19
|
-
return isUrl(value) ? value : resolvePath(value, directory);
|
|
20
|
-
}
|
|
21
16
|
async function main(args) {
|
|
22
17
|
if (args.includes('--help') || args.includes('-h')) {
|
|
23
18
|
process.stdout.write(help);
|
|
24
19
|
return;
|
|
25
20
|
}
|
|
26
21
|
if (args.includes('--version') || args.includes('-v')) {
|
|
27
|
-
const packageJson = JSON.parse(await readFile(new URL('
|
|
22
|
+
const packageJson = JSON.parse(await readFile(new URL('../../package.json', import.meta.url), 'utf8'));
|
|
28
23
|
process.stdout.write(`${packageJson.version}\n`);
|
|
29
24
|
return;
|
|
30
25
|
}
|
|
@@ -68,4 +63,4 @@ catch (error) {
|
|
|
68
63
|
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
69
64
|
process.exitCode = 1;
|
|
70
65
|
}
|
|
71
|
-
//# sourceMappingURL=
|
|
66
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAG9D,MAAM,IAAI,GAAG;;;;;;;CAOZ,CAAC;AAEF,KAAK,UAAU,IAAI,CAAC,IAAc;IAChC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3B,OAAO;IACT,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACtD,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,GAAG,CAAC,oBAAoB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAwB,CAAC;QAC9H,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,WAAW,CAAC,OAAO,IAAI,CAAC,CAAC;QACjD,OAAO;IACT,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IAC9D,CAAC;IAED,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAW,CAAC,CAAC;IAC9C,MAAM,YAAY,GAAG,CAAC,MAAM,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAA0B,CAAC;IAC7F,IAAI,CAAC,YAAY,CAAC,OAAO,IAAI,OAAO,YAAY,CAAC,OAAO,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7G,MAAM,IAAI,SAAS,CAAC,GAAG,UAAU,iDAAiD,CAAC,CAAC;IACtF,CAAC;IACD,qBAAqB,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;IAC5C,MAAM,YAAY,GAAG,YAAY,CAAC,OAAO,CAAC;IAE1C,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACtC,MAAM,MAAM,GAAkB;QAC5B,GAAG,YAAY;QACf,GAAG,CAAC,YAAY,CAAC,OAAO,IAAI;YAC1B,OAAO,EAAE;gBACP,GAAG,YAAY,CAAC,OAAO;gBACvB,MAAM,EAAE,aAAa,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;gBAC7D,MAAM,EAAE,WAAW,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;aAC5D;SACF,CAAC;QACF,GAAG,CAAC,YAAY,CAAC,OAAO,IAAI;YAC1B,OAAO,EAAE;gBACP,GAAG,YAAY,CAAC,OAAO;gBACvB,MAAM,EAAE,aAAa,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;gBAC7D,SAAS,EAAE,WAAW,CAAC,YAAY,CAAC,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC;gBACjE,MAAM,EAAE,WAAW,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;aAC5D;SACF,CAAC;KACH,CAAC;IAEF,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;IACtC,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO;QAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,MAAM,IAAI,CAAC,CAAC;AACtF,CAAC;AAED,IAAI,CAAC;IACH,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACpC,CAAC;AAAC,OAAO,KAAK,EAAE,CAAC;IACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACpF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/core/auth.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
export function validateCodegenConfig(value) {
|
|
3
|
+
const config = value;
|
|
4
|
+
if (config === null || typeof config !== 'object' || Array.isArray(config)) {
|
|
5
|
+
throw new TypeError('Codegen config must be an object.');
|
|
6
|
+
}
|
|
7
|
+
const keys = Object.keys(config);
|
|
8
|
+
if (keys.some((key) => key !== 'auth' && key !== 'openapi' && key !== 'graphql')) {
|
|
9
|
+
throw new Error(`Unknown codegen config section: ${keys.find((key) => key !== 'auth' && key !== 'openapi' && key !== 'graphql')}`);
|
|
10
|
+
}
|
|
11
|
+
if (!config.openapi && !config.graphql) {
|
|
12
|
+
throw new Error('Codegen config must contain an openapi or graphql section.');
|
|
13
|
+
}
|
|
14
|
+
const validateAuth = (auth, location) => {
|
|
15
|
+
if (!auth || typeof auth !== 'object' || Array.isArray(auth))
|
|
16
|
+
throw new TypeError(`${location} must be an object.`);
|
|
17
|
+
const allowedAuthKeys = ['storage', 'key', 'scheme', 'credentials'];
|
|
18
|
+
const unknownKey = Object.keys(auth).find((key) => !allowedAuthKeys.includes(key));
|
|
19
|
+
if (unknownKey)
|
|
20
|
+
throw new Error(`Unknown ${location} option: ${unknownKey}`);
|
|
21
|
+
if (!['localStorage', 'sessionStorage', 'cookie', 'none'].includes(auth.storage)) {
|
|
22
|
+
throw new TypeError(`${location}.storage must be localStorage, sessionStorage, cookie, or none.`);
|
|
23
|
+
}
|
|
24
|
+
if (auth.storage !== 'none' && (typeof auth.key !== 'string' || !auth.key.trim())) {
|
|
25
|
+
throw new TypeError(`${location}.key must be a non-empty string unless storage is "none".`);
|
|
26
|
+
}
|
|
27
|
+
if (auth.key !== undefined && (typeof auth.key !== 'string' || !auth.key.trim())) {
|
|
28
|
+
throw new TypeError(`${location}.key must be a non-empty string.`);
|
|
29
|
+
}
|
|
30
|
+
if (auth.scheme !== undefined && auth.scheme !== false && (typeof auth.scheme !== 'string' || !auth.scheme.trim())) {
|
|
31
|
+
throw new TypeError(`${location}.scheme must be a non-empty string or false.`);
|
|
32
|
+
}
|
|
33
|
+
if (auth.credentials !== undefined && !['omit', 'same-origin', 'include'].includes(auth.credentials)) {
|
|
34
|
+
throw new TypeError(`${location}.credentials must be omit, same-origin, or include.`);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
if (config.auth !== undefined)
|
|
38
|
+
validateAuth(config.auth, 'config.auth');
|
|
39
|
+
for (const [kind, section] of Object.entries({ openapi: config.openapi, graphql: config.graphql })) {
|
|
40
|
+
if (section === undefined)
|
|
41
|
+
continue;
|
|
42
|
+
if (!section || typeof section !== 'object' || Array.isArray(section)) {
|
|
43
|
+
throw new TypeError(`config.${kind} must be an object.`);
|
|
44
|
+
}
|
|
45
|
+
const expectedKeys = kind === 'openapi' ? ['schema', 'output', 'baseUrl', 'auth'] : ['schema', 'documents', 'output', 'endpoint', 'auth'];
|
|
46
|
+
for (const key of Object.keys(section)) {
|
|
47
|
+
if (!expectedKeys.includes(key))
|
|
48
|
+
throw new Error(`Unknown config.${kind} option: ${key}`);
|
|
49
|
+
}
|
|
50
|
+
for (const key of expectedKeys) {
|
|
51
|
+
const value = section[key];
|
|
52
|
+
if ((key === 'baseUrl' || key === 'endpoint' || key === 'auth') && value === undefined)
|
|
53
|
+
continue;
|
|
54
|
+
if (key === 'auth') {
|
|
55
|
+
validateAuth(value, `config.${kind}.auth`);
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (typeof value !== 'string' || !value.trim())
|
|
59
|
+
throw new TypeError(`config.${kind}.${key} must be a non-empty string.`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const outputs = [config.openapi?.output, config.graphql?.output].filter((value) => Boolean(value));
|
|
63
|
+
if (new Set(outputs.map((value) => resolve(value))).size !== outputs.length) {
|
|
64
|
+
throw new Error('OpenAPI and GraphQL outputs must use different files.');
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
import type { CodegenConfig, CodegenResult } from './types.js';
|
|
2
2
|
/** Generate configured OpenAPI and GraphQL clients into one TypeScript file per enabled section. */
|
|
3
3
|
export declare function generate(config: CodegenConfig): Promise<CodegenResult>;
|
|
4
|
-
export declare function validateCodegenConfig(config: unknown): asserts config is CodegenConfig;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { generateGraphqlSource } from '../graphql/generate.js';
|
|
2
|
+
import { generateOpenapiSource } from '../openapi/generate.js';
|
|
3
|
+
import { validateCodegenConfig } from './config.js';
|
|
4
|
+
import { publishOutputs } from './output.js';
|
|
5
|
+
import { resolvePath, resolveSchema } from './paths.js';
|
|
6
|
+
async function generateOpenapi(config, auth, cwd) {
|
|
7
|
+
try {
|
|
8
|
+
const content = await generateOpenapiSource(resolveSchema(config.schema, cwd), {
|
|
9
|
+
...(config.baseUrl ? { baseUrl: config.baseUrl } : {}),
|
|
10
|
+
...(auth ? { auth } : {}),
|
|
11
|
+
});
|
|
12
|
+
return { path: resolvePath(config.output, cwd), content };
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
throw new Error(`Could not generate OpenAPI client from ${resolveSchema(config.schema, cwd)}: ${errorMessage(error)}`, {
|
|
16
|
+
cause: error,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
async function generateGraphql(config, auth, cwd) {
|
|
21
|
+
try {
|
|
22
|
+
const content = await generateGraphqlSource(resolveSchema(config.schema, cwd), resolvePath(config.documents, cwd), {
|
|
23
|
+
...(config.endpoint ? { endpoint: config.endpoint } : {}),
|
|
24
|
+
...(auth ? { auth } : {}),
|
|
25
|
+
});
|
|
26
|
+
return { path: resolvePath(config.output, cwd), content };
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
throw new Error(`Could not generate GraphQL client using schema ${resolveSchema(config.schema, cwd)} and documents ${resolvePath(config.documents, cwd)}: ${errorMessage(error)}`, { cause: error });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function errorMessage(error) {
|
|
33
|
+
return error instanceof Error ? error.message : String(error);
|
|
34
|
+
}
|
|
35
|
+
/** Generate configured OpenAPI and GraphQL clients into one TypeScript file per enabled section. */
|
|
36
|
+
export async function generate(config) {
|
|
37
|
+
validateCodegenConfig(config);
|
|
38
|
+
const cwd = process.cwd();
|
|
39
|
+
const generated = [];
|
|
40
|
+
if (config.openapi)
|
|
41
|
+
generated.push(await generateOpenapi(config.openapi, config.openapi.auth ?? config.auth, cwd));
|
|
42
|
+
if (config.graphql)
|
|
43
|
+
generated.push(await generateGraphql(config.graphql, config.graphql.auth ?? config.auth, cwd));
|
|
44
|
+
publishOutputs(generated);
|
|
45
|
+
return { outputs: generated.map(({ path }) => path) };
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=generate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate.js","sourceRoot":"","sources":["../../src/core/generate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export class Names {
|
|
2
|
+
used = new Map();
|
|
3
|
+
reserve(name, location) {
|
|
4
|
+
const previous = this.used.get(name);
|
|
5
|
+
if (previous !== undefined)
|
|
6
|
+
throw new Error(`Generated name "${name}" collides between ${previous} and ${location}. Rename one of these definitions.`);
|
|
7
|
+
this.used.set(name, location);
|
|
8
|
+
return name;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export function comment(value) {
|
|
12
|
+
if (typeof value !== 'string' || !value.trim())
|
|
13
|
+
return '';
|
|
14
|
+
return `/** ${value.replaceAll('*/', '* /').replace(/\r?\n/g, '\n * ')} */\n`;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=names.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"names.js","sourceRoot":"","sources":["../../src/core/names.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,KAAK;IACC,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;IAElD,OAAO,CAAC,IAAY,EAAE,QAAgB;QACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,QAAQ,KAAK,SAAS;YACxB,MAAM,IAAI,KAAK,CAAC,mBAAmB,IAAI,sBAAsB,QAAQ,QAAQ,QAAQ,oCAAoC,CAAC,CAAC;QAC7H,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAED,MAAM,UAAU,OAAO,CAAC,KAAc;IACpC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,CAAC;IAC1D,OAAO,OAAO,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC;AAChF,CAAC"}
|