@appswave/rq-codegen 0.1.0
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 +1279 -0
- package/dist/bin/cli.js +1788 -0
- package/dist/bin/cli.js.map +1 -0
- package/dist/index.d.ts +79 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/package.json +64 -0
- package/templates/component-form/FormComponent.tsx.hbs +60 -0
- package/templates/component-form/index.ts.hbs +1 -0
- package/templates/component-shared/Component.tsx.hbs +37 -0
- package/templates/component-shared/index.ts.hbs +1 -0
- package/templates/component-ui/Component.tsx.hbs +41 -0
- package/templates/component-ui/index.ts.hbs +1 -0
- package/templates/handler/handler.ts.hbs +80 -0
- package/templates/mutation-hook/hook.ts.hbs +53 -0
- package/templates/page/Page.tsx.hbs +7 -0
- package/templates/query-hook/hook-details.ts.hbs +12 -0
- package/templates/query-hook/hook-paginated.ts.hbs +12 -0
- package/templates/query-hook/hook.ts.hbs +12 -0
- package/templates/shared-hook/hook.ts.hbs +9 -0
- package/templates/types-dto/dto.ts.hbs +40 -0
- package/templates/validation/validation.ts.hbs +22 -0
- package/templates/view/View.tsx.hbs +13 -0
- package/templates/view/index.ts.hbs +1 -0
package/README.md
ADDED
|
@@ -0,0 +1,1279 @@
|
|
|
1
|
+
# @appswave/rq-codegen
|
|
2
|
+
|
|
3
|
+
Config-driven code generator for React + TypeScript projects. Generates API handlers, React Query hooks, DTO types, components, pages, views, validation schemas, and full features — all wired to your project's aliases, paths, and conventions.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [When to Use](#when-to-use)
|
|
8
|
+
- [Quick Start](#quick-start)
|
|
9
|
+
- [CLI Commands](#cli-commands)
|
|
10
|
+
- [Generators](#generators)
|
|
11
|
+
- [handler](#handler)
|
|
12
|
+
- [types-dto](#types-dto)
|
|
13
|
+
- [query-hook](#query-hook)
|
|
14
|
+
- [mutation-hook](#mutation-hook)
|
|
15
|
+
- [component-ui](#component-ui)
|
|
16
|
+
- [component-shared](#component-shared)
|
|
17
|
+
- [component-form](#component-form)
|
|
18
|
+
- [page](#page)
|
|
19
|
+
- [view](#view)
|
|
20
|
+
- [shared-hook](#shared-hook)
|
|
21
|
+
- [validation](#validation)
|
|
22
|
+
- [feature](#feature)
|
|
23
|
+
- [Configuration Reference](#configuration-reference)
|
|
24
|
+
- [srcDir](#srcdir)
|
|
25
|
+
- [aliases](#aliases)
|
|
26
|
+
- [features](#features)
|
|
27
|
+
- [naming](#naming)
|
|
28
|
+
- [paths](#paths)
|
|
29
|
+
- [router](#router)
|
|
30
|
+
- [hooks](#hooks)
|
|
31
|
+
- [templatesDir](#templatesdir)
|
|
32
|
+
- [Feature Toggles](#feature-toggles)
|
|
33
|
+
- [Template Overrides](#template-overrides)
|
|
34
|
+
- [Path Alias Detection](#path-alias-detection)
|
|
35
|
+
- [Recommended Project Structure](#recommended-project-structure)
|
|
36
|
+
- [defineConfig()](#defineconfig)
|
|
37
|
+
- [Contributing](#contributing)
|
|
38
|
+
- [License](#license)
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## When to Use
|
|
43
|
+
|
|
44
|
+
Use `rq-codegen` every time you need to:
|
|
45
|
+
|
|
46
|
+
- **Add a new API endpoint** — generates the handler, DTO types, query hook, and mutation hook in one command
|
|
47
|
+
- **Create a new page or view** — scaffolds the component with correct folder structure and barrel exports
|
|
48
|
+
- **Build a full feature** — generates everything at once: handler + types + hooks + view + page + validation
|
|
49
|
+
- **Add a new UI component** — creates a CVA-based component with variants (shadcn/ui style)
|
|
50
|
+
- **Add a shared component** — creates a compound component with sub-components (Header, Body, Footer)
|
|
51
|
+
- **Add a form component** — creates a React Hook Form `useController`-based field component
|
|
52
|
+
- **Add a validation schema** — scaffolds a Zod schema with optional i18n support
|
|
53
|
+
- **Add a custom hook** — creates a shared utility hook with selected React imports
|
|
54
|
+
|
|
55
|
+
Every generated file respects your project's path aliases, naming conventions, and feature toggles — no manual find-and-replace needed.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Quick Start
|
|
60
|
+
|
|
61
|
+
### 1. Install
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
npm install -g @appswave/rq-codegen
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Or as a dev dependency:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npm install -D @appswave/rq-codegen
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 2. Initialize Config
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
rq-codegen init
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
This creates `rqgen.config.ts` in your project root with auto-detected settings:
|
|
80
|
+
- Reads your `tsconfig.json` / `tsconfig.app.json` to detect path aliases
|
|
81
|
+
- Detects if you have `src/`, `routes/`, `locales/` directories
|
|
82
|
+
- Asks about i18n, toast, and route registration preferences
|
|
83
|
+
|
|
84
|
+
### 3. Generate Code
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Interactive menu — pick from 12 generators
|
|
88
|
+
rq-codegen
|
|
89
|
+
|
|
90
|
+
# Or run a specific generator directly
|
|
91
|
+
rq-codegen handler
|
|
92
|
+
rq-codegen feature
|
|
93
|
+
rq-codegen page
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## CLI Commands
|
|
99
|
+
|
|
100
|
+
| Command | Description |
|
|
101
|
+
|---------|-------------|
|
|
102
|
+
| `rq-codegen` | Interactive menu — select a generator from the list |
|
|
103
|
+
| `rq-codegen <generator>` | Run a specific generator directly (e.g., `rq-codegen handler`) |
|
|
104
|
+
| `rq-codegen init` | Create `rqgen.config.ts` with auto-detected settings |
|
|
105
|
+
| `rq-codegen init --force` | Overwrite existing config file |
|
|
106
|
+
| `rq-codegen --version` | Show version |
|
|
107
|
+
| `rq-codegen --help` | Show help |
|
|
108
|
+
|
|
109
|
+
### Interactive Menu
|
|
110
|
+
|
|
111
|
+
When you run `rq-codegen` without arguments, you get an interactive menu:
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
? What would you like to generate?
|
|
115
|
+
component-ui — CVA-based UI component (shadcn/ui style)
|
|
116
|
+
component-shared — Compound shared component
|
|
117
|
+
component-form — React Hook Form component (useController-based)
|
|
118
|
+
page — Route-level page component
|
|
119
|
+
view — Feature view component
|
|
120
|
+
handler — API handler (+ types + hooks)
|
|
121
|
+
query-hook — React Query hook
|
|
122
|
+
mutation-hook — React Query mutation hook
|
|
123
|
+
types-dto — DTO type definitions
|
|
124
|
+
shared-hook — Custom utility hook
|
|
125
|
+
validation — Zod validation schema
|
|
126
|
+
feature — Full feature scaffold (handler + types + hooks + view + page)
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Generators
|
|
132
|
+
|
|
133
|
+
### handler
|
|
134
|
+
|
|
135
|
+
The most powerful single generator. Creates an API handler with typed request functions, and optionally chains DTO types, query hooks, and mutation hooks.
|
|
136
|
+
|
|
137
|
+
**Prompts:**
|
|
138
|
+
|
|
139
|
+
| Prompt | Example | Description |
|
|
140
|
+
|--------|---------|-------------|
|
|
141
|
+
| Entity name | `products` | Plural name for the handler (used for file names, handler object) |
|
|
142
|
+
| Singular name | `product` | Used for mutation hook names (e.g., `useCreateProductMutation`) |
|
|
143
|
+
| Endpoint key | `PRODUCTS` | ApiEndpoints constant key (e.g., `ApiEndpoints.PRODUCTS`) |
|
|
144
|
+
| Operations | `list, details, create, update, delete` | Which CRUD operations to generate |
|
|
145
|
+
| Also generate DTO types? | `Yes` | Chains the `types-dto` generator |
|
|
146
|
+
| Also generate query hooks? | `Yes` | Chains the `query-hook` generator |
|
|
147
|
+
| Is list paginated? | `No` | Uses paginated query hook variant |
|
|
148
|
+
| Also generate mutation hooks? | `Yes` | Chains the `mutation-hook` generator |
|
|
149
|
+
|
|
150
|
+
**Example:** `rq-codegen handler` with entity `products`, all operations, all chains enabled:
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
CREATED src/api/handlers/products.ts
|
|
154
|
+
UPDATED src/api/handlers/index.ts
|
|
155
|
+
CREATED src/types/api/ProductsDto.ts
|
|
156
|
+
UPDATED src/types/api/index.ts
|
|
157
|
+
CREATED src/lib/hooks/queries/useProductsListQuery.ts
|
|
158
|
+
UPDATED src/lib/hooks/queries/index.ts
|
|
159
|
+
CREATED src/lib/hooks/queries/useProductsDetailsQuery.ts
|
|
160
|
+
UPDATED src/lib/hooks/queries/index.ts
|
|
161
|
+
CREATED src/lib/hooks/mutations/useCreateProductMutation.ts
|
|
162
|
+
UPDATED src/lib/hooks/mutations/index.ts
|
|
163
|
+
CREATED src/lib/hooks/mutations/useUpdateProductMutation.ts
|
|
164
|
+
UPDATED src/lib/hooks/mutations/index.ts
|
|
165
|
+
CREATED src/lib/hooks/mutations/useDeleteProductMutation.ts
|
|
166
|
+
UPDATED src/lib/hooks/mutations/index.ts
|
|
167
|
+
|
|
168
|
+
Done! 7 file(s) created, 6 barrel(s) updated.
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
**Generated handler (`products.ts`):**
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
import { ApiEndpoints, HttpClient } from '@api/config';
|
|
175
|
+
|
|
176
|
+
import type {
|
|
177
|
+
ProductsForReadDto,
|
|
178
|
+
ProductsListResponseDto,
|
|
179
|
+
ProductsForCreateDto,
|
|
180
|
+
ProductsForUpdateDto,
|
|
181
|
+
} from '@app-types';
|
|
182
|
+
|
|
183
|
+
const URL = ApiEndpoints.PRODUCTS;
|
|
184
|
+
|
|
185
|
+
function getProductsList(queryString?: string): Promise<ProductsListResponseDto> {
|
|
186
|
+
const url = queryString ? `${URL.INDEX}?${queryString}` : URL.INDEX;
|
|
187
|
+
return HttpClient.get<ProductsListResponseDto>(url);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function getProductsDetails(id: string): Promise<ProductsForReadDto> {
|
|
191
|
+
return HttpClient.get<ProductsForReadDto>(URL.DETAILS.replace(':id', id));
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function createProducts(payload: ProductsForCreateDto): Promise<ProductsForReadDto> {
|
|
195
|
+
return HttpClient.post<ProductsForReadDto>(URL.INDEX, payload);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function updateProducts(id: string, payload: ProductsForUpdateDto): Promise<ProductsForReadDto> {
|
|
199
|
+
return HttpClient.put<ProductsForReadDto>(URL.DETAILS.replace(':id', id), payload);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function removeProducts(id: string): Promise<void> {
|
|
203
|
+
return HttpClient.delete<void>(URL.DETAILS.replace(':id', id));
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export const ProductsHandler = {
|
|
207
|
+
list: {
|
|
208
|
+
queryKey: 'products/list',
|
|
209
|
+
request: getProductsList,
|
|
210
|
+
},
|
|
211
|
+
details: {
|
|
212
|
+
queryKey: 'products/details',
|
|
213
|
+
request: getProductsDetails,
|
|
214
|
+
},
|
|
215
|
+
create: {
|
|
216
|
+
mutationKey: 'products/create',
|
|
217
|
+
mutationFn: createProducts,
|
|
218
|
+
},
|
|
219
|
+
update: {
|
|
220
|
+
mutationKey: 'products/update',
|
|
221
|
+
mutationFn: updateProducts,
|
|
222
|
+
},
|
|
223
|
+
remove: {
|
|
224
|
+
mutationKey: 'products/remove',
|
|
225
|
+
mutationFn: removeProducts,
|
|
226
|
+
},
|
|
227
|
+
} as const;
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
### types-dto
|
|
233
|
+
|
|
234
|
+
Generates DTO type definitions for an API entity.
|
|
235
|
+
|
|
236
|
+
**Prompts:**
|
|
237
|
+
|
|
238
|
+
| Prompt | Example | Description |
|
|
239
|
+
|--------|---------|-------------|
|
|
240
|
+
| Entity name | `products` | Name used for type prefixes |
|
|
241
|
+
| Include create DTO? | `Yes` | Adds `ForCreateDto` type |
|
|
242
|
+
| Include update DTO? | `Yes` | Adds `ForUpdateDto` type |
|
|
243
|
+
|
|
244
|
+
**Generated types (`ProductsDto.ts`):**
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
export type ProductsForReadDto = {
|
|
248
|
+
id: number;
|
|
249
|
+
// TODO: Add read fields
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
export type ProductsForCreateDto = {
|
|
253
|
+
// TODO: Add create fields
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
export type ProductsForUpdateDto = {
|
|
257
|
+
id: number;
|
|
258
|
+
// TODO: Add update fields
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
export type ProductsListDto = {
|
|
262
|
+
id: number;
|
|
263
|
+
// TODO: Add minimal list fields
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
export type ProductsListResponseDto = {
|
|
267
|
+
items: ProductsListDto[];
|
|
268
|
+
page: number;
|
|
269
|
+
pageSize: number;
|
|
270
|
+
totalCount: number;
|
|
271
|
+
lastPage: number;
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
export type ProductsParamsDto = {
|
|
275
|
+
page?: number;
|
|
276
|
+
pageSize?: number;
|
|
277
|
+
search?: string;
|
|
278
|
+
sort?: string;
|
|
279
|
+
filter?: string;
|
|
280
|
+
};
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
The DTO suffix names (`ForReadDto`, `ForCreateDto`, etc.) are fully configurable via `naming.dtoSuffixes` in your config.
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
### query-hook
|
|
288
|
+
|
|
289
|
+
Generates a React Query hook that wraps a handler.
|
|
290
|
+
|
|
291
|
+
**Prompts:**
|
|
292
|
+
|
|
293
|
+
| Prompt | Example | Description |
|
|
294
|
+
|--------|---------|-------------|
|
|
295
|
+
| Hook name | `productsList` | Used in `useProductsListQuery` |
|
|
296
|
+
| Handler name | `products` | References the handler (e.g., `ProductsHandler`) |
|
|
297
|
+
| Handler key | `list` | Handler method key (e.g., `ProductsHandler.list`) |
|
|
298
|
+
| Is paginated? | `No` | Uses paginated hook variant |
|
|
299
|
+
|
|
300
|
+
**Generated query hook (standard):**
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
import { ProductsHandler } from '@api/handlers';
|
|
304
|
+
import { useQuery } from '@tanstack/react-query';
|
|
305
|
+
|
|
306
|
+
export const useProductsListQuery = (enabled = true) => {
|
|
307
|
+
return useQuery({
|
|
308
|
+
queryKey: [ProductsHandler.list.queryKey],
|
|
309
|
+
queryFn: () => ProductsHandler.list.request(),
|
|
310
|
+
enabled,
|
|
311
|
+
staleTime: 5 * 60 * 1000,
|
|
312
|
+
gcTime: 10 * 60 * 1000,
|
|
313
|
+
});
|
|
314
|
+
};
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
**Generated query hook (details variant):**
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
import { ProductsHandler } from '@api/handlers';
|
|
321
|
+
import { useQuery } from '@tanstack/react-query';
|
|
322
|
+
|
|
323
|
+
export const useProductsDetailsQuery = (id: string | undefined, enabled = true) => {
|
|
324
|
+
return useQuery({
|
|
325
|
+
queryKey: [ProductsHandler.details.queryKey, id],
|
|
326
|
+
queryFn: () => ProductsHandler.details.request(id!),
|
|
327
|
+
enabled: enabled && !!id,
|
|
328
|
+
staleTime: 5 * 60 * 1000,
|
|
329
|
+
gcTime: 10 * 60 * 1000,
|
|
330
|
+
});
|
|
331
|
+
};
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
**Generated query hook (paginated variant):**
|
|
335
|
+
|
|
336
|
+
```typescript
|
|
337
|
+
import { ProductsHandler } from '@api/handlers';
|
|
338
|
+
import { usePaginatedDataTableQuery } from '@hooks/utils';
|
|
339
|
+
|
|
340
|
+
import type { ProductsListDto } from '@app-types';
|
|
341
|
+
|
|
342
|
+
export const useProductsPaginatedQuery = () => {
|
|
343
|
+
return usePaginatedDataTableQuery<ProductsListDto>({
|
|
344
|
+
queryKey: [ProductsHandler.list.queryKey],
|
|
345
|
+
queryFn: (params: string) => ProductsHandler.list.request(params),
|
|
346
|
+
defaultPageSize: 10,
|
|
347
|
+
});
|
|
348
|
+
};
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
### mutation-hook
|
|
354
|
+
|
|
355
|
+
Generates a React Query mutation hook with automatic query invalidation, toast notifications, and i18n support.
|
|
356
|
+
|
|
357
|
+
**Prompts:**
|
|
358
|
+
|
|
359
|
+
| Prompt | Example | Description |
|
|
360
|
+
|--------|---------|-------------|
|
|
361
|
+
| Mutation name | `CreateProduct` | Used in `useCreateProductMutation` |
|
|
362
|
+
| Handler name | `products` | References the handler |
|
|
363
|
+
| Handler key | `create` | Handler method key |
|
|
364
|
+
| Invalidate key | `list` | Query key to invalidate on success |
|
|
365
|
+
|
|
366
|
+
**Generated mutation hook (with i18n + toast enabled):**
|
|
367
|
+
|
|
368
|
+
```typescript
|
|
369
|
+
import { ProductsHandler } from '@api/handlers';
|
|
370
|
+
import { useToast } from '@hooks/shared';
|
|
371
|
+
import { useAppTranslation } from '@hooks/shared';
|
|
372
|
+
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
|
373
|
+
|
|
374
|
+
export const useCreateProductMutation = () => {
|
|
375
|
+
const queryClient = useQueryClient();
|
|
376
|
+
const { toast } = useToast();
|
|
377
|
+
const { t } = useAppTranslation();
|
|
378
|
+
|
|
379
|
+
return useMutation({
|
|
380
|
+
mutationKey: [ProductsHandler.create.mutationKey],
|
|
381
|
+
mutationFn: ProductsHandler.create.mutationFn,
|
|
382
|
+
onSuccess: () => {
|
|
383
|
+
queryClient.invalidateQueries({
|
|
384
|
+
queryKey: [ProductsHandler.list.queryKey],
|
|
385
|
+
});
|
|
386
|
+
toast({
|
|
387
|
+
variant: 'success',
|
|
388
|
+
title: t('common.success'),
|
|
389
|
+
});
|
|
390
|
+
},
|
|
391
|
+
onError: (error) => {
|
|
392
|
+
const errorMessage =
|
|
393
|
+
error?.response?.data?.title || error?.response?.data?.message || t('errors.unexpectedError');
|
|
394
|
+
toast({
|
|
395
|
+
variant: 'destructive',
|
|
396
|
+
title: errorMessage,
|
|
397
|
+
description: error?.response?.data?.detail || '',
|
|
398
|
+
});
|
|
399
|
+
},
|
|
400
|
+
});
|
|
401
|
+
};
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
When `features.toast` or `features.i18n` is disabled, the corresponding import and usage lines are omitted automatically.
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
408
|
+
### component-ui
|
|
409
|
+
|
|
410
|
+
Generates a CVA-based UI component (shadcn/ui style) with variants and barrel export.
|
|
411
|
+
|
|
412
|
+
**Prompts:**
|
|
413
|
+
|
|
414
|
+
| Prompt | Example | Description |
|
|
415
|
+
|--------|---------|-------------|
|
|
416
|
+
| Component name | `StatusBadge` | PascalCase component name |
|
|
417
|
+
|
|
418
|
+
**Generated files:**
|
|
419
|
+
|
|
420
|
+
```
|
|
421
|
+
src/components/ui/status-badge/StatusBadge.tsx
|
|
422
|
+
src/components/ui/status-badge/index.ts
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
**Generated component:**
|
|
426
|
+
|
|
427
|
+
```typescript
|
|
428
|
+
import * as React from 'react';
|
|
429
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
430
|
+
import { cn } from '@utils';
|
|
431
|
+
|
|
432
|
+
export const statusBadgeVariants = cva(
|
|
433
|
+
'inline-flex items-center justify-center',
|
|
434
|
+
{
|
|
435
|
+
variants: {
|
|
436
|
+
variant: {
|
|
437
|
+
default: '',
|
|
438
|
+
},
|
|
439
|
+
size: {
|
|
440
|
+
sm: '',
|
|
441
|
+
md: '',
|
|
442
|
+
lg: '',
|
|
443
|
+
},
|
|
444
|
+
},
|
|
445
|
+
defaultVariants: {
|
|
446
|
+
variant: 'default',
|
|
447
|
+
size: 'md',
|
|
448
|
+
},
|
|
449
|
+
},
|
|
450
|
+
);
|
|
451
|
+
|
|
452
|
+
export type StatusBadgeVariants = VariantProps<typeof statusBadgeVariants>;
|
|
453
|
+
|
|
454
|
+
type StatusBadgeProps = React.ComponentPropsWithoutRef<'div'> & StatusBadgeVariants;
|
|
455
|
+
|
|
456
|
+
export default function StatusBadge({ className, variant, size, children, ...props }: StatusBadgeProps) {
|
|
457
|
+
return (
|
|
458
|
+
<div
|
|
459
|
+
data-slot="status-badge"
|
|
460
|
+
className={cn(statusBadgeVariants({ variant, size, className }))}
|
|
461
|
+
{...props}
|
|
462
|
+
>
|
|
463
|
+
{children}
|
|
464
|
+
</div>
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
---
|
|
470
|
+
|
|
471
|
+
### component-shared
|
|
472
|
+
|
|
473
|
+
Generates a compound shared component with configurable sub-components.
|
|
474
|
+
|
|
475
|
+
**Prompts:**
|
|
476
|
+
|
|
477
|
+
| Prompt | Example | Description |
|
|
478
|
+
|--------|---------|-------------|
|
|
479
|
+
| Component name | `InfoCard` | PascalCase component name |
|
|
480
|
+
| Sub-components | `Header, Body, Footer` | Comma-separated sub-component names |
|
|
481
|
+
|
|
482
|
+
**Generated files:**
|
|
483
|
+
|
|
484
|
+
```
|
|
485
|
+
src/components/shared/info-card/InfoCard.tsx
|
|
486
|
+
src/components/shared/info-card/index.ts
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
**Generated component:**
|
|
490
|
+
|
|
491
|
+
```typescript
|
|
492
|
+
import { type FC, type ReactNode } from 'react';
|
|
493
|
+
import { cn } from '@utils';
|
|
494
|
+
|
|
495
|
+
type HeaderProps = {
|
|
496
|
+
children: ReactNode;
|
|
497
|
+
className?: string;
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
type BodyProps = {
|
|
501
|
+
children: ReactNode;
|
|
502
|
+
className?: string;
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
type InfoCardProps = {
|
|
506
|
+
children: ReactNode;
|
|
507
|
+
className?: string;
|
|
508
|
+
};
|
|
509
|
+
|
|
510
|
+
type InfoCardComponent = FC<InfoCardProps> & {
|
|
511
|
+
Header: FC<HeaderProps>;
|
|
512
|
+
Body: FC<BodyProps>;
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
const Header: FC<HeaderProps> = ({ children, className }) => (
|
|
516
|
+
<div className={cn('', className)}>{children}</div>
|
|
517
|
+
);
|
|
518
|
+
|
|
519
|
+
const Body: FC<BodyProps> = ({ children, className }) => (
|
|
520
|
+
<div className={cn('', className)}>{children}</div>
|
|
521
|
+
);
|
|
522
|
+
|
|
523
|
+
const InfoCard: InfoCardComponent = ({ children, className }) => (
|
|
524
|
+
<div className={cn('rounded-lg border bg-card', className)}>{children}</div>
|
|
525
|
+
);
|
|
526
|
+
|
|
527
|
+
InfoCard.Header = Header;
|
|
528
|
+
InfoCard.Body = Body;
|
|
529
|
+
|
|
530
|
+
export default InfoCard;
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
**Usage:**
|
|
534
|
+
|
|
535
|
+
```tsx
|
|
536
|
+
<InfoCard>
|
|
537
|
+
<InfoCard.Header>Title</InfoCard.Header>
|
|
538
|
+
<InfoCard.Body>Content</InfoCard.Body>
|
|
539
|
+
</InfoCard>
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
---
|
|
543
|
+
|
|
544
|
+
### component-form
|
|
545
|
+
|
|
546
|
+
Generates a React Hook Form `useController`-based form field component.
|
|
547
|
+
|
|
548
|
+
**Prompts:**
|
|
549
|
+
|
|
550
|
+
| Prompt | Example | Description |
|
|
551
|
+
|--------|---------|-------------|
|
|
552
|
+
| Component name | `PhoneInput` | PascalCase component name |
|
|
553
|
+
|
|
554
|
+
**Generated files:**
|
|
555
|
+
|
|
556
|
+
```
|
|
557
|
+
src/components/forms/form-phone-input/FormPhoneInput.tsx
|
|
558
|
+
src/components/forms/form-phone-input/index.ts
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
---
|
|
562
|
+
|
|
563
|
+
### page
|
|
564
|
+
|
|
565
|
+
Generates a route-level page component. Optionally auto-registers the route in your router.
|
|
566
|
+
|
|
567
|
+
**Prompts:**
|
|
568
|
+
|
|
569
|
+
| Prompt | Example | Description |
|
|
570
|
+
|--------|---------|-------------|
|
|
571
|
+
| Page name | `Dashboard` | PascalCase page name |
|
|
572
|
+
| Category | `admin` or `Create new category` | Folder grouping |
|
|
573
|
+
| Register route? | `Yes` | (Only when `routeRegistration` enabled) |
|
|
574
|
+
| Layout | `DashboardLayout` | (Only when registering route) |
|
|
575
|
+
| Is protected? | `Yes` | (Only when registering route) |
|
|
576
|
+
| Route path | `/admin/dashboard` | (Only when registering route) |
|
|
577
|
+
|
|
578
|
+
**Generated file:**
|
|
579
|
+
|
|
580
|
+
```
|
|
581
|
+
src/pages/admin/DashboardPage.tsx
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
**Generated component:**
|
|
585
|
+
|
|
586
|
+
```typescript
|
|
587
|
+
export default function DashboardPage() {
|
|
588
|
+
return (
|
|
589
|
+
<div>
|
|
590
|
+
<h1>Dashboard</h1>
|
|
591
|
+
</div>
|
|
592
|
+
);
|
|
593
|
+
}
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
The page suffix (`Page`) is configurable via `naming.pageSuffix`.
|
|
597
|
+
|
|
598
|
+
---
|
|
599
|
+
|
|
600
|
+
### view
|
|
601
|
+
|
|
602
|
+
Generates a feature view component with barrel exports.
|
|
603
|
+
|
|
604
|
+
**Prompts:**
|
|
605
|
+
|
|
606
|
+
| Prompt | Example | Description |
|
|
607
|
+
|--------|---------|-------------|
|
|
608
|
+
| View name | `ProductCard` | PascalCase view name |
|
|
609
|
+
| Category | `products` or `Create new category` | Feature folder grouping |
|
|
610
|
+
|
|
611
|
+
**Generated files:**
|
|
612
|
+
|
|
613
|
+
```
|
|
614
|
+
src/views/products/product-card/ProductCard.tsx
|
|
615
|
+
src/views/products/product-card/index.ts
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
---
|
|
619
|
+
|
|
620
|
+
### shared-hook
|
|
621
|
+
|
|
622
|
+
Generates a custom utility hook.
|
|
623
|
+
|
|
624
|
+
**Prompts:**
|
|
625
|
+
|
|
626
|
+
| Prompt | Example | Description |
|
|
627
|
+
|--------|---------|-------------|
|
|
628
|
+
| Hook name | `windowSize` | camelCase name (generates `useWindowSize`) |
|
|
629
|
+
| React imports | `useState, useEffect` | Selected from checkbox |
|
|
630
|
+
|
|
631
|
+
**Generated file:**
|
|
632
|
+
|
|
633
|
+
```
|
|
634
|
+
src/lib/hooks/shared/useWindowSize.ts
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
**Generated hook:**
|
|
638
|
+
|
|
639
|
+
```typescript
|
|
640
|
+
import { useState, useEffect } from 'react';
|
|
641
|
+
|
|
642
|
+
export const useWindowSize = () => {
|
|
643
|
+
// TODO: Implement hook logic
|
|
644
|
+
|
|
645
|
+
return {
|
|
646
|
+
// TODO: Return hook values
|
|
647
|
+
};
|
|
648
|
+
};
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
---
|
|
652
|
+
|
|
653
|
+
### validation
|
|
654
|
+
|
|
655
|
+
Generates a Zod validation schema with optional i18n support.
|
|
656
|
+
|
|
657
|
+
**Prompts:**
|
|
658
|
+
|
|
659
|
+
| Prompt | Example | Description |
|
|
660
|
+
|--------|---------|-------------|
|
|
661
|
+
| Schema name | `product` | camelCase name |
|
|
662
|
+
|
|
663
|
+
**Generated file:**
|
|
664
|
+
|
|
665
|
+
```
|
|
666
|
+
src/validations/product.schema.ts
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
**Generated schema (with i18n enabled):**
|
|
670
|
+
|
|
671
|
+
```typescript
|
|
672
|
+
import { z } from 'zod';
|
|
673
|
+
import type { TFunction } from 'i18next';
|
|
674
|
+
|
|
675
|
+
export const productSchema = (t: TFunction) =>
|
|
676
|
+
z.object({
|
|
677
|
+
// TODO: Add validation fields
|
|
678
|
+
// Example:
|
|
679
|
+
// name: z.string().min(1, t('validation.product.name.required')),
|
|
680
|
+
});
|
|
681
|
+
|
|
682
|
+
export type ProductFormData = z.infer<ReturnType<typeof productSchema>>;
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
**Generated schema (without i18n):**
|
|
686
|
+
|
|
687
|
+
```typescript
|
|
688
|
+
import { z } from 'zod';
|
|
689
|
+
|
|
690
|
+
export const productSchema = z.object({
|
|
691
|
+
// TODO: Add validation fields
|
|
692
|
+
// Example:
|
|
693
|
+
// name: z.string().min(1, 'Name is required'),
|
|
694
|
+
});
|
|
695
|
+
|
|
696
|
+
export type ProductFormData = z.infer<typeof productSchema>;
|
|
697
|
+
```
|
|
698
|
+
|
|
699
|
+
The validation file suffix (`.schema.ts`) is configurable via `naming.validationSuffix`.
|
|
700
|
+
|
|
701
|
+
---
|
|
702
|
+
|
|
703
|
+
### feature
|
|
704
|
+
|
|
705
|
+
The composite generator. Scaffolds an entire feature in one command — selecting which artifacts to generate.
|
|
706
|
+
|
|
707
|
+
**Prompts:**
|
|
708
|
+
|
|
709
|
+
| Prompt | Example | Description |
|
|
710
|
+
|--------|---------|-------------|
|
|
711
|
+
| Feature name | `products` | Plural entity name |
|
|
712
|
+
| Singular name | `product` | For mutation naming |
|
|
713
|
+
| Endpoint key | `PRODUCTS` | ApiEndpoints constant |
|
|
714
|
+
| Artifacts | (checkbox) | Select what to generate |
|
|
715
|
+
| Is paginated? | `No` | (When query list selected) |
|
|
716
|
+
|
|
717
|
+
**Available artifacts:**
|
|
718
|
+
|
|
719
|
+
- API Handler
|
|
720
|
+
- DTO Types
|
|
721
|
+
- Query Hook (list)
|
|
722
|
+
- Query Hook (details)
|
|
723
|
+
- Mutation Hook (create)
|
|
724
|
+
- Mutation Hook (update)
|
|
725
|
+
- Mutation Hook (delete)
|
|
726
|
+
- View Component
|
|
727
|
+
- Page Component
|
|
728
|
+
- Validation Schema
|
|
729
|
+
|
|
730
|
+
**Example:** Running `rq-codegen feature` with `products`, all artifacts selected:
|
|
731
|
+
|
|
732
|
+
```
|
|
733
|
+
CREATED src/types/api/ProductsDto.ts
|
|
734
|
+
UPDATED src/types/api/index.ts
|
|
735
|
+
CREATED src/api/handlers/products.ts
|
|
736
|
+
UPDATED src/api/handlers/index.ts
|
|
737
|
+
CREATED src/lib/hooks/queries/useProductsListQuery.ts
|
|
738
|
+
UPDATED src/lib/hooks/queries/index.ts
|
|
739
|
+
CREATED src/lib/hooks/queries/useProductsDetailsQuery.ts
|
|
740
|
+
UPDATED src/lib/hooks/queries/index.ts
|
|
741
|
+
CREATED src/lib/hooks/mutations/useCreateProductMutation.ts
|
|
742
|
+
UPDATED src/lib/hooks/mutations/index.ts
|
|
743
|
+
CREATED src/lib/hooks/mutations/useUpdateProductMutation.ts
|
|
744
|
+
UPDATED src/lib/hooks/mutations/index.ts
|
|
745
|
+
CREATED src/lib/hooks/mutations/useDeleteProductMutation.ts
|
|
746
|
+
UPDATED src/lib/hooks/mutations/index.ts
|
|
747
|
+
CREATED src/views/products/products-list/ProductsList.tsx
|
|
748
|
+
CREATED src/views/products/products-list/index.ts
|
|
749
|
+
UPDATED src/views/products/index.ts
|
|
750
|
+
UPDATED src/views/index.ts
|
|
751
|
+
CREATED src/pages/products/ProductsPage.tsx
|
|
752
|
+
CREATED src/validations/products.schema.ts
|
|
753
|
+
UPDATED src/validations/index.ts
|
|
754
|
+
|
|
755
|
+
Done! 11 file(s) created, 10 barrel(s) updated.
|
|
756
|
+
```
|
|
757
|
+
|
|
758
|
+
---
|
|
759
|
+
|
|
760
|
+
## Configuration Reference
|
|
761
|
+
|
|
762
|
+
Configuration is loaded from `rqgen.config.ts` (or `.js`, `.mjs`, `.mts`) in your project root, or from a `"rqgen"` field in `package.json`.
|
|
763
|
+
|
|
764
|
+
### Full Config Example
|
|
765
|
+
|
|
766
|
+
```typescript
|
|
767
|
+
// rqgen.config.ts
|
|
768
|
+
import { defineConfig } from '@appswave/rq-codegen';
|
|
769
|
+
|
|
770
|
+
export default defineConfig({
|
|
771
|
+
srcDir: './src',
|
|
772
|
+
|
|
773
|
+
aliases: {
|
|
774
|
+
api: '@api',
|
|
775
|
+
components: '@components',
|
|
776
|
+
hooks: '@hooks',
|
|
777
|
+
types: '@app-types',
|
|
778
|
+
utils: '@utils',
|
|
779
|
+
contexts: '@contexts',
|
|
780
|
+
constants: '@constants',
|
|
781
|
+
views: '@views',
|
|
782
|
+
pages: '@pages',
|
|
783
|
+
validations: '@validations',
|
|
784
|
+
assets: '@assets',
|
|
785
|
+
routes: '@routes',
|
|
786
|
+
hoc: '@hoc',
|
|
787
|
+
appConfig: '@app-config',
|
|
788
|
+
},
|
|
789
|
+
|
|
790
|
+
features: {
|
|
791
|
+
i18n: true,
|
|
792
|
+
toast: true,
|
|
793
|
+
barrel: true,
|
|
794
|
+
routeRegistration: true,
|
|
795
|
+
},
|
|
796
|
+
|
|
797
|
+
naming: {
|
|
798
|
+
dtoSuffixes: {
|
|
799
|
+
read: 'ForReadDto',
|
|
800
|
+
create: 'ForCreateDto',
|
|
801
|
+
update: 'ForUpdateDto',
|
|
802
|
+
list: 'ListDto',
|
|
803
|
+
listResponse: 'ListResponseDto',
|
|
804
|
+
params: 'ParamsDto',
|
|
805
|
+
},
|
|
806
|
+
validationSuffix: '.schema.ts',
|
|
807
|
+
pageSuffix: 'Page',
|
|
808
|
+
hookPrefix: 'use',
|
|
809
|
+
},
|
|
810
|
+
|
|
811
|
+
paths: {
|
|
812
|
+
handlers: 'api/handlers',
|
|
813
|
+
apiConfig: 'api/config',
|
|
814
|
+
types: 'types/api',
|
|
815
|
+
queries: 'lib/hooks/queries',
|
|
816
|
+
mutations: 'lib/hooks/mutations',
|
|
817
|
+
sharedHooks: 'lib/hooks/shared',
|
|
818
|
+
hookUtils: 'lib/hooks/utils',
|
|
819
|
+
uiComponents: 'components/ui',
|
|
820
|
+
sharedComponents: 'components/shared',
|
|
821
|
+
formComponents: 'components/forms',
|
|
822
|
+
pages: 'pages',
|
|
823
|
+
views: 'views',
|
|
824
|
+
validations: 'validations',
|
|
825
|
+
},
|
|
826
|
+
|
|
827
|
+
router: {
|
|
828
|
+
routerFile: 'routes/router.tsx',
|
|
829
|
+
routesFile: 'routes/routes.ts',
|
|
830
|
+
layouts: ['MainLayout', 'DashboardLayout'],
|
|
831
|
+
},
|
|
832
|
+
|
|
833
|
+
hooks: {
|
|
834
|
+
toast: { import: 'useToast', from: '@hooks/shared' },
|
|
835
|
+
translation: { import: 'useAppTranslation', from: '@hooks/shared' },
|
|
836
|
+
paginatedQuery: { import: 'usePaginatedDataTableQuery', from: '@hooks/utils' },
|
|
837
|
+
},
|
|
838
|
+
|
|
839
|
+
templatesDir: './my-templates',
|
|
840
|
+
});
|
|
841
|
+
```
|
|
842
|
+
|
|
843
|
+
### srcDir
|
|
844
|
+
|
|
845
|
+
**Type:** `string`
|
|
846
|
+
**Default:** `'./src'`
|
|
847
|
+
|
|
848
|
+
Root source directory. All `paths` are relative to this directory.
|
|
849
|
+
|
|
850
|
+
```typescript
|
|
851
|
+
srcDir: './src',
|
|
852
|
+
```
|
|
853
|
+
|
|
854
|
+
### aliases
|
|
855
|
+
|
|
856
|
+
**Type:** `AliasConfig`
|
|
857
|
+
|
|
858
|
+
Path aliases used in import statements of generated files. These should match your `tsconfig.json` `paths` configuration.
|
|
859
|
+
|
|
860
|
+
```typescript
|
|
861
|
+
aliases: {
|
|
862
|
+
api: '@api', // Used in: import { HttpClient } from '@api/config'
|
|
863
|
+
components: '@components', // Used in: import { Button } from '@components/ui'
|
|
864
|
+
hooks: '@hooks', // Used in: import { useToast } from '@hooks/shared'
|
|
865
|
+
types: '@app-types', // Used in: import type { UserDto } from '@app-types'
|
|
866
|
+
utils: '@utils', // Used in: import { cn } from '@utils'
|
|
867
|
+
contexts: '@contexts',
|
|
868
|
+
constants: '@constants',
|
|
869
|
+
views: '@views',
|
|
870
|
+
pages: '@pages',
|
|
871
|
+
validations: '@validations',
|
|
872
|
+
assets: '@assets',
|
|
873
|
+
routes: '@routes',
|
|
874
|
+
hoc: '@hoc',
|
|
875
|
+
appConfig: '@app-config',
|
|
876
|
+
},
|
|
877
|
+
```
|
|
878
|
+
|
|
879
|
+
**Tip:** `rq-codegen init` auto-detects aliases from your `tsconfig.json` or `tsconfig.app.json`.
|
|
880
|
+
|
|
881
|
+
### features
|
|
882
|
+
|
|
883
|
+
**Type:** `FeatureToggles`
|
|
884
|
+
|
|
885
|
+
Toggle features on/off to control what gets generated. See [Feature Toggles](#feature-toggles) for details.
|
|
886
|
+
|
|
887
|
+
```typescript
|
|
888
|
+
features: {
|
|
889
|
+
i18n: true, // Include i18n imports in mutations and validations
|
|
890
|
+
toast: true, // Include toast notifications in mutations
|
|
891
|
+
barrel: true, // Auto-update barrel (index.ts) exports
|
|
892
|
+
routeRegistration: true, // Enable route auto-registration for pages
|
|
893
|
+
},
|
|
894
|
+
```
|
|
895
|
+
|
|
896
|
+
### naming
|
|
897
|
+
|
|
898
|
+
**Type:** `NamingConfig`
|
|
899
|
+
|
|
900
|
+
Customize naming conventions for generated files and types.
|
|
901
|
+
|
|
902
|
+
```typescript
|
|
903
|
+
naming: {
|
|
904
|
+
dtoSuffixes: {
|
|
905
|
+
read: 'ForReadDto', // e.g., ProductsForReadDto
|
|
906
|
+
create: 'ForCreateDto', // e.g., ProductsForCreateDto
|
|
907
|
+
update: 'ForUpdateDto', // e.g., ProductsForUpdateDto
|
|
908
|
+
list: 'ListDto', // e.g., ProductsListDto
|
|
909
|
+
listResponse: 'ListResponseDto', // e.g., ProductsListResponseDto
|
|
910
|
+
params: 'ParamsDto', // e.g., ProductsParamsDto
|
|
911
|
+
},
|
|
912
|
+
validationSuffix: '.schema.ts', // File suffix: product.schema.ts
|
|
913
|
+
pageSuffix: 'Page', // Component suffix: DashboardPage
|
|
914
|
+
hookPrefix: 'use', // Hook prefix: useProducts
|
|
915
|
+
},
|
|
916
|
+
```
|
|
917
|
+
|
|
918
|
+
**Custom DTO suffixes example:**
|
|
919
|
+
|
|
920
|
+
```typescript
|
|
921
|
+
naming: {
|
|
922
|
+
dtoSuffixes: {
|
|
923
|
+
read: 'Dto', // ProductsDto instead of ProductsForReadDto
|
|
924
|
+
create: 'CreateDto', // ProductsCreateDto instead of ProductsForCreateDto
|
|
925
|
+
},
|
|
926
|
+
},
|
|
927
|
+
```
|
|
928
|
+
|
|
929
|
+
### paths
|
|
930
|
+
|
|
931
|
+
**Type:** `PathsConfig`
|
|
932
|
+
|
|
933
|
+
Relative paths (from `srcDir`) where generated files are placed.
|
|
934
|
+
|
|
935
|
+
```typescript
|
|
936
|
+
paths: {
|
|
937
|
+
handlers: 'api/handlers', // API handler files
|
|
938
|
+
apiConfig: 'api/config', // ApiEndpoints, HttpClient
|
|
939
|
+
types: 'types/api', // DTO type definitions
|
|
940
|
+
queries: 'lib/hooks/queries', // React Query hooks
|
|
941
|
+
mutations: 'lib/hooks/mutations', // Mutation hooks
|
|
942
|
+
sharedHooks: 'lib/hooks/shared', // Shared utility hooks
|
|
943
|
+
hookUtils: 'lib/hooks/utils', // Hook utilities (pagination, etc.)
|
|
944
|
+
uiComponents: 'components/ui', // UI primitives (shadcn/ui style)
|
|
945
|
+
sharedComponents: 'components/shared', // Compound shared components
|
|
946
|
+
formComponents: 'components/forms', // Form field components
|
|
947
|
+
pages: 'pages', // Route-level pages
|
|
948
|
+
views: 'views', // Feature view components
|
|
949
|
+
validations: 'validations', // Zod validation schemas
|
|
950
|
+
},
|
|
951
|
+
```
|
|
952
|
+
|
|
953
|
+
### router
|
|
954
|
+
|
|
955
|
+
**Type:** `RouterConfig`
|
|
956
|
+
|
|
957
|
+
Configuration for route auto-registration (used by the `page` generator when `features.routeRegistration` is enabled).
|
|
958
|
+
|
|
959
|
+
```typescript
|
|
960
|
+
router: {
|
|
961
|
+
routerFile: 'routes/router.tsx', // File containing React Router config
|
|
962
|
+
routesFile: 'routes/routes.ts', // File containing route constants
|
|
963
|
+
layouts: ['MainLayout', 'DashboardLayout'], // Available layout options
|
|
964
|
+
},
|
|
965
|
+
```
|
|
966
|
+
|
|
967
|
+
### hooks
|
|
968
|
+
|
|
969
|
+
**Type:** `HooksConfig`
|
|
970
|
+
|
|
971
|
+
Configure import paths for hooks used in generated templates. This allows the generated code to import the exact hooks your project provides.
|
|
972
|
+
|
|
973
|
+
```typescript
|
|
974
|
+
hooks: {
|
|
975
|
+
toast: {
|
|
976
|
+
import: 'useToast', // Hook function name
|
|
977
|
+
from: '@hooks/shared', // Import path
|
|
978
|
+
},
|
|
979
|
+
translation: {
|
|
980
|
+
import: 'useAppTranslation', // Hook function name
|
|
981
|
+
from: '@hooks/shared', // Import path
|
|
982
|
+
},
|
|
983
|
+
paginatedQuery: {
|
|
984
|
+
import: 'usePaginatedDataTableQuery', // Hook function name
|
|
985
|
+
from: '@hooks/utils', // Import path
|
|
986
|
+
},
|
|
987
|
+
},
|
|
988
|
+
```
|
|
989
|
+
|
|
990
|
+
### templatesDir
|
|
991
|
+
|
|
992
|
+
**Type:** `string | undefined`
|
|
993
|
+
**Default:** `undefined` (uses bundled templates)
|
|
994
|
+
|
|
995
|
+
Path to a local directory containing template overrides. Any `.hbs` file found in this directory takes precedence over the bundled template with the same relative path.
|
|
996
|
+
|
|
997
|
+
```typescript
|
|
998
|
+
templatesDir: './my-templates',
|
|
999
|
+
```
|
|
1000
|
+
|
|
1001
|
+
See [Template Overrides](#template-overrides) for details.
|
|
1002
|
+
|
|
1003
|
+
---
|
|
1004
|
+
|
|
1005
|
+
## Feature Toggles
|
|
1006
|
+
|
|
1007
|
+
### `i18n`
|
|
1008
|
+
|
|
1009
|
+
When **enabled**, generated code includes:
|
|
1010
|
+
- `import type { TFunction } from 'i18next'` in validation schemas
|
|
1011
|
+
- Validation schemas accept a `t` function parameter for translated messages
|
|
1012
|
+
- `import { useAppTranslation } from '@hooks/shared'` in mutation hooks
|
|
1013
|
+
- Translated toast messages using `t('common.success')`
|
|
1014
|
+
|
|
1015
|
+
When **disabled**, all i18n-related imports and logic are omitted.
|
|
1016
|
+
|
|
1017
|
+
### `toast`
|
|
1018
|
+
|
|
1019
|
+
When **enabled**, generated mutation hooks include:
|
|
1020
|
+
- `import { useToast } from '@hooks/shared'`
|
|
1021
|
+
- `onSuccess` toast notification
|
|
1022
|
+
- `onError` toast notification with error message extraction
|
|
1023
|
+
|
|
1024
|
+
When **disabled**, mutation hooks omit all toast-related code.
|
|
1025
|
+
|
|
1026
|
+
### `barrel`
|
|
1027
|
+
|
|
1028
|
+
When **enabled**, every generator that creates a file also adds an `export * from './...'` line to the nearest `index.ts` barrel file. If the barrel file doesn't exist, it's created.
|
|
1029
|
+
|
|
1030
|
+
When **disabled**, barrel exports are skipped — you manage imports manually.
|
|
1031
|
+
|
|
1032
|
+
### `routeRegistration`
|
|
1033
|
+
|
|
1034
|
+
When **enabled**, the `page` generator shows additional prompts:
|
|
1035
|
+
- Which layout to use
|
|
1036
|
+
- Whether the route is protected
|
|
1037
|
+
- The route URL path
|
|
1038
|
+
|
|
1039
|
+
And generates a `route-register` action that adds the lazy import and route entry to your router files.
|
|
1040
|
+
|
|
1041
|
+
When **disabled**, the `page` generator only creates the page component file.
|
|
1042
|
+
|
|
1043
|
+
---
|
|
1044
|
+
|
|
1045
|
+
## Template Overrides
|
|
1046
|
+
|
|
1047
|
+
Every generated file comes from a Handlebars template (`.hbs`). You can override any template by creating a local copy.
|
|
1048
|
+
|
|
1049
|
+
### Steps
|
|
1050
|
+
|
|
1051
|
+
1. Set `templatesDir` in your config:
|
|
1052
|
+
|
|
1053
|
+
```typescript
|
|
1054
|
+
export default defineConfig({
|
|
1055
|
+
templatesDir: './templates',
|
|
1056
|
+
});
|
|
1057
|
+
```
|
|
1058
|
+
|
|
1059
|
+
2. Create the template file with the same relative path as the bundled template:
|
|
1060
|
+
|
|
1061
|
+
```
|
|
1062
|
+
your-project/
|
|
1063
|
+
├── templates/
|
|
1064
|
+
│ └── handler/
|
|
1065
|
+
│ └── handler.ts.hbs # Overrides the default handler template
|
|
1066
|
+
└── rqgen.config.ts
|
|
1067
|
+
```
|
|
1068
|
+
|
|
1069
|
+
3. The local template is used instead of the bundled one. All Handlebars helpers (`configAlias`, `dtoSuffix`, `ifFeature`, `pascalCase`, etc.) are available.
|
|
1070
|
+
|
|
1071
|
+
### Available Templates
|
|
1072
|
+
|
|
1073
|
+
| Path | Description |
|
|
1074
|
+
|------|-------------|
|
|
1075
|
+
| `component-ui/Component.tsx.hbs` | CVA UI component |
|
|
1076
|
+
| `component-ui/index.ts.hbs` | UI component barrel |
|
|
1077
|
+
| `component-shared/Component.tsx.hbs` | Compound shared component |
|
|
1078
|
+
| `component-shared/index.ts.hbs` | Shared component barrel |
|
|
1079
|
+
| `component-form/FormComponent.tsx.hbs` | Form field component |
|
|
1080
|
+
| `component-form/index.ts.hbs` | Form component barrel |
|
|
1081
|
+
| `page/Page.tsx.hbs` | Page component |
|
|
1082
|
+
| `view/View.tsx.hbs` | View component |
|
|
1083
|
+
| `view/index.ts.hbs` | View barrel |
|
|
1084
|
+
| `handler/handler.ts.hbs` | API handler |
|
|
1085
|
+
| `query-hook/hook.ts.hbs` | Standard query hook |
|
|
1086
|
+
| `query-hook/hook-details.ts.hbs` | Details query hook |
|
|
1087
|
+
| `query-hook/hook-paginated.ts.hbs` | Paginated query hook |
|
|
1088
|
+
| `mutation-hook/hook.ts.hbs` | Mutation hook |
|
|
1089
|
+
| `types-dto/dto.ts.hbs` | DTO type definitions |
|
|
1090
|
+
| `shared-hook/hook.ts.hbs` | Shared utility hook |
|
|
1091
|
+
| `validation/validation.ts.hbs` | Zod validation schema |
|
|
1092
|
+
|
|
1093
|
+
### Available Handlebars Helpers
|
|
1094
|
+
|
|
1095
|
+
| Helper | Usage | Description |
|
|
1096
|
+
|--------|-------|-------------|
|
|
1097
|
+
| `pascalCase` | `{{pascalCase name}}` | Converts to PascalCase |
|
|
1098
|
+
| `camelCase` | `{{camelCase name}}` | Converts to camelCase |
|
|
1099
|
+
| `kebabCase` | `{{kebabCase name}}` | Converts to kebab-case |
|
|
1100
|
+
| `constantCase` | `{{constantCase name}}` | Converts to CONSTANT_CASE |
|
|
1101
|
+
| `configAlias` | `{{configAlias "api"}}` | Returns alias from config (e.g., `@api`) |
|
|
1102
|
+
| `configPath` | `{{configPath "handlers"}}` | Returns path from config |
|
|
1103
|
+
| `dtoSuffix` | `{{dtoSuffix "read"}}` | Returns DTO suffix (e.g., `ForReadDto`) |
|
|
1104
|
+
| `ifFeature` | `{{#ifFeature "toast"}}...{{/ifFeature}}` | Conditional block based on feature toggle |
|
|
1105
|
+
| `plural` | `{{plural name}}` | Basic pluralization |
|
|
1106
|
+
| `eq` | `{{#if (eq a b)}}` | Equality check |
|
|
1107
|
+
| `neq` | `{{#if (neq a b)}}` | Inequality check |
|
|
1108
|
+
| `includes` | `{{#if (includes arr val)}}` | Array includes check |
|
|
1109
|
+
| `join` | `{{join arr ", "}}` | Join array with separator |
|
|
1110
|
+
|
|
1111
|
+
---
|
|
1112
|
+
|
|
1113
|
+
## Path Alias Detection
|
|
1114
|
+
|
|
1115
|
+
When you run `rq-codegen init`, aliases are auto-detected from your TypeScript config:
|
|
1116
|
+
|
|
1117
|
+
1. Reads `tsconfig.json` in the current directory
|
|
1118
|
+
2. If it has `"extends"`, follows to `tsconfig.app.json` (or whatever it extends)
|
|
1119
|
+
3. Parses the `compilerOptions.paths` field
|
|
1120
|
+
4. Maps known alias patterns to config keys:
|
|
1121
|
+
|
|
1122
|
+
| tsconfig paths | Config key | Default value |
|
|
1123
|
+
|---------------|------------|---------------|
|
|
1124
|
+
| `@api/*` | `aliases.api` | `@api` |
|
|
1125
|
+
| `@components/*` | `aliases.components` | `@components` |
|
|
1126
|
+
| `@hooks/*` | `aliases.hooks` | `@hooks` |
|
|
1127
|
+
| `@app-types` or `@types/*` | `aliases.types` | `@app-types` |
|
|
1128
|
+
| `@utils` | `aliases.utils` | `@utils` |
|
|
1129
|
+
| `@contexts` | `aliases.contexts` | `@contexts` |
|
|
1130
|
+
| `@constants` | `aliases.constants` | `@constants` |
|
|
1131
|
+
| `@views/*` | `aliases.views` | `@views` |
|
|
1132
|
+
| `@pages/*` | `aliases.pages` | `@pages` |
|
|
1133
|
+
| `@validations/*` | `aliases.validations` | `@validations` |
|
|
1134
|
+
| `@assets/*` | `aliases.assets` | `@assets` |
|
|
1135
|
+
| `@routes` | `aliases.routes` | `@routes` |
|
|
1136
|
+
| `@hoc` | `aliases.hoc` | `@hoc` |
|
|
1137
|
+
| `@app-config` | `aliases.appConfig` | `@app-config` |
|
|
1138
|
+
|
|
1139
|
+
---
|
|
1140
|
+
|
|
1141
|
+
## Recommended Project Structure
|
|
1142
|
+
|
|
1143
|
+
`rq-codegen` works best with this structure (all paths are configurable):
|
|
1144
|
+
|
|
1145
|
+
```
|
|
1146
|
+
src/
|
|
1147
|
+
├── api/
|
|
1148
|
+
│ ├── config/ # ApiEndpoints.ts, HttpClient.ts, etc.
|
|
1149
|
+
│ └── handlers/ # Generated API handlers + index.ts barrel
|
|
1150
|
+
├── components/
|
|
1151
|
+
│ ├── ui/ # Generated UI components + index.ts barrel
|
|
1152
|
+
│ ├── shared/ # Generated shared components + index.ts barrel
|
|
1153
|
+
│ └── forms/ # Generated form components + index.ts barrel
|
|
1154
|
+
├── lib/
|
|
1155
|
+
│ └── hooks/
|
|
1156
|
+
│ ├── queries/ # Generated query hooks + index.ts barrel
|
|
1157
|
+
│ ├── mutations/ # Generated mutation hooks + index.ts barrel
|
|
1158
|
+
│ ├── shared/ # Generated shared hooks + index.ts barrel
|
|
1159
|
+
│ └── utils/ # Paginated query hook, etc.
|
|
1160
|
+
├── pages/ # Generated pages (grouped by category)
|
|
1161
|
+
├── views/ # Generated views (grouped by feature)
|
|
1162
|
+
├── types/
|
|
1163
|
+
│ └── api/ # Generated DTO types + index.ts barrel
|
|
1164
|
+
├── validations/ # Generated Zod schemas + index.ts barrel
|
|
1165
|
+
└── routes/ # Router config (for auto-registration)
|
|
1166
|
+
```
|
|
1167
|
+
|
|
1168
|
+
---
|
|
1169
|
+
|
|
1170
|
+
## defineConfig()
|
|
1171
|
+
|
|
1172
|
+
The `defineConfig()` helper provides type-safe configuration with IntelliSense:
|
|
1173
|
+
|
|
1174
|
+
```typescript
|
|
1175
|
+
// rqgen.config.ts
|
|
1176
|
+
import { defineConfig } from '@appswave/rq-codegen';
|
|
1177
|
+
|
|
1178
|
+
export default defineConfig({
|
|
1179
|
+
// Full IntelliSense for all config options
|
|
1180
|
+
features: {
|
|
1181
|
+
i18n: true,
|
|
1182
|
+
},
|
|
1183
|
+
});
|
|
1184
|
+
```
|
|
1185
|
+
|
|
1186
|
+
You only need to specify the fields you want to override — everything else uses sensible defaults.
|
|
1187
|
+
|
|
1188
|
+
### Exported Types
|
|
1189
|
+
|
|
1190
|
+
```typescript
|
|
1191
|
+
import type {
|
|
1192
|
+
RqCodegenConfig,
|
|
1193
|
+
AliasConfig,
|
|
1194
|
+
FeatureToggles,
|
|
1195
|
+
NamingConfig,
|
|
1196
|
+
PathsConfig,
|
|
1197
|
+
RouterConfig,
|
|
1198
|
+
HooksConfig,
|
|
1199
|
+
HookImportConfig,
|
|
1200
|
+
DtoSuffixes,
|
|
1201
|
+
} from '@appswave/rq-codegen';
|
|
1202
|
+
```
|
|
1203
|
+
|
|
1204
|
+
---
|
|
1205
|
+
|
|
1206
|
+
## Contributing
|
|
1207
|
+
|
|
1208
|
+
### Setup
|
|
1209
|
+
|
|
1210
|
+
```bash
|
|
1211
|
+
git clone <repo-url>
|
|
1212
|
+
cd rq-codegen
|
|
1213
|
+
npm install
|
|
1214
|
+
```
|
|
1215
|
+
|
|
1216
|
+
### Development
|
|
1217
|
+
|
|
1218
|
+
```bash
|
|
1219
|
+
# Build
|
|
1220
|
+
npm run build
|
|
1221
|
+
|
|
1222
|
+
# Watch mode
|
|
1223
|
+
npm run dev
|
|
1224
|
+
|
|
1225
|
+
# Type check
|
|
1226
|
+
npm run typecheck
|
|
1227
|
+
|
|
1228
|
+
# Run tests
|
|
1229
|
+
npm test
|
|
1230
|
+
|
|
1231
|
+
# Watch tests
|
|
1232
|
+
npm run test:watch
|
|
1233
|
+
```
|
|
1234
|
+
|
|
1235
|
+
### Local Testing
|
|
1236
|
+
|
|
1237
|
+
```bash
|
|
1238
|
+
# Link globally
|
|
1239
|
+
npm link
|
|
1240
|
+
|
|
1241
|
+
# Use in any project
|
|
1242
|
+
cd /path/to/your/project
|
|
1243
|
+
rq-codegen init
|
|
1244
|
+
rq-codegen handler
|
|
1245
|
+
```
|
|
1246
|
+
|
|
1247
|
+
### Project Structure
|
|
1248
|
+
|
|
1249
|
+
```
|
|
1250
|
+
rq-codegen/
|
|
1251
|
+
├── bin/cli.ts # CLI entry point
|
|
1252
|
+
├── src/
|
|
1253
|
+
│ ├── index.ts # Public API (defineConfig + types)
|
|
1254
|
+
│ ├── cli.ts # Commander setup
|
|
1255
|
+
│ ├── commands/
|
|
1256
|
+
│ │ ├── generate.ts # rq-codegen [generator]
|
|
1257
|
+
│ │ └── init.ts # rq-codegen init
|
|
1258
|
+
│ ├── config/
|
|
1259
|
+
│ │ ├── types.ts # RqCodegenConfig type
|
|
1260
|
+
│ │ ├── schema.ts # Zod validation
|
|
1261
|
+
│ │ ├── defaults.ts # Default values
|
|
1262
|
+
│ │ └── loader.ts # Config discovery + merge
|
|
1263
|
+
│ ├── core/
|
|
1264
|
+
│ │ ├── engine.ts # Handlebars engine + action executor
|
|
1265
|
+
│ │ ├── helpers.ts # 13 Handlebars helpers
|
|
1266
|
+
│ │ ├── actions.ts # barrel-append + route-register
|
|
1267
|
+
│ │ └── template-resolver.ts # Local override fallback
|
|
1268
|
+
│ ├── generators/ # 12 generators
|
|
1269
|
+
│ └── utils/ # String, validation, filesystem utilities
|
|
1270
|
+
├── templates/ # 17 bundled Handlebars templates
|
|
1271
|
+
├── tsup.config.ts # Build config (ESM)
|
|
1272
|
+
└── vitest.config.ts # Test config
|
|
1273
|
+
```
|
|
1274
|
+
|
|
1275
|
+
---
|
|
1276
|
+
|
|
1277
|
+
## License
|
|
1278
|
+
|
|
1279
|
+
MIT
|