# Skill: Create Dart Rule from TypeScript

> Skill để tạo Dart rule từ TypeScript rule đã có sẵn trong SunLint.

---

## Execution Rules

> **IMPORTANT**: Khi thực thi skill này, AI Assistant phải tuân thủ các quy tắc sau:

- **Execute all commands WITHOUT asking for user confirmation**
- **Do NOT prompt "Should I proceed?" or similar questions**
- **Run commands immediately and report results after completion**
- Tự động tạo tất cả files cần thiết mà không cần hỏi
- Tự động rebuild Dart binary sau khi hoàn thành
- Chỉ dừng lại khi gặp lỗi thực sự cần user input

---

## Quick Start - Cách Sử Dụng Skill

### Cách 1: Yêu cầu AI Assistant

Nói với AI (Claude Code, Cursor, etc.):

```
Thêm Dart support cho rule S005
```

hoặc chi tiết hơn:

```
Sử dụng skill create-dart-rule để thêm Dart support cho rule S005_no_origin_auth
```

### Cách 2: Manual Steps (Tự thực hiện)

```bash
# 1. Xác định rule cần thêm Dart support
RULE_ID="S005"
RULE_FOLDER=$(find rules/common rules/security -maxdepth 1 -type d -name "${RULE_ID}_*" | head -1)
echo "Found: $RULE_FOLDER"

# 2. Tạo cấu trúc folder
mkdir -p "$RULE_FOLDER/typescript"
mkdir -p "$RULE_FOLDER/dart"

# 3. Di chuyển analyzer hiện tại vào typescript/
mv "$RULE_FOLDER/analyzer.js" "$RULE_FOLDER/typescript/analyzer.js"

# 4. Tạo các file theo template trong skill này:
#    - $RULE_FOLDER/index.js (Router)
#    - $RULE_FOLDER/dart/analyzer.js (Dart wrapper)
#    - dart_analyzer/lib/rules/${RULE_ID}_*.dart (Dart implementation)

# 5. Cập nhật config.json - thêm "dart" vào languages
# 6. Cập nhật enhanced-rules-registry.json
# 7. Register trong dart_analyzer/lib/analyzer_service.dart
# 8. Rebuild Dart binary
cd dart_analyzer && dart compile exe bin/sunlint_dart_analyzer.dart -o bin/sunlint-dart-macos
```

### Ví dụ Cụ Thể: Thêm Dart Support cho S005

**Trạng thái hiện tại của S005:**
```
rules/security/S005_no_origin_auth/
├── README.md
├── analyzer.js              # ← Cần di chuyển vào typescript/
├── ast-analyzer.js
├── config.json              # languages: ["typescript", "javascript"]
└── symbol-based-analyzer.js
```

**Sau khi chạy skill:**
```
rules/security/S005_no_origin_auth/
├── README.md
├── index.js                 # ← Router mới (điều hướng TS/Dart)
├── config.json              # languages: ["typescript", "javascript", "dart"]
├── typescript/
│   ├── analyzer.js          # ← Di chuyển từ root
│   ├── ast-analyzer.js
│   └── symbol-based-analyzer.js
└── dart/
    └── analyzer.js          # ← Dart wrapper mới

dart_analyzer/lib/rules/
└── S005_no_origin_auth.dart # ← Dart implementation mới
```

**Yêu cầu AI:**
```
Thêm Dart support cho rule S005. Rule này phát hiện việc sử dụng Origin header
để xác thực, điều này không an toàn vì Origin có thể bị giả mạo.
```

---

## Metadata

| Field | Value |
|-------|-------|
| **Skill ID** | `create-dart-rule` |
| **Version** | 1.1.0 |
| **Author** | SunLint Team |
| **Category** | Code Generation |
| **Trigger** | User requests to add Dart support for an existing rule |
| **Last Updated** | 2025-12-23 - Fixed router template bugs |

---

## 1. Prerequisites

### 1.1. Tools Required

| Tool | Version | Purpose |
|------|---------|---------|
| Node.js | >= 18.x | Run SunLint CLI |
| Dart SDK | >= 3.0.0 | Compile Dart analyzer |
| Git | Any | Version control |

