{"_id":"@appswave/rq-codegen","_rev":"3-6d33d6ded5603481f9457b11f30e83ec","name":"@appswave/rq-codegen","dist-tags":{"latest":"0.1.2"},"versions":{"0.1.0":{"name":"@appswave/rq-codegen","version":"0.1.0","keywords":["react","typescript","code-generator","cli","react-query","plop","scaffolding","handler","dto"],"author":{"name":"Appswave"},"license":"MIT","_id":"@appswave/rq-codegen@0.1.0","maintainers":[{"name":"msafia","email":"msafia@appswave.io"},{"name":"xaleel","email":"xaleelchess@gmail.com"},{"name":"osama-kanash","email":"okanash@appswave.io"}],"bin":{"rq-codegen":"dist/bin/cli.js"},"dist":{"shasum":"145a6b9f6d2a7b5eaeefca15472dc86ddf5fcad5","tarball":"https://registry.npmjs.org/@appswave/rq-codegen/-/rq-codegen-0.1.0.tgz","fileCount":24,"integrity":"sha512-8+Y11uH/hiqkfkOTmc9pAtE3qLQif9nTlUtCDPHUDFutEjGelJuq8ax6xgVo8w+fPO1vy7WJNw4v+nHi4ZvB7A==","signatures":[{"sig":"MEUCIQCSw+VNmQg5BJvAVdoAO5glC7lvMMpOcZk4iZPXxwaMrgIgDdeVRrffLaeDVpS4E08E+ceXs2t33PUtjMVGzoMaJ5k=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":215808},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"npm run build"},"_npmUser":{"name":"msafia","email":"msafia@appswave.io"},"_npmVersion":"10.5.0","description":"Config-driven code generator for React + TypeScript projects with React Query, handlers, DTOs, and more","directories":{},"_nodeVersion":"20.12.2","dependencies":{"ora":"^8.1.1","zod":"^3.23.8","chalk":"^5.3.0","inquirer":"^9.3.7","commander":"^12.1.0","handlebars":"^4.7.8","cosmiconfig":"^9.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.5","vitest":"^4.0.18","typescript":"^5.5.4","@types/node":"^20.17.0","@types/inquirer":"^9.0.7"},"_npmOperationalInternal":{"tmp":"tmp/rq-codegen_0.1.0_1770547519821_0.6221817966212497","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@appswave/rq-codegen","version":"0.1.1","keywords":["react","typescript","code-generator","cli","react-query","plop","scaffolding","handler","dto"],"author":{"name":"Appswave"},"license":"MIT","_id":"@appswave/rq-codegen@0.1.1","maintainers":[{"name":"msafia","email":"msafia@appswave.io"},{"name":"xaleel","email":"xaleelchess@gmail.com"},{"name":"osama-kanash","email":"okanash@appswave.io"}],"bin":{"rq-codegen":"dist/bin/cli.js"},"dist":{"shasum":"5f35bc32c4115f798feb22b669f2347c3155b027","tarball":"https://registry.npmjs.org/@appswave/rq-codegen/-/rq-codegen-0.1.1.tgz","fileCount":24,"integrity":"sha512-s2XG8xTzyER5uairMTck86FMU7NOlVRGP0YLq/HjqlIe5Z7w4O/SwlCa6IjgEcjL2GNdBz7sGs99hLDyXvk+Vg==","signatures":[{"sig":"MEUCIHg9ffrF3mos6kPX0Hl4VABYvj/62WtXxzsZsYs/rBTqAiEA2pCuP5S1oNncHsbtpr9pO5Tjs/p5yVp4/g112PJBmtk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":216228},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"c57073b4ca7b3e1dca04b8df2dff312f88237c61","scripts":{"dev":"tsup --watch","test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"npm run build"},"_npmUser":{"name":"msafia","email":"msafia@appswave.io"},"_npmVersion":"10.5.0","description":"Config-driven code generator for React + TypeScript projects with React Query, handlers, DTOs, and more","directories":{},"_nodeVersion":"20.12.2","dependencies":{"ora":"^8.1.1","zod":"^3.23.8","jiti":"^2.6.1","chalk":"^5.3.0","inquirer":"^9.3.7","commander":"^12.1.0","handlebars":"^4.7.8"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.5","vitest":"^4.0.18","typescript":"^5.5.4","@types/node":"^20.17.0","@types/inquirer":"^9.0.7"},"_npmOperationalInternal":{"tmp":"tmp/rq-codegen_0.1.1_1770551687703_0.8267397633828117","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@appswave/rq-codegen","version":"0.1.2","description":"Config-driven code generator for React + TypeScript projects with React Query, handlers, DTOs, and more","type":"module","bin":{"rq-codegen":"dist/bin/cli.js"},"main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"import":"./dist/index.js","types":"./dist/index.d.ts"}},"engines":{"node":">=18.0.0"},"scripts":{"build":"tsup","dev":"tsup --watch","test":"vitest run","test:watch":"vitest","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"keywords":["react","typescript","code-generator","cli","react-query","plop","scaffolding","handler","dto"],"license":"MIT","author":{"name":"Appswave"},"publishConfig":{"access":"public"},"dependencies":{"chalk":"^5.3.0","commander":"^12.1.0","handlebars":"^4.7.8","inquirer":"^9.3.7","jiti":"^2.6.1","ora":"^8.1.1","zod":"^3.23.8"},"devDependencies":{"@types/inquirer":"^9.0.7","@types/node":"^20.17.0","tsup":"^8.3.5","typescript":"^5.5.4","vitest":"^4.0.18"},"_id":"@appswave/rq-codegen@0.1.2","gitHead":"7c1652cdac6cae7a316aee08bd791b6086f843dd","_nodeVersion":"20.12.2","_npmVersion":"10.5.0","dist":{"integrity":"sha512-cmRTyykWKh7TykRxx/YjoBg0lLaO5G2kd1LyylhVn/YrpfasIXtqUuina6Y2k0eZSh1R0ZkBtMEq+VGoDsjAKA==","shasum":"47b02ec06cf31804529a685b6d0b87aebd0ad2ce","tarball":"https://registry.npmjs.org/@appswave/rq-codegen/-/rq-codegen-0.1.2.tgz","fileCount":24,"unpackedSize":232442,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCFaLn+v/Y08yoy6e9HLieyTTa1UiN0Jj0iBkqEJThp6AIhALwQMgLhQAB08xBRMlU2LhHrJXZF4lx3oPeVJeOgamDi"}]},"_npmUser":{"name":"msafia","email":"msafia@appswave.io"},"directories":{},"maintainers":[{"name":"msafia","email":"msafia@appswave.io"},{"name":"xaleel","email":"xaleelchess@gmail.com"},{"name":"osama-kanash","email":"okanash@appswave.io"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/rq-codegen_0.1.2_1770885360103_0.18429774386429387"},"_hasShrinkwrap":false}},"time":{"created":"2026-02-08T10:45:19.728Z","modified":"2026-02-12T08:36:00.467Z","0.1.0":"2026-02-08T10:45:19.983Z","0.1.1":"2026-02-08T11:54:47.848Z","0.1.2":"2026-02-12T08:36:00.269Z"},"author":{"name":"Appswave"},"license":"MIT","keywords":["react","typescript","code-generator","cli","react-query","plop","scaffolding","handler","dto"],"description":"Config-driven code generator for React + TypeScript projects with React Query, handlers, DTOs, and more","maintainers":[{"name":"msafia","email":"msafia@appswave.io"},{"name":"xaleel","email":"xaleelchess@gmail.com"},{"name":"osama-kanash","email":"okanash@appswave.io"}],"readme":"# @appswave/rq-codegen\n\nConfig-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.\n\n## Table of Contents\n\n- [When to Use](#when-to-use)\n- [Quick Start](#quick-start)\n- [CLI Commands](#cli-commands)\n- [Generators](#generators)\n  - [handler](#handler)\n  - [types-dto](#types-dto)\n  - [query-hook](#query-hook)\n  - [mutation-hook](#mutation-hook)\n  - [component-ui](#component-ui)\n  - [component-shared](#component-shared)\n  - [component-form](#component-form)\n  - [page](#page)\n  - [view](#view)\n  - [shared-hook](#shared-hook)\n  - [validation](#validation)\n  - [feature](#feature)\n- [Configuration Reference](#configuration-reference)\n  - [srcDir](#srcdir)\n  - [aliases](#aliases)\n  - [features](#features)\n  - [naming](#naming)\n  - [paths](#paths)\n  - [router](#router)\n  - [hooks](#hooks)\n  - [templatesDir](#templatesdir)\n- [Feature Toggles](#feature-toggles)\n- [Template Overrides](#template-overrides)\n- [Path Alias Detection](#path-alias-detection)\n- [Recommended Project Structure](#recommended-project-structure)\n- [defineConfig()](#defineconfig)\n- [Contributing](#contributing)\n- [License](#license)\n\n---\n\n## When to Use\n\nUse `rq-codegen` every time you need to:\n\n- **Add a new API endpoint** — generates the handler, DTO types, query hook, and mutation hook in one command\n- **Create a new page or view** — scaffolds the component with correct folder structure and barrel exports\n- **Build a full feature** — generates everything at once: handler + types + hooks + view + page + validation\n- **Add a new UI component** — creates a CVA-based component with variants (shadcn/ui style)\n- **Add a shared component** — creates a compound component with sub-components (Header, Body, Footer)\n- **Add a form component** — creates a React Hook Form `useController`-based field component\n- **Add a validation schema** — scaffolds a Zod schema with optional i18n support\n- **Add a custom hook** — creates a shared utility hook with selected React imports\n\nEvery generated file respects your project's path aliases, naming conventions, and feature toggles — no manual find-and-replace needed.\n\n---\n\n## Quick Start\n\n### 1. Install\n\n```bash\nnpm install -g @appswave/rq-codegen\n```\n\nOr as a dev dependency:\n\n```bash\nnpm install -D @appswave/rq-codegen\n```\n\n### 2. Initialize Config\n\n```bash\nrq-codegen init\n```\n\nThis creates `rqgen.config.ts` in your project root with auto-detected settings:\n- Reads your `tsconfig.json` / `tsconfig.app.json` to detect path aliases\n- Detects if you have `src/`, `routes/`, `locales/` directories\n- Asks about i18n, toast, and route registration preferences\n\n### 3. Generate Code\n\n```bash\n# Interactive menu — pick from 12 generators\nrq-codegen\n\n# Or run a specific generator directly\nrq-codegen handler\nrq-codegen feature\nrq-codegen page\n```\n\n---\n\n## CLI Commands\n\n| Command | Description |\n|---------|-------------|\n| `rq-codegen` | Interactive menu — select a generator from the list |\n| `rq-codegen <generator>` | Run a specific generator directly (e.g., `rq-codegen handler`) |\n| `rq-codegen init` | Create `rqgen.config.ts` with auto-detected settings |\n| `rq-codegen init --force` | Overwrite existing config file |\n| `rq-codegen --version` | Show version |\n| `rq-codegen --help` | Show help |\n\n### Interactive Menu\n\nWhen you run `rq-codegen` without arguments, you get an interactive menu:\n\n```\n? What would you like to generate?\n  component-ui       — CVA-based UI component (shadcn/ui style)\n  component-shared   — Compound shared component\n  component-form     — React Hook Form component (useController-based)\n  page               — Route-level page component\n  view               — Feature view component\n  handler            — API handler (+ types + hooks)\n  query-hook         — React Query hook\n  mutation-hook      — React Query mutation hook\n  types-dto          — DTO type definitions\n  shared-hook        — Custom utility hook\n  validation         — Zod validation schema\n  feature            — Full feature scaffold (handler + types + hooks + view + page)\n```\n\n---\n\n## Generators\n\n### handler\n\nThe most powerful single generator. Creates an API handler with typed request functions, and optionally chains DTO types, query hooks, and mutation hooks.\n\n**Prompts:**\n\n| Prompt | Example | Description |\n|--------|---------|-------------|\n| Entity name | `products` | Plural name for the handler (used for file names, handler object) |\n| Singular name | `product` | Used for mutation hook names (e.g., `useCreateProductMutation`) |\n| Endpoint key | `PRODUCTS` | ApiEndpoints constant key (e.g., `ApiEndpoints.PRODUCTS`) |\n| Operations | `list, details, create, update, delete` | Which CRUD operations to generate |\n| Also generate DTO types? | `Yes` | Chains the `types-dto` generator |\n| Also generate query hooks? | `Yes` | Chains the `query-hook` generator |\n| Is list paginated? | `No` | Uses paginated query hook variant |\n| Also generate mutation hooks? | `Yes` | Chains the `mutation-hook` generator |\n\n**Example:** `rq-codegen handler` with entity `products`, all operations, all chains enabled:\n\n```\n  CREATED  src/api/handlers/products.ts\n  UPDATED  src/api/handlers/index.ts\n  CREATED  src/types/api/ProductsDto.ts\n  UPDATED  src/types/api/index.ts\n  CREATED  src/lib/hooks/queries/useProductsListQuery.ts\n  UPDATED  src/lib/hooks/queries/index.ts\n  CREATED  src/lib/hooks/queries/useProductsDetailsQuery.ts\n  UPDATED  src/lib/hooks/queries/index.ts\n  CREATED  src/lib/hooks/mutations/useCreateProductMutation.ts\n  UPDATED  src/lib/hooks/mutations/index.ts\n  CREATED  src/lib/hooks/mutations/useUpdateProductMutation.ts\n  UPDATED  src/lib/hooks/mutations/index.ts\n  CREATED  src/lib/hooks/mutations/useDeleteProductMutation.ts\n  UPDATED  src/lib/hooks/mutations/index.ts\n\n  Done! 7 file(s) created, 6 barrel(s) updated.\n```\n\n**Generated handler (`products.ts`):**\n\n```typescript\nimport { ApiEndpoints, HttpClient } from '@api/config';\n\nimport type {\n  ProductsForReadDto,\n  ProductsListResponseDto,\n  ProductsForCreateDto,\n  ProductsForUpdateDto,\n} from '@app-types';\n\nconst URL = ApiEndpoints.PRODUCTS;\n\nfunction getProductsList(queryString?: string): Promise<ProductsListResponseDto> {\n  const url = queryString ? `${URL.INDEX}?${queryString}` : URL.INDEX;\n  return HttpClient.get<ProductsListResponseDto>(url);\n}\n\nfunction getProductsDetails(id: string): Promise<ProductsForReadDto> {\n  return HttpClient.get<ProductsForReadDto>(URL.DETAILS.replace(':id', id));\n}\n\nfunction createProducts(payload: ProductsForCreateDto): Promise<ProductsForReadDto> {\n  return HttpClient.post<ProductsForReadDto>(URL.INDEX, payload);\n}\n\nfunction updateProducts(id: string, payload: ProductsForUpdateDto): Promise<ProductsForReadDto> {\n  return HttpClient.put<ProductsForReadDto>(URL.DETAILS.replace(':id', id), payload);\n}\n\nfunction removeProducts(id: string): Promise<void> {\n  return HttpClient.delete<void>(URL.DETAILS.replace(':id', id));\n}\n\nexport const ProductsHandler = {\n  list: {\n    queryKey: 'products/list',\n    request: getProductsList,\n  },\n  details: {\n    queryKey: 'products/details',\n    request: getProductsDetails,\n  },\n  create: {\n    mutationKey: 'products/create',\n    mutationFn: createProducts,\n  },\n  update: {\n    mutationKey: 'products/update',\n    mutationFn: updateProducts,\n  },\n  remove: {\n    mutationKey: 'products/remove',\n    mutationFn: removeProducts,\n  },\n} as const;\n```\n\n---\n\n### types-dto\n\nGenerates DTO type definitions for an API entity.\n\n**Prompts:**\n\n| Prompt | Example | Description |\n|--------|---------|-------------|\n| Entity name | `products` | Name used for type prefixes |\n| Include create DTO? | `Yes` | Adds `ForCreateDto` type |\n| Include update DTO? | `Yes` | Adds `ForUpdateDto` type |\n\n**Generated types (`ProductsDto.ts`):**\n\n```typescript\nexport type ProductsForReadDto = {\n  id: number;\n  // TODO: Add read fields\n};\n\nexport type ProductsForCreateDto = {\n  // TODO: Add create fields\n};\n\nexport type ProductsForUpdateDto = {\n  id: number;\n  // TODO: Add update fields\n};\n\nexport type ProductsListDto = {\n  id: number;\n  // TODO: Add minimal list fields\n};\n\nexport type ProductsListResponseDto = {\n  items: ProductsListDto[];\n  page: number;\n  pageSize: number;\n  totalCount: number;\n  lastPage: number;\n};\n\nexport type ProductsParamsDto = {\n  page?: number;\n  pageSize?: number;\n  search?: string;\n  sort?: string;\n  filter?: string;\n};\n```\n\nThe DTO suffix names (`ForReadDto`, `ForCreateDto`, etc.) are fully configurable via `naming.dtoSuffixes` in your config.\n\n---\n\n### query-hook\n\nGenerates a React Query hook that wraps a handler.\n\n**Prompts:**\n\n| Prompt | Example | Description |\n|--------|---------|-------------|\n| Hook name | `productsList` | Used in `useProductsListQuery` |\n| Handler name | `products` | References the handler (e.g., `ProductsHandler`) |\n| Handler key | `list` | Handler method key (e.g., `ProductsHandler.list`) |\n| Is paginated? | `No` | Uses paginated hook variant |\n\n**Generated query hook (standard):**\n\n```typescript\nimport { ProductsHandler } from '@api/handlers';\nimport { useQuery } from '@tanstack/react-query';\n\nexport const useProductsListQuery = (enabled = true) => {\n  return useQuery({\n    queryKey: [ProductsHandler.list.queryKey],\n    queryFn: () => ProductsHandler.list.request(),\n    enabled,\n    staleTime: 5 * 60 * 1000,\n    gcTime: 10 * 60 * 1000,\n  });\n};\n```\n\n**Generated query hook (details variant):**\n\n```typescript\nimport { ProductsHandler } from '@api/handlers';\nimport { useQuery } from '@tanstack/react-query';\n\nexport const useProductsDetailsQuery = (id: string | undefined, enabled = true) => {\n  return useQuery({\n    queryKey: [ProductsHandler.details.queryKey, id],\n    queryFn: () => ProductsHandler.details.request(id!),\n    enabled: enabled && !!id,\n    staleTime: 5 * 60 * 1000,\n    gcTime: 10 * 60 * 1000,\n  });\n};\n```\n\n**Generated query hook (paginated variant):**\n\n```typescript\nimport { ProductsHandler } from '@api/handlers';\nimport { usePaginatedDataTableQuery } from '@hooks/utils';\n\nimport type { ProductsListDto } from '@app-types';\n\nexport const useProductsPaginatedQuery = () => {\n  return usePaginatedDataTableQuery<ProductsListDto>({\n    queryKey: [ProductsHandler.list.queryKey],\n    queryFn: (params: string) => ProductsHandler.list.request(params),\n    defaultPageSize: 10,\n  });\n};\n```\n\n---\n\n### mutation-hook\n\nGenerates a React Query mutation hook with automatic query invalidation, toast notifications, and i18n support.\n\n**Prompts:**\n\n| Prompt | Example | Description |\n|--------|---------|-------------|\n| Mutation name | `CreateProduct` | Used in `useCreateProductMutation` |\n| Handler name | `products` | References the handler |\n| Handler key | `create` | Handler method key |\n| Invalidate key | `list` | Query key to invalidate on success |\n\n**Generated mutation hook (with i18n + toast enabled):**\n\n```typescript\nimport { ProductsHandler } from '@api/handlers';\nimport { useToast } from '@hooks/shared';\nimport { useAppTranslation } from '@hooks/shared';\nimport { useMutation, useQueryClient } from '@tanstack/react-query';\n\nexport const useCreateProductMutation = () => {\n  const queryClient = useQueryClient();\n  const { toast } = useToast();\n  const { t } = useAppTranslation();\n\n  return useMutation({\n    mutationKey: [ProductsHandler.create.mutationKey],\n    mutationFn: ProductsHandler.create.mutationFn,\n    onSuccess: () => {\n      queryClient.invalidateQueries({\n        queryKey: [ProductsHandler.list.queryKey],\n      });\n      toast({\n        variant: 'success',\n        title: t('common.success'),\n      });\n    },\n    onError: (error) => {\n      const errorMessage =\n        error?.response?.data?.title || error?.response?.data?.message || t('errors.unexpectedError');\n      toast({\n        variant: 'destructive',\n        title: errorMessage,\n        description: error?.response?.data?.detail || '',\n      });\n    },\n  });\n};\n```\n\nWhen `features.toast` or `features.i18n` is disabled, the corresponding import and usage lines are omitted automatically.\n\n---\n\n### component-ui\n\nGenerates a CVA-based UI component (shadcn/ui style) with variants and barrel export.\n\n**Prompts:**\n\n| Prompt | Example | Description |\n|--------|---------|-------------|\n| Component name | `StatusBadge` | PascalCase component name |\n\n**Generated files:**\n\n```\nsrc/components/ui/status-badge/StatusBadge.tsx\nsrc/components/ui/status-badge/index.ts\n```\n\n**Generated component:**\n\n```typescript\nimport * as React from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '@utils';\n\nexport const statusBadgeVariants = cva(\n  'inline-flex items-center justify-center',\n  {\n    variants: {\n      variant: {\n        default: '',\n      },\n      size: {\n        sm: '',\n        md: '',\n        lg: '',\n      },\n    },\n    defaultVariants: {\n      variant: 'default',\n      size: 'md',\n    },\n  },\n);\n\nexport type StatusBadgeVariants = VariantProps<typeof statusBadgeVariants>;\n\ntype StatusBadgeProps = React.ComponentPropsWithoutRef<'div'> & StatusBadgeVariants;\n\nexport default function StatusBadge({ className, variant, size, children, ...props }: StatusBadgeProps) {\n  return (\n    <div\n      data-slot=\"status-badge\"\n      className={cn(statusBadgeVariants({ variant, size, className }))}\n      {...props}\n    >\n      {children}\n    </div>\n  );\n}\n```\n\n---\n\n### component-shared\n\nGenerates a compound shared component with configurable sub-components.\n\n**Prompts:**\n\n| Prompt | Example | Description |\n|--------|---------|-------------|\n| Component name | `InfoCard` | PascalCase component name |\n| Sub-components | `Header, Body, Footer` | Comma-separated sub-component names |\n\n**Generated files:**\n\n```\nsrc/components/shared/info-card/InfoCard.tsx\nsrc/components/shared/info-card/index.ts\n```\n\n**Generated component:**\n\n```typescript\nimport { type FC, type ReactNode } from 'react';\nimport { cn } from '@utils';\n\ntype HeaderProps = {\n  children: ReactNode;\n  className?: string;\n};\n\ntype BodyProps = {\n  children: ReactNode;\n  className?: string;\n};\n\ntype InfoCardProps = {\n  children: ReactNode;\n  className?: string;\n};\n\ntype InfoCardComponent = FC<InfoCardProps> & {\n  Header: FC<HeaderProps>;\n  Body: FC<BodyProps>;\n};\n\nconst Header: FC<HeaderProps> = ({ children, className }) => (\n  <div className={cn('', className)}>{children}</div>\n);\n\nconst Body: FC<BodyProps> = ({ children, className }) => (\n  <div className={cn('', className)}>{children}</div>\n);\n\nconst InfoCard: InfoCardComponent = ({ children, className }) => (\n  <div className={cn('rounded-lg border bg-card', className)}>{children}</div>\n);\n\nInfoCard.Header = Header;\nInfoCard.Body = Body;\n\nexport default InfoCard;\n```\n\n**Usage:**\n\n```tsx\n<InfoCard>\n  <InfoCard.Header>Title</InfoCard.Header>\n  <InfoCard.Body>Content</InfoCard.Body>\n</InfoCard>\n```\n\n---\n\n### component-form\n\nGenerates a React Hook Form `useController`-based form field component.\n\n**Prompts:**\n\n| Prompt | Example | Description |\n|--------|---------|-------------|\n| Component name | `PhoneInput` | PascalCase component name |\n\n**Generated files:**\n\n```\nsrc/components/forms/form-phone-input/FormPhoneInput.tsx\nsrc/components/forms/form-phone-input/index.ts\n```\n\n---\n\n### page\n\nGenerates a route-level page component. Optionally auto-registers the route in your router.\n\n**Prompts:**\n\n| Prompt | Example | Description |\n|--------|---------|-------------|\n| Page name | `Dashboard` | PascalCase page name |\n| Category | `admin` or `Create new category` | Folder grouping |\n| Register route? | `Yes` | (Only when `routeRegistration` enabled) |\n| Layout | `DashboardLayout` | (Only when registering route) |\n| Is protected? | `Yes` | (Only when registering route) |\n| Route path | `/admin/dashboard` | (Only when registering route) |\n\n**Generated file:**\n\n```\nsrc/pages/admin/DashboardPage.tsx\n```\n\n**Generated component:**\n\n```typescript\nexport default function DashboardPage() {\n  return (\n    <div>\n      <h1>Dashboard</h1>\n    </div>\n  );\n}\n```\n\nThe page suffix (`Page`) is configurable via `naming.pageSuffix`.\n\n---\n\n### view\n\nGenerates a feature view component with barrel exports.\n\n**Prompts:**\n\n| Prompt | Example | Description |\n|--------|---------|-------------|\n| View name | `ProductCard` | PascalCase view name |\n| Category | `products` or `Create new category` | Feature folder grouping |\n\n**Generated files:**\n\n```\nsrc/views/products/product-card/ProductCard.tsx\nsrc/views/products/product-card/index.ts\n```\n\n---\n\n### shared-hook\n\nGenerates a custom utility hook.\n\n**Prompts:**\n\n| Prompt | Example | Description |\n|--------|---------|-------------|\n| Hook name | `windowSize` | camelCase name (generates `useWindowSize`) |\n| React imports | `useState, useEffect` | Selected from checkbox |\n\n**Generated file:**\n\n```\nsrc/lib/hooks/shared/useWindowSize.ts\n```\n\n**Generated hook:**\n\n```typescript\nimport { useState, useEffect } from 'react';\n\nexport const useWindowSize = () => {\n  // TODO: Implement hook logic\n\n  return {\n    // TODO: Return hook values\n  };\n};\n```\n\n---\n\n### validation\n\nGenerates a Zod validation schema with optional i18n support.\n\n**Prompts:**\n\n| Prompt | Example | Description |\n|--------|---------|-------------|\n| Schema name | `product` | camelCase name |\n\n**Generated file:**\n\n```\nsrc/validations/product.schema.ts\n```\n\n**Generated schema (with i18n enabled):**\n\n```typescript\nimport { z } from 'zod';\nimport type { TFunction } from 'i18next';\n\nexport const productSchema = (t: TFunction) =>\n  z.object({\n    // TODO: Add validation fields\n    // Example:\n    // name: z.string().min(1, t('validation.product.name.required')),\n  });\n\nexport type ProductFormData = z.infer<ReturnType<typeof productSchema>>;\n```\n\n**Generated schema (without i18n):**\n\n```typescript\nimport { z } from 'zod';\n\nexport const productSchema = z.object({\n  // TODO: Add validation fields\n  // Example:\n  // name: z.string().min(1, 'Name is required'),\n});\n\nexport type ProductFormData = z.infer<typeof productSchema>;\n```\n\nThe validation file suffix (`.schema.ts`) is configurable via `naming.validationSuffix`.\n\n---\n\n### feature\n\nThe composite generator. Scaffolds an entire feature in one command — selecting which artifacts to generate.\n\n**Prompts:**\n\n| Prompt | Example | Description |\n|--------|---------|-------------|\n| Feature name | `products` | Plural entity name |\n| Singular name | `product` | For mutation naming |\n| Endpoint key | `PRODUCTS` | ApiEndpoints constant |\n| Artifacts | (checkbox) | Select what to generate |\n| Is paginated? | `No` | (When query list selected) |\n\n**Available artifacts:**\n\n- API Handler\n- DTO Types\n- Query Hook (list)\n- Query Hook (details)\n- Mutation Hook (create)\n- Mutation Hook (update)\n- Mutation Hook (delete)\n- View Component\n- Page Component\n- Validation Schema\n\n**Example:** Running `rq-codegen feature` with `products`, all artifacts selected:\n\n```\n  CREATED  src/types/api/ProductsDto.ts\n  UPDATED  src/types/api/index.ts\n  CREATED  src/api/handlers/products.ts\n  UPDATED  src/api/handlers/index.ts\n  CREATED  src/lib/hooks/queries/useProductsListQuery.ts\n  UPDATED  src/lib/hooks/queries/index.ts\n  CREATED  src/lib/hooks/queries/useProductsDetailsQuery.ts\n  UPDATED  src/lib/hooks/queries/index.ts\n  CREATED  src/lib/hooks/mutations/useCreateProductMutation.ts\n  UPDATED  src/lib/hooks/mutations/index.ts\n  CREATED  src/lib/hooks/mutations/useUpdateProductMutation.ts\n  UPDATED  src/lib/hooks/mutations/index.ts\n  CREATED  src/lib/hooks/mutations/useDeleteProductMutation.ts\n  UPDATED  src/lib/hooks/mutations/index.ts\n  CREATED  src/views/products/products-list/ProductsList.tsx\n  CREATED  src/views/products/products-list/index.ts\n  UPDATED  src/views/products/index.ts\n  UPDATED  src/views/index.ts\n  CREATED  src/pages/products/ProductsPage.tsx\n  CREATED  src/validations/products.schema.ts\n  UPDATED  src/validations/index.ts\n\n  Done! 11 file(s) created, 10 barrel(s) updated.\n```\n\n---\n\n## Configuration Reference\n\nConfiguration is loaded from `rqgen.config.ts` (or `.js`, `.mjs`, `.mts`) in your project root, or from a `\"rqgen\"` field in `package.json`.\n\n### Full Config Example\n\n```typescript\n// rqgen.config.ts\nimport { defineConfig } from '@appswave/rq-codegen';\n\nexport default defineConfig({\n  srcDir: './src',\n\n  aliases: {\n    api: '@api',\n    components: '@components',\n    hooks: '@hooks',\n    types: '@app-types',\n    utils: '@utils',\n    contexts: '@contexts',\n    constants: '@constants',\n    views: '@views',\n    pages: '@pages',\n    validations: '@validations',\n    assets: '@assets',\n    routes: '@routes',\n    hoc: '@hoc',\n    appConfig: '@app-config',\n  },\n\n  features: {\n    i18n: true,\n    toast: true,\n    barrel: true,\n    routeRegistration: true,\n  },\n\n  naming: {\n    dtoSuffixes: {\n      read: 'ForReadDto',\n      create: 'ForCreateDto',\n      update: 'ForUpdateDto',\n      list: 'ListDto',\n      listResponse: 'ListResponseDto',\n      params: 'ParamsDto',\n    },\n    validationSuffix: '.schema.ts',\n    pageSuffix: 'Page',\n    hookPrefix: 'use',\n  },\n\n  paths: {\n    handlers: 'api/handlers',\n    apiConfig: 'api/config',\n    types: 'types/api',\n    queries: 'lib/hooks/queries',\n    mutations: 'lib/hooks/mutations',\n    sharedHooks: 'lib/hooks/shared',\n    hookUtils: 'lib/hooks/utils',\n    uiComponents: 'components/ui',\n    sharedComponents: 'components/shared',\n    formComponents: 'components/forms',\n    pages: 'pages',\n    views: 'views',\n    validations: 'validations',\n  },\n\n  router: {\n    routerFile: 'routes/router.tsx',\n    routesFile: 'routes/routes.ts',\n    layouts: ['MainLayout', 'DashboardLayout'],\n  },\n\n  hooks: {\n    toast: { import: 'useToast', from: '@hooks/shared' },\n    translation: { import: 'useAppTranslation', from: '@hooks/shared' },\n    paginatedQuery: { import: 'usePaginatedDataTableQuery', from: '@hooks/utils' },\n  },\n\n  templatesDir: './my-templates',\n});\n```\n\n### srcDir\n\n**Type:** `string`\n**Default:** `'./src'`\n\nRoot source directory. All `paths` are relative to this directory.\n\n```typescript\nsrcDir: './src',\n```\n\n### aliases\n\n**Type:** `AliasConfig`\n\nPath aliases used in import statements of generated files. These should match your `tsconfig.json` `paths` configuration.\n\n```typescript\naliases: {\n  api: '@api',           // Used in: import { HttpClient } from '@api/config'\n  components: '@components', // Used in: import { Button } from '@components/ui'\n  hooks: '@hooks',       // Used in: import { useToast } from '@hooks/shared'\n  types: '@app-types',   // Used in: import type { UserDto } from '@app-types'\n  utils: '@utils',       // Used in: import { cn } from '@utils'\n  contexts: '@contexts',\n  constants: '@constants',\n  views: '@views',\n  pages: '@pages',\n  validations: '@validations',\n  assets: '@assets',\n  routes: '@routes',\n  hoc: '@hoc',\n  appConfig: '@app-config',\n},\n```\n\n**Tip:** `rq-codegen init` auto-detects aliases from your `tsconfig.json` or `tsconfig.app.json`.\n\n### features\n\n**Type:** `FeatureToggles`\n\nToggle features on/off to control what gets generated. See [Feature Toggles](#feature-toggles) for details.\n\n```typescript\nfeatures: {\n  i18n: true,              // Include i18n imports in mutations and validations\n  toast: true,             // Include toast notifications in mutations\n  barrel: true,            // Auto-update barrel (index.ts) exports\n  routeRegistration: true, // Enable route auto-registration for pages\n},\n```\n\n### naming\n\n**Type:** `NamingConfig`\n\nCustomize naming conventions for generated files and types.\n\n```typescript\nnaming: {\n  dtoSuffixes: {\n    read: 'ForReadDto',            // e.g., ProductsForReadDto\n    create: 'ForCreateDto',        // e.g., ProductsForCreateDto\n    update: 'ForUpdateDto',        // e.g., ProductsForUpdateDto\n    list: 'ListDto',               // e.g., ProductsListDto\n    listResponse: 'ListResponseDto', // e.g., ProductsListResponseDto\n    params: 'ParamsDto',           // e.g., ProductsParamsDto\n  },\n  validationSuffix: '.schema.ts', // File suffix: product.schema.ts\n  pageSuffix: 'Page',             // Component suffix: DashboardPage\n  hookPrefix: 'use',              // Hook prefix: useProducts\n},\n```\n\n**Custom DTO suffixes example:**\n\n```typescript\nnaming: {\n  dtoSuffixes: {\n    read: 'Dto',        // ProductsDto instead of ProductsForReadDto\n    create: 'CreateDto', // ProductsCreateDto instead of ProductsForCreateDto\n  },\n},\n```\n\n### paths\n\n**Type:** `PathsConfig`\n\nRelative paths (from `srcDir`) where generated files are placed.\n\n```typescript\npaths: {\n  handlers: 'api/handlers',            // API handler files\n  apiConfig: 'api/config',             // ApiEndpoints, HttpClient\n  types: 'types/api',                  // DTO type definitions\n  queries: 'lib/hooks/queries',        // React Query hooks\n  mutations: 'lib/hooks/mutations',    // Mutation hooks\n  sharedHooks: 'lib/hooks/shared',     // Shared utility hooks\n  hookUtils: 'lib/hooks/utils',        // Hook utilities (pagination, etc.)\n  uiComponents: 'components/ui',       // UI primitives (shadcn/ui style)\n  sharedComponents: 'components/shared', // Compound shared components\n  formComponents: 'components/forms',   // Form field components\n  pages: 'pages',                       // Route-level pages\n  views: 'views',                       // Feature view components\n  validations: 'validations',           // Zod validation schemas\n},\n```\n\n### router\n\n**Type:** `RouterConfig`\n\nConfiguration for route auto-registration (used by the `page` generator when `features.routeRegistration` is enabled).\n\n```typescript\nrouter: {\n  routerFile: 'routes/router.tsx',           // File containing React Router config\n  routesFile: 'routes/routes.ts',            // File containing route constants\n  layouts: ['MainLayout', 'DashboardLayout'], // Available layout options\n},\n```\n\n### hooks\n\n**Type:** `HooksConfig`\n\nConfigure import paths for hooks used in generated templates. This allows the generated code to import the exact hooks your project provides.\n\n```typescript\nhooks: {\n  toast: {\n    import: 'useToast',           // Hook function name\n    from: '@hooks/shared',        // Import path\n  },\n  translation: {\n    import: 'useAppTranslation',  // Hook function name\n    from: '@hooks/shared',        // Import path\n  },\n  paginatedQuery: {\n    import: 'usePaginatedDataTableQuery', // Hook function name\n    from: '@hooks/utils',                  // Import path\n  },\n},\n```\n\n### templatesDir\n\n**Type:** `string | undefined`\n**Default:** `undefined` (uses bundled templates)\n\nPath 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.\n\n```typescript\ntemplatesDir: './my-templates',\n```\n\nSee [Template Overrides](#template-overrides) for details.\n\n---\n\n## Feature Toggles\n\n### `i18n`\n\nWhen **enabled**, generated code includes:\n- `import type { TFunction } from 'i18next'` in validation schemas\n- Validation schemas accept a `t` function parameter for translated messages\n- `import { useAppTranslation } from '@hooks/shared'` in mutation hooks\n- Translated toast messages using `t('common.success')`\n\nWhen **disabled**, all i18n-related imports and logic are omitted.\n\n### `toast`\n\nWhen **enabled**, generated mutation hooks include:\n- `import { useToast } from '@hooks/shared'`\n- `onSuccess` toast notification\n- `onError` toast notification with error message extraction\n\nWhen **disabled**, mutation hooks omit all toast-related code.\n\n### `barrel`\n\nWhen **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.\n\nWhen **disabled**, barrel exports are skipped — you manage imports manually.\n\n### `routeRegistration`\n\nWhen **enabled**, the `page` generator shows additional prompts:\n- Which layout to use\n- Whether the route is protected\n- The route URL path\n\nAnd generates a `route-register` action that adds the lazy import and route entry to your router files.\n\nWhen **disabled**, the `page` generator only creates the page component file.\n\n---\n\n## Template Overrides\n\nEvery generated file comes from a Handlebars template (`.hbs`). You can override any template by creating a local copy.\n\n### Steps\n\n1. Set `templatesDir` in your config:\n\n```typescript\nexport default defineConfig({\n  templatesDir: './templates',\n});\n```\n\n2. Create the template file with the same relative path as the bundled template:\n\n```\nyour-project/\n├── templates/\n│   └── handler/\n│       └── handler.ts.hbs    # Overrides the default handler template\n└── rqgen.config.ts\n```\n\n3. The local template is used instead of the bundled one. All Handlebars helpers (`configAlias`, `dtoSuffix`, `ifFeature`, `pascalCase`, etc.) are available.\n\n### Available Templates\n\n| Path | Description |\n|------|-------------|\n| `component-ui/Component.tsx.hbs` | CVA UI component |\n| `component-ui/index.ts.hbs` | UI component barrel |\n| `component-shared/Component.tsx.hbs` | Compound shared component |\n| `component-shared/index.ts.hbs` | Shared component barrel |\n| `component-form/FormComponent.tsx.hbs` | Form field component |\n| `component-form/index.ts.hbs` | Form component barrel |\n| `page/Page.tsx.hbs` | Page component |\n| `view/View.tsx.hbs` | View component |\n| `view/index.ts.hbs` | View barrel |\n| `handler/handler.ts.hbs` | API handler |\n| `query-hook/hook.ts.hbs` | Standard query hook |\n| `query-hook/hook-details.ts.hbs` | Details query hook |\n| `query-hook/hook-paginated.ts.hbs` | Paginated query hook |\n| `mutation-hook/hook.ts.hbs` | Mutation hook |\n| `types-dto/dto.ts.hbs` | DTO type definitions |\n| `shared-hook/hook.ts.hbs` | Shared utility hook |\n| `validation/validation.ts.hbs` | Zod validation schema |\n\n### Available Handlebars Helpers\n\n| Helper | Usage | Description |\n|--------|-------|-------------|\n| `pascalCase` | `{{pascalCase name}}` | Converts to PascalCase |\n| `camelCase` | `{{camelCase name}}` | Converts to camelCase |\n| `kebabCase` | `{{kebabCase name}}` | Converts to kebab-case |\n| `constantCase` | `{{constantCase name}}` | Converts to CONSTANT_CASE |\n| `configAlias` | `{{configAlias \"api\"}}` | Returns alias from config (e.g., `@api`) |\n| `configPath` | `{{configPath \"handlers\"}}` | Returns path from config |\n| `dtoSuffix` | `{{dtoSuffix \"read\"}}` | Returns DTO suffix (e.g., `ForReadDto`) |\n| `ifFeature` | `{{#ifFeature \"toast\"}}...{{/ifFeature}}` | Conditional block based on feature toggle |\n| `plural` | `{{plural name}}` | Basic pluralization |\n| `eq` | `{{#if (eq a b)}}` | Equality check |\n| `neq` | `{{#if (neq a b)}}` | Inequality check |\n| `includes` | `{{#if (includes arr val)}}` | Array includes check |\n| `join` | `{{join arr \", \"}}` | Join array with separator |\n\n---\n\n## Path Alias Detection\n\nWhen you run `rq-codegen init`, aliases are auto-detected from your TypeScript config:\n\n1. Reads `tsconfig.json` in the current directory\n2. If it has `\"extends\"`, follows to `tsconfig.app.json` (or whatever it extends)\n3. Parses the `compilerOptions.paths` field\n4. Maps known alias patterns to config keys:\n\n| tsconfig paths | Config key | Default value |\n|---------------|------------|---------------|\n| `@api/*` | `aliases.api` | `@api` |\n| `@components/*` | `aliases.components` | `@components` |\n| `@hooks/*` | `aliases.hooks` | `@hooks` |\n| `@app-types` or `@types/*` | `aliases.types` | `@app-types` |\n| `@utils` | `aliases.utils` | `@utils` |\n| `@contexts` | `aliases.contexts` | `@contexts` |\n| `@constants` | `aliases.constants` | `@constants` |\n| `@views/*` | `aliases.views` | `@views` |\n| `@pages/*` | `aliases.pages` | `@pages` |\n| `@validations/*` | `aliases.validations` | `@validations` |\n| `@assets/*` | `aliases.assets` | `@assets` |\n| `@routes` | `aliases.routes` | `@routes` |\n| `@hoc` | `aliases.hoc` | `@hoc` |\n| `@app-config` | `aliases.appConfig` | `@app-config` |\n\n---\n\n## Recommended Project Structure\n\n`rq-codegen` works best with this structure (all paths are configurable):\n\n```\nsrc/\n├── api/\n│   ├── config/              # ApiEndpoints.ts, HttpClient.ts, etc.\n│   └── handlers/            # Generated API handlers + index.ts barrel\n├── components/\n│   ├── ui/                  # Generated UI components + index.ts barrel\n│   ├── shared/              # Generated shared components + index.ts barrel\n│   └── forms/               # Generated form components + index.ts barrel\n├── lib/\n│   └── hooks/\n│       ├── queries/         # Generated query hooks + index.ts barrel\n│       ├── mutations/       # Generated mutation hooks + index.ts barrel\n│       ├── shared/          # Generated shared hooks + index.ts barrel\n│       └── utils/           # Paginated query hook, etc.\n├── pages/                   # Generated pages (grouped by category)\n├── views/                   # Generated views (grouped by feature)\n├── types/\n│   └── api/                 # Generated DTO types + index.ts barrel\n├── validations/             # Generated Zod schemas + index.ts barrel\n└── routes/                  # Router config (for auto-registration)\n```\n\n---\n\n## defineConfig()\n\nThe `defineConfig()` helper provides type-safe configuration with IntelliSense:\n\n```typescript\n// rqgen.config.ts\nimport { defineConfig } from '@appswave/rq-codegen';\n\nexport default defineConfig({\n  // Full IntelliSense for all config options\n  features: {\n    i18n: true,\n  },\n});\n```\n\nYou only need to specify the fields you want to override — everything else uses sensible defaults.\n\n### Exported Types\n\n```typescript\nimport type {\n  RqCodegenConfig,\n  AliasConfig,\n  FeatureToggles,\n  NamingConfig,\n  PathsConfig,\n  RouterConfig,\n  HooksConfig,\n  HookImportConfig,\n  DtoSuffixes,\n} from '@appswave/rq-codegen';\n```\n\n---\n\n## Contributing\n\n### Setup\n\n```bash\ngit clone <repo-url>\ncd rq-codegen\nnpm install\n```\n\n### Development\n\n```bash\n# Build\nnpm run build\n\n# Watch mode\nnpm run dev\n\n# Type check\nnpm run typecheck\n\n# Run tests\nnpm test\n\n# Watch tests\nnpm run test:watch\n```\n\n### Local Testing\n\n```bash\n# Link globally\nnpm link\n\n# Use in any project\ncd /path/to/your/project\nrq-codegen init\nrq-codegen handler\n```\n\n### Project Structure\n\n```\nrq-codegen/\n├── bin/cli.ts                     # CLI entry point\n├── src/\n│   ├── index.ts                   # Public API (defineConfig + types)\n│   ├── cli.ts                     # Commander setup\n│   ├── commands/\n│   │   ├── generate.ts            # rq-codegen [generator]\n│   │   └── init.ts                # rq-codegen init\n│   ├── config/\n│   │   ├── types.ts               # RqCodegenConfig type\n│   │   ├── schema.ts              # Zod validation\n│   │   ├── defaults.ts            # Default values\n│   │   └── loader.ts              # Config discovery + merge\n│   ├── core/\n│   │   ├── engine.ts              # Handlebars engine + action executor\n│   │   ├── helpers.ts             # 13 Handlebars helpers\n│   │   ├── actions.ts             # barrel-append + route-register\n│   │   └── template-resolver.ts   # Local override fallback\n│   ├── generators/                # 12 generators\n│   └── utils/                     # String, validation, filesystem utilities\n├── templates/                     # 17 bundled Handlebars templates\n├── tsup.config.ts                 # Build config (ESM)\n└── vitest.config.ts               # Test config\n```\n\n---\n\n## License\n\nMIT\n","readmeFilename":"README.md"}