From 5a294c5182c3379d082ed85171b8beb03e163ac0 Mon Sep 17 00:00:00 2001 From: Melvin Ragusa Date: Fri, 30 Jan 2026 05:27:45 +0100 Subject: [PATCH] chore: update AGENTS.md --- AGENTS.md | 161 ++++++++++++++++++++++++------------------------------ 1 file changed, 70 insertions(+), 91 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index db2834a..adb8a04 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -3,129 +3,131 @@ ## Build Commands ```bash +# Install dependencies +pnpm install + # Development server (port 3000) -npm run dev +pnpm dev # Production build -npm run build +pnpm build # Preview production build -npm run preview +pnpm preview ``` ## Test Commands +Use `pnpm exec` to run local binaries. + ```bash # Run all tests -npx vitest +pnpm exec vitest # Run tests in watch mode -npx vitest --watch +pnpm exec vitest --watch # Run tests with coverage -npx vitest --coverage +pnpm exec vitest --coverage -# Run a single test file -npx vitest src/components/ui/__tests__/Button.test.tsx +# Run a single test file (Preferred method) +pnpm exec vitest src/components/ui/__tests__/Button.test.tsx # Run tests matching a pattern -npx vitest --grep "Button" +pnpm exec vitest --grep "Button" # Run specific test by name -npx vitest -t "passes aria-label to the button element" +pnpm exec vitest -t "passes aria-label to the button element" +``` + +## Lint & Type Check + +```bash +# Type check (strict) +pnpm exec tsc --noEmit ``` ## Code Style Guidelines ### TypeScript -- Use **strict TypeScript** configuration -- Always define explicit return types for functions -- Use `type` for type definitions, `interface` for object shapes that may be extended -- Avoid `any` - use `unknown` when type is uncertain +- Use **strict TypeScript** configuration (`strict: true`). +- Always define explicit return types for functions. +- Use `type` for type definitions, `interface` for object shapes that may be extended. +- Avoid `any` - use `unknown` when type is uncertain. +- Use `import type` for type-only imports when possible. ### Imports (Order) -1. React imports -2. Third-party libraries (alphabetical) -3. Absolute imports from project (`@/components`, `@/utils`) -4. Relative imports -5. CSS/SCSS imports last +1. React imports (`react`, `react-dom`) +2. Third-party libraries (alphabetical, e.g., `motion/react`, `react-icons`) +3. Absolute imports from project (`@/components`, `@/utils` if configured, otherwise relative) +4. Relative imports (`../../utils`) +5. CSS/SCSS imports last (`./Component.module.css`) ```typescript -import { useState, useEffect } from 'react'; +import { type ReactNode, type ButtonHTMLAttributes } from 'react'; import { motion } from 'motion/react'; import { Link } from 'react-router-dom'; -import { useTranslation } from '../../i18n'; import { debounce } from '../../utils/debounce'; import styles from './Navbar.module.css'; ``` ### Component Structure -- Use **named exports** for all components -- Props interface should be named `[ComponentName]Props` -- Place props interface immediately before component -- Use CSS Modules for styling (`.module.css`) -- Destructure props in function signature with defaults +- Use **named exports** for all components. +- Props interface should be named `[ComponentName]Props`. +- Place props interface immediately before component. +- Use CSS Modules for styling (`.module.css`). +- Use `motion` components (e.g., `motion.button`) for animations. ```typescript -interface ButtonProps extends ButtonHTMLAttributes { +interface ButtonProps extends Omit, 'onDrag'> { variant?: 'primary' | 'secondary' | 'outline'; - size?: 'sm' | 'md' | 'lg'; isLoading?: boolean; } export function Button({ variant = 'primary', - size = 'md', isLoading = false, children, + className, ...props }: ButtonProps) { - // Implementation + return ( + + {children} + + ); } ``` ### Naming Conventions - **Components**: PascalCase (e.g., `Navbar`, `Button`) -- **Hooks**: camelCase with `use` prefix (e.g., `useRateLimit`, `useTypingEffect`) +- **Hooks**: camelCase with `use` prefix (e.g., `useRateLimit`) - **Utilities**: camelCase (e.g., `debounce`, `formatDate`) -- **Types/Interfaces**: PascalCase (e.g., `ButtonProps`, `Translations`) -- **Constants**: UPPER_SNAKE_CASE for module-level constants +- **Types/Interfaces**: PascalCase (e.g., `ButtonProps`) - **Files**: Match default export name (e.g., `Navbar.tsx` exports `Navbar`) +- **Test Files**: `[Filename].test.tsx` inside `__tests__` directory or alongside file. ### Error Handling -- Use try-catch for async operations -- Provide meaningful error messages -- Use early returns to avoid nested conditionals -- Clean up resources (timers, event listeners) in useEffect cleanup - -```typescript -useEffect(() => { - const handleScroll = () => { - if (!ticking) { - window.requestAnimationFrame(() => { - setIsScrolled(window.scrollY > 20); - ticking = false; - }); - ticking = true; - } - }; - window.addEventListener('scroll', handleScroll, { passive: true }); - return () => window.removeEventListener('scroll', handleScroll); -}, []); -``` +- Use try-catch for async operations. +- Provide meaningful error messages. +- Clean up resources (timers, event listeners) in `useEffect` cleanup. ### Testing -- Add `// @vitest-environment jsdom` at top of test files -- Use `describe` and `it` blocks with descriptive names -- Clean up after each test with `cleanup()` from testing-library -- Mock external dependencies appropriately -- Test behavior, not implementation +- Add `// @vitest-environment jsdom` at top of test files. +- Use `describe` and `it` blocks. +- Clean up after each test with `cleanup()` from `@testing-library/react`. +- Mock external dependencies appropriately. +- Test behavior, not implementation details. ```typescript // @vitest-environment jsdom @@ -133,9 +135,7 @@ import { render, screen, cleanup } from '@testing-library/react'; import { describe, it, expect, afterEach } from 'vitest'; describe('Button', () => { - afterEach(() => { - cleanup(); - }); + afterEach(() => cleanup()); it('renders with correct aria-label', () => { render(); @@ -144,46 +144,25 @@ describe('Button', () => { }); ``` -### Performance +### Performance & Best Practices -- Use `React.lazy()` for code splitting on routes -- Memoize expensive calculations with `useMemo` -- Use `requestAnimationFrame` for scroll/resize handlers -- Debounce expensive operations (use `debounce` utility) -- Add `will-change` CSS sparingly for GPU acceleration - -### Accessibility - -- Always include meaningful `aria-label` for interactive elements -- Use semantic HTML elements (`
`, `