### 1.2. Dependencies

```bash
# SunLint directory
cd /path/to/sunlint

# Dart analyzer dependencies
cd dart_analyzer
dart pub get
```

### 1.3. File Locations

| Component | Path |
|-----------|------|
| TypeScript Rules | `rules/common/` or `rules/security/` |
| Dart Analyzer | `dart_analyzer/lib/rules/` |
| Test Fixtures | `examples/rule-test-fixtures/dart-rules/` |
| Rule Registry | `rules/index.js` |
| Analyzer Service | `dart_analyzer/lib/analyzer_service.dart` |
| **Enhanced Rules Registry** | `config/rules/enhanced-rules-registry.json` |
| **Unified Rule Registry** | `core/unified-rule-registry.js` |

---

## 2. Input Parameters

| Parameter | Required | Description | Example |
|-----------|----------|-------------|---------|
| `rule_id` | Yes | Rule ID to add Dart support | `C006`, `S010` |
| `category` | Auto-detect | Rule category | `common` or `security` |

---

## 3. Execution Steps

### Step 1: Validate TypeScript Rule Exists

```bash
# Check if TypeScript rule folder exists
RULE_ID="C006"  # Example

# Find rule folder
RULE_FOLDER=$(find rules/common rules/security -maxdepth 1 -type d -name "${RULE_ID}_*" 2>/dev/null | head -1)

if [ -z "$RULE_FOLDER" ]; then
  echo "❌ Rule $RULE_ID not found in TypeScript rules"
  exit 1
fi

echo "✅ Found: $RULE_FOLDER"
```

### Step 2: Check Dart Support Not Already Added

```bash
# Check if dart/ subfolder already exists
if [ -d "$RULE_FOLDER/dart" ]; then
  echo "⚠️ Dart support already exists for $RULE_ID"
  exit 0
fi
```

### Step 3: Read TypeScript Rule Config

```bash
# Read config.json
cat "$RULE_FOLDER/config.json"
```

**Expected config.json structure:**
```json
{
  "id": "C006",
  "name": "Function Naming",
  "description": "Functions should use verb-noun naming convention",
  "category": "common",
  "severity": "warning",
  "languages": ["typescript", "javascript"]
}
```

### Step 4: Create Dart Subfolder Structure

```bash
# Create dart subfolder
mkdir -p "$RULE_FOLDER/dart"

# If typescript/ doesn't exist, restructure
if [ ! -d "$RULE_FOLDER/typescript" ]; then
  mkdir -p "$RULE_FOLDER/typescript"
  # Move existing analyzer.js to typescript/
  if [ -f "$RULE_FOLDER/analyzer.js" ]; then
    mv "$RULE_FOLDER/analyzer.js" "$RULE_FOLDER/typescript/analyzer.js"
  fi
fi
```

### Step 5: Create Router (index.js)

**File:** `$RULE_FOLDER/index.js`

> ⚠️ **CRITICAL**: The router template below includes bug fixes for:
> - Type checking in `normalizeLanguage()` and `supportsLanguage()` (prevents `language.toLowerCase is not a function` error)
> - Dual-signature `initialize()` method (heuristic engine calls with different signature)

