Skip to content

Latest commit

 

History

History
131 lines (102 loc) · 10.1 KB

File metadata and controls

131 lines (102 loc) · 10.1 KB

File Structure and Naming

  • All React components live in src/components/ with PascalCase filenames matching the component export: src/components/UserProfile.tsx exports UserProfile
  • All screens live in src/screens/ with PascalCase filenames: src/screens/HomeScreen.tsx
  • All navigation configuration lives in src/navigation/ — never define navigation stacks inside screen files
  • All hooks live in src/hooks/ with camelCase filenames prefixed with use: src/hooks/useUserData.ts
  • All utilities live in src/utils/ with camelCase filenames by function: src/utils/dateFormatting.ts, src/utils/validation.ts
  • All theme and styling constants live in src/theme/ — never create a styles.ts file in component directories
  • All API calls live in src/api/ with resource-based filenames: src/api/users.ts, src/api/posts.ts
  • All types live in src/types/ with camelCase filenames: src/types/user.ts, src/types/navigation.ts
  • Test files must live adjacent to source with .test.ts or .test.tsx suffix: src/utils/dateFormatting.test.ts

Export Conventions

  • Every file exports exactly one default export if it's a component or hook: export default UserProfile
  • Named exports are forbidden for components and hooks — use default export only
  • Utility files may have multiple named exports: export const formatDate = ... and export const parseDate = ...
  • Never use export * — always name what you export
  • Re-export patterns are forbidden — if src/index.ts exists, it must not re-export from other files

Theme and Styling

  • All colors must come from src/theme/colors.ts — never use hardcoded color strings like #FF5733 or 'red'
  • All spacing values must come from src/theme/spacing.ts — never use hardcoded pixel values like 16 or '20px'
  • All font sizes must come from src/theme/typography.ts — never use hardcoded sizes
  • StyleSheet.create() calls must only reference theme tokens: color: colors.primary, marginTop: spacing.md
  • Platform-specific styles must use Platform.select() inside StyleSheet.create: Platform.select({ ios: {...}, android: {...} })
  • Never create inline styles with style={{}} — always use StyleSheet.create
  • Dark mode support requires conditional theme selection: const theme = isDarkMode ? darkTheme : lightTheme — never hardcode light-only colors

Component Patterns

  • Every component that accepts props must define a TypeScript interface named {ComponentName}Props: interface UserProfileProps { userId: string }
  • Components must not directly call navigation functions — pass navigation as a prop or use useNavigation() hook only in screen components
  • Components must not fetch data directly — data must be passed as props or fetched in parent screen component
  • Every component with conditional rendering must use early returns, never ternary operators in JSX: if (!user) return null; then render
  • Components must not use any type — use unknown and type guard, or define explicit interface
  • Ref forwarding requires forwardRef wrapper: const Button = forwardRef<...>((props, ref) => ...)

Server State Management

  • All server data fetching must use React Query with useQuery() — never use useState for server data
  • Query keys must be defined in src/api/queryKeys.ts as constants: export const userKeys = { all: ['users'], byId: (id: string) => ['users', id] }
  • Every useQuery() call must specify staleTime and gcTime explicitly — never rely on defaults
  • Mutations must use useMutation() with onSuccess and onError callbacks — never chain .then() on mutation
  • Optimistic updates must use setQueryData() before mutation — never assume mutation will succeed
  • Cache invalidation must use queryClient.invalidateQueries() with specific query keys — never use refetchQueries: 'all'

Keyboard and Input Handling

  • Every screen with TextInput must wrap content in KeyboardAvoidingView with behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
  • Every TextInput must have returnKeyType set explicitly: returnKeyType="next" or returnKeyType="done"
  • Every TextInput must have onSubmitEditing handler — never leave it undefined
  • Form inputs must use controlled components: value={state} and onChangeText={setState} — never use uncontrolled inputs
  • Input validation must happen on blur, not on every keystroke — use onBlur handler for validation
  • Password inputs must have secureTextEntry={true} — never display passwords in plain text

