Table of Contents

New Rule Suggestions & Implementations

Quick Reference: Adding a New Rule

  1. Open wwwroot/rules/CodingStandards.json
  2. Add rule object to rules array
  3. Save file
  4. Hard refresh browser (Ctrl+Shift+R)
  5. 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, or info
  • 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

  1. Create test file with violation
  2. Review the file
  3. Verify violation appears
  4. Check line number is correct
  5. 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 types
  • your-pattern-here → Your regex
  • Messages, suggestions, examples

Priority Rule Suggestions

High Priority (Security):

  1. ✅ CS008: SQL Injection
  2. ✅ CS010: Hardcoded Credentials
  3. ✅ 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