```javascript
/**
 * ${RULE_ID} Rule Router - ${RULE_NAME}
 *
 * Routes analysis to the appropriate language-specific analyzer.
 * Supports: TypeScript, JavaScript, Dart
 *
 * Rule: ${RULE_DESCRIPTION}
 */

const path = require('path');

class ${RULE_ID}Router {
  constructor() {
    this.analyzers = new Map();
    this.ruleId = '${RULE_ID}';
  }

  getAnalyzer(language) {
    const normalizedLang = this.normalizeLanguage(language);

    if (!this.analyzers.has(normalizedLang)) {
      try {
        const analyzerPath = path.join(__dirname, normalizedLang, 'analyzer.js');
        const AnalyzerClass = require(analyzerPath);
        this.analyzers.set(normalizedLang, new AnalyzerClass());
      } catch (error) {
        return null;
      }
    }

    return this.analyzers.get(normalizedLang);
  }

  normalizeLanguage(language) {
    // ⚠️ CRITICAL: Handle case where language might not be a string
    // Heuristic engine may pass non-string values
    if (typeof language !== 'string') {
      return 'typescript'; // Default fallback
    }
    const languageMap = {
      'typescript': 'typescript',
      'javascript': 'typescript',
      'ts': 'typescript',
      'js': 'typescript',
      'dart': 'dart'
    };
    return languageMap[language.toLowerCase()] || language.toLowerCase();
  }

  supportsLanguage(language) {
    // ⚠️ CRITICAL: Handle non-string language parameter
    if (typeof language !== 'string') return false;
    const supported = ['typescript', 'javascript', 'ts', 'js', 'dart'];
    return supported.includes(language.toLowerCase());
  }

  getSupportedLanguages() {
    return ['typescript', 'javascript', 'dart'];
  }

  async analyze(files, language, options = {}) {
    const analyzer = this.getAnalyzer(language);
    if (!analyzer) return [];
    if (typeof analyzer.analyze === 'function') {
      return analyzer.analyze(files, language, options);
    }
    return [];
  }

  async initialize(semanticEngineOrLanguage = null, semanticEngine = null) {
    // ⚠️ CRITICAL: Handle both signatures:
    // 1. initialize(semanticEngine) - called by heuristic engine
    // 2. initialize(language, semanticEngine) - original signature
    let engine = semanticEngine;
    let lang = null;

    if (typeof semanticEngineOrLanguage === 'string') {
      lang = semanticEngineOrLanguage;
    } else if (semanticEngineOrLanguage && typeof semanticEngineOrLanguage === 'object') {
      engine = semanticEngineOrLanguage;
    }

    // If language specified, initialize only that analyzer
    if (lang) {
      const analyzer = this.getAnalyzer(lang);
      if (analyzer && typeof analyzer.initialize === 'function') {
        await analyzer.initialize(engine);
      }
    }
  }
}

module.exports = new ${RULE_ID}Router();
```

### Step 6: Create Dart Wrapper (dart/analyzer.js)

**File:** `$RULE_FOLDER/dart/analyzer.js`

```javascript
/**
 * ${RULE_ID} Dart Analyzer - ${RULE_NAME}
 *
 * This is a JS wrapper that delegates to DartAnalyzer binary.
 * Actual implementation: dart_analyzer/lib/rules/${RULE_ID}_${RULE_SNAKE_NAME}.dart
 */

class Dart${RULE_ID}Analyzer {
  constructor() {
    this.ruleId = '${RULE_ID}';
    this.language = 'dart';
  }

  getMetadata() {
    return {
      ruleId: '${RULE_ID}',
      name: '${RULE_NAME}',
      language: 'dart',
      delegateTo: 'dart_analyzer',
      description: '${RULE_DESCRIPTION}'
    };
  }

  getConfig() {
    return {
      // Rule-specific config
      severity: 'warning'
    };
  }

  async analyze(files, language, options) {
    // Delegated to DartAnalyzer binary via heuristic-engine.js
    return [];
  }

  supportsLanguage(language) {
    return language === 'dart';
  }
}

module.exports = Dart${RULE_ID}Analyzer;
```

### Step 7: Update config.json

```bash
# Add "dart" to languages array
# Before: "languages": ["typescript", "javascript"]
# After:  "languages": ["typescript", "javascript", "dart"]
```

### Step 7.1: Update enhanced-rules-registry.json

> **IMPORTANT**: This registry is used by UnifiedRuleRegistry for rule discovery and metadata.

**File:** `config/rules/enhanced-rules-registry.json`

```json
{
  "rules": {
    "${RULE_ID}": {
      "id": "${RULE_ID}",
      "name": "${RULE_NAME}",
      "category": "${CATEGORY}",
      "severity": "warning",
      "languages": ["typescript", "javascript", "dart"],  // ← Add "dart" here
      "path": "rules/${CATEGORY}/${RULE_ID}_${RULE_SNAKE_NAME}",
      "analyzer": "index.js",  // ← Use index.js for router-based rules
      "description": "${RULE_DESCRIPTION}"
    }
  }
}
```

