Skip to content

Latest commit

 

History

History
115 lines (88 loc) · 7.73 KB

File metadata and controls

115 lines (88 loc) · 7.73 KB

Export Style

  • All exports must be named exports. Default exports are forbidden except for Next.js page components in /pages and /app directories.
  • Export statements must appear at the end of the file, never inline with declarations.
  • Re-export barrels in index.ts files must use export { NamedExport } from './module' syntax only.

File Naming and Organization

  • React components must be PascalCase: UserProfile.tsx, never userProfile.tsx or user-profile.tsx.
  • Utility functions must be camelCase: formatDate.ts, validateEmail.ts.
  • Hook files must start with use: useAuth.ts, useFetchUser.ts.
  • Test files must be colocated with source and named ComponentName.test.tsx or functionName.test.ts.
  • Store all components in /src/components, organized by feature subdirectories: /src/components/auth/LoginForm.tsx, never flat.
  • Store all hooks in /src/hooks, never nested in component directories.
  • Store all utilities in /src/utils, organized by domain: /src/utils/api/, /src/utils/validation/.
  • Store all types in /src/types, with files named by domain: user.ts, api.ts, never a single types.ts.

TypeScript Type Safety

  • Never use any type. If shape is unknown, use unknown and narrow with type guards or Zod validation.
  • Never use as type assertions outside of .test.ts files. Use type guards, satisfies, or Zod .parse() instead.
  • All function parameters must have explicit types. No implicit any.
  • All function return types must be explicit. No implicit inference for exported functions.
  • Object shapes must be defined as interfaces or types before use, never inline in function signatures.
  • Use Record<string, T> for object maps, never { [key: string]: T }.
  • Use readonly for immutable arrays and objects in type definitions.

React Component Patterns

  • All components must be functional components with hooks. Class components are forbidden.
  • Component files must export exactly one component. Helper components must be in separate files.
  • Props interfaces must be named {ComponentName}Props and defined above the component.
  • Props must be destructured in the function signature, never accessed via props.x.
  • All components must have explicit return type: React.ReactNode, JSX.Element, or null.
  • Never use React.FC or React.FunctionComponent. Use function declaration with explicit return type.

State Management

  • State updates must never mutate directly. Always use spread operator or immutable patterns.
  • For object state: setState({ ...state, field: newValue }).
  • For array state: setState([...array, newItem]) or setState(array.map(...)), never array.push().
  • Use useCallback for any function passed to child components or used in dependency arrays.
  • Use useMemo only when computation is expensive (>1ms) or dependency array prevents re-renders. Never use for simple values.

useEffect Rules

  • Every useEffect must have an explicit dependency array. Never omit it.
  • Data fetching must use useEffect with cleanup: abort controller or cleanup function that cancels pending requests.
  • Never call async functions directly in useEffect. Wrap in an inner async function or use a library like react-query.
  • If useEffect sets state, it must have a cleanup function that cancels or ignores results: isMounted flag or AbortController.
  • Multiple related state updates in useEffect must be batched with flushSync if order matters, otherwise React batches automatically.

Error Handling

  • All async functions must have try/catch blocks. Never let promises reject unhandled.
  • Caught errors must be typed: catch (err) { if (err instanceof SpecificError) ... }, never catch (e: any) or bare catch.
  • Create an AppError class in /src/utils/errors.ts with code, message, and statusCode properties. Throw only AppError instances from business logic.
  • HTTP errors must be caught and converted to AppError with appropriate status codes before returning to components.
  • Components must display error states: render error message from state, never console.log errors.
  • Error boundaries must wrap feature sections in /src/components/ErrorBoundary.tsx. Never leave error boundaries unimplemented.

Data Fetching

  • All API calls must go through /src/utils/api/client.ts, a centralized fetch wrapper that handles auth headers and error conversion.
  • API response types must be defined in /src/types/api.ts with request and response shapes separated: GetUserRequest, GetUserResponse.
  • Validate all API responses with Zod schemas in /src/utils/validation/schemas.ts before using in components.
  • Loading and error states must always be tracked: { data, loading, error } or equivalent, never assume success.
  • Never hardcode API URLs. Use environment variables: process.env.REACT_APP_API_URL, validated at app startup in /src/config.ts.

Input Validation

  • All user inputs must be validated at the component boundary before sending to API or state.
  • Use Zod for validation: const schema = z.object({ email: z.string().email() }); schema.parse(input).
  • Form validation must happen on blur and submit, never on every keystroke.
  • Display validation errors inline next to form fields, never in console or alerts.
  • Never trust data from URL params or query strings. Parse and validate with Zod before use.

Security

  • Never commit secrets, API keys, or tokens to git. Use .env.local (gitignored) for local development.
  • All environment variables must be prefixed with REACT_APP_ to be accessible in browser code.
  • Validate and sanitize all data from external sources (API, URL params, localStorage) before rendering or using in logic.
  • Never use dangerouslySetInnerHTML. If HTML rendering is required, use a sanitization library like DOMPurify.
  • CSRF tokens must be included in all state-changing requests (POST, PUT, DELETE). Retrieve from response headers or meta tags, never hardcode.

Testing

  • Every component must have a .test.tsx file with at least one test. Untested components block PR merge.
  • Every utility function must have a .test.ts file. Pure functions must have >80% branch coverage.
  • Tests must use React Testing Library, never Enzyme or shallow rendering.
  • Test user interactions, not implementation: userEvent.click(screen.getByRole('button', { name: /submit/i })), never wrapper.find('.submit-btn').simulate('click').
  • Mock API calls with msw (Mock Service Worker) in /src/mocks/handlers.ts, never mock fetch directly.
  • Async tests must use await screen.findBy*() or waitFor(), never setTimeout.
  • Test error states explicitly: render component with error prop, verify error message displays.

Naming Conventions

  • Boolean variables and functions must start with is, has, can, or should: isLoading, hasError, canSubmit.
  • Event handlers must be named handle{Event}: handleClick, handleSubmit, handleInputChange.
  • Callback props must be named on{Event}: onClick, onSubmit, onInputChange.
  • API functions must be named fetch{Resource} or get{Resource}: fetchUser, getUserById, never just getUser if it takes parameters.
  • Constants must be UPPER_SNAKE_CASE: MAX_RETRIES, API_TIMEOUT_MS.

Async/Await

  • Never use .then() chains. Always use async/await for readability.
  • All async functions must have explicit Promise<ReturnType> return type.
  • Promise.all() must be used for parallel operations, never sequential awaits.
  • Timeouts must be explicit: wrap with Promise.race([operation, timeout(ms)]) or use library utilities, never rely on implicit timeouts.

Source: Codelibrium — the marketplace for AI behaviour files. Browse multiple rulesets at codelibrium.com or install via CLI: npx codelibrium-cli install <ruleset-name>