Cursor rule
.cursor/rules/coding-standards.mdc[object Object]
Cursor rules
Quality
36/100
Scores the file, not the repository.Length
1,667 words
0 headings · 6 code blocksRepository
9
— · pushed 394 days agoLast changed
3 days ago
First indexed 3 days ago.123456Rule Name: coding-standards7Description:8This rule defines the coding standards and formatting guidelines that must be followed for all code changes in this project.910<coding_format>1112A. Syntax & Structure13- File names must be dash-case (word-cloud.service.ts) unless an existing pattern differs.14- Group imports: node/standard → npm packages → internal paths. No unused imports.15- Use arrow functions everywhere except inside class bodies, where concise method syntax is allowed.16- Prefer early returns; nested if/else blocks deeper than two levels are disallowed.17- Early returns must use block format with braces (e.g., `if (!value) { return }`) for readability.18- Extract function call results as scope variables before using in conditions (e.g., `const trimmedText = text.trim(); if (!trimmedText) {...}` instead of `if (!text.trim()) {...}`).19- Use async/await—never chain .then().20- No .forEach for side effects; use for (const x of arr) instead.21- Array combinators (map, reduce, filter) are allowed only when you return their result.22- Identifiers must be English.23- No commented code allowed.2425B. Functional-Programming Rules26- Each function must:27 * Be ≤ 50 lines (preferably; extract helpers if longer).28 * Take ≤ 4 parameters (optional ones last).29 * Have a single responsibility.30 * Be pure unless it is an intentional I/O wrapper (e.g. DB write); such wrappers must be ≤ 15 lines.31 * Name functions with camelCase imperative verbs (calculateTotals, getUserById).3233C. Type Safety & Error Handling34- Explicitly type all function parameters, return types, and exported constants.35- Type all local variables inside a function.36- **Special attention for async operations**: Variables from awaited functions (e.g., `const { userId } = await auth()`) must be explicitly typed, especially in Next.js components where auth results should use proper domain types.37- No any; if an external library forces it, wrap and narrow.38- Error handling in catch blocks:39 - If the error variable is not used, use `catch {}` (no parameter).40 - If the error is used, type it as `unknown` and handle it safely within the catch block.4142D. React Component Standards4344- Always define props with interfaces, never inline types45- Place interfaces directly above component definitions46- Use const arrow functions for component definitions47- Use implicit return syntax when components only return JSX (no logic before return)48- Export components using export default pattern (required for Next.js pages/layouts)49- Handler functions inside components must be ≤ 20 lines and have a single, clear responsibility. Extract helper functions for complex logic.5051 **Wrong (~50 lines in one handler):**52```tsx53 const handleFormSubmit = async (): Promise<void> => {54 const trimmedName: string = formData.name.trim()55 const trimmedEmail: string = formData.email.trim()56 const trimmedMessage: string = formData.message.trim()5758 if (!trimmedName) {59 setErrors({ ...errors, name: "Name is required" })60 toast({ title: "Error", description: "Name is required", variant: "destructive" })61 return62 }6364 if (!trimmedEmail || !trimmedEmail.includes("@")) {65 setErrors({ ...errors, email: "Valid email is required" })66 toast({ title: "Error", description: "Valid email is required", variant: "destructive" })67 return68 }6970 if (!trimmedMessage || trimmedMessage.length < 10) {71 setErrors({ ...errors, message: "Message must be at least 10 characters" })72 toast({ title: "Error", description: "Message too short", variant: "destructive" })73 return74 }7576 setIsSubmitting(true)77 setErrors({})7879 try {80 const payload: FormPayload = {81 name: trimmedName,82 email: trimmedEmail,83 message: trimmedMessage,84 timestamp: new Date().toISOString()85 }8687 const response: Response = await fetch("/api/contact", {88 method: "POST",89 headers: { "Content-Type": "application/json" },90 body: JSON.stringify(payload)91 })9293 if (!response.ok) {94 throw new Error("Failed to submit")95 }9697 const result: SubmissionResult = await response.json()9899 setFormData({ name: "", email: "", message: "" })100 setSubmissionCount(prev => prev + 1)101102 toast({ title: "Success", description: "Message sent successfully!" })103104 if (onSuccess) {105 onSuccess(result)106 }107 } catch (error: unknown) {108 const errorMessage: string = error instanceof Error ? error.message : "Unknown error"109 console.error("Submission error:", errorMessage)110 setErrors({ submit: "Failed to send message" })111 toast({ title: "Error", description: "Failed to send message", variant: "destructive" })112 } finally {113 setIsSubmitting(false)114 }115 }116```117118 **Good (broken into focused helpers ≤ 20 lines each):**119```tsx120 const validateForm = (): boolean => {121 const trimmedName: string = formData.name.trim()122 const trimmedEmail: string = formData.email.trim()123 const trimmedMessage: string = formData.message.trim()124125 if (!trimmedName) {126 setErrors({ ...errors, name: "Name is required" })127 toast({ title: "Error", description: "Name is required", variant: "destructive" })128 return false129 }130131 if (!trimmedEmail || !trimmedEmail.includes("@")) {132 setErrors({ ...errors, email: "Valid email is required" })133 toast({ title: "Error", description: "Valid email is required", variant: "destructive" })134 return false135 }136137 if (!trimmedMessage || trimmedMessage.length < 10) {138 setErrors({ ...errors, message: "Message must be at least 10 characters" })139 toast({ title: "Error", description: "Message too short", variant: "destructive" })140 return false141 }142143 return true144 }145146 const submitForm = async (): Promise<SubmissionResult> => {147 const payload: FormPayload = {148 name: formData.name.trim(),149 email: formData.email.trim(),150 message: formData.message.trim(),151 timestamp: new Date().toISOString()152 }153154 const response: Response = await fetch("/api/contact", {155 method: "POST",156 headers: { "Content-Type": "application/json" },157 body: JSON.stringify(payload)158 })159160 if (!response.ok) {161 throw new Error("Failed to submit")162 }163164 return response.json()165 }166167 const handleSuccess = (result: SubmissionResult): void => {168 setFormData({ name: "", email: "", message: "" })169 setSubmissionCount((prev: number) => prev + 1)170 toast({ title: "Success", description: "Message sent successfully!" })171172 if (onSuccess) {173 onSuccess(result)174 }175 }176177 const handleError = (error: unknown): void => {178 const errorMessage: string = error instanceof Error ? error.message : "Unknown error"179 console.error("Submission error:", errorMessage)180 setErrors({ submit: "Failed to send message" })181 toast({ title: "Error", description: "Failed to send message", variant: "destructive" })182 }183184 const handleFormSubmit = async (): Promise<void> => {185 const isValid: boolean = validateForm()186187 if (!isValid) {188 return189 }190191 setIsSubmitting(true)192 setErrors({})193194 try {195 const result: SubmissionResult = await submitForm()196 handleSuccess(result)197 } catch (error: unknown) {198 handleError(error)199 } finally {200 setIsSubmitting(false)201 }202 }203```204- Example with implicit return:205206```tsx207 interface MyComponentProps {208 title: string209 children: React.ReactNode210 }211212 const MyComponent = ({ title, children }: MyComponentProps) => (213 <div>214 {title}215 {children}216 </div>217 )218219 export default MyComponent220```221222- Example with explicit return (when logic is present):223224```tsx225 interface MyComponentProps {226 title: string227 children: React.ReactNode228 }229230 const MyComponent = ({ title, children }: MyComponentProps) => {231 const processedTitle = title.toUpperCase()232233 return (234 <div>235 {processedTitle}236 {children}237 </div>238 )239 }240241 export default MyComponent242```243244- Normal components that are not Next.js pages/layouts should be exported245 using export const pattern246- Example with implicit return:247248```tsx249 interface NotAPageOrLayoutComponentProps {250 title: string251 children: React.ReactNode252 }253254 export const NotAPageOrLayoutComponent = ({255 title,256 children257 }: NotAPageOrLayoutComponentProps) => (258 <div>259 {title}260 {children}261 </div>262 )263264E. Component Granularity & Organization265- Break down large components into smaller, focused components for better maintainability.266- When a component contains multiple logical sections (e.g., Card with CardHeader + CardContent), extract each section into separate components.267- Create dedicated folders for related component groups:268 * Use kebab-case folder names matching the main component concept269 * Place related sub-components within the same folder using kebab-case file names270 * Example structure: `component-name/component-name-header.tsx`, `component-name/component-name-content.tsx`271- Each sub-component should have a single, clear responsibility.272- Maintain the parent component as a composition wrapper that orchestrates child components.273- Follow this pattern when refactoring existing components or creating new feature components.274275F. Advanced Component Architecture Patterns276277F.1. Pure Functions and Constants Organization278- **Pure functions** (no side effects, deterministic output) must be extracted outside components:279 * Place above the component definition280 * Examples: `getGreeting()`, `getMembershipBadgeColor()`, `formatDate()`281- **Constants and static data** must be moved outside components:282 * Place after imports and interfaces, before pure functions283 * Use SCREAMING_SNAKE_CASE for naming (e.g., `TEMPLATE_FEATURES`, `TECH_STACK`)284 * **Always explicitly type constants** with appropriate type annotations285 * Examples: `const API_URL: string = "..."`, `const MAX_RETRIES: number = 3`286 * Use `as const` for immutable values when type inference is sufficient287 * Group related constants together288289F.1.1. Custom Hooks Organization290- **Custom hooks** must be extracted to separate files in the `/hooks/` directory:291 * Use kebab-case file naming: `use-scroll-detection.ts`, `use-local-storage.ts`292 * Start hook names with `use` prefix following React conventions293 * Place hooks in `/hooks/` folder at project root level294 * Export hooks using named exports: `export const useScrollDetection = () => {}`295 * **Always explicitly type hook return values** and parameters296 * Examples: `useScrollDetection(): boolean`, `useLocalStorage<T>(key: string): [T, (value: T) => void]`297 * Group related hooks in the same file only if they're tightly coupled298299F.1.2. Whitespace and Formatting Rules300- **Component variable organization**: Maintain consistent whitespace between different types of declarations:301 * Add a blank line between React state declarations and custom hook calls302 * Add a blank line between custom hook calls and other variable declarations303 * Example:304 ```tsx305 const [isMenuOpen, setIsMenuOpen] = useState<boolean>(false)306 const [isVisible, setIsVisible] = useState<boolean>(true)307308 const isScrolled: boolean = useScrollDetection()309 const userData: UserData = useUserData()310311 const processedData: ProcessedData = processUserData(userData)312```313314F.2. Nested Component Structure for Complex Components315When a component has multiple distinct sections, create nested folder structure:316317```318dashboard-welcome/319├── dashboard-welcome.tsx // Main orchestrator component320├── greeting.tsx // Self-contained greeting section321├── whats-included/ // Folder for multi-part section322│ ├── whats-included.tsx // Section orchestrator323│ ├── whats-included-title.tsx // Title sub-component324│ └── whats-included-features.tsx // Features list sub-component325├── core-technologies/ // Folder for multi-part section326│ ├── core-technologies.tsx // Section orchestrator327│ ├── core-technologies-title.tsx // Title sub-component328│ └── core-technologies-list.tsx // Tech list sub-component329└── get-started/ // Folder for multi-part section330 ├── get-started.tsx // Section orchestrator331 ├── get-started-title.tsx // Title sub-component332 ├── get-started-features.tsx // Features grid sub-component333 └── get-started-feature-2.tsx // Individual feature card334```335336F.3. Component Organization Rules3371. **Main orchestrator**: Composition only, minimal logic, imports and renders sub-components3382. **Section orchestrators**: Handle section-specific logic, render related sub-components3393. **Leaf components**: Single responsibility, pure presentation, accept props only3404. **Shared constants**: Extract to file level, use proper naming conventions3415. **Pure functions**: Extract above component definitions, properly typed3426. **File structure**: Mirror logical component hierarchy in folder structure343344</coding_format>345346<usage_guidelines>3473481. Apply these standards to all new code and when refactoring existing code.3492. When making any code changes, ensure they conform to these guidelines.3503. If existing code doesn't follow these standards, update it to comply when modifying those files.3514. Use these standards as a checklist when reviewing code changes.3525. Prefer extracting helper functions over writing long, complex functions.3536. Always prioritize code readability and maintainability.354355</usage_guidelines>
Also in sportiz91/vibe-template
Diff this repo’s formatsOne repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| sportiz91/vibe-template.cursor/rules/auth.mdc · 9 | Cursor rules | securitydo-not | 32/100 | 3 days ago | |
| sportiz91/vibe-template.cursor/rules/storage.mdc · 9 | Cursor rules | archsecuritydo-not | 65/100 | 3 days ago | |
| sportiz91/vibe-template.cursor/rules/backend.mdc · 9 | Cursor rules | do-not | 61/100 | 3 days ago | |
| sportiz91/vibe-template.cursor/rules/frontend.mdc · 9 | Cursor rules | do-not | 61/100 | 3 days ago | |
| sportiz91/vibe-template.cursor/rules/general.mdc · 9 | Cursor rules | stylearchsecuritydo-not+1 | 69/100 | 3 days ago | |
| sportiz91/vibe-template.cursorrules · 9 | .cursorrules | stylearchsecuritydo-not+1 | 49/100 | 3 days ago | |
| sportiz91/vibe-templateCLAUDE.md · 9 | CLAUDE.md | setuptestlint-formatstyle+7 | 88/100 | 3 days ago |
Similar configs
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| hiromaily/go-crypto-wallet.cursor/rules/typescript.mdc · 126 | Cursor rules | setupbuildtestlint-format+6 | 100/100 | 3 days ago | |
| TechSquidTV/Hermes.cursor/rules/10-hermes-api.mdc · 45 | Cursor rules | testlint-formatstylearch+5 | 100/100 | 3 days ago | |
| markstev/mark-starter.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+6 | 99/100 | 3 days ago | |
| Allymahmoud/case-intake-platform.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 3 days ago | |
| dodgecfr/combatfilms-webapp.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 3 days ago | |
| deifos/clipmira-subtitles.cursor/rules/frontend.mdc · 1 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 3 days ago | |
| langflow-ai/langflow.cursor/rules/docs_development.mdc · 153k | Cursor rules | setupbuildtestlint-format+7 | 97/100 | 3 days ago | |
| TechSquidTV/Hermes.cursor/rules/20-hermes-api-tests.mdc · 45 | Cursor rules | teststyletesting-strategysecurity+3 | 97/100 | 3 days ago |