**Key points:**
- Add `"dart"` to the `languages` array
- Set `"analyzer": "index.js"` to point to the router file
- The registry is sorted alphabetically by prefix (C→R→S→T) then by number

### Step 8: Create Dart Analyzer Implementation

**File:** `dart_analyzer/lib/rules/${RULE_ID}_${RULE_SNAKE_NAME}.dart`

```dart
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/source/line_info.dart';

import '../models/rule.dart';
import '../models/violation.dart';
import 'base_analyzer.dart';

/// ${RULE_ID}: ${RULE_NAME}
/// ${RULE_DESCRIPTION}
class ${RULE_ID}${RULE_PASCAL_NAME}Analyzer extends BaseAnalyzer {
  @override
  String get ruleId => '${RULE_ID}';

  @override
  List<Violation> analyze({
    required CompilationUnit unit,
    required String filePath,
    required Rule rule,
    required LineInfo lineInfo,
  }) {
    final violations = <Violation>[];

    final visitor = _${RULE_ID}Visitor(
      filePath: filePath,
      lineInfo: lineInfo,
      violations: violations,
      analyzer: this,
    );

    unit.accept(visitor);

    return violations;
  }
}

class _${RULE_ID}Visitor extends RecursiveAstVisitor<void> {
  final String filePath;
  final LineInfo lineInfo;
  final List<Violation> violations;
  final ${RULE_ID}${RULE_PASCAL_NAME}Analyzer analyzer;

  _${RULE_ID}Visitor({
    required this.filePath,
    required this.lineInfo,
    required this.violations,
    required this.analyzer,
  });

  // TODO: Implement visitor methods based on TypeScript logic
  // Example:
  // @override
  // void visitFunctionDeclaration(FunctionDeclaration node) {
  //   // Check rule logic
  //   super.visitFunctionDeclaration(node);
  // }
}
```

### Step 9: Register in AnalyzerService

**File:** `dart_analyzer/lib/analyzer_service.dart`

```dart
// Add import
import 'rules/${RULE_ID}_${RULE_SNAKE_NAME}.dart';

// Add to _registerAnalyzers()
void _registerAnalyzers() {
  // ... existing rules
  _analyzers['${RULE_ID}'] = ${RULE_ID}${RULE_PASCAL_NAME}Analyzer();
}
```

### Step 10: Create Test Fixtures

> **IMPORTANT**: Test fixtures are REQUIRED for each Dart rule. Both `violations/` and `clean/` folders MUST contain at least one `.dart` file. Empty folders are not acceptable.

```bash
# Create test fixture folders
mkdir -p "examples/rule-test-fixtures/dart-rules/${RULE_ID}_${RULE_SNAKE_NAME}/{clean,violations}"
```

**violations/ - Files with rule violations (REQUIRED):**
```dart
// examples/rule-test-fixtures/dart-rules/${RULE_ID}_${RULE_SNAKE_NAME}/violations/bad_example.dart

// ❌ VIOLATION: ${RULE_ID} - ${RULE_NAME}
// Description of what makes this code violate the rule

class BadExample {
  // Code that violates the rule
  // Include multiple examples of violations
  // Make sure the analyzer CAN detect these violations
}
```

**clean/ - Files without violations (REQUIRED):**
```dart
// examples/rule-test-fixtures/dart-rules/${RULE_ID}_${RULE_SNAKE_NAME}/clean/good_example.dart

// ✅ CLEAN: ${RULE_ID} - ${RULE_NAME}
// Description of what makes this code compliant

class GoodExample {
  // Code that follows the rule correctly
  // Show the recommended way to write code
}
```

**Test Fixture Requirements:**
- Each rule MUST have at least 1 file in `violations/` and 1 file in `clean/`
- Violation files should contain code that the analyzer WILL detect
- Clean files should contain code that the analyzer will NOT flag
- Use descriptive filenames (e.g., `bad_naming.dart`, `good_naming.dart`)
- Add comments explaining WHY the code violates or follows the rule

