Cursor rule
.cursor/rules/utilities.mdcGuidelines for implementing utility functions
Cursor rules
Quality
54/100
Scores the file, not the repository.Length
1,163 words
9 headings · 10 code blocksRepository
192
— · pushed 309 days agoLast changed
3 days ago
First indexed 3 days ago.1234567# Utility Function Guidelines89## General Principles1011- **Function Scope**:12 - ✅ DO: Create utility functions that serve multiple modules13 - ✅ DO: Keep functions single-purpose and focused14 - ❌ DON'T: Include business logic in utility functions15 - ❌ DON'T: Create utilities with side effects1617```javascript18 // ✅ DO: Create focused, reusable utilities19 /**20 * Truncates text to a specified length21 * @param {string} text - The text to truncate22 * @param {number} maxLength - The maximum length23 * @returns {string} The truncated text24 */25 function truncate(text, maxLength) {26 if (!text || text.length <= maxLength) {27 return text;28 }29 return text.slice(0, maxLength - 3) + '...';30 }31```3233```javascript34 // ❌ DON'T: Add side effects to utilities35 function truncate(text, maxLength) {36 if (!text || text.length <= maxLength) {37 return text;38 }3940 // Side effect - modifying global state or logging41 console.log(`Truncating text from ${text.length} to ${maxLength} chars`);4243 return text.slice(0, maxLength - 3) + '...';44 }45```4647## Documentation Standards4849- **JSDoc Format**:50 - ✅ DO: Document all parameters and return values51 - ✅ DO: Include descriptions for complex logic52 - ✅ DO: Add examples for non-obvious usage53 - ❌ DON'T: Skip documentation for "simple" functions5455```javascript56 // ✅ DO: Provide complete JSDoc documentation57 /**58 * Reads and parses a JSON file59 * @param {string} filepath - Path to the JSON file60 * @returns {Object|null} Parsed JSON data or null if error occurs61 */62 function readJSON(filepath) {63 try {64 const rawData = fs.readFileSync(filepath, 'utf8');65 return JSON.parse(rawData);66 } catch (error) {67 log('error', `Error reading JSON file ${filepath}:`, error.message);68 if (CONFIG.debug) {69 console.error(error);70 }71 return null;72 }73 }74```7576## Configuration Management7778- **Environment Variables**:79 - ✅ DO: Provide default values for all configuration80 - ✅ DO: Use environment variables for customization81 - ✅ DO: Document available configuration options82 - ❌ DON'T: Hardcode values that should be configurable8384```javascript85 // ✅ DO: Set up configuration with defaults and environment overrides86 const CONFIG = {87 model: process.env.MODEL || 'claude-3-7-sonnet-20250219',88 maxTokens: parseInt(process.env.MAX_TOKENS || '4000'),89 temperature: parseFloat(process.env.TEMPERATURE || '0.7'),90 debug: process.env.DEBUG === "true",91 logLevel: process.env.LOG_LEVEL || "info",92 defaultSubtasks: parseInt(process.env.DEFAULT_SUBTASKS || "3"),93 defaultPriority: process.env.DEFAULT_PRIORITY || "medium",94 projectName: process.env.PROJECT_NAME || "Task Master",95 projectVersion: "1.5.0" // Version should be hardcoded96 };97```9899## Logging Utilities100101- **Log Levels**:102 - ✅ DO: Support multiple log levels (debug, info, warn, error)103 - ✅ DO: Use appropriate icons for different log levels104 - ✅ DO: Respect the configured log level105 - ❌ DON'T: Add direct console.log calls outside the logging utility106107```javascript108 // ✅ DO: Implement a proper logging utility109 const LOG_LEVELS = {110 debug: 0,111 info: 1,112 warn: 2,113 error: 3114 };115116 function log(level, ...args) {117 const icons = {118 debug: chalk.gray('🔍'),119 info: chalk.blue('ℹ️'),120 warn: chalk.yellow('⚠️'),121 error: chalk.red('❌'),122 success: chalk.green('✅')123 };124125 if (LOG_LEVELS[level] >= LOG_LEVELS[CONFIG.logLevel]) {126 const icon = icons[level] || '';127 console.log(`${icon} ${args.join(' ')}`);128 }129 }130```131132## File Operations133134- **Error Handling**:135 - ✅ DO: Use try/catch blocks for all file operations136 - ✅ DO: Return null or a default value on failure137 - ✅ DO: Log detailed error information138 - ❌ DON'T: Allow exceptions to propagate unhandled139140```javascript141 // ✅ DO: Handle file operation errors properly142 function writeJSON(filepath, data) {143 try {144 fs.writeFileSync(filepath, JSON.stringify(data, null, 2));145 } catch (error) {146 log('error', `Error writing JSON file ${filepath}:`, error.message);147 if (CONFIG.debug) {148 console.error(error);149 }150 }151 }152```153154## Task-Specific Utilities155156- **Task ID Formatting**:157 - ✅ DO: Create utilities for consistent ID handling158 - ✅ DO: Support different ID formats (numeric, string, dot notation)159 - ❌ DON'T: Duplicate formatting logic across modules160161```javascript162 // ✅ DO: Create utilities for common operations163 /**164 * Formats a task ID as a string165 * @param {string|number} id - The task ID to format166 * @returns {string} The formatted task ID167 */168 function formatTaskId(id) {169 if (typeof id === 'string' && id.includes('.')) {170 return id; // Already formatted as a string with a dot (e.g., "1.2")171 }172173 if (typeof id === 'number') {174 return id.toString();175 }176177 return id;178 }179```180181- **Task Search**:182 - ✅ DO: Implement reusable task finding utilities183 - ✅ DO: Support both task and subtask lookups184 - ✅ DO: Add context to subtask results185186```javascript187 // ✅ DO: Create comprehensive search utilities188 /**189 * Finds a task by ID in the tasks array190 * @param {Array} tasks - The tasks array191 * @param {string|number} taskId - The task ID to find192 * @returns {Object|null} The task object or null if not found193 */194 function findTaskById(tasks, taskId) {195 if (!taskId || !tasks || !Array.isArray(tasks)) {196 return null;197 }198199 // Check if it's a subtask ID (e.g., "1.2")200 if (typeof taskId === 'string' && taskId.includes('.')) {201 const [parentId, subtaskId] = taskId.split('.').map(id => parseInt(id, 10));202 const parentTask = tasks.find(t => t.id === parentId);203204 if (!parentTask || !parentTask.subtasks) {205 return null;206 }207208 const subtask = parentTask.subtasks.find(st => st.id === subtaskId);209 if (subtask) {210 // Add reference to parent task for context211 subtask.parentTask = {212 id: parentTask.id,213 title: parentTask.title,214 status: parentTask.status215 };216 subtask.isSubtask = true;217 }218219 return subtask || null;220 }221222 const id = parseInt(taskId, 10);223 return tasks.find(t => t.id === id) || null;224 }225```226227## Cycle Detection228229- **Graph Algorithms**:230 - ✅ DO: Implement cycle detection using graph traversal231 - ✅ DO: Track visited nodes and recursion stack232 - ✅ DO: Return specific information about cycles233234```javascript235 // ✅ DO: Implement proper cycle detection236 /**237 * Find cycles in a dependency graph using DFS238 * @param {string} subtaskId - Current subtask ID239 * @param {Map} dependencyMap - Map of subtask IDs to their dependencies240 * @param {Set} visited - Set of visited nodes241 * @param {Set} recursionStack - Set of nodes in current recursion stack242 * @returns {Array} - List of dependency edges that need to be removed to break cycles243 */244 function findCycles(subtaskId, dependencyMap, visited = new Set(), recursionStack = new Set(), path = []) {245 // Mark the current node as visited and part of recursion stack246 visited.add(subtaskId);247 recursionStack.add(subtaskId);248 path.push(subtaskId);249250 const cyclesToBreak = [];251252 // Get all dependencies of the current subtask253 const dependencies = dependencyMap.get(subtaskId) || [];254255 // For each dependency256 for (const depId of dependencies) {257 // If not visited, recursively check for cycles258 if (!visited.has(depId)) {259 const cycles = findCycles(depId, dependencyMap, visited, recursionStack, [...path]);260 cyclesToBreak.push(...cycles);261 }262 // If the dependency is in the recursion stack, we found a cycle263 else if (recursionStack.has(depId)) {264 // The last edge in the cycle is what we want to remove265 cyclesToBreak.push(depId);266 }267 }268269 // Remove the node from recursion stack before returning270 recursionStack.delete(subtaskId);271272 return cyclesToBreak;273 }274```275276## Export Organization277278- **Grouping Related Functions**:279 - ✅ DO: Export all utility functions in a single statement280 - ✅ DO: Group related exports together281 - ✅ DO: Export configuration constants282 - ❌ DON'T: Use default exports283284```javascript285 // ✅ DO: Organize exports logically286 export {287 // Configuration288 CONFIG,289 LOG_LEVELS,290291 // Logging292 log,293294 // File operations295 readJSON,296 writeJSON,297298 // String manipulation299 sanitizePrompt,300 truncate,301302 // Task utilities303 readComplexityReport,304 findTaskInComplexityReport,305 taskExists,306 formatTaskId,307 findTaskById,308309 // Graph algorithms310 findCycles,311 };312```313314Refer to [`utils.js`](mdc:scripts/modules/utils.js) for implementation examples and [`new_features.mdc`](mdc:.cursor/rules/new_features.mdc) for integration guidelines.
Also in skindhu/AI-TASK-MANAGER
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 |
|---|---|---|---|---|---|
| skindhu/AI-TASK-MANAGER.cursor/rules/ui.mdc · 192 | Cursor rules | ui | 62/100 | 3 days ago | |
| skindhu/AI-TASK-MANAGER.cursor/rules/architecture.mdc · 192 | Cursor rules | testarchtesting-strategy | 42/100 | 3 days ago | |
| skindhu/AI-TASK-MANAGER.cursor/rules/commands.mdc · 192 | Cursor rules | stylearch | 62/100 | 3 days ago | |
| skindhu/AI-TASK-MANAGER.cursor/rules/cursor_rules.mdc · 192 | Cursor rules | no sections | 36/100 | 3 days ago | |
| skindhu/AI-TASK-MANAGER.cursor/rules/dependencies.mdc · 192 | Cursor rules | arch | 66/100 | 3 days ago | |
| skindhu/AI-TASK-MANAGER.cursor/rules/dev_workflow.mdc · 192 | Cursor rules | setup | 52/100 | 3 days ago | |
| skindhu/AI-TASK-MANAGER.cursor/rules/new_features.mdc · 192 | Cursor rules | testtesting-strategydocs | 65/100 | 3 days ago | |
| skindhu/AI-TASK-MANAGER.cursor/rules/self_improve.mdc · 192 | Cursor rules | no sections | 36/100 | 3 days ago | |
| skindhu/AI-TASK-MANAGER.cursor/rules/tasks.mdc · 192 | Cursor rules | arch | 70/100 | 3 days ago | |
| skindhu/AI-TASK-MANAGER.cursor/rules/tests.mdc · 192 | Cursor rules | teststylearchtesting-strategy+1 | 74/100 | 3 days ago | |
| skindhu/AI-TASK-MANAGERassets/.windsurfrules · 192 | Windsurf rules | setup | 40/100 | 3 days ago |
Diff against .cursor/rules/ui.mdc Diff against .cursor/rules/architecture.mdc Diff against .cursor/rules/commands.mdc Diff against .cursor/rules/cursor_rules.mdc Diff against .cursor/rules/dependencies.mdc Diff against .cursor/rules/dev_workflow.mdc Diff against .cursor/rules/new_features.mdc Diff against .cursor/rules/self_improve.mdc Diff against .cursor/rules/tasks.mdc Diff against .cursor/rules/tests.mdc Diff against assets/.windsurfrules
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 | |
| deifos/clipmira-subtitles.cursor/rules/frontend.mdc · 1 | 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 | |
| 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 |