Navigation

  • All navigation stacks must be defined in src/navigation/RootNavigator.tsx — never define stacks in screen files
  • Navigation params must be typed in src/types/navigation.ts with RootStackParamList interface
  • Navigation must use useNavigation<NativeStackNavigationProp<RootStackParamList>>() — never use untyped navigation
  • Deep linking configuration must live in src/navigation/linking.ts — never inline linking config
  • Screen options must be defined in src/navigation/screenOptions.ts — never pass options inline to Screen components
  • Back button handling must use useFocusEffect() with BackHandler.addEventListener() — never use useEffect()

Error Handling

  • All async functions must have try/catch blocks — never leave promises unhandled
  • Caught errors must be typed: catch (err) { if (err instanceof AppError) {...} else if (err instanceof NetworkError) {...} } — never use catch (e: any)
  • All API calls must throw typed errors from src/types/errors.ts: class AppError extends Error { code: string }
  • Network errors must be caught and transformed to NetworkError type — never expose raw fetch/axios errors
  • Error messages shown to users must come from src/utils/errorMessages.ts — never show raw error.message
  • Every screen must have error boundary or error state — never let errors crash the app silently

API and Network

  • All API endpoints must be defined in src/api/endpoints.ts as constants: export const ENDPOINTS = { users: '/users', userById: (id) => /users/${id} }
  • All API calls must include timeout: fetch(url, { timeout: 10000 }) — never make requests without timeout
  • All request/response bodies must be validated with Zod schemas in src/api/schemas/ — never trust API responses
  • API base URL must come from environment variables: process.env.EXPO_PUBLIC_API_URL — never hardcode URLs
  • All API calls must include retry logic with exponential backoff — use React Query's retry and retryDelay options
  • Sensitive data like auth tokens must never be logged — use console.log() only in development with __DEV__ guard

Security

  • All environment variables must be prefixed with EXPO_PUBLIC_ for client-side access — never use unprefixed variables
  • Secrets must never be stored in code — use .env.local (gitignored) for development
  • All user input must be validated at component boundary using Zod: const parsed = userSchema.parse(input) — never skip validation
  • Authentication tokens must be stored in secure storage: SecureStore.setItemAsync() — never store in AsyncStorage
  • All API requests to protected endpoints must include auth token in header: Authorization: Bearer ${token} — never send tokens in query params
  • CORS headers must be validated on backend — never disable CORS checks in production

Testing

  • Every utility function must have a .test.ts file with 100% line coverage — no exceptions
  • Every hook must have a .test.tsx file using renderHook() from @testing-library/react-native — never test hooks in component tests
  • Every screen must have a .test.tsx file testing navigation and error states — never skip screen tests
  • Test files must use describe() blocks organized by function: describe('UserProfile', () => { describe('rendering', () => {...}); describe('interactions', () => {...}); })
  • Mock API calls with jest.mock('src/api/users') — never make real API calls in tests
  • Mock navigation with jest.mock('@react-navigation/native') — never test actual navigation in component tests
  • All async tests must use waitFor() from @testing-library/react-native — never use setTimeout() in tests

Platform-Specific Code

  • Every platform-specific implementation must use Platform.OS === 'ios' or Platform.OS === 'android' — never use Platform.select() for logic, only for styles
  • iOS-specific code must live in src/utils/ios/ and Android-specific in src/utils/android/ — never mix platform code in shared files
  • Platform-specific components must use .ios.tsx and .android.tsx file extensions: Button.ios.tsx and Button.android.tsx
  • Every platform-specific feature must have a fallback for unsupported platforms — never crash on unsupported platforms
  • Permissions must be checked before use: const { status } = await Permissions.askAsync(Permissions.CAMERA) — never assume permissions are granted

Performance

  • All lists must use FlatList with keyExtractor and maxToRenderPerBatch — never use ScrollView with map()
  • Every FlatList must have removeClippedSubviews={true} on Android — never render all items
  • Images must use Image component with explicit width and height — never use resizeMode="contain" without dimensions
  • Heavy computations must use useMemo() with explicit dependency array — never compute in render
  • Event handlers must use useCallback() with explicit dependency array — never define functions inline in JSX

Logging and Debugging

  • All logging must be wrapped in if (__DEV__) guard — never log in production builds
  • Sensitive data must never be logged — no tokens, passwords, or PII in logs
  • Error logging must use structured format: { code: string, message: string, context: object } — never log raw errors
  • Console methods must be typed: console.error() for errors, console.warn() for warnings, console.log() for info — never use console.log() for errors

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