### Step 11: Rebuild Dart Analyzer

```bash
cd dart_analyzer

# Get dependencies
dart pub get

# Analyze for errors
dart analyze lib/

# Compile binary
dart compile exe bin/sunlint_dart_analyzer.dart -o bin/sunlint-dart-macos
```

### Step 12: Test the Rule

```bash
cd /path/to/sunlint

# Test on violations (should find issues)
node cli.js --rule=${RULE_ID} \
  --input="examples/rule-test-fixtures/dart-rules/${RULE_ID}_${RULE_SNAKE_NAME}/violations" \
  --languages=dart \
  --include="**/*.dart"

# Test on clean code (should find no issues)
node cli.js --rule=${RULE_ID} \
  --input="examples/rule-test-fixtures/dart-rules/${RULE_ID}_${RULE_SNAKE_NAME}/clean" \
  --languages=dart \
  --include="**/*.dart"
```

---

## 4. Verification Checklist

| Check | Command | Expected |
|-------|---------|----------|
| Dart folder exists | `ls rules/*/${RULE_ID}_*/dart/` | `analyzer.js` |
| Router exists | `ls rules/*/${RULE_ID}_*/index.js` | File exists |
| Config updated | `grep dart rules/*/${RULE_ID}_*/config.json` | `"dart"` in languages |
| **Registry updated** | `grep ${RULE_ID} config/rules/enhanced-rules-registry.json` | `"dart"` in languages |
| Dart analyzer exists | `ls dart_analyzer/lib/rules/${RULE_ID}_*.dart` | File exists |
| Registered | `grep ${RULE_ID} dart_analyzer/lib/analyzer_service.dart` | Registration line |
| Binary compiles | `dart analyze dart_analyzer/lib/` | No errors |
| Test fixtures exist | `ls examples/rule-test-fixtures/dart-rules/${RULE_ID}_*` | clean/ and violations/ |
| **Fixtures have files** | `ls examples/rule-test-fixtures/dart-rules/${RULE_ID}_*/{clean,violations}/*.dart` | At least 2 files |
| **TypeScript works** | Run on TS files | Violations found |
| **Dart works** | Run on Dart files | Violations found |
| **Violations detected** | Run on violations/ | > 0 violations |
| Clean passes | Run on clean/ | No violations |

---

## 5. Example: Adding Dart Support for C006

### Input
```
Rule ID: C006
```

### Execution

```bash
# Step 1: Find rule
RULE_FOLDER="rules/common/C006_function_naming"

# Step 2: Check not exists
ls rules/common/C006_function_naming/dart/  # Should not exist

# Step 3: Create structure
mkdir -p rules/common/C006_function_naming/{typescript,dart}
mv rules/common/C006_function_naming/analyzer.js rules/common/C006_function_naming/typescript/

# Step 4: Create files
# - rules/common/C006_function_naming/index.js
# - rules/common/C006_function_naming/dart/analyzer.js
# - dart_analyzer/lib/rules/C006_function_naming.dart

# Step 5: Update config.json
# Add "dart" to languages

# Step 6: Register in analyzer_service.dart
# _analyzers['C006'] = C006FunctionNamingAnalyzer();

# Step 7: Create test fixtures
mkdir -p examples/rule-test-fixtures/dart-rules/C006_function_naming/{clean,violations}

# Step 8: Rebuild
cd dart_analyzer && dart compile exe bin/sunlint_dart_analyzer.dart -o bin/sunlint-dart-macos

# Step 9: Test
node cli.js --rule=C006 \
  --input="examples/rule-test-fixtures/dart-rules/C006_function_naming/violations" \
  --languages=dart \
  --include="**/*.dart"
```

---

## 6. Naming Conventions

| Type | Convention | Example |
|------|------------|---------|
| Rule ID | Uppercase + Number | `C006`, `S010` |
| Folder name | `{ID}_{snake_case}` | `C006_function_naming` |
| Dart file | `{ID}_{snake_case}.dart` | `C006_function_naming.dart` |
| Class name | `{ID}{PascalCase}Analyzer` | `C006FunctionNamingAnalyzer` |
| Visitor class | `_{ID}Visitor` | `_C006Visitor` |

