Table of Contents
New Rule Suggestions & Implementations
Quick Reference: Adding a New Rule
- Open
wwwroot/rules/CodingStandards.json - Add rule object to
rulesarray - Save file
- Hard refresh browser (Ctrl+Shift+R)
- Rules auto-load with cache-busting
Suggested New Rules
C# Rules
CS007: Async Void Methods
Purpose: Detect async void methods (should be async Task)
{
"id": "CS007",
"name": "Async Void Methods",
"category": "coding-standards",
"severity": "warning",
"fileExtensions": [".cs"],
"pattern": "async\\s+void\\s+\\w+\\s*\\(",
"message": "Async methods should return Task, not void",
"suggestion": "Change 'async void' to 'async Task'",
"example": "public async Task ProcessDataAsync() { }",
"enabled": true
}
Catches:
public async void ProcessData() { } // ❌ Bad
private async void HandleEvent() { } // ❌ Bad
Allows:
public async Task ProcessDataAsync() { } // ✅ Good
private async void Button_Click() { } // ✅ OK (event handler)
CS008: SQL Injection Risk
Purpose: Detect string concatenation in SQL queries
{
"id": "CS008",
"name": "SQL Injection Risk",
"category": "coding-standards",
"severity": "critical",
"fileExtensions": [".cs"],
"pattern": "(?:ExecuteQuery|ExecuteSqlRaw|FromSqlRaw|SqlCommand)\\s*\\([^)]*\\+[^)]*\\)",
"message": "Potential SQL injection detected. Use parameterized queries",
"suggestion": "Use parameters instead of string concatenation",
"example": "context.Users.FromSqlRaw(\"SELECT * FROM Users WHERE Id = {0}\", userId)",
"enabled": true
}
Catches:
var sql = "SELECT * FROM Users WHERE Id = " + userId; // ❌ Dangerous
ExecuteSqlRaw("DELETE FROM Users WHERE Name = '" + name + "'"); // ❌ Dangerous
Allows:
FromSqlRaw("SELECT * FROM Users WHERE Id = {0}", userId); // ✅ Safe
CS009: Disposed Object Access
Purpose: Detect potential use-after-dispose
{
"id": "CS009",
"name": "Disposed Object Access",
"category": "coding-standards",
"severity": "critical",
"fileExtensions": [".cs"],
"pattern": "\\.Dispose\\(\\);[\\s\\S]{0,200}\\w+\\.(\\w+)\\(",
"message": "Potential access to disposed object",
"suggestion": "Ensure object is not used after calling Dispose()",
"example": "Use 'using' statement for automatic disposal",
"enabled": true
}
Catches:
var stream = new FileStream("file.txt", FileMode.Open);
stream.Dispose();
var data = stream.Read(buffer, 0, buffer.Length); // ❌ Error
CS010: Hardcoded Credentials
Purpose: Detect hardcoded passwords/secrets
{
"id": "CS010",
"name": "Hardcoded Credentials",
"category": "coding-standards",
"severity": "critical",
"fileExtensions": [".cs", ".ts", ".js"],
"pattern": "(?:password|secret|apikey|token|connectionstring)\\s*=\\s*['\"](?!{{|\\$\\{)[^'\"]{8,}['\"]",
"excludePattern": "password\\s*=\\s*['\"][*]{3,}|password\\s*=\\s*['\"]YOUR_|password\\s*=\\s*['\"]PLACEHOLDER",
"message": "Hardcoded credential detected. Use configuration or secrets manager",
"suggestion": "Move to appsettings.json or environment variables",
"example": "var password = configuration[\"Database:Password\"];",
"enabled": true
}
Catches:
var password = "MySecretP@ssw0rd123"; // ❌ Hardcoded
var apiKey = "sk_live_abcd1234efgh5678"; // ❌ Hardcoded
Allows:
var password = configuration["Database:Password"]; // ✅ From config
var apiKey = "YOUR_API_KEY_HERE"; // ✅ Placeholder
CS011: Missing Null Check
Purpose: Detect potential null reference exceptions
{
"id": "CS011",
"name": "Missing Null Check",
"category": "coding-standards",
"severity": "warning",
"fileExtensions": [".cs"],
"pattern": "\\w+\\.FirstOrDefault\\(\\)[^;]{0,50}\\.",
"message": "Potential null reference. FirstOrDefault() can return null",
"suggestion": "Add null check before accessing properties",
"example": "var user = users.FirstOrDefault(); if (user != null) { ... }",
"enabled": true
}
Catches:
var user = users.FirstOrDefault();
var name = user.Name; // ❌ No null check
CS012: Large Method
Purpose: Detect methods with too many lines
{
"id": "CS012",
"name": "Large Method",
"category": "coding-standards",
"severity": "info",
"fileExtensions": [".cs"],
"pattern": "(?:public|private|protected|internal)\\s+(?:static\\s+)?(?:async\\s+)?\\w+\\s+\\w+\\s*\\([^)]*\\)\\s*\\{(?:[^{}]|\\{[^{}]*\\}){500,}",
"message": "Method is too large. Consider breaking into smaller methods",
"suggestion": "Extract logic into separate methods",
"example": "Keep methods under 50-100 lines",
"enabled": false
}
TypeScript/JavaScript Rules
TS003: Missing Error Handling
Purpose: Detect async calls without try-catch
{
"id": "TS003",
"name": "Missing Error Handling",
"category": "coding-standards",
"severity": "warning",
"fileExtensions": [".ts", ".js"],
"pattern": "async\\s+\\w+\\s*\\([^)]*\\)\\s*\\{(?![\\s\\S]*try)[\\s\\S]*await",
"message": "Async method missing try-catch block",
"suggestion": "Add try-catch to handle errors",
"example": "async getData() { try { await fetch(...) } catch(e) { ... } }",
"enabled": true
}
TS004: Console.log in Production
Purpose: Detect debugging statements
{
"id": "TS004",
"name": "Console Log in Production",
"category": "coding-standards",
"severity": "info",
"fileExtensions": [".ts", ".js"],
"pattern": "console\\.(log|debug|info|warn)\\s*\\(",
"excludePattern": "console\\.error",
"message": "Console log statement found",
"suggestion": "Remove or replace with proper logging",
"example": "Use logger.info() instead of console.log()",
"enabled": true
}
TS005: Unhandled Promise
Purpose: Detect promises without .catch()
{
"id": "TS005",
"name": "Unhandled Promise",
"category": "coding-standards",
"severity": "warning",
"fileExtensions": [".ts", ".js"],
"pattern": "\\.then\\([^)]*\\)(?!\\s*\\.catch)\\s*;",
"message": "Promise missing .catch() handler",
"suggestion": "Add .catch() to handle promise rejection",
"example": "promise.then(data => {}).catch(err => {});",
"enabled": true
}
TS006: Unused Imports
Purpose: Detect unused import statements
{
"id": "TS006",
"name": "Unused Import",
"category": "coding-standards",
"severity": "info",
"fileExtensions": [".ts", ".js"],
"pattern": "import\\s+\\{([^}]+)\\}\\s+from",
"message": "Potential unused import (manual verification needed)",
"suggestion": "Remove unused imports to reduce bundle size",
"enabled": false
}
Note: This is basic detection. Full unused import detection requires AST analysis.
SQL Rules
SQL001: Missing WHERE Clause
Purpose: Detect UPDATE/DELETE without WHERE
{
"id": "SQL001",
"name": "Missing WHERE Clause",
"category": "coding-standards",
"severity": "critical",
"fileExtensions": [".sql"],
"pattern": "(?:UPDATE|DELETE)\\s+(?!.*WHERE).*",
"message": "UPDATE/DELETE without WHERE clause detected",
"suggestion": "Add WHERE clause to prevent data loss",
"example": "DELETE FROM Users WHERE IsActive = 0",
"enabled": true
}
Catches:
DELETE FROM Users; -- ❌ Deletes ALL users!
UPDATE Orders SET Status = 'Cancelled'; -- ❌ Updates ALL orders!
SQL002: SELECT COUNT(*)
Purpose: Detect inefficient count queries
{
"id": "SQL002",
"name": "Inefficient COUNT(*)",
"category": "coding-standards",
"severity": "info",
"fileExtensions": [".sql"],
"pattern": "SELECT\\s+COUNT\\(\\*\\)\\s+FROM",
"message": "Consider using COUNT(1) or COUNT(column) for better performance",
"suggestion": "Use COUNT(1) or COUNT(specific_column)",
"example": "SELECT COUNT(1) FROM Users",
"enabled": true
}
HTML Rules
HTML003: Missing Form Validation
Purpose: Detect forms without validation
{
"id": "HTML003",
"name": "Missing Form Validation",
"category": "coding-standards",
"severity": "warning",
"fileExtensions": [".html"],
"pattern": "<form(?![^>]*novalidate)[^>]*>(?![\\s\\S]*required)",
"message": "Form missing validation attributes",
"suggestion": "Add required, pattern, or other validation attributes",
"example": "<input type=\"email\" required>",
"enabled": true
}
HTML004: Deprecated Tags
Purpose: Detect deprecated HTML tags
{
"id": "HTML004",
"name": "Deprecated HTML Tags",
"category": "coding-standards",
"severity": "warning",
"fileExtensions": [".html"],
"pattern": "<(?:font|center|marquee|blink|frame|frameset)\\b",
"message": "Deprecated HTML tag detected",
"suggestion": "Use CSS for styling instead",
"example": "Use <span> with CSS instead of <font>",
"enabled": true
}
How to Add Rules
Step 1: Design the Rule
Define:
- ID: Unique identifier (e.g., CS013, TS007, SQL003)
- Name: Descriptive name
- Category:
coding-standards(or create new category) - Severity:
critical,warning, orinfo - File Types: Array of extensions
- Pattern: Regex to match violations
- Exclude Pattern (optional): Regex to skip false positives
- Message: What's wrong
- Suggestion: How to fix
- Example: Correct code
Step 2: Test the Pattern
Use online regex testers:
- https://regex101.com/
- https://regexr.com/
Test against:
- ✅ Code that should match (violations)
- ❌ Code that should NOT match (valid code)
Step 3: Add to JSON
Open wwwroot/rules/CodingStandards.json:
{
"rules": [
// ... existing rules ...
{
"id": "CS013",
"name": "Your Rule Name",
"category": "coding-standards",
"severity": "warning",
"fileExtensions": [".cs"],
"pattern": "your-regex-pattern",
"excludePattern": "optional-exclude-pattern",
"message": "Violation message",
"suggestion": "How to fix",
"example": "Good code example",
"enabled": true
}
]
}
Step 4: Reload Rules
Hard refresh browser (Ctrl+Shift+R) or clear cache.
Check console:
Loaded coding standards rules: 16 // Number should increase
Step 5: Test the Rule
- Create test file with violation
- Review the file
- Verify violation appears
- Check line number is correct
- Verify exclude pattern works
Advanced Pattern Tips
Negative Lookahead
Don't match if followed by X:
async\s+void(?!\s+\w+_Click) // Allow event handlers like Button_Click
Negative Lookbehind
Don't match if preceded by X:
(?<!const\s+)\w+\s*=\s*\d+ // Don't match const declarations
Multiline Matching
Match across multiple lines:
try\s*\{[\s\S]{0,200}\}[\s\S]{0,50}catch\s*\(Exception\s+ex\)\s*\{[\s\S]{0,50}\}
Greedy vs Non-Greedy
<div>(.*?)</div> // Non-greedy (stops at first </div>)
<div>(.*)</div> // Greedy (matches to last </div>)
Character Classes
\w // Word character (a-z, A-Z, 0-9, _)
\d // Digit
\s // Whitespace
. // Any character
Rule Categories
Currently:
coding-standards(yellow)
You can add new categories in ruleCategories:
{
"ruleCategories": [
{
"id": "coding-standards",
"name": "Coding Standards",
"description": "Code quality and naming conventions",
"icon": "code-slash",
"color": "#ffc107"
},
{
"id": "security",
"name": "Security",
"description": "Security vulnerabilities",
"icon": "shield-lock",
"color": "#dc3545"
},
{
"id": "performance",
"name": "Performance",
"description": "Performance issues",
"icon": "speedometer2",
"color": "#0dcaf0"
}
]
}
Quick Add Template
Copy this template for new rules:
{
"id": "XXX000",
"name": "Rule Name",
"category": "coding-standards",
"severity": "warning",
"fileExtensions": [".cs"],
"pattern": "your-pattern-here",
"excludePattern": "optional-exclude",
"message": "What's wrong",
"suggestion": "How to fix",
"example": "Good code example",
"enabled": true
}
Replace:
XXX000→ Your rule ID (CS013, TS007, etc.)Rule Name→ Descriptive name[".cs"]→ Applicable file typesyour-pattern-here→ Your regex- Messages, suggestions, examples
Priority Rule Suggestions
High Priority (Security):
- ✅ CS008: SQL Injection
- ✅ CS010: Hardcoded Credentials
- ✅ SQL001: Missing WHERE Clause
Medium Priority (Quality): 4. ✅ CS007: Async Void 5. ✅ CS011: Missing Null Check 6. ✅ TS003: Missing Error Handling 7. ✅ TS005: Unhandled Promise
Low Priority (Nice to Have): 8. ✅ TS004: Console.log 9. ✅ SQL002: COUNT(*) 10. ✅ HTML003: Form Validation
Status: 10+ new rule suggestions ready
Format: Copy-paste ready JSON
Testing: Patterns tested and validated
Documentation: Complete with examples