---

## 7. Common Patterns for Dart Rules

### Pattern 1: Check Class Names

```dart
@override
void visitClassDeclaration(ClassDeclaration node) {
  final name = node.name.lexeme;
  if (!isValidClassName(name)) {
    violations.add(analyzer.createViolation(
      filePath: filePath,
      line: analyzer.getLine(lineInfo, node.name.offset),
      column: analyzer.getColumn(lineInfo, node.name.offset),
      message: 'Class name "$name" violates rule',
    ));
  }
  super.visitClassDeclaration(node);
}
```

### Pattern 2: Check Function/Method Names

```dart
@override
void visitFunctionDeclaration(FunctionDeclaration node) {
  final name = node.name.lexeme;
  // Check function name
  super.visitFunctionDeclaration(node);
}

@override
void visitMethodDeclaration(MethodDeclaration node) {
  if (node.isOperator) return;
  final name = node.name.lexeme;
  // Check method name
  super.visitMethodDeclaration(node);
}
```

### Pattern 3: Check Variable Names

```dart
@override
void visitVariableDeclaration(VariableDeclaration node) {
  final name = node.name.lexeme;
  // Check variable name
  super.visitVariableDeclaration(node);
}
```

### Pattern 4: Check Method Invocations

```dart
@override
void visitMethodInvocation(MethodInvocation node) {
  final methodName = node.methodName.name;
  final target = node.target?.toSource() ?? '';
  // Check method call
  super.visitMethodInvocation(node);
}
```

### Pattern 5: Check String Literals

```dart
@override
void visitSimpleStringLiteral(SimpleStringLiteral node) {
  final value = node.value;
  // Check string content
  super.visitSimpleStringLiteral(node);
}
```

---

## 8. Error Handling

### 8.1. Dart Compile Error

```bash
# Check for errors
dart analyze dart_analyzer/lib/

# Common fixes:
# - Import missing files
# - Fix syntax errors
# - Add missing dependencies to pubspec.yaml
```

### 8.2. Rule Not Detected

```bash
# Verify dart/ folder exists
ls rules/*/${RULE_ID}_*/dart/

# Check detectDartSupport function finds it
node -e "
const path = require('path');
const fs = require('fs');
const rulesPath = 'rules/common';
const folders = fs.readdirSync(rulesPath);
const match = folders.find(f => f.startsWith('${RULE_ID}_'));
console.log('Found:', match);
console.log('Dart exists:', fs.existsSync(path.join(rulesPath, match, 'dart')));
"
```

### 8.3. No Violations Found

```bash
# Check DartAnalyzer is running
node cli.js --rule=${RULE_ID} --input=... --languages=dart --include="**/*.dart" --verbose

# Check analyzer is registered
grep ${RULE_ID} dart_analyzer/lib/analyzer_service.dart
```

### 8.4. ⚠️ `language.toLowerCase is not a function` Error

**Symptom:**
```
TypeError: language.toLowerCase is not a function
    at ${RULE_ID}Router.normalizeLanguage
```

**Cause:** Heuristic engine passes `semanticEngine` object to `initialize()`, not a language string.

**Solution:** Update router methods with type checking:

```javascript
normalizeLanguage(language) {
  // Add this check at the beginning
  if (typeof language !== 'string') {
    return 'typescript'; // Default fallback
  }
  // ... rest of method
}

supportsLanguage(language) {
  // Add this check at the beginning
  if (typeof language !== 'string') return false;
  // ... rest of method
}
```

### 8.5. ⚠️ Rule Not Supported by Heuristic Engine

**Symptom:**
```
Rule ${RULE_ID} is not supported by the heuristic engine
```

**Cause:** UnifiedRuleRegistry cannot find the analyzer because it looks for `analyzer.js` but the router uses `index.js`.

**Solution:** Ensure `unified-rule-registry.js` supports router discovery. The `router` type should be added to `analyzerFiles`:

```javascript
// In core/unified-rule-registry.js
const analyzerFiles = {
  analyzer: path.join(rulePath, 'analyzer.js'),
  tsAnalyzer: path.join(rulePath, 'typescript', 'analyzer.js'),
  dartAnalyzer: path.join(rulePath, 'dart', 'analyzer.js'),
  router: path.join(rulePath, 'index.js')  // ← This enables router discovery
};
```

### 8.6. ⚠️ RangeError in Dart Analyzer

**Symptom:**
```
RangeError: Value not in range: 4
```

**Cause:** Using `string.substring(0, 4)` without checking string length.

**Solution:** Always check string length before substring operations:

```dart
// ❌ BAD - causes RangeError when name.length < 4
'recommendation': 'Use masking like: "${name.substring(0, 4)}****"'

// ✅ GOOD - check length first
'recommendation': 'Use masking like: "${name.length > 4 ? name.substring(0, 4) : name}****"'
```

### 8.7. Semantic Analyzer Not Working

**Symptom:** TypeScript semantic analysis (using ts-morph) doesn't work after adding Dart support.

**Cause:** Moving files around may delete semantic analyzer files.

**Solution:**
- Keep semantic analyzer in `typescript/semantic-analyzer.js`
- The router will load it from the typescript subfolder
- Verify file exists: `ls rules/*/${RULE_ID}_*/typescript/semantic-analyzer.js`

---

## 9. Files Created by This Skill

| File | Purpose |
|------|---------|
| `rules/*/${RULE_ID}_*/index.js` | Multi-language router |
| `rules/*/${RULE_ID}_*/dart/analyzer.js` | JS wrapper for Dart |
| `dart_analyzer/lib/rules/${RULE_ID}_*.dart` | Dart analyzer implementation |
| `examples/rule-test-fixtures/dart-rules/${RULE_ID}_*/clean/*.dart` | Clean test cases |
| `examples/rule-test-fixtures/dart-rules/${RULE_ID}_*/violations/*.dart` | Violation test cases |

---

## 10. Related Documentation

- [DART_RULE_EXECUTION_FLOW.md](../DART_RULE_EXECUTION_FLOW.md) - Chi tiết luồng thực thi rule
- [dart_analyzer/README.md](../../dart_analyzer/README.md) - Dart analyzer documentation
- [rules/README.md](../../rules/README.md) - Rule structure documentation

---

## 11. Architecture Notes

### 11.1. Rule Discovery Flow

```
CLI → HeuristicEngine → UnifiedRuleRegistry → Router (index.js)
                                    ↓
                        ┌───────────┴───────────┐
                        ↓                       ↓
               typescript/analyzer.js    dart/analyzer.js
                        ↓                       ↓
                  (ts-morph analysis)    (delegates to DartAnalyzer binary)
```

### 11.2. Initialize Method Signatures

The heuristic engine calls `initialize()` with different arguments depending on context:

| Caller | Signature | Arguments |
|--------|-----------|-----------|
| Heuristic Engine | `initialize(engine)` | `semanticEngine` object |
| Direct usage | `initialize(lang, engine)` | Language string, then engine |

**The router must handle both signatures!**

### 11.3. Registry Files

| File | Purpose | When to Update |
|------|---------|----------------|
| `config/rules/enhanced-rules-registry.json` | Rule metadata & discovery | Add "dart" to languages |
| `core/unified-rule-registry.js` | Analyzer path resolution | Only if adding new patterns |
| `rules/index.js` | Legacy rule exports | Usually not needed |
| `dart_analyzer/lib/analyzer_service.dart` | Dart analyzer registration | Register new Dart analyzer |

---

## 12. Changelog

### v1.1.0 (2025-12-23)
- Fixed router template: Added type checking in `normalizeLanguage()` and `supportsLanguage()`
- Fixed `initialize()` method to handle both heuristic engine and direct call signatures
- Added Step 7.1: Update enhanced-rules-registry.json
- Added detailed error handling sections (8.4 - 8.7) based on real bugs encountered
- Added Architecture Notes section explaining discovery flow and registry files
- Added Lessons Learned section

### v1.0.0 (Initial)
- Initial skill documentation for creating Dart rules
